From 041d1ea37802bf7178a31a53f96c26efa6b8fb7b Mon Sep 17 00:00:00 2001 From: James Date: Fri, 16 Nov 2012 10:41:01 +0000 Subject: fish --- util/bash-completion.d/Makefile.am | 13 + util/bash-completion.d/Makefile.in | 963 ++++++++++++++ util/bash-completion.d/grub-completion.bash.in | 489 +++++++ util/bin2h.c | 127 ++ util/deviceiter.c | 891 +++++++++++++ util/devicemap.c | 13 + util/grub-editenv.c | 313 +++++ util/grub-fstest.c | 557 ++++++++ util/grub-install.in | 666 ++++++++++ util/grub-kbdcomp.in | 12 + util/grub-macho2img.c | 118 ++ util/grub-menulst2cfg.c | 126 ++ util/grub-mkconfig.in | 308 +++++ util/grub-mkconfig_lib.in | 227 ++++ util/grub-mkdevicemap.c | 171 +++ util/grub-mkfont.c | 1240 ++++++++++++++++++ util/grub-mkimage.c | 1620 ++++++++++++++++++++++++ util/grub-mkimagexx.c | 756 +++++++++++ util/grub-mklayout.c | 505 ++++++++ util/grub-mknetdir.in | 230 ++++ util/grub-mkpasswd-pbkdf2.c | 314 +++++ util/grub-mkrelpath.c | 109 ++ util/grub-mkrescue.in | 315 +++++ util/grub-pe2elf.c | 537 ++++++++ util/grub-probe.c | 419 ++++++ util/grub-reboot.in | 135 ++ util/grub-script-check.c | 201 +++ util/grub-set-default.in | 126 ++ util/grub-setup.c | 1017 +++++++++++++++ util/grub.d/00_header.in | 271 ++++ util/grub.d/10_hurd.in | 127 ++ util/grub.d/10_kfreebsd.in | 192 +++ util/grub.d/10_linux.in | 199 +++ util/grub.d/10_netbsd.in | 143 +++ util/grub.d/10_windows.in | 94 ++ util/grub.d/20_linux_xen.in | 174 +++ util/grub.d/30_os-prober.in | 204 +++ util/grub.d/40_custom.in | 5 + util/grub.d/41_custom.in | 7 + util/grub.d/README | 11 + util/i386/efi/grub-dumpdevtree | 22 + util/ieee1275/devicemap.c | 49 + util/ieee1275/grub-ofpathname.c | 47 + util/ieee1275/ofpath.c | 425 +++++++ util/import_gcry.py | 346 +++++ util/import_unicode.py | 189 +++ util/lvm.c | 52 + util/misc.c | 379 ++++++ util/powerpc/ieee1275/grub-mkrescue.in | 143 +++ util/raid.c | 86 ++ util/resolve.c | 270 ++++ util/update-grub_lib.in | 23 + 52 files changed, 15976 insertions(+) create mode 100644 util/bash-completion.d/Makefile.am create mode 100644 util/bash-completion.d/Makefile.in create mode 100644 util/bash-completion.d/grub-completion.bash.in create mode 100644 util/bin2h.c create mode 100644 util/deviceiter.c create mode 100644 util/devicemap.c create mode 100644 util/grub-editenv.c create mode 100644 util/grub-fstest.c create mode 100644 util/grub-install.in create mode 100644 util/grub-kbdcomp.in create mode 100644 util/grub-macho2img.c create mode 100644 util/grub-menulst2cfg.c create mode 100644 util/grub-mkconfig.in create mode 100644 util/grub-mkconfig_lib.in create mode 100644 util/grub-mkdevicemap.c create mode 100644 util/grub-mkfont.c create mode 100644 util/grub-mkimage.c create mode 100644 util/grub-mkimagexx.c create mode 100644 util/grub-mklayout.c create mode 100644 util/grub-mknetdir.in create mode 100644 util/grub-mkpasswd-pbkdf2.c create mode 100644 util/grub-mkrelpath.c create mode 100644 util/grub-mkrescue.in create mode 100644 util/grub-pe2elf.c create mode 100644 util/grub-probe.c create mode 100644 util/grub-reboot.in create mode 100644 util/grub-script-check.c create mode 100644 util/grub-set-default.in create mode 100644 util/grub-setup.c create mode 100644 util/grub.d/00_header.in create mode 100644 util/grub.d/10_hurd.in create mode 100644 util/grub.d/10_kfreebsd.in create mode 100644 util/grub.d/10_linux.in create mode 100644 util/grub.d/10_netbsd.in create mode 100644 util/grub.d/10_windows.in create mode 100644 util/grub.d/20_linux_xen.in create mode 100644 util/grub.d/30_os-prober.in create mode 100644 util/grub.d/40_custom.in create mode 100644 util/grub.d/41_custom.in create mode 100644 util/grub.d/README create mode 100644 util/i386/efi/grub-dumpdevtree create mode 100644 util/ieee1275/devicemap.c create mode 100644 util/ieee1275/grub-ofpathname.c create mode 100644 util/ieee1275/ofpath.c create mode 100644 util/import_gcry.py create mode 100644 util/import_unicode.py create mode 100644 util/lvm.c create mode 100644 util/misc.c create mode 100644 util/powerpc/ieee1275/grub-mkrescue.in create mode 100644 util/raid.c create mode 100644 util/resolve.c create mode 100644 util/update-grub_lib.in (limited to 'util') diff --git a/util/bash-completion.d/Makefile.am b/util/bash-completion.d/Makefile.am new file mode 100644 index 0000000..136287c --- /dev/null +++ b/util/bash-completion.d/Makefile.am @@ -0,0 +1,13 @@ + +bash_completion_source = grub-completion.bash.in +bash_completion_script = grub + +EXTRA_DIST = $(bash_completion_source) + +CLEANFILES = $(bash_completion_script) config.log + +bashcompletiondir = $(sysconfdir)/bash_completion.d +bashcompletion_DATA = $(bash_completion_script) + +$(bash_completion_script): $(bash_completion_source) $(top_builddir)/config.status + $(top_builddir)/config.status --file=$@:$< diff --git a/util/bash-completion.d/Makefile.in b/util/bash-completion.d/Makefile.in new file mode 100644 index 0000000..960aefc --- /dev/null +++ b/util/bash-completion.d/Makefile.in @@ -0,0 +1,963 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = util/bash-completion.d +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/00gnulib.m4 \ + $(top_srcdir)/m4/alloca.m4 $(top_srcdir)/m4/argp.m4 \ + $(top_srcdir)/m4/asm-underscore.m4 $(top_srcdir)/m4/btowc.m4 \ + $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/dirname.m4 \ + $(top_srcdir)/m4/dos.m4 $(top_srcdir)/m4/double-slash-root.m4 \ + $(top_srcdir)/m4/errno_h.m4 $(top_srcdir)/m4/error.m4 \ + $(top_srcdir)/m4/extensions.m4 $(top_srcdir)/m4/fcntl-o.m4 \ + $(top_srcdir)/m4/float_h.m4 $(top_srcdir)/m4/fnmatch.m4 \ + $(top_srcdir)/m4/getdelim.m4 $(top_srcdir)/m4/getline.m4 \ + $(top_srcdir)/m4/getopt.m4 $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/gnulib-common.m4 \ + $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/include_next.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intmax_t.m4 \ + $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/langinfo_h.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/localcharset.m4 $(top_srcdir)/m4/locale-fr.m4 \ + $(top_srcdir)/m4/locale-ja.m4 $(top_srcdir)/m4/locale-zh.m4 \ + $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/malloc.m4 \ + $(top_srcdir)/m4/mbrtowc.m4 $(top_srcdir)/m4/mbsinit.m4 \ + $(top_srcdir)/m4/mbsrtowcs.m4 $(top_srcdir)/m4/mbstate_t.m4 \ + $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/mempcpy.m4 \ + $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/multiarch.m4 \ + $(top_srcdir)/m4/nl_langinfo.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/printf.m4 \ + $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/rawmemchr.m4 \ + $(top_srcdir)/m4/realloc.m4 $(top_srcdir)/m4/regex.m4 \ + $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sleep.m4 \ + $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stdbool.m4 \ + $(top_srcdir)/m4/stddef_h.m4 $(top_srcdir)/m4/stdint.m4 \ + $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/stdio_h.m4 \ + $(top_srcdir)/m4/stdlib_h.m4 $(top_srcdir)/m4/strcase.m4 \ + $(top_srcdir)/m4/strchrnul.m4 $(top_srcdir)/m4/strerror.m4 \ + $(top_srcdir)/m4/string_h.m4 $(top_srcdir)/m4/strings_h.m4 \ + $(top_srcdir)/m4/strndup.m4 $(top_srcdir)/m4/strnlen.m4 \ + $(top_srcdir)/m4/sys_wait_h.m4 $(top_srcdir)/m4/sysexits.m4 \ + $(top_srcdir)/m4/unistd_h.m4 $(top_srcdir)/m4/vasnprintf.m4 \ + $(top_srcdir)/m4/vsnprintf.m4 $(top_srcdir)/m4/warn-on-use.m4 \ + $(top_srcdir)/m4/wchar_h.m4 $(top_srcdir)/m4/wchar_t.m4 \ + $(top_srcdir)/m4/wcrtomb.m4 $(top_srcdir)/m4/wctype_h.m4 \ + $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/xsize.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config-util.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(bashcompletiondir)" +DATA = $(bashcompletion_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ADDR32 = @ADDR32@ +ALLOCA = @ALLOCA@ +ALLOCA_H = @ALLOCA_H@ +AMTAR = @AMTAR@ +APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@ +ASM_SYMBOL_PREFIX = @ASM_SYMBOL_PREFIX@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@ +BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@ +BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@ +BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@ +BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@ +BSS_START_SYMBOL = @BSS_START_SYMBOL@ +BUILD_CC = @BUILD_CC@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CMP = @CMP@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATA32 = @DATA32@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@ +EMULTIHOP_VALUE = @EMULTIHOP_VALUE@ +END_SYMBOL = @END_SYMBOL@ +ENOLINK_HIDDEN = @ENOLINK_HIDDEN@ +ENOLINK_VALUE = @ENOLINK_VALUE@ +EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@ +EOVERFLOW_VALUE = @EOVERFLOW_VALUE@ +ERRNO_H = @ERRNO_H@ +EXEEXT = @EXEEXT@ +FLOAT_H = @FLOAT_H@ +FNMATCH_H = @FNMATCH_H@ +FONT_SOURCE = @FONT_SOURCE@ +FREETYPE = @FREETYPE@ +GETOPT_H = @GETOPT_H@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLIBC21 = @GLIBC21@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNULIB_ATOLL = @GNULIB_ATOLL@ +GNULIB_BTOWC = @GNULIB_BTOWC@ +GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@ +GNULIB_CANONICALIZE_FILE_NAME = @GNULIB_CANONICALIZE_FILE_NAME@ +GNULIB_CHOWN = @GNULIB_CHOWN@ +GNULIB_CLOSE = @GNULIB_CLOSE@ +GNULIB_DPRINTF = @GNULIB_DPRINTF@ +GNULIB_DUP2 = @GNULIB_DUP2@ +GNULIB_DUP3 = @GNULIB_DUP3@ +GNULIB_ENVIRON = @GNULIB_ENVIRON@ +GNULIB_EUIDACCESS = @GNULIB_EUIDACCESS@ +GNULIB_FACCESSAT = @GNULIB_FACCESSAT@ +GNULIB_FCHDIR = @GNULIB_FCHDIR@ +GNULIB_FCHOWNAT = @GNULIB_FCHOWNAT@ +GNULIB_FCLOSE = @GNULIB_FCLOSE@ +GNULIB_FFLUSH = @GNULIB_FFLUSH@ +GNULIB_FOPEN = @GNULIB_FOPEN@ +GNULIB_FPRINTF = @GNULIB_FPRINTF@ +GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@ +GNULIB_FPURGE = @GNULIB_FPURGE@ +GNULIB_FPUTC = @GNULIB_FPUTC@ +GNULIB_FPUTS = @GNULIB_FPUTS@ +GNULIB_FREOPEN = @GNULIB_FREOPEN@ +GNULIB_FSEEK = @GNULIB_FSEEK@ +GNULIB_FSEEKO = @GNULIB_FSEEKO@ +GNULIB_FSYNC = @GNULIB_FSYNC@ +GNULIB_FTELL = @GNULIB_FTELL@ +GNULIB_FTELLO = @GNULIB_FTELLO@ +GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@ +GNULIB_FWRITE = @GNULIB_FWRITE@ +GNULIB_GETCWD = @GNULIB_GETCWD@ +GNULIB_GETDELIM = @GNULIB_GETDELIM@ +GNULIB_GETDOMAINNAME = @GNULIB_GETDOMAINNAME@ +GNULIB_GETDTABLESIZE = @GNULIB_GETDTABLESIZE@ +GNULIB_GETGROUPS = @GNULIB_GETGROUPS@ +GNULIB_GETHOSTNAME = @GNULIB_GETHOSTNAME@ +GNULIB_GETLINE = @GNULIB_GETLINE@ +GNULIB_GETLOADAVG = @GNULIB_GETLOADAVG@ +GNULIB_GETLOGIN = @GNULIB_GETLOGIN@ +GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@ +GNULIB_GETPAGESIZE = @GNULIB_GETPAGESIZE@ +GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@ +GNULIB_GETUSERSHELL = @GNULIB_GETUSERSHELL@ +GNULIB_GRANTPT = @GNULIB_GRANTPT@ +GNULIB_LCHOWN = @GNULIB_LCHOWN@ +GNULIB_LINK = @GNULIB_LINK@ +GNULIB_LINKAT = @GNULIB_LINKAT@ +GNULIB_LSEEK = @GNULIB_LSEEK@ +GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@ +GNULIB_MBRLEN = @GNULIB_MBRLEN@ +GNULIB_MBRTOWC = @GNULIB_MBRTOWC@ +GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@ +GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@ +GNULIB_MBSCHR = @GNULIB_MBSCHR@ +GNULIB_MBSCSPN = @GNULIB_MBSCSPN@ +GNULIB_MBSINIT = @GNULIB_MBSINIT@ +GNULIB_MBSLEN = @GNULIB_MBSLEN@ +GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@ +GNULIB_MBSNLEN = @GNULIB_MBSNLEN@ +GNULIB_MBSNRTOWCS = @GNULIB_MBSNRTOWCS@ +GNULIB_MBSPBRK = @GNULIB_MBSPBRK@ +GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@ +GNULIB_MBSRCHR = @GNULIB_MBSRCHR@ +GNULIB_MBSRTOWCS = @GNULIB_MBSRTOWCS@ +GNULIB_MBSSEP = @GNULIB_MBSSEP@ +GNULIB_MBSSPN = @GNULIB_MBSSPN@ +GNULIB_MBSSTR = @GNULIB_MBSSTR@ +GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@ +GNULIB_MEMCHR = @GNULIB_MEMCHR@ +GNULIB_MEMMEM = @GNULIB_MEMMEM@ +GNULIB_MEMPCPY = @GNULIB_MEMPCPY@ +GNULIB_MEMRCHR = @GNULIB_MEMRCHR@ +GNULIB_MKDTEMP = @GNULIB_MKDTEMP@ +GNULIB_MKOSTEMP = @GNULIB_MKOSTEMP@ +GNULIB_MKOSTEMPS = @GNULIB_MKOSTEMPS@ +GNULIB_MKSTEMP = @GNULIB_MKSTEMP@ +GNULIB_MKSTEMPS = @GNULIB_MKSTEMPS@ +GNULIB_NL_LANGINFO = @GNULIB_NL_LANGINFO@ +GNULIB_OBSTACK_PRINTF = @GNULIB_OBSTACK_PRINTF@ +GNULIB_OBSTACK_PRINTF_POSIX = @GNULIB_OBSTACK_PRINTF_POSIX@ +GNULIB_PERROR = @GNULIB_PERROR@ +GNULIB_PIPE2 = @GNULIB_PIPE2@ +GNULIB_POPEN = @GNULIB_POPEN@ +GNULIB_PREAD = @GNULIB_PREAD@ +GNULIB_PRINTF = @GNULIB_PRINTF@ +GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@ +GNULIB_PTSNAME = @GNULIB_PTSNAME@ +GNULIB_PUTC = @GNULIB_PUTC@ +GNULIB_PUTCHAR = @GNULIB_PUTCHAR@ +GNULIB_PUTENV = @GNULIB_PUTENV@ +GNULIB_PUTS = @GNULIB_PUTS@ +GNULIB_PWRITE = @GNULIB_PWRITE@ +GNULIB_RANDOM_R = @GNULIB_RANDOM_R@ +GNULIB_RAWMEMCHR = @GNULIB_RAWMEMCHR@ +GNULIB_READLINK = @GNULIB_READLINK@ +GNULIB_READLINKAT = @GNULIB_READLINKAT@ +GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@ +GNULIB_REALPATH = @GNULIB_REALPATH@ +GNULIB_REMOVE = @GNULIB_REMOVE@ +GNULIB_RENAME = @GNULIB_RENAME@ +GNULIB_RENAMEAT = @GNULIB_RENAMEAT@ +GNULIB_RMDIR = @GNULIB_RMDIR@ +GNULIB_RPMATCH = @GNULIB_RPMATCH@ +GNULIB_SETENV = @GNULIB_SETENV@ +GNULIB_SLEEP = @GNULIB_SLEEP@ +GNULIB_SNPRINTF = @GNULIB_SNPRINTF@ +GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@ +GNULIB_STDIO_H_SIGPIPE = @GNULIB_STDIO_H_SIGPIPE@ +GNULIB_STPCPY = @GNULIB_STPCPY@ +GNULIB_STPNCPY = @GNULIB_STPNCPY@ +GNULIB_STRCASESTR = @GNULIB_STRCASESTR@ +GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@ +GNULIB_STRDUP = @GNULIB_STRDUP@ +GNULIB_STRERROR = @GNULIB_STRERROR@ +GNULIB_STRNCAT = @GNULIB_STRNCAT@ +GNULIB_STRNDUP = @GNULIB_STRNDUP@ +GNULIB_STRNLEN = @GNULIB_STRNLEN@ +GNULIB_STRPBRK = @GNULIB_STRPBRK@ +GNULIB_STRSEP = @GNULIB_STRSEP@ +GNULIB_STRSIGNAL = @GNULIB_STRSIGNAL@ +GNULIB_STRSTR = @GNULIB_STRSTR@ +GNULIB_STRTOD = @GNULIB_STRTOD@ +GNULIB_STRTOK_R = @GNULIB_STRTOK_R@ +GNULIB_STRTOLL = @GNULIB_STRTOLL@ +GNULIB_STRTOULL = @GNULIB_STRTOULL@ +GNULIB_STRVERSCMP = @GNULIB_STRVERSCMP@ +GNULIB_SYMLINK = @GNULIB_SYMLINK@ +GNULIB_SYMLINKAT = @GNULIB_SYMLINKAT@ +GNULIB_TMPFILE = @GNULIB_TMPFILE@ +GNULIB_TTYNAME_R = @GNULIB_TTYNAME_R@ +GNULIB_UNISTD_H_GETOPT = @GNULIB_UNISTD_H_GETOPT@ +GNULIB_UNISTD_H_SIGPIPE = @GNULIB_UNISTD_H_SIGPIPE@ +GNULIB_UNLINK = @GNULIB_UNLINK@ +GNULIB_UNLINKAT = @GNULIB_UNLINKAT@ +GNULIB_UNLOCKPT = @GNULIB_UNLOCKPT@ +GNULIB_UNSETENV = @GNULIB_UNSETENV@ +GNULIB_USLEEP = @GNULIB_USLEEP@ +GNULIB_VASPRINTF = @GNULIB_VASPRINTF@ +GNULIB_VDPRINTF = @GNULIB_VDPRINTF@ +GNULIB_VFPRINTF = @GNULIB_VFPRINTF@ +GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@ +GNULIB_VPRINTF = @GNULIB_VPRINTF@ +GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@ +GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@ +GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@ +GNULIB_WCRTOMB = @GNULIB_WCRTOMB@ +GNULIB_WCSNRTOMBS = @GNULIB_WCSNRTOMBS@ +GNULIB_WCSRTOMBS = @GNULIB_WCSRTOMBS@ +GNULIB_WCTOB = @GNULIB_WCTOB@ +GNULIB_WCWIDTH = @GNULIB_WCWIDTH@ +GNULIB_WRITE = @GNULIB_WRITE@ +GNULIB__EXIT = @GNULIB__EXIT@ +GREP = @GREP@ +GRUB_BOOT_MACHINE_LINK_ADDR = @GRUB_BOOT_MACHINE_LINK_ADDR@ +HAVE_ASM_USCORE = @HAVE_ASM_USCORE@ +HAVE_ATOLL = @HAVE_ATOLL@ +HAVE_BTOWC = @HAVE_BTOWC@ +HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@ +HAVE_CHOWN = @HAVE_CHOWN@ +HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@ +HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@ +HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@ +HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@ +HAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@ +HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@ +HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@ +HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@ +HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@ +HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@ +HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@ +HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@ +HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@ +HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@ +HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@ +HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@ +HAVE_DECL_STRSIGNAL = @HAVE_DECL_STRSIGNAL@ +HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@ +HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@ +HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@ +HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@ +HAVE_DPRINTF = @HAVE_DPRINTF@ +HAVE_DUP2 = @HAVE_DUP2@ +HAVE_DUP3 = @HAVE_DUP3@ +HAVE_EUIDACCESS = @HAVE_EUIDACCESS@ +HAVE_FACCESSAT = @HAVE_FACCESSAT@ +HAVE_FCHDIR = @HAVE_FCHDIR@ +HAVE_FCHOWNAT = @HAVE_FCHOWNAT@ +HAVE_FSEEKO = @HAVE_FSEEKO@ +HAVE_FSYNC = @HAVE_FSYNC@ +HAVE_FTELLO = @HAVE_FTELLO@ +HAVE_FTRUNCATE = @HAVE_FTRUNCATE@ +HAVE_GETDOMAINNAME = @HAVE_GETDOMAINNAME@ +HAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@ +HAVE_GETGROUPS = @HAVE_GETGROUPS@ +HAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@ +HAVE_GETLOGIN = @HAVE_GETLOGIN@ +HAVE_GETOPT_H = @HAVE_GETOPT_H@ +HAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@ +HAVE_GETSUBOPT = @HAVE_GETSUBOPT@ +HAVE_GRANTPT = @HAVE_GRANTPT@ +HAVE_INTTYPES_H = @HAVE_INTTYPES_H@ +HAVE_ISWBLANK = @HAVE_ISWBLANK@ +HAVE_ISWCNTRL = @HAVE_ISWCNTRL@ +HAVE_LANGINFO_CODESET = @HAVE_LANGINFO_CODESET@ +HAVE_LANGINFO_ERA = @HAVE_LANGINFO_ERA@ +HAVE_LANGINFO_H = @HAVE_LANGINFO_H@ +HAVE_LANGINFO_T_FMT_AMPM = @HAVE_LANGINFO_T_FMT_AMPM@ +HAVE_LANGINFO_YESEXPR = @HAVE_LANGINFO_YESEXPR@ +HAVE_LCHOWN = @HAVE_LCHOWN@ +HAVE_LINK = @HAVE_LINK@ +HAVE_LINKAT = @HAVE_LINKAT@ +HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@ +HAVE_MBRLEN = @HAVE_MBRLEN@ +HAVE_MBRTOWC = @HAVE_MBRTOWC@ +HAVE_MBSINIT = @HAVE_MBSINIT@ +HAVE_MBSLEN = @HAVE_MBSLEN@ +HAVE_MBSNRTOWCS = @HAVE_MBSNRTOWCS@ +HAVE_MBSRTOWCS = @HAVE_MBSRTOWCS@ +HAVE_MEMCHR = @HAVE_MEMCHR@ +HAVE_MEMPCPY = @HAVE_MEMPCPY@ +HAVE_MKDTEMP = @HAVE_MKDTEMP@ +HAVE_MKOSTEMP = @HAVE_MKOSTEMP@ +HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@ +HAVE_MKSTEMP = @HAVE_MKSTEMP@ +HAVE_MKSTEMPS = @HAVE_MKSTEMPS@ +HAVE_NL_LANGINFO = @HAVE_NL_LANGINFO@ +HAVE_OS_H = @HAVE_OS_H@ +HAVE_PIPE2 = @HAVE_PIPE2@ +HAVE_PREAD = @HAVE_PREAD@ +HAVE_PTSNAME = @HAVE_PTSNAME@ +HAVE_PWRITE = @HAVE_PWRITE@ +HAVE_RANDOM_H = @HAVE_RANDOM_H@ +HAVE_RANDOM_R = @HAVE_RANDOM_R@ +HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@ +HAVE_READLINK = @HAVE_READLINK@ +HAVE_READLINKAT = @HAVE_READLINKAT@ +HAVE_REALPATH = @HAVE_REALPATH@ +HAVE_RENAMEAT = @HAVE_RENAMEAT@ +HAVE_RPMATCH = @HAVE_RPMATCH@ +HAVE_SETENV = @HAVE_SETENV@ +HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@ +HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@ +HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@ +HAVE_SLEEP = @HAVE_SLEEP@ +HAVE_STDINT_H = @HAVE_STDINT_H@ +HAVE_STPCPY = @HAVE_STPCPY@ +HAVE_STPNCPY = @HAVE_STPNCPY@ +HAVE_STRCASECMP = @HAVE_STRCASECMP@ +HAVE_STRCASESTR = @HAVE_STRCASESTR@ +HAVE_STRCHRNUL = @HAVE_STRCHRNUL@ +HAVE_STRPBRK = @HAVE_STRPBRK@ +HAVE_STRSEP = @HAVE_STRSEP@ +HAVE_STRTOD = @HAVE_STRTOD@ +HAVE_STRTOLL = @HAVE_STRTOLL@ +HAVE_STRTOULL = @HAVE_STRTOULL@ +HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@ +HAVE_STRVERSCMP = @HAVE_STRVERSCMP@ +HAVE_SYMLINK = @HAVE_SYMLINK@ +HAVE_SYMLINKAT = @HAVE_SYMLINKAT@ +HAVE_SYSEXITS_H = @HAVE_SYSEXITS_H@ +HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@ +HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@ +HAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@ +HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@ +HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@ +HAVE_TTYNAME_R = @HAVE_TTYNAME_R@ +HAVE_UNISTD_H = @HAVE_UNISTD_H@ +HAVE_UNLINKAT = @HAVE_UNLINKAT@ +HAVE_UNLOCKPT = @HAVE_UNLOCKPT@ +HAVE_UNSETENV = @HAVE_UNSETENV@ +HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@ +HAVE_USLEEP = @HAVE_USLEEP@ +HAVE_VASPRINTF = @HAVE_VASPRINTF@ +HAVE_VDPRINTF = @HAVE_VDPRINTF@ +HAVE_WCHAR_H = @HAVE_WCHAR_H@ +HAVE_WCHAR_T = @HAVE_WCHAR_T@ +HAVE_WCRTOMB = @HAVE_WCRTOMB@ +HAVE_WCSNRTOMBS = @HAVE_WCSNRTOMBS@ +HAVE_WCSRTOMBS = @HAVE_WCSRTOMBS@ +HAVE_WCTYPE_H = @HAVE_WCTYPE_H@ +HAVE_WINT_T = @HAVE_WINT_T@ +HAVE__BOOL = @HAVE__BOOL@ +HAVE__EXIT = @HAVE__EXIT@ +HELP2MAN = @HELP2MAN@ +HOST_CC = @HOST_CC@ +HOST_CCASFLAGS = @HOST_CCASFLAGS@ +HOST_CFLAGS = @HOST_CFLAGS@ +HOST_CPPFLAGS = @HOST_CPPFLAGS@ +HOST_LDFLAGS = @HOST_LDFLAGS@ +INCLUDE_NEXT = @INCLUDE_NEXT@ +INCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCURSES = @LIBCURSES@ +LIBDEVMAPPER = @LIBDEVMAPPER@ +LIBGEOM = @LIBGEOM@ +LIBGNU_LIBDEPS = @LIBGNU_LIBDEPS@ +LIBGNU_LTLIBDEPS = @LIBGNU_LTLIBDEPS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLZMA = @LIBLZMA@ +LIBNVPAIR = @LIBNVPAIR@ +LIBOBJS = @LIBOBJS@ +LIBPCIACCESS = @LIBPCIACCESS@ +LIBS = @LIBS@ +LIBSDL = @LIBSDL@ +LIBUSB = @LIBUSB@ +LIBUTIL = @LIBUTIL@ +LIBZFS = @LIBZFS@ +LN_S = @LN_S@ +LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@ +LOCALE_FR = @LOCALE_FR@ +LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@ +LOCALE_JA = @LOCALE_JA@ +LOCALE_ZH_CN = @LOCALE_ZH_CN@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NEED_ENABLE_EXECUTE_STACK = @NEED_ENABLE_EXECUTE_STACK@ +NEED_REGISTER_FRAME_INFO = @NEED_REGISTER_FRAME_INFO@ +NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@ +NEXT_AS_FIRST_DIRECTIVE_FLOAT_H = @NEXT_AS_FIRST_DIRECTIVE_FLOAT_H@ +NEXT_AS_FIRST_DIRECTIVE_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@ +NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H = @NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H@ +NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@ +NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@ +NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@ +NEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@ +NEXT_AS_FIRST_DIRECTIVE_STRINGS_H = @NEXT_AS_FIRST_DIRECTIVE_STRINGS_H@ +NEXT_AS_FIRST_DIRECTIVE_STRING_H = @NEXT_AS_FIRST_DIRECTIVE_STRING_H@ +NEXT_AS_FIRST_DIRECTIVE_SYSEXITS_H = @NEXT_AS_FIRST_DIRECTIVE_SYSEXITS_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_WAIT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_WAIT_H@ +NEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@ +NEXT_AS_FIRST_DIRECTIVE_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@ +NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@ +NEXT_ERRNO_H = @NEXT_ERRNO_H@ +NEXT_FLOAT_H = @NEXT_FLOAT_H@ +NEXT_GETOPT_H = @NEXT_GETOPT_H@ +NEXT_LANGINFO_H = @NEXT_LANGINFO_H@ +NEXT_STDDEF_H = @NEXT_STDDEF_H@ +NEXT_STDINT_H = @NEXT_STDINT_H@ +NEXT_STDIO_H = @NEXT_STDIO_H@ +NEXT_STDLIB_H = @NEXT_STDLIB_H@ +NEXT_STRINGS_H = @NEXT_STRINGS_H@ +NEXT_STRING_H = @NEXT_STRING_H@ +NEXT_SYSEXITS_H = @NEXT_SYSEXITS_H@ +NEXT_SYS_WAIT_H = @NEXT_SYS_WAIT_H@ +NEXT_UNISTD_H = @NEXT_UNISTD_H@ +NEXT_WCHAR_H = @NEXT_WCHAR_H@ +NEXT_WCTYPE_H = @NEXT_WCTYPE_H@ +NM = @NM@ +OBJCONV = @OBJCONV@ +OBJCOPY = @OBJCOPY@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@ +PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@ +RANLIB = @RANLIB@ +REPLACE_BTOWC = @REPLACE_BTOWC@ +REPLACE_CALLOC = @REPLACE_CALLOC@ +REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@ +REPLACE_CHOWN = @REPLACE_CHOWN@ +REPLACE_CLOSE = @REPLACE_CLOSE@ +REPLACE_DPRINTF = @REPLACE_DPRINTF@ +REPLACE_DUP = @REPLACE_DUP@ +REPLACE_DUP2 = @REPLACE_DUP2@ +REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@ +REPLACE_FCLOSE = @REPLACE_FCLOSE@ +REPLACE_FFLUSH = @REPLACE_FFLUSH@ +REPLACE_FOPEN = @REPLACE_FOPEN@ +REPLACE_FPRINTF = @REPLACE_FPRINTF@ +REPLACE_FPURGE = @REPLACE_FPURGE@ +REPLACE_FREOPEN = @REPLACE_FREOPEN@ +REPLACE_FSEEK = @REPLACE_FSEEK@ +REPLACE_FSEEKO = @REPLACE_FSEEKO@ +REPLACE_FTELL = @REPLACE_FTELL@ +REPLACE_FTELLO = @REPLACE_FTELLO@ +REPLACE_GETCWD = @REPLACE_GETCWD@ +REPLACE_GETDELIM = @REPLACE_GETDELIM@ +REPLACE_GETGROUPS = @REPLACE_GETGROUPS@ +REPLACE_GETLINE = @REPLACE_GETLINE@ +REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@ +REPLACE_ISWBLANK = @REPLACE_ISWBLANK@ +REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@ +REPLACE_LCHOWN = @REPLACE_LCHOWN@ +REPLACE_LINK = @REPLACE_LINK@ +REPLACE_LINKAT = @REPLACE_LINKAT@ +REPLACE_LSEEK = @REPLACE_LSEEK@ +REPLACE_MALLOC = @REPLACE_MALLOC@ +REPLACE_MBRLEN = @REPLACE_MBRLEN@ +REPLACE_MBRTOWC = @REPLACE_MBRTOWC@ +REPLACE_MBSINIT = @REPLACE_MBSINIT@ +REPLACE_MBSNRTOWCS = @REPLACE_MBSNRTOWCS@ +REPLACE_MBSRTOWCS = @REPLACE_MBSRTOWCS@ +REPLACE_MBSTATE_T = @REPLACE_MBSTATE_T@ +REPLACE_MEMCHR = @REPLACE_MEMCHR@ +REPLACE_MEMMEM = @REPLACE_MEMMEM@ +REPLACE_MKSTEMP = @REPLACE_MKSTEMP@ +REPLACE_NL_LANGINFO = @REPLACE_NL_LANGINFO@ +REPLACE_NULL = @REPLACE_NULL@ +REPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@ +REPLACE_PERROR = @REPLACE_PERROR@ +REPLACE_POPEN = @REPLACE_POPEN@ +REPLACE_PREAD = @REPLACE_PREAD@ +REPLACE_PRINTF = @REPLACE_PRINTF@ +REPLACE_PUTENV = @REPLACE_PUTENV@ +REPLACE_PWRITE = @REPLACE_PWRITE@ +REPLACE_READLINK = @REPLACE_READLINK@ +REPLACE_REALLOC = @REPLACE_REALLOC@ +REPLACE_REALPATH = @REPLACE_REALPATH@ +REPLACE_REMOVE = @REPLACE_REMOVE@ +REPLACE_RENAME = @REPLACE_RENAME@ +REPLACE_RENAMEAT = @REPLACE_RENAMEAT@ +REPLACE_RMDIR = @REPLACE_RMDIR@ +REPLACE_SETENV = @REPLACE_SETENV@ +REPLACE_SLEEP = @REPLACE_SLEEP@ +REPLACE_SNPRINTF = @REPLACE_SNPRINTF@ +REPLACE_SPRINTF = @REPLACE_SPRINTF@ +REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@ +REPLACE_STPNCPY = @REPLACE_STPNCPY@ +REPLACE_STRCASESTR = @REPLACE_STRCASESTR@ +REPLACE_STRDUP = @REPLACE_STRDUP@ +REPLACE_STRERROR = @REPLACE_STRERROR@ +REPLACE_STRNCAT = @REPLACE_STRNCAT@ +REPLACE_STRNDUP = @REPLACE_STRNDUP@ +REPLACE_STRNLEN = @REPLACE_STRNLEN@ +REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@ +REPLACE_STRSTR = @REPLACE_STRSTR@ +REPLACE_STRTOD = @REPLACE_STRTOD@ +REPLACE_STRTOK_R = @REPLACE_STRTOK_R@ +REPLACE_SYMLINK = @REPLACE_SYMLINK@ +REPLACE_TMPFILE = @REPLACE_TMPFILE@ +REPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@ +REPLACE_UNLINK = @REPLACE_UNLINK@ +REPLACE_UNLINKAT = @REPLACE_UNLINKAT@ +REPLACE_UNSETENV = @REPLACE_UNSETENV@ +REPLACE_USLEEP = @REPLACE_USLEEP@ +REPLACE_VASPRINTF = @REPLACE_VASPRINTF@ +REPLACE_VDPRINTF = @REPLACE_VDPRINTF@ +REPLACE_VFPRINTF = @REPLACE_VFPRINTF@ +REPLACE_VPRINTF = @REPLACE_VPRINTF@ +REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@ +REPLACE_VSPRINTF = @REPLACE_VSPRINTF@ +REPLACE_WCRTOMB = @REPLACE_WCRTOMB@ +REPLACE_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@ +REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@ +REPLACE_WCTOB = @REPLACE_WCTOB@ +REPLACE_WCWIDTH = @REPLACE_WCWIDTH@ +REPLACE_WRITE = @REPLACE_WRITE@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@ +SIZE_T_SUFFIX = @SIZE_T_SUFFIX@ +STDBOOL_H = @STDBOOL_H@ +STDDEF_H = @STDDEF_H@ +STDINT_H = @STDINT_H@ +STRIP = @STRIP@ +SYSEXITS_H = @SYSEXITS_H@ +TARGET_APPLE_CC = @TARGET_APPLE_CC@ +TARGET_CC = @TARGET_CC@ +TARGET_CCAS = @TARGET_CCAS@ +TARGET_CCASFLAGS = @TARGET_CCASFLAGS@ +TARGET_CFLAGS = @TARGET_CFLAGS@ +TARGET_CPP = @TARGET_CPP@ +TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ +TARGET_IMG_BASE_LDOPT = @TARGET_IMG_BASE_LDOPT@ +TARGET_IMG_CFLAGS = @TARGET_IMG_CFLAGS@ +TARGET_IMG_LDFLAGS = @TARGET_IMG_LDFLAGS@ +TARGET_IMG_LDSCRIPT = @TARGET_IMG_LDSCRIPT@ +TARGET_LDFLAGS = @TARGET_LDFLAGS@ +TARGET_MODULE_FORMAT = @TARGET_MODULE_FORMAT@ +TARGET_OBJ2ELF = @TARGET_OBJ2ELF@ +UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@ +UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@ +UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@ +USE_APPLE_CC_FIXES = @USE_APPLE_CC_FIXES@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@ +WINT_T_SUFFIX = @WINT_T_SUFFIX@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_TARGET_CC = @ac_ct_TARGET_CC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +bootdirname = @bootdirname@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_efiemu = @enable_efiemu@ +enable_grub_emu_pci = @enable_grub_emu_pci@ +enable_grub_emu_sdl = @enable_grub_emu_sdl@ +enable_grub_emu_usb = @enable_grub_emu_usb@ +enable_grub_mkfont = @enable_grub_mkfont@ +exec_prefix = @exec_prefix@ +freetype_cflags = @freetype_cflags@ +freetype_libs = @freetype_libs@ +gl_LIBOBJS = @gl_LIBOBJS@ +gl_LTLIBOBJS = @gl_LTLIBOBJS@ +gltests_LIBOBJS = @gltests_LIBOBJS@ +gltests_LTLIBOBJS = @gltests_LTLIBOBJS@ +gltests_WITNESS = @gltests_WITNESS@ +grubdirname = @grubdirname@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_kernel = @host_kernel@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkglibrootdir = @pkglibrootdir@ +platform = @platform@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +bash_completion_source = grub-completion.bash.in +bash_completion_script = grub +EXTRA_DIST = $(bash_completion_source) +CLEANFILES = $(bash_completion_script) config.log +bashcompletiondir = $(sysconfdir)/bash_completion.d +bashcompletion_DATA = $(bash_completion_script) +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu util/bash-completion.d/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu util/bash-completion.d/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-bashcompletionDATA: $(bashcompletion_DATA) + @$(NORMAL_INSTALL) + test -z "$(bashcompletiondir)" || $(MKDIR_P) "$(DESTDIR)$(bashcompletiondir)" + @list='$(bashcompletion_DATA)'; test -n "$(bashcompletiondir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(bashcompletiondir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(bashcompletiondir)" || exit $$?; \ + done + +uninstall-bashcompletionDATA: + @$(NORMAL_UNINSTALL) + @list='$(bashcompletion_DATA)'; test -n "$(bashcompletiondir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bashcompletiondir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bashcompletiondir)" && rm -f $$files +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bashcompletiondir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-bashcompletionDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-bashcompletionDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-bashcompletionDATA install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am uninstall uninstall-am \ + uninstall-bashcompletionDATA + + +$(bash_completion_script): $(bash_completion_source) $(top_builddir)/config.status + $(top_builddir)/config.status --file=$@:$< + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in new file mode 100644 index 0000000..65cbb80 --- /dev/null +++ b/util/bash-completion.d/grub-completion.bash.in @@ -0,0 +1,489 @@ +# +# Bash completion for grub +# +# 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 . +# bash completion for grub + +__grub_dir() { + local i c=1 boot_dir + + for (( c=1; c <= ${#COMP_WORDS[@]}; c++ )); do + i="${COMP_WORDS[c]}" + case "$i" in + --boot-directory) + c=$((++c)) + i="${COMP_WORDS[c]}" + boot_dir="${i##*=}"; + break + ;; + esac + done + boot_dir=${boot_dir-/@bootdirname@} + echo "${boot_dir%/}/@grubdirname@" +} + + +# This function generates completion reply with compgen +# - arg: accepts 1, 2, 3, or 4 arguments +# $1 wordlist separate by space, tab or newline +# $2 (optional) prefix to add +# $3 (optional) current word to complete +# $4 (optional) suffix to add +__grubcomp () { + local cur="${COMP_WORDS[COMP_CWORD]}" + if [ $# -gt 2 ]; then + cur="$3" + fi + case "$cur" in + --*=) + COMPREPLY=() + ;; + *) + local IFS=' '$'\t'$'\n' + COMPREPLY=($(compgen -P "${2-}" -W "${1-}" -S "${4-}" -- "$cur")) + ;; + esac +} + +# Function that return long options from the help of the command +# - arg: $1 (optional) command to get the long options from +__grub_get_options_from_help () { + local prog + + if [ $# -ge 1 ]; then + prog="$1" + else + prog="${COMP_WORDS[0]}" + fi + + local i IFS=" "$'\t'$'\n' + for i in $(LC_ALL=C $prog --help) + do + case $i in + --*) echo "${i%=*}";; + esac + done +} + +# Function that return long options from the usage of the command +# - arg: $1 (optional) command to get the long options from +__grub_get_options_from_usage () { + local prog + + if [ $# -ge 1 ]; then + prog="$1" + else + prog="${COMP_WORDS[0]}" + fi + + local i IFS=" "$'\t'$'\n' + for i in $(LC_ALL=C $prog --usage) + do + case $i in + \[--*\]) i=${i#[} # Remove leading [ + echo ${i%%?(=*)]} # Remove optional value and trailing ] + ;; + esac + done +} + +__grub_get_last_option () { + local i + for (( i=$COMP_CWORD-1; i > 0; i-- )); do + if [[ "${COMP_WORDS[i]}" == -* ]]; then + echo "${COMP_WORDS[i]}" + break; + fi + done +} + +__grub_list_menuentries () { + local cur="${COMP_WORDS[COMP_CWORD]}" + local config_file=$(__grub_dir)/grub.cfg + + if [ -f "$config_file" ];then + local IFS=$'\n' + COMPREPLY=( $(compgen \ + -W "$( awk -F "[\"']" '/menuentry/ { print $2 }' $config_file )" \ + -- "$cur" )) #'# Help emacs syntax highlighting + fi +} + +__grub_list_modules () { + local grub_dir=$(__grub_dir) + local IFS=$'\n' + COMPREPLY=( $( compgen -f -X '!*/*.mod' -- "${grub_dir}/$cur" | { + while read -r tmp; do + [ -n $tmp ] && { + tmp=${tmp##*/} + printf '%s\n' ${tmp%.mod} + } + done + } + )) +} + +# +# grub-set-default & grub-reboot +# +_grub_set_entry () { + local cur prev split=false + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + + _split_longopt && split=true + + case "$prev" in + --boot-directory) + _filedir -d + return + ;; + esac + + $split && return 0 + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a menuentry + __grub_list_menuentries + fi +} + +__grub_set_default_program=$( echo grub-set-default | sed "@program_transform_name@" ) +have ${__grub_set_default_program} && \ + complete -F _grub_set_entry -o filenames ${__grub_set_default_program} +unset __grub_set_default_program + +__grub_reboot_program=$( echo grub-reboot | sed "@program_transform_name@" ) +have ${__grub_reboot_program} && \ + complete -F _grub_set_entry -o filenames ${__grub_reboot_program} +unset __grub_reboot_program + + +# +# grub-editenv +# +_grub_editenv () { + local cur prev + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + + case "$prev" in + create|list|set|unset) + COMPREPLY=( "" ) + return + ;; + esac + + __grubcomp "$(__grub_get_options_from_help) + create list set unset" +} + +__grub_editenv_program=$( echo grub-editenv | sed "@program_transform_name@" ) +have ${__grub_editenv_program} && \ + complete -F _grub_editenv -o filenames ${__grub_editenv_program} +unset __grub_editenv_program + + +# +# grub-mkconfig +# +_grub_mkconfig () { + local cur prev + + COMPREPLY=() + cur=`_get_cword` + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + _filedir + fi +} +__grub_mkconfig_program=$( echo grub-mkconfig | sed "@program_transform_name@" ) +have ${__grub_mkconfig_program} && \ + complete -F _grub_mkconfig -o filenames ${__grub_mkconfig_program} +unset __grub_mkconfig_program + + +# +# grub-setup +# +_grub_setup () { + local cur prev split=false + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + + _split_longopt && split=true + + case "$prev" in + -d|--directory) + _filedir -d + return + ;; + esac + + $split && return 0 + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a filename + _filedir + fi +} +__grub_setup_program=$( echo grub-setup | sed "@program_transform_name@" ) +have ${__grub_setup_program} && \ + complete -F _grub_setup -o filenames ${__grub_setup_program} +unset __grub_setup_program + + +# +# grub-install +# +_grub_install () { + local cur prev last split=false + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + last=$(__grub_get_last_option) + + _split_longopt && split=true + + case "$prev" in + --boot-directory) + _filedir -d + return + ;; + --disk-module) + __grubcomp "biosdisk ata" + return + ;; + esac + + $split && return 0 + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + case "$last" in + --modules) + __grub_list_modules + return + ;; + esac + + # Default complete with a filename + _filedir + fi +} +__grub_install_program=$( echo grub-install | sed "@program_transform_name@" ) +have ${__grub_install_program} && \ + complete -F _grub_install -o filenames ${__grub_install_program} +unset __grub_install_program + + +# +# grub-mkfont +# +_grub_mkfont () { + local cur + + COMPREPLY=() + cur=`_get_cword` + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a filename + _filedir + fi +} +__grub_mkfont_program=$( echo grub-mkfont | sed "@program_transform_name@" ) +have ${__grub_mkfont_program} && \ + complete -F _grub_mkfont -o filenames ${__grub_mkfont_program} +unset __grub_mkfont_program + + +# +# grub-mkrescue +# +_grub_mkrescue () { + local cur prev last + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + last=$(__grub_get_last_option) + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + case "$last" in + --modules) + __grub_list_modules + return + ;; + esac + + # Default complete with a filename + _filedir + fi +} +__grub_mkrescue_program=$( echo grub-mkrescue | sed "@program_transform_name@" ) +have ${__grub_mkrescue_program} && \ + complete -F _grub_mkrescue -o filenames ${__grub_mkrescue_program} +unset __grub_mkrescue_program + + +# +# grub-mkimage +# +_grub_mkimage () { + local cur prev split=false + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + + _split_longopt && split=true + + case "$prev" in + -d|--directory|-p|--prefix) + _filedir -d + return + ;; + -O|--format) + # Get available format from help + local prog=${COMP_WORDS[0]} + __grubcomp "$(LC_ALL=C $prog --help | \ + awk -F ":" '/available formats/ { print $2 }' | \ + sed 's/, / /g')" + return + ;; + esac + + $split && return 0 + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a filename + _filedir + fi +} +__grub_mkimage_program=$( echo grub-mkimage | sed "@program_transform_name@" ) +have ${__grub_mkimage_program} && \ + complete -F _grub_mkimage -o filenames ${__grub_mkimage_program} +unset __grub_mkimage_program + + +# +# grub-mkpasswd-pbkdf2 +# +_grub_mkpasswd-pbkdf2 () { + local cur + + COMPREPLY=() + cur=`_get_cword` + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a filename + _filedir + fi +} +__grub_mkpasswd_pbkdf2_program=$( echo grub-mkpasswd-pbkdf2 | sed "@program_transform_name@" ) +have ${__grub_mkpasswd_pbkdf2_program} && \ + complete -F _grub_mkpasswd-pbkdf2 -o filenames ${__grub_mkpasswd_pbkdf2_program} +unset __grub_mkpasswd_pbkdf2_program + + +# +# grub-probe +# +_grub_probe () { + local cur prev split=false + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + + _split_longopt && split=true + + case "$prev" in + -t|--target) + # Get target type from help + local prog=${COMP_WORDS[0]} + __grubcomp "$(LC_ALL=C $prog --help | \ + awk -F "[()]" '/--target=/ { print $2 }' | \ + sed 's/|/ /g')" + return + ;; + esac + + $split && return 0 + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a filename + _filedir + fi +} +__grub_probe_program=$( echo grub-probe | sed "@program_transform_name@" ) +have ${__grub_probe_program} && \ + complete -F _grub_probe -o filenames ${__grub_probe_program} +unset __grub_probe_program + + +# +# grub-script-check +# +_grub_script-check () { + local cur + + COMPREPLY=() + cur=`_get_cword` + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a filename + _filedir + fi +} +__grub_script_check_program=$( echo grub-script-check | sed "@program_transform_name@" ) +have ${__grub_script_check_program} && \ + complete -F _grub_script-check -o filenames ${__grub_script_check_program} + + +# Local variables: +# mode: shell-script +# sh-basic-offset: 4 +# sh-indent-comment: t +# indent-tabs-mode: nil +# End: +# ex: ts=4 sw=4 et filetype=sh diff --git a/util/bin2h.c b/util/bin2h.c new file mode 100644 index 0000000..ee1c7fd --- /dev/null +++ b/util/bin2h.c @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2008,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include + +#define _GNU_SOURCE 1 +#include + +#include "progname.h" + +static struct option options[] = + { + {"help", no_argument, 0, 'h' }, + {"version", no_argument, 0, 'V' }, + {0, 0, 0, 0 } + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, + "Try ``%s --help'' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTIONS] SYMBOL-NAME\n\ +\n\ +Convert a binary file to a C header.\n\ +\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ +\n\ +Report bugs to <%s>.\n\ +", program_name, PACKAGE_BUGREPORT); + + exit (status); +} + +int +main (int argc, char *argv[]) +{ + int b, i; + char *sym; + + set_program_name (argv[0]); + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "snm:r:hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + default: + usage (1); + break; + } + } + + if (optind >= argc) + usage (1); + + if (optind + 1 != argc) + usage (1); + + sym = argv[optind]; + + b = getchar (); + if (b == EOF) + goto abort; + + printf ("/* THIS CHUNK OF BYTES IS AUTOMATICALLY GENERATED */\n" + "unsigned char %s[] =\n{\n", sym); + + while (1) + { + printf ("0x%02x", b); + + b = getchar (); + if (b == EOF) + goto end; + + for (i = 0; i < 16 - 1; i++) + { + printf (", 0x%02x", b); + + b = getchar (); + if (b == EOF) + goto end; + } + + printf (",\n"); + } + +end: + printf ("\n};\n"); + +abort: + exit (0); +} diff --git a/util/deviceiter.c b/util/deviceiter.c new file mode 100644 index 0000000..30c18be --- /dev/null +++ b/util/deviceiter.c @@ -0,0 +1,891 @@ +/* deviceiter.c - iterate over system devices */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef __linux__ +# 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)) */ +# 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 FLOPPY_MAJOR +# define FLOPPY_MAJOR 2 /* the major number for floppy */ +# endif /* ! FLOPPY_MAJOR */ +# ifndef MAJOR +# define MAJOR(dev) \ + ({ \ + unsigned long long __dev = (dev); \ + (unsigned) ((__dev >> 8) & 0xfff) \ + | ((unsigned int) (__dev >> 32) & ~0xfff); \ + }) +# endif /* ! MAJOR */ +# ifndef MINOR +# define MINOR(dev) \ + ({ \ + unsigned long long __dev = (dev); \ + (unsigned) (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff); \ + }) +# endif /* ! MINOR */ +# ifndef CDROM_GET_CAPABILITY +# define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */ +# endif /* ! CDROM_GET_CAPABILITY */ +# ifndef BLKGETSIZE +# define BLKGETSIZE _IO(0x12,96) /* return device size */ +# endif /* ! BLKGETSIZE */ + +#ifdef HAVE_DEVICE_MAPPER +# include +#endif +#endif /* __linux__ */ + +/* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with + kFreeBSD-based non-FreeBSD systems (e.g. GNU/kFreeBSD) */ +#if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__) +# define __FreeBSD_kernel__ +#endif +#ifdef __FreeBSD_kernel__ + /* Obtain version of kFreeBSD headers */ +# include +# ifndef __FreeBSD_kernel_version +# define __FreeBSD_kernel_version __FreeBSD_version +# endif + + /* Runtime detection of kernel */ +# include +int +get_kfreebsd_version (void) +{ + struct utsname uts; + int major; + int minor; + int v[2]; + + uname (&uts); + sscanf (uts.release, "%d.%d", &major, &minor); + + if (major >= 9) + major = 9; + if (major >= 5) + { + v[0] = minor/10; v[1] = minor%10; + } + else + { + v[0] = minor%10; v[1] = minor/10; + } + return major*100000+v[0]*10000+v[1]*1000; +} +#endif /* __FreeBSD_kernel__ */ + +#if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) +# include /* ioctl */ +# include +# include /* CDIOCCLRDEBUG */ +# if defined(__FreeBSD_kernel__) +# include +# if __FreeBSD_kernel_version >= 500040 +# include +# endif +# endif /* __FreeBSD_kernel__ */ +#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */ + +#ifdef HAVE_OPENDISK +# include +#endif /* HAVE_OPENDISK */ + +#ifdef __linux__ +/* Check if we have devfs support. */ +static int +have_devfs (void) +{ + struct stat st; + return stat ("/dev/.devfsd", &st) == 0; +} +#endif /* __linux__ */ + +/* These three functions are quite different among OSes. */ +static void +get_floppy_disk_name (char *name, int unit) +{ +#if defined(__linux__) + /* GNU/Linux */ + if (have_devfs ()) + sprintf (name, "/dev/floppy/%d", unit); + else + sprintf (name, "/dev/fd%d", unit); +#elif defined(__GNU__) + /* GNU/Hurd */ + sprintf (name, "/dev/fd%d", unit); +#elif defined(__FreeBSD_kernel__) + /* kFreeBSD */ + if (get_kfreebsd_version () >= 400000) + sprintf (name, "/dev/fd%d", unit); + else + sprintf (name, "/dev/rfd%d", unit); +#elif defined(__NetBSD__) + /* NetBSD */ + /* opendisk() doesn't work for floppies. */ + sprintf (name, "/dev/rfd%da", unit); +#elif defined(__OpenBSD__) + /* OpenBSD */ + sprintf (name, "/dev/rfd%dc", unit); +#elif defined(__QNXNTO__) + /* QNX RTP */ + sprintf (name, "/dev/fd%d", unit); +#elif defined(__CYGWIN__) + /* Cygwin */ + sprintf (name, "/dev/fd%d", unit); +#elif defined(__MINGW32__) + (void) unit; + *name = 0; +#else +# warning "BIOS floppy drives cannot be guessed in your operating system." + /* Set NAME to a bogus string. */ + *name = 0; +#endif +} + +static void +get_ide_disk_name (char *name, int unit) +{ +#if defined(__linux__) + /* GNU/Linux */ + sprintf (name, "/dev/hd%c", unit + 'a'); +#elif defined(__GNU__) + /* GNU/Hurd */ + sprintf (name, "/dev/hd%d", unit); +#elif defined(__FreeBSD_kernel__) + /* kFreeBSD */ + if (get_kfreebsd_version () >= 400000) + sprintf (name, "/dev/ad%d", unit); + else + sprintf (name, "/dev/rwd%d", unit); +#elif defined(__NetBSD__) && defined(HAVE_OPENDISK) + /* NetBSD */ + char shortname[16]; + int fd; + + sprintf (shortname, "wd%d", unit); + fd = opendisk (shortname, O_RDONLY, name, + 16, /* length of NAME */ + 0 /* char device */ + ); + close (fd); +#elif defined(__OpenBSD__) + /* OpenBSD */ + sprintf (name, "/dev/rwd%dc", unit); +#elif defined(__QNXNTO__) + /* QNX RTP */ + /* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could + contain SCSI disks. */ + sprintf (name, "/dev/hd%d", unit); +#elif defined(__CYGWIN__) + /* Cygwin emulates all disks as /dev/sdX. */ + (void) unit; + *name = 0; +#elif defined(__MINGW32__) + sprintf (name, "//./PHYSICALDRIVE%d", unit); +#else +# warning "BIOS IDE drives cannot be guessed in your operating system." + /* Set NAME to a bogus string. */ + *name = 0; +#endif +} + +static void +get_scsi_disk_name (char *name, int unit) +{ +#if defined(__linux__) + /* GNU/Linux */ + sprintf (name, "/dev/sd%c", unit + 'a'); +#elif defined(__GNU__) + /* GNU/Hurd */ + sprintf (name, "/dev/sd%d", unit); +#elif defined(__FreeBSD_kernel__) + /* kFreeBSD */ + if (get_kfreebsd_version () >= 400000) + sprintf (name, "/dev/da%d", unit); + else + sprintf (name, "/dev/rda%d", unit); +#elif defined(__NetBSD__) && defined(HAVE_OPENDISK) + /* NetBSD */ + char shortname[16]; + int fd; + + sprintf (shortname, "sd%d", unit); + fd = opendisk (shortname, O_RDONLY, name, + 16, /* length of NAME */ + 0 /* char device */ + ); + close (fd); +#elif defined(__OpenBSD__) + /* OpenBSD */ + sprintf (name, "/dev/rsd%dc", unit); +#elif defined(__QNXNTO__) + /* QNX RTP */ + /* QNX RTP doesn't distinguish SCSI from IDE, so it is better to + disable the detection of SCSI disks here. */ + *name = 0; +#elif defined(__CYGWIN__) + /* Cygwin emulates all disks as /dev/sdX. */ + sprintf (name, "/dev/sd%c", unit + 'a'); +#elif defined(__MINGW32__) + (void) unit; + *name = 0; +#else +# warning "BIOS SCSI drives cannot be guessed in your operating system." + /* Set NAME to a bogus string. */ + *name = 0; +#endif +} + +#ifdef __linux__ +static void +get_virtio_disk_name (char *name, int unit) +{ +#ifdef __sparc__ + sprintf (name, "/dev/vdisk%c", unit + 'a'); +#else + sprintf (name, "/dev/vd%c", unit + 'a'); +#endif +} + +static void +get_dac960_disk_name (char *name, int controller, int drive) +{ + sprintf (name, "/dev/rd/c%dd%d", controller, drive); +} + +static void +get_acceleraid_disk_name (char *name, int controller, int drive) +{ + sprintf (name, "/dev/rs/c%dd%d", controller, drive); +} + +static void +get_ataraid_disk_name (char *name, int unit) +{ + sprintf (name, "/dev/ataraid/d%c", unit + '0'); +} + +static void +get_i2o_disk_name (char *name, char unit) +{ + sprintf (name, "/dev/i2o/hd%c", unit); +} + +static void +get_cciss_disk_name (char *name, int controller, int drive) +{ + sprintf (name, "/dev/cciss/c%dd%d", controller, drive); +} + +static void +get_ida_disk_name (char *name, int controller, int drive) +{ + sprintf (name, "/dev/ida/c%dd%d", controller, drive); +} + +static void +get_mmc_disk_name (char *name, int unit) +{ + sprintf (name, "/dev/mmcblk%d", unit); +} + +static void +get_xvd_disk_name (char *name, int unit) +{ + sprintf (name, "/dev/xvd%c", unit + 'a'); +} +#endif + +static struct seen_device +{ + struct seen_device *next; + const char *name; +} *seen; + +/* Check if DEVICE can be read. Skip any DEVICE that we have already seen. + If an error occurs, return zero, otherwise return non-zero. */ +static int +check_device_readable_unique (const char *device) +{ + char *real_device; + char buf[512]; + FILE *fp; + struct seen_device *seen_elt; + + /* If DEVICE is empty, just return error. */ + if (*device == 0) + return 0; + + /* Have we seen this device already? */ + real_device = canonicalize_file_name (device); + if (! real_device) + return 0; + if (grub_named_list_find (GRUB_AS_NAMED_LIST (seen), real_device)) + { + grub_dprintf ("deviceiter", "Already seen %s (%s)\n", + device, real_device); + goto fail; + } + + fp = fopen (device, "r"); + if (! fp) + { + switch (errno) + { +#ifdef ENOMEDIUM + case ENOMEDIUM: +# if 0 + /* At the moment, this finds only CDROMs, which can't be + read anyway, so leave it out. Code should be + reactivated if `removable disks' and CDROMs are + supported. */ + /* Accept it, it may be inserted. */ + return 1; +# endif + break; +#endif /* ENOMEDIUM */ + default: + /* Break case and leave. */ + break; + } + /* Error opening the device. */ + goto fail; + } + + /* Make sure CD-ROMs don't get assigned a BIOS disk number + before SCSI disks! */ +#ifdef __linux__ +# ifdef CDROM_GET_CAPABILITY + if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0) + goto fail; +# else /* ! CDROM_GET_CAPABILITY */ + /* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */ + { + struct hd_geometry hdg; + struct stat st; + + if (fstat (fileno (fp), &st)) + goto fail; + + /* If it is a block device and isn't a floppy, check if HDIO_GETGEO + succeeds. */ + if (S_ISBLK (st.st_mode) + && MAJOR (st.st_rdev) != FLOPPY_MAJOR + && ioctl (fileno (fp), HDIO_GETGEO, &hdg)) + goto fail; + } +# endif /* ! CDROM_GET_CAPABILITY */ +#endif /* __linux__ */ + +#if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) +# ifdef CDIOCCLRDEBUG + if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0) + goto fail; +# endif /* CDIOCCLRDEBUG */ +#endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */ + + /* Attempt to read the first sector. */ + if (fread (buf, 1, 512, fp) != 512) + { + fclose (fp); + goto fail; + } + + /* Remember that we've seen this device. */ + seen_elt = xmalloc (sizeof (*seen_elt)); + seen_elt->name = real_device; /* steal memory */ + grub_list_push (GRUB_AS_LIST_P (&seen), GRUB_AS_LIST (seen_elt)); + + fclose (fp); + return 1; + +fail: + free (real_device); + return 0; +} + +static void +clear_seen_devices (void) +{ + while (seen) + { + struct seen_device *seen_elt = seen; + seen = seen->next; + free (seen_elt); + } + seen = NULL; +} + +#ifdef __linux__ +struct device +{ + char *stable; + char *kernel; +}; + +/* Sort by the kernel name for preference since that most closely matches + older device.map files, but sort by stable by-id names as a fallback. + This is because /dev/disk/by-id/ usually has a few alternative + identifications of devices (e.g. ATA vs. SATA). + check_device_readable_unique will ensure that we only get one for any + given disk, but sort the list so that the choice of which one we get is + stable. */ +static int +compare_devices (const void *a, const void *b) +{ + const struct device *left = (const struct device *) a; + const struct device *right = (const struct device *) b; + + if (left->kernel && right->kernel) + { + int ret = strcmp (left->kernel, right->kernel); + if (ret) + return ret; + } + + return strcmp (left->stable, right->stable); +} +#endif /* __linux__ */ + +void +grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int), + int floppy_disks) +{ + int i; + + clear_seen_devices (); + + /* Floppies. */ + for (i = 0; i < floppy_disks; i++) + { + char name[16]; + struct stat st; + + get_floppy_disk_name (name, i); + if (stat (name, &st) < 0) + break; + /* In floppies, write the map, whether check_device_readable_unique + succeeds or not, because the user just may not insert floppies. */ + if (hook (name, 1)) + goto out; + } + +#ifdef __linux__ + { + DIR *dir = opendir ("/dev/disk/by-id"); + + if (dir) + { + struct dirent *entry; + struct device *devs; + size_t devs_len = 0, devs_max = 1024, i; + + devs = xmalloc (devs_max * sizeof (*devs)); + + /* Dump all the directory entries into names, resizing if + necessary. */ + for (entry = readdir (dir); entry; entry = readdir (dir)) + { + /* Skip current and parent directory entries. */ + if (strcmp (entry->d_name, ".") == 0 || + strcmp (entry->d_name, "..") == 0) + continue; + /* Skip partition entries. */ + if (strstr (entry->d_name, "-part")) + continue; + /* Skip device-mapper entries; we'll handle the ones we want + later. */ + if (strncmp (entry->d_name, "dm-", sizeof ("dm-") - 1) == 0) + continue; + /* Skip RAID entries; they are handled by upper layers. */ + if (strncmp (entry->d_name, "md-", sizeof ("md-") - 1) == 0) + continue; + if (devs_len >= devs_max) + { + devs_max *= 2; + devs = xrealloc (devs, devs_max * sizeof (*devs)); + } + devs[devs_len].stable = + xasprintf ("/dev/disk/by-id/%s", entry->d_name); + devs[devs_len].kernel = + canonicalize_file_name (devs[devs_len].stable); + devs_len++; + } + + qsort (devs, devs_len, sizeof (*devs), &compare_devices); + + closedir (dir); + + /* Now add all the devices in sorted order. */ + for (i = 0; i < devs_len; ++i) + { + if (check_device_readable_unique (devs[i].stable)) + { + if (hook (devs[i].stable, 0)) + goto out; + } + free (devs[i].stable); + free (devs[i].kernel); + } + free (devs); + } + } + + if (have_devfs ()) + { + i = 0; + while (1) + { + char discn[32]; + char name[PATH_MAX]; + struct stat st; + + /* Linux creates symlinks "/dev/discs/discN" for convenience. + The way to number disks is the same as GRUB's. */ + sprintf (discn, "/dev/discs/disc%d", i++); + if (stat (discn, &st) < 0) + break; + + if (realpath (discn, name)) + { + strcat (name, "/disc"); + if (hook (name, 0)) + goto out; + } + } + goto out; + } +#endif /* __linux__ */ + + /* IDE disks. */ + for (i = 0; i < 96; i++) + { + char name[16]; + + get_ide_disk_name (name, i); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } + +#ifdef __linux__ + /* Virtio disks. */ + for (i = 0; i < 26; i++) + { + char name[16]; + + get_virtio_disk_name (name, i); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } + + /* ATARAID disks. */ + for (i = 0; i < 8; i++) + { + char name[20]; + + get_ataraid_disk_name (name, i); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } + + /* Xen virtual block devices. */ + for (i = 0; i < 26; i++) + { + char name[16]; + + get_xvd_disk_name (name, i); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } +#endif /* __linux__ */ + + /* The rest is SCSI disks. */ + for (i = 0; i < 48; i++) + { + char name[16]; + + get_scsi_disk_name (name, i); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } + +#ifdef __linux__ + /* This is for DAC960 - we have + /dev/rd/cdp. + + DAC960 driver currently supports up to 8 controllers, 32 logical + drives, and 7 partitions. */ + { + int controller, drive; + + for (controller = 0; controller < 8; controller++) + { + for (drive = 0; drive < 15; drive++) + { + char name[24]; + + get_dac960_disk_name (name, controller, drive); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } + } + } + + /* This is for Mylex Acceleraid - we have + /dev/rd/cdp. */ + { + int controller, drive; + + for (controller = 0; controller < 8; controller++) + { + for (drive = 0; drive < 15; drive++) + { + char name[24]; + + get_acceleraid_disk_name (name, controller, drive); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } + } + } + + /* This is for CCISS - we have + /dev/cciss/cdp. */ + { + int controller, drive; + + for (controller = 0; controller < 3; controller++) + { + for (drive = 0; drive < 16; drive++) + { + char name[24]; + + get_cciss_disk_name (name, controller, drive); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } + } + } + + /* This is for Compaq Intelligent Drive Array - we have + /dev/ida/cdp. */ + { + int controller, drive; + + for (controller = 0; controller < 3; controller++) + { + for (drive = 0; drive < 16; drive++) + { + char name[24]; + + get_ida_disk_name (name, controller, drive); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } + } + } + + /* This is for I2O - we have /dev/i2o/hd */ + { + char unit; + + for (unit = 'a'; unit < 'f'; unit++) + { + char name[24]; + + get_i2o_disk_name (name, unit); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } + } + + /* MultiMediaCard (MMC). */ + for (i = 0; i < 10; i++) + { + char name[16]; + + get_mmc_disk_name (name, i); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + goto out; + } + } + +# ifdef HAVE_DEVICE_MAPPER +# define dmraid_check(cond, ...) \ + if (! (cond)) \ + { \ + grub_dprintf ("deviceiter", __VA_ARGS__); \ + goto dmraid_end; \ + } + + /* DM-RAID. */ + if (grub_device_mapper_supported ()) + { + struct dm_tree *tree = NULL; + struct dm_task *task = NULL; + struct dm_names *names = NULL; + unsigned int next = 0; + void *top_handle, *second_handle; + struct dm_tree_node *root, *top, *second; + + /* Build DM tree for all devices. */ + tree = dm_tree_create (); + dmraid_check (tree, "dm_tree_create failed\n"); + task = dm_task_create (DM_DEVICE_LIST); + dmraid_check (task, "dm_task_create failed\n"); + dmraid_check (dm_task_run (task), "dm_task_run failed\n"); + names = dm_task_get_names (task); + dmraid_check (names, "dm_task_get_names failed\n"); + dmraid_check (names->dev, "No DM devices found\n"); + do + { + names = (void *) names + next; + dmraid_check (dm_tree_add_dev (tree, MAJOR (names->dev), + MINOR (names->dev)), + "dm_tree_add_dev (%s) failed\n", names->name); + next = names->next; + } + while (next); + + /* Walk the second-level children of the inverted tree; that is, devices + which are directly composed of non-DM devices such as hard disks. + This class includes all DM-RAID disks and excludes all DM-RAID + partitions. */ + root = dm_tree_find_node (tree, 0, 0); + top_handle = NULL; + top = dm_tree_next_child (&top_handle, root, 1); + while (top) + { + second_handle = NULL; + second = dm_tree_next_child (&second_handle, top, 1); + while (second) + { + const char *node_name, *node_uuid; + char *name; + + node_name = dm_tree_node_get_name (second); + dmraid_check (node_name, "dm_tree_node_get_name failed\n"); + node_uuid = dm_tree_node_get_uuid (second); + dmraid_check (node_uuid, "dm_tree_node_get_uuid failed\n"); + if (strncmp (node_uuid, "DMRAID-", 7) != 0) + { + grub_dprintf ("deviceiter", "%s is not DM-RAID\n", node_name); + goto dmraid_next_child; + } + + name = xasprintf ("/dev/mapper/%s", node_name); + if (check_device_readable_unique (name)) + { + if (hook (name, 0)) + { + free (name); + if (task) + dm_task_destroy (task); + if (tree) + dm_tree_free (tree); + goto out; + } + } + free (name); + +dmraid_next_child: + second = dm_tree_next_child (&second_handle, top, 1); + } + top = dm_tree_next_child (&top_handle, root, 1); + } + +dmraid_end: + if (task) + dm_task_destroy (task); + if (tree) + dm_tree_free (tree); + } +# endif /* HAVE_DEVICE_MAPPER */ +#endif /* __linux__ */ + +out: + clear_seen_devices (); +} + diff --git a/util/devicemap.c b/util/devicemap.c new file mode 100644 index 0000000..c618644 --- /dev/null +++ b/util/devicemap.c @@ -0,0 +1,13 @@ +#include + +#include + +void +grub_util_emit_devicemap_entry (FILE *fp, char *name, int is_floppy, + int *num_fd, int *num_hd) +{ + if (is_floppy) + fprintf (fp, "(fd%d)\t%s\n", (*num_fd)++, name); + else + fprintf (fp, "(hd%d)\t%s\n", (*num_hd)++, name); +} diff --git a/util/grub-editenv.c b/util/grub-editenv.c new file mode 100644 index 0000000..5199454 --- /dev/null +++ b/util/grub-editenv.c @@ -0,0 +1,313 @@ +/* grub-editenv.c - tool to edit environment block. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 "progname.h" + +#define DEFAULT_ENVBLK_SIZE 1024 +#define DEFAULT_ENVBLK_PATH DEFAULT_DIRECTORY "/" GRUB_ENVBLK_DEFCFG + +static struct argp_option options[] = { + {0, 0, 0, OPTION_DOC, N_("Commands:"), 1}, + {"create", 0, 0, OPTION_DOC|OPTION_NO_USAGE, + N_("Create a blank environment block file."), 0}, + {"list", 0, 0, OPTION_DOC|OPTION_NO_USAGE, + N_("List the current variables."), 0}, + {"set [name=value ...]", 0, 0, OPTION_DOC|OPTION_NO_USAGE, + N_("Set variables."), 0}, + {"unset [name ....]", 0, 0, OPTION_DOC|OPTION_NO_USAGE, + N_("Delete variables."), 0}, + + {0, 0, 0, OPTION_DOC, N_("Options:"), -1}, + {"verbose", 'v', 0, 0, N_("Print verbose messages."), 0}, + + { 0, 0, 0, 0, 0, 0 } +}; + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state) +{ + fprintf (stream, "%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); +} +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Set the bug report address */ +const char *argp_program_bug_address = "<"PACKAGE_BUGREPORT">"; + +error_t argp_parser (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'v': + verbosity++; + break; + + case ARGP_KEY_NO_ARGS: + fprintf (stderr, "%s", + _("You need to specify at least one command.\n")); + argp_usage (state); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +static char * +help_filter (int key, const char *text, void *input __attribute__ ((unused))) +{ + switch (key) + { + case ARGP_KEY_HELP_POST_DOC: + return xasprintf(text, DEFAULT_ENVBLK_PATH); + + default: + return (char *) text; + } +} + +struct argp argp = { + options, argp_parser, N_("FILENAME COMMAND"), + "\n"N_("\ +Tool to edit environment block.") +"\v"N_("\ +If FILENAME is '-', the default value %s is used."), + NULL, help_filter, NULL +}; + +static void +create_envblk_file (const char *name) +{ + FILE *fp; + char *buf; + char *namenew; + + buf = malloc (DEFAULT_ENVBLK_SIZE); + if (! buf) + grub_util_error ("out of memory"); + + namenew = xasprintf ("%s.new", name); + fp = fopen (namenew, "wb"); + if (! fp) + grub_util_error ("cannot open the file %s", namenew); + + memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1); + memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#', + DEFAULT_ENVBLK_SIZE - sizeof (GRUB_ENVBLK_SIGNATURE) + 1); + + if (fwrite (buf, 1, DEFAULT_ENVBLK_SIZE, fp) != DEFAULT_ENVBLK_SIZE) + grub_util_error ("cannot write to the file %s", namenew); + + fsync (fileno (fp)); + free (buf); + fclose (fp); + + if (rename (namenew, name) < 0) + grub_util_error ("cannot rename the file %s to %s", namenew, name); + free (namenew); +} + +static grub_envblk_t +open_envblk_file (const char *name) +{ + FILE *fp; + char *buf; + size_t size; + grub_envblk_t envblk; + + fp = fopen (name, "rb"); + if (! fp) + { + /* Create the file implicitly. */ + create_envblk_file (name); + fp = fopen (name, "rb"); + if (! fp) + grub_util_error ("cannot open the file %s", name); + } + + if (fseek (fp, 0, SEEK_END) < 0) + grub_util_error ("cannot seek the file %s", name); + + size = (size_t) ftell (fp); + + if (fseek (fp, 0, SEEK_SET) < 0) + grub_util_error ("cannot seek the file %s", name); + + buf = malloc (size); + if (! buf) + grub_util_error ("out of memory"); + + if (fread (buf, 1, size, fp) != size) + grub_util_error ("cannot read the file %s", name); + + fclose (fp); + + envblk = grub_envblk_open (buf, size); + if (! envblk) + grub_util_error ("invalid environment block"); + + return envblk; +} + +static void +list_variables (const char *name) +{ + grub_envblk_t envblk; + + auto int print_var (const char *name, const char *value); + int print_var (const char *name, const char *value) + { + printf ("%s=%s\n", name, value); + return 0; + } + + envblk = open_envblk_file (name); + grub_envblk_iterate (envblk, print_var); + grub_envblk_close (envblk); +} + +static void +write_envblk (const char *name, grub_envblk_t envblk) +{ + FILE *fp; + + fp = fopen (name, "wb"); + if (! fp) + grub_util_error ("cannot open the file %s", name); + + if (fwrite (grub_envblk_buffer (envblk), 1, grub_envblk_size (envblk), fp) + != grub_envblk_size (envblk)) + grub_util_error ("cannot write to the file %s", name); + + fsync (fileno (fp)); + fclose (fp); +} + +static void +set_variables (const char *name, int argc, char *argv[]) +{ + grub_envblk_t envblk; + + envblk = open_envblk_file (name); + while (argc) + { + char *p; + + p = strchr (argv[0], '='); + if (! p) + grub_util_error ("invalid parameter %s", argv[0]); + + *(p++) = 0; + + if (! grub_envblk_set (envblk, argv[0], p)) + grub_util_error ("environment block too small"); + + argc--; + argv++; + } + + write_envblk (name, envblk); + grub_envblk_close (envblk); +} + +static void +unset_variables (const char *name, int argc, char *argv[]) +{ + grub_envblk_t envblk; + + envblk = open_envblk_file (name); + while (argc) + { + grub_envblk_delete (envblk, argv[0]); + + argc--; + argv++; + } + + write_envblk (name, envblk); + grub_envblk_close (envblk); +} + +int +main (int argc, char *argv[]) +{ + char *filename; + char *command; + int index, arg_count; + + set_program_name (argv[0]); + + grub_util_init_nls (); + + /* Parse our arguments */ + if (argp_parse (&argp, argc, argv, 0, &index, 0) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + arg_count = argc - index; + + if (arg_count == 1) + { + filename = DEFAULT_ENVBLK_PATH; + command = argv[index++]; + } + else + { + filename = argv[index++]; + if (strcmp (filename, "-") == 0) + filename = DEFAULT_ENVBLK_PATH; + command = argv[index++]; + } + + if (strcmp (command, "create") == 0) + create_envblk_file (filename); + else if (strcmp (command, "list") == 0) + list_variables (filename); + else if (strcmp (command, "set") == 0) + set_variables (filename, argc - index, argv + index); + else if (strcmp (command, "unset") == 0) + unset_variables (filename, argc - index, argv + index); + else + { + char *program = xstrdup(program_name); + fprintf (stderr, _("Unknown command `%s'.\n"), command); + argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program); + free(program); + exit(1); + } + + return 0; +} diff --git a/util/grub-fstest.c b/util/grub-fstest.c new file mode 100644 index 0000000..293bdf7 --- /dev/null +++ b/util/grub-fstest.c @@ -0,0 +1,557 @@ +/* grub-fstest.c - debug tool for filesystem driver */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 "progname.h" +#include "argp.h" + +static grub_err_t +execute_command (char *name, int n, char **args) +{ + grub_command_t cmd; + + cmd = grub_command_find (name); + if (! cmd) + grub_util_error (_("can\'t find command %s"), name); + + return (cmd->func) (cmd, n, args); +} + +#define CMD_LS 1 +#define CMD_CP 2 +#define CMD_CMP 3 +#define CMD_HEX 4 +#define CMD_CRC 6 +#define CMD_BLOCKLIST 7 + +#define BUF_SIZE 32256 + +static grub_disk_addr_t skip, leng; + +static void +read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len)) +{ + static char buf[BUF_SIZE]; + grub_file_t file; + grub_off_t ofs, len; + + if ((pathname[0] == '-') && (pathname[1] == 0)) + { + grub_device_t dev; + + dev = grub_device_open (0); + if ((! dev) || (! dev->disk)) + grub_util_error (_("can\'t open device")); + + grub_util_info ("total sectors : %lld", + (unsigned long long) dev->disk->total_sectors); + + if (! leng) + leng = (dev->disk->total_sectors << GRUB_DISK_SECTOR_BITS) - skip; + + while (leng) + { + grub_size_t len; + + len = (leng > BUF_SIZE) ? BUF_SIZE : leng; + + if (grub_disk_read (dev->disk, 0, skip, len, buf)) + grub_util_error (_("disk read fails at offset %lld, length %d"), + skip, len); + + if (hook (skip, buf, len)) + break; + + skip += len; + leng -= len; + } + + grub_device_close (dev); + return; + } + + grub_file_filter_disable_compression (); + file = grub_file_open (pathname); + if (!file) + { + grub_util_error (_("cannot open file %s:%s"), pathname, + grub_errmsg); + return; + } + + grub_util_info ("file size : %lld", (unsigned long long) file->size); + + if (skip > file->size) + { + grub_util_error (_("invalid skip value %lld"), (unsigned long long) skip); + return; + } + + ofs = skip; + len = file->size - skip; + if ((leng) && (leng < len)) + len = leng; + + file->offset = skip; + + while (len) + { + grub_ssize_t sz; + + sz = grub_file_read (file, buf, (len > BUF_SIZE) ? BUF_SIZE : len); + if (sz < 0) + { + grub_util_error (_("read error at offset %llu: %s"), ofs, + grub_errmsg); + break; + } + + if ((sz == 0) || (hook (ofs, buf, sz))) + break; + + ofs += sz; + len -= sz; + } + + grub_file_close (file); +} + +static void +cmd_cp (char *src, char *dest) +{ + FILE *ff; + + auto int cp_hook (grub_off_t ofs, char *buf, int len); + int cp_hook (grub_off_t ofs, char *buf, int len) + { + (void) ofs; + + if ((int) fwrite (buf, 1, len, ff) != len) + { + grub_util_error (_("write error")); + return 1; + } + + return 0; + } + + ff = fopen (dest, "wb"); + if (ff == NULL) + { + grub_util_error (_("open error")); + return; + } + read_file (src, cp_hook); + fclose (ff); +} + +static void +cmd_cmp (char *src, char *dest) +{ + FILE *ff; + static char buf_1[BUF_SIZE]; + + auto int cmp_hook (grub_off_t ofs, char *buf, int len); + int cmp_hook (grub_off_t ofs, char *buf, int len) + { + if ((int) fread (buf_1, 1, len, ff) != len) + { + grub_util_error (_("read error at offset %llu: %s"), ofs, grub_errmsg); + return 1; + } + + if (grub_memcmp (buf, buf_1, len)) + { + int i; + + for (i = 0; i < len; i++, ofs++) + if (buf_1[i] != buf[i]) + { + grub_util_error (_("compare fail at offset %llu"), ofs); + return 1; + } + } + return 0; + } + + ff = fopen (dest, "rb"); + if (ff == NULL) + { + grub_util_error (_("open error")); + return; + } + + if ((skip) && (fseeko (ff, skip, SEEK_SET))) + grub_util_error (_("seek error")); + + read_file (src, cmp_hook); + + { + grub_uint64_t pre; + pre = ftell (ff); + fseek (ff, 0, SEEK_END); + if (pre != ftell (ff)) + grub_util_error (_("unexpected end of file")); + } + fclose (ff); +} + +static void +cmd_hex (char *pathname) +{ + auto int hex_hook (grub_off_t ofs, char *buf, int len); + int hex_hook (grub_off_t ofs, char *buf, int len) + { + hexdump (ofs, buf, len); + return 0; + } + + read_file (pathname, hex_hook); +} + +static void +cmd_crc (char *pathname) +{ + grub_uint8_t crc32_context[GRUB_MD_CRC32->contextsize]; + GRUB_MD_CRC32->init(crc32_context); + + auto int crc_hook (grub_off_t ofs, char *buf, int len); + int crc_hook (grub_off_t ofs, char *buf, int len) + { + (void) ofs; + + GRUB_MD_CRC32->write(crc32_context, buf, len); + return 0; + } + + read_file (pathname, crc_hook); + GRUB_MD_CRC32->final(crc32_context); + printf ("%08x\n", + grub_be_to_cpu32(*(grub_uint32_t*)GRUB_MD_CRC32->read(crc32_context))); +} + +static char *root = NULL; +static int args_count = 0; +static int nparm = 0; +static int num_disks = 1; +static char **images = NULL; +static int cmd = 0; +static char *debug_str = NULL; +static char **args = NULL; + +static void +fstest (int n, char **args) +{ + char *host_file; + char *loop_name; + int i; + + for (i = 0; i < num_disks; i++) + { + char *argv[2]; + loop_name = grub_xasprintf ("loop%d", i); + if (!loop_name) + grub_util_error (grub_errmsg); + + host_file = grub_xasprintf ("(host)%s", images[i]); + if (!host_file) + grub_util_error (grub_errmsg); + + argv[0] = loop_name; + argv[1] = host_file; + + if (execute_command ("loopback", 2, argv)) + grub_util_error (_("loopback command fails")); + + grub_free (loop_name); + grub_free (host_file); + } + + grub_lvm_fini (); + grub_mdraid09_fini (); + grub_mdraid1x_fini (); + grub_raid_fini (); + grub_raid_init (); + grub_mdraid09_init (); + grub_mdraid1x_init (); + grub_lvm_init (); + + switch (cmd) + { + case CMD_LS: + execute_command ("ls", n, args); + break; + case CMD_CP: + cmd_cp (args[0], args[1]); + break; + case CMD_CMP: + cmd_cmp (args[0], args[1]); + break; + case CMD_HEX: + cmd_hex (args[0]); + break; + case CMD_CRC: + cmd_crc (args[0]); + break; + case CMD_BLOCKLIST: + execute_command ("blocklist", n, args); + grub_printf ("\n"); + } + + for (i = 0; i < num_disks; i++) + { + char *argv[2]; + + loop_name = grub_xasprintf ("loop%d", i); + if (!loop_name) + grub_util_error (grub_errmsg); + + argv[0] = "-d"; + argv[1] = loop_name; + + execute_command ("loopback", 2, argv); + + grub_free (loop_name); + } +} + +static struct argp_option options[] = { + {0, 0, 0 , OPTION_DOC, N_("Commands:"), 1}, + {N_("ls PATH"), 0, 0 , OPTION_DOC, N_("List files in PATH."), 1}, + {N_("cp FILE LOCAL"), 0, 0, OPTION_DOC, N_("Copy FILE to local file LOCAL."), 1}, + {N_("cmp FILE LOCAL"), 0, 0, OPTION_DOC, N_("Compare FILE with local file LOCAL."), 1}, + {N_("hex FILE"), 0, 0 , OPTION_DOC, N_("Hex dump FILE."), 1}, + {N_("crc FILE"), 0, 0 , OPTION_DOC, N_("Get crc32 checksum of FILE."), 1}, + {N_("blocklist FILE"), 0, 0, OPTION_DOC, N_("Display blocklist of FILE."), 1}, + + {"root", 'r', N_("DEVICE_NAME"), 0, N_("Set root device."), 2}, + {"skip", 's', "N", 0, N_("Skip N bytes from output file."), 2}, + {"length", 'n', "N", 0, N_("Handle N bytes in output file."), 2}, + {"diskcount", 'c', "N", 0, N_("N input files."), 2}, + {"debug", 'd', "S", 0, N_("Set debug environment variable."), 2}, + {"verbose", 'v', NULL, OPTION_ARG_OPTIONAL, N_("Print verbose messages."), 2}, + {0, 0, 0, 0, 0, 0} +}; + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state) +{ + fprintf (stream, "%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); +} +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + char *p; + + switch (key) + { + case 'r': + root = arg; + return 0; + + case 's': + skip = grub_strtoul (arg, &p, 0); + if (*p == 's') + skip <<= GRUB_DISK_SECTOR_BITS; + return 0; + + case 'n': + leng = grub_strtoul (arg, &p, 0); + if (*p == 's') + leng <<= GRUB_DISK_SECTOR_BITS; + return 0; + + case 'c': + num_disks = grub_strtoul (arg, NULL, 0); + if (num_disks < 1) + { + fprintf (stderr, "%s", _("Invalid disk count.\n")); + argp_usage (state); + } + if (args_count != 0) + { + fprintf (stderr, "%s", _("Disk count must precede disks list.\n")); + argp_usage (state); + } + return 0; + + case 'd': + debug_str = arg; + return 0; + + case 'v': + verbosity++; + return 0; + + case ARGP_KEY_END: + if (args_count < num_disks) + { + fprintf (stderr, "%s", _("No command is specified.\n")); + argp_usage (state); + } + if (args_count - 1 - num_disks < nparm) + { + fprintf (stderr, "%s", _("Not enough parameters to command.\n")); + argp_usage (state); + } + return 0; + + case ARGP_KEY_ARG: + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + if (args_count < num_disks) + { + if (arg[0] != '/') + { + fprintf (stderr, "%s", _("Must use absolute path.\n")); + argp_usage (state); + } + if (args_count == 0) + images = xmalloc (num_disks * sizeof (images[0])); + images[args_count] = xstrdup (arg); + args_count++; + return 0; + } + + if (args_count == num_disks) + { + if (!grub_strcmp (arg, "ls")) + { + cmd = CMD_LS; + } + else if (!grub_strcmp (arg, "cp")) + { + cmd = CMD_CP; + nparm = 2; + } + else if (!grub_strcmp (arg, "cmp")) + { + cmd = CMD_CMP; + nparm = 2; + } + else if (!grub_strcmp (arg, "hex")) + { + cmd = CMD_HEX; + nparm = 1; + } + else if (!grub_strcmp (arg, "crc")) + { + cmd = CMD_CRC; + nparm = 1; + } + else if (!grub_strcmp (arg, "blocklist")) + { + cmd = CMD_BLOCKLIST; + nparm = 1; + } + else + { + fprintf (stderr, _("Invalid command %s.\n"), arg); + argp_usage (state); + } + args_count++; + return 0; + } + + args[args_count - 1 - num_disks] = xstrdup (arg); + args_count++; + return 0; +} + +struct argp argp = { + options, argp_parser, N_("IMAGE_PATH COMMANDS"), + N_("Debug tool for filesystem driver."), + NULL, NULL, NULL +}; + +int +main (int argc, char *argv[]) +{ + char *default_root, *alloc_root; + + set_program_name (argv[0]); + + grub_util_init_nls (); + + args = xmalloc (argc * sizeof (args[0])); + + argp_parse (&argp, argc, argv, 0, 0, 0); + + /* Initialize all modules. */ + grub_init_all (); + + if (debug_str) + grub_env_set ("debug", debug_str); + + default_root = (num_disks == 1) ? "loop0" : "md0"; + alloc_root = 0; + if (root) + { + if ((*root >= '0') && (*root <= '9')) + { + alloc_root = xmalloc (strlen (default_root) + strlen (root) + 2); + + sprintf (alloc_root, "%s,%s", default_root, root); + root = alloc_root; + } + } + else + root = default_root; + + grub_env_set ("root", root); + + if (alloc_root) + free (alloc_root); + + /* Do it. */ + fstest (args_count - 1 - num_disks, args); + + /* Free resources. */ + grub_fini_all (); + + return 0; +} diff --git a/util/grub-install.in b/util/grub-install.in new file mode 100644 index 0000000..ff8bea8 --- /dev/null +++ b/util/grub-install.in @@ -0,0 +1,666 @@ +#! /bin/sh + +# Install GRUB on your drive. +# Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +# Initialize some variables. +transform="@program_transform_name@" + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +sbindir="@sbindir@" +bindir="@bindir@" +libdir="@libdir@" +sysconfdir="@sysconfdir@" +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_TARNAME=@PACKAGE_TARNAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +target_cpu=@target_cpu@ +platform=@platform@ +host_os=@host_os@ +pkglibdir="${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}`" +localedir="@datadir@/locale" + +self="`basename $0`" + +grub_setup="${sbindir}/`echo grub-setup | sed ${transform}`" +grub_mkimage="${bindir}/`echo grub-mkimage | sed ${transform}`" +grub_mkdevicemap="${sbindir}/`echo grub-mkdevicemap | sed ${transform}`" +grub_probe="${sbindir}/`echo grub-probe | sed ${transform}`" +grub_editenv="${bindir}/`echo grub-editenv | sed ${transform}`" +grub_mkrelpath="${bindir}/`echo grub-mkrelpath | sed ${transform}`" +rootdir= +bootdir= +grubdir="`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`" +modules= + +install_device= +no_floppy= +force_lba= +recheck=no +debug=no +debug_image= + +update_nvram=yes + +removable=no +efi_quiet= + +# Get GRUB_DISTRIBUTOR. +if test -f "${sysconfdir}/default/grub" ; then + . "${sysconfdir}/default/grub" +fi + +bootloader_id="$(echo "$GRUB_DISTRIBUTOR" | tr 'A-Z' 'a-z' | cut -d' ' -f1)" +if test -z "$bootloader_id"; then + bootloader_id=grub +fi + +if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then + disk_module=biosdisk +elif [ "${platform}" = "ieee1275" ] || [ "${platform}" = "efi" ] ; then + disk_module= +else + disk_module=ata +fi + +# Usage: usage +# Print the usage. +usage () { +if [ "${target_cpu}-${platform}" = "i386-pc" ] \ + || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ]; then + cat <. +EOF +} + +argument () { + opt="$1" + shift + + if test $# -eq 0; then + echo "$0: option requires an argument -- '$opt'" 1>&2 + exit 1 + fi + echo "$1" +} + +allow_floppy="" + +# Check the arguments. +while test $# -gt 0 +do + option=$1 + shift + + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" + exit 0 ;; + + --modules) + modules=`argument $option "$@"`; shift;; + --modules=*) + modules=`echo "$option" | sed 's/--modules=//'` ;; + +# Accept and ignore for compatibility + --font) + shift;; + --font=*) + ;; + +# Accept for compatibility + --root-directory) + rootdir="`argument $option "$@"`"; shift;; + --root-directory=*) + rootdir="`echo "$option" | sed 's/--root-directory=//'`" ;; + + --boot-directory) + bootdir="`argument $option "$@"`"; shift;; + --boot-directory=*) + bootdir="`echo "$option" | sed 's/--boot-directory=//'`" ;; + + --grub-setup) + grub_setup="`argument "$option" "$@"`"; shift;; + --grub-setup=*) + grub_setup="`echo "$option" | sed 's/--grub-setup=//'`" ;; + + --bootloader-id) + bootloader_id="`argument $option "$@"`"; shift;; + --bootloader-id=*) + bootloader_id="`echo "$option" | sed 's/--bootloader-id=//'`" ;; + + --grub-mkimage) + grub_mkimage="`argument $option "$@"`"; shift;; + --grub-mkimage=*) + grub_mkimage="`echo "$option" | sed 's/--grub-mkimage=//'`" ;; + + --grub-mkrelpath) + grub_mkrelpath="`argument "$option" "$@"`"; shift;; + --grub-mkrelpath=*) + grub_mkrelpath="`echo "$option" | sed 's/--grub-mkrelpath=//'`" ;; + + --grub-mkdevicemap) + grub_mkdevicemap="`argument "$option" "$@"`"; shift;; + --grub-mkdevicemap=*) + grub_mkdevicemap="`echo "$option" | sed 's/--grub-mkdevicemap=//'`" ;; + + --grub-probe) + grub_probe="`argument "$option" "$@"`"; shift;; + --grub-probe=*) + grub_probe="`echo "$option" | sed 's/--grub-probe=//'`" ;; + + --no-floppy) + no_floppy="--no-floppy" ;; + --recheck) + recheck=yes ;; + --removable) + removable=yes ;; + + --allow-floppy) + allow_floppy="--allow-floppy" ;; + + --disk-module) + if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then + disk_module="`argument "$option" "$@"`"; shift; + fi ;; + --disk-module=*) + if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then + disk_module="`echo "$option" | sed 's/--disk-module=//'`" + fi ;; + + --no-nvram) + update_nvram=no ;; + + # This is an undocumented feature... + --debug) + debug=yes ;; + --debug-image) + debug_image="`argument "$option" "$@"`"; shift;; + --debug-image=*) + debug_image="`echo "$option" | sed 's/--debug-image=//'`" ;; + + -f | --force) + setup_force="--force" ;; + + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + *) + if test "x$install_device" != x; then + echo "More than one install_devices?" 1>&2 + usage + exit 1 + fi + install_device="${option}" ;; + esac +done + +if test "x$install_device" = x && ([ "${target_cpu}-${platform}" = "i386-pc" ] \ + || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ]); then + echo "install_device not specified." 1>&2 + usage + exit 1 +fi + +if ! ([ "${target_cpu}-${platform}" = "i386-pc" ] \ + || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ]); then + install_device= +fi + +# If the debugging feature is enabled, print commands. +setup_verbose= +if test x"$debug" = xyes; then + set -x + setup_verbose="--verbose" + efi_quiet=-q +fi + +if [ -z "$bootdir" ]; then + # Default bootdir if bootdir not initialized. + bootdir="/@bootdirname@" + + if [ -n "$rootdir" ] ; then + # Initialize bootdir if rootdir was initialized. + bootdir="${rootdir}/@bootdirname@" + fi +fi + +grubdir="`echo "${bootdir}/@grubdirname@" | sed 's,//*,/,g'`" +device_map="${grubdir}/device.map" + + +# Check if GRUB is installed. +if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then + set $grub_setup dummy + if test -f "$1"; then + : + else + echo "$1: Not found." 1>&2 + exit 1 + fi +fi + +set "$grub_mkimage" dummy +if test -f "$1"; then + : +else + echo "$1: Not found." 1>&2 + exit 1 +fi + +set "$grub_mkdevicemap" dummy +if test -f "$1"; then + : +else + echo "$1: Not found." 1>&2 + exit 1 +fi + +if [ x"$platform" = xefi ]; then + # Find the EFI System Partition. + efidir= + if test -d "${bootdir}/efi"; then + install_device="`"$grub_mkdevicemap" --device-map=/dev/stdout | "$grub_probe" --target=device --device-map=/dev/stdin "${bootdir}/efi"`" + # Is it a mount point? + if test "x$install_device" != "x`"$grub_mkdevicemap" --device-map=/dev/stdout | "$grub_probe" --target=device --device-map=/dev/stdin "${bootdir}"`"; then + efidir="${bootdir}/efi" + fi + elif test -n "$rootdir" && test "x$rootdir" != "x/"; then + # The EFI System Partition may have been given directly using + # --root-directory. + install_device="`"$grub_mkdevicemap" --device-map=/dev/stdout | "$grub_probe" --target=device --device-map=/dev/stdin "${rootdir}"`" + # Is it a mount point? + if test "x$install_device" != "x`"$grub_mkdevicemap" --device-map=/dev/stdout | "$grub_probe" --target=device --device-map=/dev/stdin "${rootdir}/.."`"; then + efidir="${rootdir}" + fi + fi + + if test -n "$efidir"; then + efi_fs=`"$grub_probe" --target=fs "--device-map=${device_map}" "${efidir}"` + if test "x$efi_fs" = xfat; then :; else + echo "${efidir} doesn't look like an EFI partition." 1>&2 + efidir= + fi + fi + + if test -n "$efidir"; then + # The EFI specification requires that an EFI System Partition must + # contain an "EFI" subdirectory, and that OS loaders are stored in + # subdirectories below EFI. Vendors are expected to pick names that do + # not collide with other vendors. To minimise collisions, we use the + # name of our distributor if possible. + efi_distributor="$bootloader_id" + if test $removable = yes; then + # The specification makes stricter requirements of removable + # devices, in order that only one image can be automatically loaded + # from them. The image must always reside under /EFI/BOOT, and it + # must have a specific file name depending on the architecture. + efi_distributor=BOOT + case "$target_cpu" in + i386) + efi_file=BOOTIA32.EFI ;; + x86_64) + efi_file=BOOTX64.EFI ;; + # GRUB does not yet support these architectures, but they're defined + # by the specification so we include them here to ease future + # expansion. + ia64) + efi_file=BOOTIA64.EFI ;; + esac + else + # It is convenient for each architecture to have a different + # efi_file, so that different versions can be installed in parallel. + case "$target_cpu" in + i386) + efi_file=grubia32.efi ;; + x86_64) + efi_file=grubx64.efi ;; + # GRUB does not yet support these architectures, but they're defined + # by the specification so we include them here to ease future + # expansion. + ia64) + efi_file=grubia64.efi ;; + *) + efi_file=grub.efi ;; + esac + # TODO: We should also use efibootmgr, if available, to add a Boot + # entry for ourselves. + fi + efidir="$efidir/EFI/$efi_distributor" + mkdir -p "$efidir" || exit 1 + else + # We don't know what's going on. Fall back to traditional + # (non-specification-compliant) behaviour. + efidir="$grubdir" + efi_distributor= + efi_file=grub.efi + fi +fi + +# Create the GRUB directory if it is not present. +mkdir -p "$grubdir" || exit 1 + +# If --recheck is specified, remove the device map, if present. +if test $recheck = yes; then + rm -f "$device_map" +fi + +# Create the device map file if it is not present. +if test -f "$device_map"; then + : +else + # Create a safe temporary file. + test -n "$mklog" && log_file=`$mklog` + + "$grub_mkdevicemap" "--device-map=$device_map" $no_floppy || exit 1 +fi + +# Make sure that there is no duplicated entry. +tmp=`sed -n '/^([fh]d[0-9]*)/s/\(^(.*)\).*/\1/p' "$device_map" \ + | sort | uniq -d | sed -n 1p` +if test -n "$tmp"; then + echo "The drive $tmp is defined multiple times in the device map $device_map" 1>&2 + exit 1 +fi + +# Copy the GRUB images to the GRUB directory. +for file in "${grubdir}"/*.mod "${grubdir}"/*.lst "${grubdir}"/*.img "${grubdir}"/efiemu??.o; do + if test -f "$file" && [ "`basename $file`" != menu.lst ]; then + rm -f "$file" || exit 1 + fi +done +for file in "${pkglibdir}"/*.mod "${pkglibdir}"/*.lst; do + cp -f "$file" "${grubdir}" || exit 1 +done +if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then + for file in "${pkglibdir}"/*.img "${pkglibdir}"/efiemu??.o; do + if test -f "$file"; then + cp -f "$file" "${grubdir}" || exit 1 + fi + done +fi + +# Copy gettext files +mkdir -p "${grubdir}"/locale/ +for dir in "${localedir}"/*; do + if test -f "$dir/LC_MESSAGES/grub.mo"; then + cp -f "$dir/LC_MESSAGES/grub.mo" "${grubdir}/locale/${dir##*/}.mo" + fi +done + +# Write device to a variable so we don't have to traverse /dev every time. +grub_device="`"$grub_probe" --device-map="${device_map}" --target=device "${grubdir}"`" || exit 1 + +if ! test -f "${grubdir}"/grubenv; then + "$grub_editenv" "${grubdir}"/grubenv create +fi + +# Create the core image. First, auto-detect the filesystem module. +fs_module="`"$grub_probe" --device-map="${device_map}" --target=fs --device "${grub_device}"`" +if test "x$fs_module" = x ; then + echo "Auto-detection of a filesystem of ${grub_device} failed." 1>&2 + echo "Try with --recheck." 1>&2 + echo "If the problem persists please report this together with the output of \"$grub_probe --device-map=\"${device_map}\" --target=fs -v ${grubdir}\" to " 1>&2 + exit 1 +fi + +# Then the partition map module. In order to support partition-less media, +# this command is allowed to fail (--target=fs already grants us that the +# filesystem will be accessible). +partmap_module= +for x in `"$grub_probe" --device-map="${device_map}" --target=partmap --device "${grub_device}" 2> /dev/null`; do + case "$x" in + netbsd | openbsd) + partmap_module="$partmap_module part_bsd";; + "") ;; + *) + partmap_module="$partmap_module part_$x";; + esac +done + +# Device abstraction module, if any (lvm, raid). +devabstraction_module="`"$grub_probe" --device-map="${device_map}" --target=abstraction --device "${grub_device}"`" + +# The order in this list is critical. Be careful when modifying it. +modules="$modules $disk_module" +modules="$modules $fs_module $partmap_module $devabstraction_module" + +relative_grubdir="`"$grub_mkrelpath" "${grubdir}"`" || exit 1 +if [ "x${relative_grubdir}" = "x" ] ; then + relative_grubdir=/ +fi + +prefix_drive= +config_opt= + +rm -f "${grubdir}/load.cfg" + +if [ "x${debug_image}" != x ]; then + echo "set debug='${debug_image}'" >> "${grubdir}/load.cfg" + config_opt="-c ${grubdir}/load.cfg " +fi + +if [ "x${devabstraction_module}" = "x" ] ; then + if [ x"${install_device}" != x ]; then + if echo "${install_device}" | grep -qx "(.*)" ; then + install_drive="${install_device}" + else + install_drive="`"$grub_probe" --device-map="${device_map}" --target=drive --device "${install_device}"`" || exit 1 + fi + install_drive="`echo "${install_drive}" | sed -e s/,[a-z0-9,]*//g`" + fi + grub_drive="`"$grub_probe" --device-map="${device_map}" --target=drive --device "${grub_device}"`" || exit 1 + + # Strip partition number + grub_partition="`echo "${grub_drive}" | sed -e 's/^[^,]*[,)]//; s/)$//'`" + grub_drive="`echo "${grub_drive}" | sed -e s/,[a-z0-9,]*//g`" + if [ "$disk_module" = ata ] || [ "x${grub_drive}" != "x${install_drive}" ] || ([ "x$platform" != xefi ] && [ "x$platform" != xpc ] && [ x"${target_cpu}-${platform}" != x"sparc64-ieee1275" ]) ; then + # generic method (used on coreboot and ata mod) + uuid="`"$grub_probe" --device-map="${device_map}" --target=fs_uuid --device "${grub_device}"`" + if [ "x${uuid}" = "x" ] ; then + if [ "x$platform" != xefi ] && [ "x$platform" != xpc ] && [ x"${target_cpu}-${platform}" != x"sparc64-ieee1275" ]; then + echo "UUID needed with $platform, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2 + elif [ "$disk_module" = ata ]; then + echo "UUID needed with ata mod, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2 + else + echo "UUID needed with cross-disk installs, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2 + fi + + exit 1 + fi + echo "search.fs_uuid ${uuid} root " >> "${grubdir}/load.cfg" + echo 'set prefix=($root)'"${relative_grubdir}" >> "${grubdir}/load.cfg" + config_opt="-c ${grubdir}/load.cfg " + modules="$modules search_fs_uuid" + elif [ "x$platform" = xefi ] || [ "x$platform" = xpc ]; then + # we need to hardcode the partition number in the core image's prefix. + if [ x"$grub_partition" = x ]; then + prefix_drive="()" + else + prefix_drive="(,$grub_partition)" + fi + fi +else + prefix_drive=`"$grub_probe" --device-map="${device_map}" --target=drive --device "${grub_device}"` || exit 1 +fi + +case "${target_cpu}-${platform}" in + sparc64-ieee1275) mkimage_target=sparc64-ieee1275-raw ;; + mips-yeeloong) mkimage_target=mipsel-yeeloong-elf ;; + *) mkimage_target="${target_cpu}-${platform}" ;; +esac + +case "${target_cpu}-${platform}" in + i386-efi | x86_64-efi) imgext=efi ;; + mips-yeeloong | i386-coreboot | i386-multiboot | i386-ieee1275 \ + | powerpc-ieee1275) imgext=elf ;; + *) imgext=img ;; +esac + + +"$grub_mkimage" ${config_opt} -d "${pkglibdir}" -O ${mkimage_target} --output="${grubdir}/core.${imgext}" --prefix="${prefix_drive}${relative_grubdir}" $modules || exit 1 + +# Backward-compatibility kludges +if [ "${target_cpu}-${platform}" = "mips-yeeloong" ]; then + cp "${grubdir}/core.${imgext}" "${bootdir}"/grub.elf +elif [ "${target_cpu}-${platform}" = "i386-ieee1275" ] || [ "${target_cpu}-${platform}" = "powerpc-ieee1275" ]; then + cp "${grubdir}/core.${imgext}" "${grubdir}/grub" +elif [ "${target_cpu}-${platform}" = "i386-efi" ] || [ "${target_cpu}-${platform}" = "x86_64-efi" ]; then + "$grub_mkimage" ${config_opt} -d "${pkglibdir}" -O ${mkimage_target} --output="${grubdir}/grub.efi" --prefix="" $modules || exit 1 +fi + + +# Perform the platform-dependent install +if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then + # Now perform the installation. + "$grub_setup" ${allow_floppy} ${setup_verbose} ${setup_force} --directory="${grubdir}" \ + --device-map="${device_map}" "${install_device}" || exit 1 +elif [ "${target_cpu}-${platform}" = "i386-ieee1275" ] || [ "${target_cpu}-${platform}" = "powerpc-ieee1275" ]; then + if [ x"$update_nvram" = xyes ]; then + ofpathname="`which ofpathname`" + nvsetenv="`which nvsetenv`" + set "$ofpathname" dummy + if test -f "$1"; then + : + else + echo "$1: Not found." 1>&2 + exit 1 + fi + set "$nvsetenv" dummy + if test -f "$1"; then + : + else + echo "$1: Not found." 1>&2 + exit 1 + fi + # Get the Open Firmware device tree path translation. + dev="`echo $grub_device | sed -e 's/\/dev\///' -e 's/[0-9]\+//'`" + partno="`echo $grub_device | sed -e 's/.*[^0-9]\([0-9]\+\)$/\1/'`" + ofpath="`$ofpathname $dev`" || { + echo "Couldn't find Open Firmware device tree path for $dev." + echo "You will have to set boot-device manually." + exit 1 + } + + # Point boot-device at the new grub install + boot_device="$ofpath:$partno,"`"$grub_mkrelpath" "${grubdir}/core.${imgext}" | sed 's,/,\\\\,g'` + "$nvsetenv" boot-device "$boot_device" || { + echo "$nvsetenv failed." + echo "You will have to set boot-device manually. At the Open Firmware prompt, type:" + echo " setenv boot-device $boot_device" + exit 1 + } + fi +elif [ x"$platform" = xefi ]; then + cp "${grubdir}/core.${imgext}" "${efidir}/${efi_file}" + # For old macs. Suggested by Peter Jones. + if [ x$target_cpu = xi386 ]; then + cp "${grubdir}/core.${imgext}" "${efidir}/boot.efi" + fi + + # Try to make this image bootable using the EFI Boot Manager, if available. + efibootmgr="`which efibootmgr`" + if test "$removable" = no && test -n "$efi_distributor" && \ + test -n "$efibootmgr"; then + # On Linux, we need the efivars kernel modules. + case "$host_os" in + linux*) + modprobe -q efivars 2>/dev/null || true ;; + esac + + # Delete old entries from the same distributor. + for bootnum in `efibootmgr | grep '^Boot[0-9]' | \ + fgrep -i " $efi_distributor" | cut -b5-8`; do + efibootmgr $efi_quiet -b "$bootnum" -B + done + + # Add a new entry for the image we just created. efibootmgr needs to be + # given the disk device and partition number separately, so we have to + # fiddle about with grub-probe to get hold of this reasonably reliably. + # Use fresh device map text to avoid any problems with stale data, since + # all we need here is a one-to-one mapping. + clean_devmap="$($grub_mkdevicemap --device-map=/dev/stdout)" + efidir_drive="$(echo "$clean_devmap" | "$grub_probe" --device-map="${device_map}" --target=drive --device-map=/dev/stdin "$efidir")" + if test -z "$efidir_drive"; then + echo "Can't find GRUB drive for $efidir; unable to create EFI Boot Manager entry." >&2 + else + efidir_disk="$(echo "$clean_devmap" | grep "^$(echo "$efidir_drive" | sed 's/,[^)]*//')" | cut -f2)" + efidir_part="$(echo "$efidir_drive" | sed 's/^([^,]*,[^0-9]*//; s/[^0-9].*//')" + efibootmgr $efi_quiet -c -d "$efidir_disk" -p "$efidir_part" -w \ + -L "$bootloader_id" -l "\\EFI\\$efi_distributor\\$efi_file" + fi + fi +fi + +echo "Installation finished. No error reported." + +# Bye. +exit 0 diff --git a/util/grub-kbdcomp.in b/util/grub-kbdcomp.in new file mode 100644 index 0000000..05e516d --- /dev/null +++ b/util/grub-kbdcomp.in @@ -0,0 +1,12 @@ +#!/bin/sh + +transform="@program_transform_name@" + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +bindir="@bindir@" + +grub_mklayout=${bindir}/`echo grub-mklayout | sed ${transform}` + +ckbcomp "$@" | $grub_mklayout -o "$1".gkb + diff --git a/util/grub-macho2img.c b/util/grub-macho2img.c new file mode 100644 index 0000000..bce0a06 --- /dev/null +++ b/util/grub-macho2img.c @@ -0,0 +1,118 @@ +/* macho2img.c - tool to convert Mach-O to raw imagw. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include + +#include +#include +#include +#include +#include + +/* XXX: this file assumes particular Mach-O layout and does no checks. */ +/* However as build system ensures correct usage of this tool this + shouldn't be a problem. */ + +int +main (int argc, char **argv) +{ + FILE *in, *out; + int do_bss = 0; + char *buf; + int bufsize; + struct grub_macho_header32 *head; + struct grub_macho_segment32 *curcmd; + unsigned i; + unsigned bssstart = 0; + unsigned bssend = 0; + + if (argc && strcmp (argv[1], "--bss") == 0) + do_bss = 1; + if (argc < 2 + do_bss) + { + printf ("Usage: %s [--bss] filename.exec filename.img\n" + "Convert Mach-O into raw image\n", argv[0]); + return 0; + } + in = fopen (argv[1 + do_bss], "rb"); + if (! in) + { + printf ("Couldn't open %s\n", argv[1 + do_bss]); + return 1; + } + out = fopen (argv[2 + do_bss], "wb"); + if (! out) + { + fclose (in); + printf ("Couldn't open %s\n", argv[2 + do_bss]); + return 2; + } + fseek (in, 0, SEEK_END); + bufsize = ftell (in); + fseek (in, 0, SEEK_SET); + buf = malloc (bufsize); + if (! buf) + { + fclose (in); + fclose (out); + printf ("Couldn't allocate buffer\n"); + return 3; + } + fread (buf, 1, bufsize, in); + head = (struct grub_macho_header32 *) buf; + if (grub_le_to_cpu32 (head->magic) != GRUB_MACHO_MAGIC32) + { + fclose (in); + fclose (out); + free (buf); + printf ("Invalid Mach-O file\n"); + return 4; + } + curcmd = (struct grub_macho_segment32 *) (buf + sizeof (*head)); + for (i = 0; i < grub_le_to_cpu32 (head->ncmds); i++, + curcmd = (struct grub_macho_segment32 *) + (((char *) curcmd) + curcmd->cmdsize)) + { + if (curcmd->cmd != GRUB_MACHO_CMD_SEGMENT32) + continue; + fwrite (buf + grub_le_to_cpu32 (curcmd->fileoff), 1, + grub_le_to_cpu32 (curcmd->filesize), out); + if (grub_le_to_cpu32 (curcmd->vmsize) + > grub_le_to_cpu32 (curcmd->filesize)) + { + bssstart = grub_le_to_cpu32 (curcmd->vmaddr) + + grub_le_to_cpu32 (curcmd->filesize) ; + bssend = grub_le_to_cpu32 (curcmd->vmaddr) + + grub_le_to_cpu32 (curcmd->vmsize) ; + } + } + if (do_bss) + { + grub_uint32_t tmp; + fseek (out, 0x5c, SEEK_SET); + tmp = grub_cpu_to_le32 (bssstart); + fwrite (&tmp, 4, 1, out); + tmp = grub_cpu_to_le32 (bssend); + fwrite (&tmp, 4, 1, out); + } + fclose (in); + fclose (out); + printf("macho2img complete\n"); + return 0; +} diff --git a/util/grub-menulst2cfg.c b/util/grub-menulst2cfg.c new file mode 100644 index 0000000..513af47 --- /dev/null +++ b/util/grub-menulst2cfg.c @@ -0,0 +1,126 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#include + +int +main (int argc, char **argv) +{ + FILE *in, *out; + char *entryname = NULL; + char *buf = NULL; + size_t bufsize = 0; + char *suffix = xstrdup (""); + int suffixlen = 0; + + if (argc >= 2 && argv[1][0] == '-') + { + fprintf (stdout, "Usage: %s [INFILE [OUTFILE]]\n", argv[0]); + return 0; + } + + if (argc >= 2) + { + in = fopen (argv[1], "r"); + if (!in) + { + fprintf (stderr, "Couldn't open %s for reading: %s\n", + argv[1], strerror (errno)); + return 1; + } + } + else + in = stdin; + + if (argc >= 3) + { + out = fopen (argv[2], "w"); + if (!out) + { + if (in != stdin) + fclose (in); + fprintf (stderr, "Couldn't open %s for writing: %s\n", + argv[2], strerror (errno)); + return 1; + } + } + else + out = stdout; + + while (1) + { + char *parsed; + + if (getline (&buf, &bufsize, in) < 0) + break; + + { + char *oldname = NULL; + char *newsuffix; + char *ptr; + + for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++); + + oldname = entryname; + parsed = grub_legacy_parse (ptr, &entryname, &newsuffix); + if (newsuffix) + { + suffixlen += strlen (newsuffix); + suffix = xrealloc (suffix, suffixlen + 1); + strcat (suffix, newsuffix); + } + if (oldname != entryname && oldname) + fprintf (out, "}\n\n"); + if (oldname != entryname) + { + char *escaped = grub_legacy_escape (entryname, strlen (entryname)); + fprintf (out, "menuentry \'%s\' {\n", escaped); + free (escaped); + free (oldname); + } + } + + if (parsed) + fprintf (out, "%s%s", entryname ? " " : "", parsed); + free (parsed); + parsed = NULL; + } + + if (entryname) + fprintf (out, "}\n\n"); + + fwrite (suffix, 1, suffixlen, out); + + free (buf); + free (suffix); + free (entryname); + + if (in != stdin) + fclose (in); + if (out != stdout) + fclose (out); + + return 0; +} diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in new file mode 100644 index 0000000..afc66f8 --- /dev/null +++ b/util/grub-mkconfig.in @@ -0,0 +1,308 @@ +#! /bin/sh +set -e + +# Generate grub.cfg by inspecting /boot contents. +# Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +sbindir=@sbindir@ +bindir=@bindir@ +libdir=@libdir@ +sysconfdir=@sysconfdir@ +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +host_os=@host_os@ +datarootdir=@datarootdir@ +datadir=@datadir@ +pkgdatadir=${datadir}/`echo @PACKAGE_TARNAME@ | sed "${transform}"` +grub_cfg="" +grub_mkconfig_dir=${sysconfdir}/grub.d + +self=`basename $0` + +grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed "${transform}"` +grub_probe=${sbindir}/`echo grub-probe | sed "${transform}"` +grub_script_check="${bindir}/`echo grub-script-check | sed "${transform}"`" + +GRUB_PREFIX=`echo '/@bootdirname@/@grubdirname@' | sed "s,//*,/,g"` + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +argument () { + opt=$1 + shift + + if test $# -eq 0; then + echo "$0: option requires an argument -- '$opt'" 1>&2 + exit 1 + fi + echo $1 +} + +# Check the arguments. +while test $# -gt 0 +do + option=$1 + shift + + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" + exit 0 ;; + -o | --output) + grub_cfg=`argument $option "$@"`; shift;; + --output=*) + grub_cfg=`echo "$option" | sed 's/--output=//'` + ;; + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + # Explicitly ignore non-option arguments, for compatibility. + esac +done + +. ${libdir}/grub/grub-mkconfig_lib + +if [ "x$EUID" = "x" ] ; then + EUID=`id -u` +fi + +if [ "$EUID" != 0 ] ; then + root=f + case "`uname 2>/dev/null`" in + CYGWIN*) + # Cygwin: Assume root if member of admin group + for g in `id -G 2>/dev/null` ; do + case $g in + 0|544) root=t ;; + esac + done ;; + esac + if [ $root != t ] ; then + echo "$self: You must run this as root" >&2 + exit 1 + fi +fi + +set $grub_mkdevicemap dummy +if test -f "$1"; then + : +else + echo "$1: Not found." 1>&2 + exit 1 +fi + +set $grub_probe dummy +if test -f "$1"; then + : +else + echo "$1: Not found." 1>&2 + exit 1 +fi + +mkdir -p ${GRUB_PREFIX} + +if test -e ${GRUB_PREFIX}/device.map ; then : ; else + ${grub_mkdevicemap} +fi + +# Device containing our userland. Typically used for root= parameter. +GRUB_DEVICE="`${grub_probe} --target=device /`" +GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true + +# Device containing our /boot partition. Usually the same as GRUB_DEVICE. +GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`" +GRUB_DEVICE_BOOT_UUID="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`" || true + +# Filesystem for the device containing our userland. Used for stuff like +# choosing Hurd filesystem module. +GRUB_FS="`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2> /dev/null || echo unknown`" + +if test -f ${sysconfdir}/default/grub ; then + . ${sysconfdir}/default/grub +fi + +# XXX: should this be deprecated at some point? +if [ "x${GRUB_TERMINAL}" != "x" ] ; then + GRUB_TERMINAL_INPUT="${GRUB_TERMINAL}" + GRUB_TERMINAL_OUTPUT="${GRUB_TERMINAL}" +fi + +termoutdefault=0 +if [ "x${GRUB_TERMINAL_OUTPUT}" = "x" ]; then + GRUB_TERMINAL_OUTPUT=gfxterm; + termoutdefault=1; +fi + +for x in ${GRUB_TERMINAL_OUTPUT}; do + if [ "x${x}" = "xgfxterm" ]; then + if [ -n "$GRUB_FONT" ] ; then + if is_path_readable_by_grub ${GRUB_FONT} > /dev/null ; then + GRUB_FONT_PATH=${GRUB_FONT} + else + echo "No such font or not readable by grub: ${GRUB_FONT}" >&2 + exit 1 + fi + else + for dir in ${pkgdatadir} ${GRUB_PREFIX} /usr/share/grub ; do + for basename in unicode unifont ascii; do + path="${dir}/${basename}.pf2" + if is_path_readable_by_grub ${path} > /dev/null ; then + GRUB_FONT_PATH=${path} + else + continue + fi + if [ "${basename}" = "ascii" ] ; then + # make sure all our children behave in conformance with ascii.. + export LANG=C + fi + break 2 + done + done + fi + if [ -z "${GRUB_FONT_PATH}" ] ; then + if [ "x$termoutdefault" != "x1" ]; then + echo "No font for gfxterm found." >&2 ; exit 1 + fi + GRUB_TERMINAL_OUTPUT= + fi + fi +done + +for x in ${GRUB_TERMINAL_OUTPUT}; do + case "x${x}" in + xgfxterm) ;; + xconsole | xserial | xofconsole) + # make sure all our children behave in conformance with ascii.. + export LANG=C;; + *) echo "Invalid output terminal \"${GRUB_TERMINAL_OUTPUT}\"" >&2 ; exit 1 ;; + esac +done + +# These are defined in this script, export them here so that user can +# override them. +export GRUB_DEVICE \ + GRUB_DEVICE_UUID \ + GRUB_DEVICE_BOOT \ + GRUB_DEVICE_BOOT_UUID \ + GRUB_FS \ + GRUB_FONT_PATH \ + GRUB_PRELOAD_MODULES \ + GRUB_PREFIX + +# These are optional, user-defined variables. +export GRUB_DEFAULT \ + GRUB_HIDDEN_TIMEOUT \ + GRUB_HIDDEN_TIMEOUT_QUIET \ + GRUB_TIMEOUT \ + GRUB_DEFAULT_BUTTON \ + GRUB_HIDDEN_TIMEOUT_BUTTON \ + GRUB_TIMEOUT_BUTTON \ + GRUB_BUTTON_CMOS_ADDRESS \ + GRUB_BUTTON_CMOS_CLEAN \ + GRUB_DISTRIBUTOR \ + GRUB_CMDLINE_LINUX \ + GRUB_CMDLINE_LINUX_DEFAULT \ + GRUB_CMDLINE_XEN \ + GRUB_CMDLINE_XEN_DEFAULT \ + GRUB_CMDLINE_NETBSD \ + GRUB_CMDLINE_NETBSD_DEFAULT \ + GRUB_TERMINAL_INPUT \ + GRUB_TERMINAL_OUTPUT \ + GRUB_SERIAL_COMMAND \ + GRUB_DISABLE_LINUX_UUID \ + GRUB_DISABLE_RECOVERY \ + GRUB_VIDEO_BACKEND \ + GRUB_GFXMODE \ + GRUB_BACKGROUND \ + GRUB_THEME \ + GRUB_GFXPAYLOAD_LINUX \ + GRUB_DISABLE_OS_PROBER \ + GRUB_INIT_TUNE \ + GRUB_SAVEDEFAULT \ + GRUB_BADRAM + +if test "x${grub_cfg}" != "x"; then + rm -f ${grub_cfg}.new + exec > ${grub_cfg}.new + + # Allow this to fail, since /boot/grub/ might need to be fatfs to support some + # firmware implementations (e.g. OFW or EFI). + chmod 400 ${grub_cfg}.new || grub_warn "Could not make ${grub_cfg}.new readable by only root.\ + This means that if the generated config contains a password it is readable by everyone" +fi +echo "Generating grub.cfg ..." >&2 + +cat << EOF +# +# DO NOT EDIT THIS FILE +# +# It is automatically generated by $self using templates +# from ${grub_mkconfig_dir} and settings from ${sysconfdir}/default/grub +# +EOF + +for i in ${grub_mkconfig_dir}/* ; do + case "$i" in + # emacsen backup files. FIXME: support other editors + *~) ;; + # emacsen autosave files. FIXME: support other editors + \#*\#) ;; + *) + if grub_file_is_not_garbage "$i" && test -x "$i" ; then + echo + echo "### BEGIN $i ###" + "$i" + echo "### END $i ###" + fi + ;; + esac +done + +if test "x${grub_cfg}" != "x" ; then + if ! ${grub_script_check} ${grub_cfg}.new; then + echo "Syntax errors are detected in generated GRUB config file." >&2 + echo "Ensure that there are no errors in /etc/default/grub" >&2 + echo "and /etc/grub.d/* files or please file a bug report with" >&2 + echo "${grub_cfg}.new file attached." >&2 + else + # none of the children aborted with error, install the new grub.cfg + mv -f ${grub_cfg}.new ${grub_cfg} + fi +fi + +echo "done" >&2 diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in new file mode 100644 index 0000000..2c5fd8c --- /dev/null +++ b/util/grub-mkconfig_lib.in @@ -0,0 +1,227 @@ +# Helper library for grub-mkconfig +# 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 . + +transform="@program_transform_name@" + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +datadir="@datadir@" +bindir="@bindir@" +sbindir="@sbindir@" +pkgdatadir="${datadir}/`echo "@PACKAGE_TARNAME@" | sed "${transform}"`" + +if test "x$grub_probe" = x; then + grub_probe="${sbindir}/`echo grub-probe | sed "${transform}"`" +fi +if test "x$grub_mkrelpath" = x; then + grub_mkrelpath="${bindir}/`echo grub-mkrelpath | sed "${transform}"`" +fi + +if $(which gettext >/dev/null 2>/dev/null) ; then + gettext="gettext" +else + gettext="echo" +fi + +grub_warn () +{ + echo "Warning: $@" >&2 +} + +make_system_path_relative_to_its_root () +{ + "${grub_mkrelpath}" "$1" +} + +is_path_readable_by_grub () +{ + path="$1" + + # abort if path doesn't exist + if test -e "$path" ; then : ;else + return 1 + fi + + # abort if file is in a filesystem we can't read + if "${grub_probe}" -t fs "$path" > /dev/null 2>&1 ; then : ; else + return 1 + fi + + # ... or if we can't figure out the abstraction module, for example if + # memberlist fails on an LVM volume group. + if ${grub_probe} -t abstraction $path > /dev/null 2>&1 ; then : ; else + return 1 + fi + + return 0 +} + +convert_system_path_to_grub_path () +{ + path="$1" + + grub_warn "convert_system_path_to_grub_path() is deprecated. Use prepare_grub_to_access_device() instead." + + # abort if GRUB can't access the path + if is_path_readable_by_grub "${path}" ; then : ; else + return 1 + fi + + if drive="`"${grub_probe}" -t drive "$path"`" ; then : ; else + return 1 + fi + + if relative_path="`make_system_path_relative_to_its_root "$path"`" ; then : ; else + return 1 + fi + + echo "${drive}${relative_path}" +} + +save_default_entry () +{ + if [ "x${GRUB_SAVEDEFAULT}" = "xtrue" ] ; then + cat << EOF +savedefault +EOF + fi +} + +prepare_grub_to_access_device () +{ + device="$1" + + # Abstraction modules aren't auto-loaded. + abstraction="`"${grub_probe}" --device "${device}" --target=abstraction`" + for module in ${abstraction} ; do + echo "insmod ${module}" + done + + partmap="`"${grub_probe}" --device "${device}" --target=partmap`" + for module in ${partmap} ; do + case "${module}" in + netbsd | openbsd) + echo "insmod part_bsd";; + *) + echo "insmod part_${module}";; + esac + done + + fs="`"${grub_probe}" --device "${device}" --target=fs`" + for module in ${fs} ; do + echo "insmod ${module}" + done + + # If there's a filesystem UUID that GRUB is capable of identifying, use it; + # otherwise set root as per value in device.map. + echo "set root='`"${grub_probe}" --device "${device}" --target=drive`'" + if fs_uuid="`"${grub_probe}" --device "${device}" --target=fs_uuid 2> /dev/null`" ; then + echo "search --no-floppy --fs-uuid --set=root ${fs_uuid}" + fi +} + +grub_file_is_not_garbage () +{ + if test -f "$1" ; then + case "$1" in + *.dpkg-*) return 1 ;; # debian dpkg + README*) return 1 ;; # documentation + esac + else + return 1 + fi + return 0 +} + +version_test_numeric () +{ + local a="$1" + local cmp="$2" + local b="$3" + if [ "$a" = "$b" ] ; then + case "$cmp" in + ge|eq|le) return 0 ;; + gt|lt) return 1 ;; + esac + fi + if [ "$cmp" = "lt" ] ; then + c="$a" + a="$b" + b="$c" + fi + if (echo "$a" ; echo "$b") | sort -n | head -n 1 | grep -qx "$b" ; then + return 0 + else + return 1 + fi +} + +version_test_gt () +{ + local a="`echo "$1" | sed -e "s/[^-]*-//"`" + local b="`echo "$2" | sed -e "s/[^-]*-//"`" + local cmp=gt + if [ "x$b" = "x" ] ; then + return 0 + fi + case "$a:$b" in + *.old:*.old) ;; + *.old:*) a="`echo -n "$a" | sed -e 's/\.old$//'`" ; cmp=gt ;; + *:*.old) b="`echo -n "$b" | sed -e 's/\.old$//'`" ; cmp=ge ;; + esac + version_test_numeric "$a" "$cmp" "$b" + return "$?" +} + +version_find_latest () +{ + local a="" + for i in "$@" ; do + if version_test_gt "$i" "$a" ; then + a="$i" + fi + done + echo "$a" +} + +# One layer of quotation is eaten by "", the second by sed, and the third by +# printf; so this turns ' into \'. Note that you must use the output of +# this function in a printf format string. +gettext_quoted () { + "$gettext" "$@" | sed "s/'/'\\\\\\\\''/g" +} + +# Run the first argument through gettext_quoted, and then pass that and all +# remaining arguments to printf. This is a useful abbreviation and tends to +# be easier to type. +gettext_printf () { + local format="$1" + shift + printf "$(gettext_quoted "$format")" "$@" +} + +uses_abstraction () { + device="$1" + + abstraction="`"${grub_probe}" --device "${device}" --target=abstraction`" + for module in ${abstraction}; do + if test "x${module}" = "x$2"; then + return 0 + fi + done + return 1 +} diff --git a/util/grub-mkdevicemap.c b/util/grub-mkdevicemap.c new file mode 100644 index 0000000..bdecae4 --- /dev/null +++ b/util/grub-mkdevicemap.c @@ -0,0 +1,171 @@ +/* grub-mkdevicemap.c - make a device map file automatically */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009,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 + +#define _GNU_SOURCE 1 +#include + +#include "progname.h" + +static void +make_device_map (const char *device_map, int floppy_disks) +{ + int num_hd = 0; + int num_fd = 0; + FILE *fp; + + auto int NESTED_FUNC_ATTR process_device (const char *name, int is_floppy); + + int NESTED_FUNC_ATTR process_device (const char *name, int is_floppy) + { + grub_util_emit_devicemap_entry (fp, (char *) name, + is_floppy, &num_fd, &num_hd); + return 0; + } + + if (strcmp (device_map, "-") == 0) + fp = stdout; + else + fp = fopen (device_map, "w"); + + if (! fp) + grub_util_error ("cannot open %s", device_map); + + grub_util_iterate_devices (process_device, floppy_disks); + + if (fp != stdout) + fclose (fp); +} + +static struct option options[] = + { + {"device-map", required_argument, 0, 'm'}, + {"probe-second-floppy", no_argument, 0, 's'}, + {"no-floppy", no_argument, 0, 'n'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, + "Try `%s --help' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTION]...\n\ +\n\ +Generate a device map file automatically.\n\ +\n\ + -n, --no-floppy do not probe any floppy drive\n\ + -s, --probe-second-floppy probe the second floppy drive\n\ + -m, --device-map=FILE use FILE as the device map [default=%s]\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print verbose messages\n\ +\n\ +Report bugs to <%s>.\n\ +", program_name, + DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT); + + exit (status); +} + +int +main (int argc, char *argv[]) +{ + char *dev_map = 0; + int floppy_disks = 1; + + set_program_name (argv[0]); + + grub_util_init_nls (); + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "snm:r:hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'm': + if (dev_map) + free (dev_map); + + dev_map = xstrdup (optarg); + break; + + case 'n': + floppy_disks = 0; + break; + + case 's': + floppy_disks = 2; + break; + + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + if (verbosity > 1) + grub_env_set ("debug", "all"); + + make_device_map (dev_map ? : DEFAULT_DEVICE_MAP, floppy_disks); + + free (dev_map); + + return 0; +} diff --git a/util/grub-mkfont.c b/util/grub-mkfont.c new file mode 100644 index 0000000..3108d46 --- /dev/null +++ b/util/grub-mkfont.c @@ -0,0 +1,1240 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include FT_FREETYPE_H +#include FT_TRUETYPE_TAGS_H +#include FT_TRUETYPE_TABLES_H +#include + +#undef __FTERRORS_H__ +#define FT_ERROR_START_LIST const char *ft_errmsgs[] = { +#define FT_ERRORDEF(e, v, s) [e] = s, +#define FT_ERROR_END_LIST }; +#include FT_ERRORS_H + +#include "progname.h" + +#define GRUB_FONT_DEFAULT_SIZE 16 + +#define GRUB_FONT_RANGE_BLOCK 1024 + +struct grub_glyph_info +{ + struct grub_glyph_info *next; + grub_uint32_t char_code; + int width; + int height; + int x_ofs; + int y_ofs; + int device_width; + int bitmap_size; + grub_uint8_t *bitmap; +}; + +enum file_formats +{ + PF2, + ASCII_BITMAPS, + WIDTH_SPEC +}; + +#define GRUB_FONT_FLAG_BOLD 1 +#define GRUB_FONT_FLAG_NOBITMAP 2 +#define GRUB_FONT_FLAG_NOHINTING 4 +#define GRUB_FONT_FLAG_FORCEHINT 8 + +struct grub_font_info +{ + char* name; + int style; + int desc; + int asce; + int size; + int max_width; + int max_height; + int min_y; + int max_y; + int flags; + int num_range; + grub_uint32_t *ranges; + struct grub_glyph_info *glyphs_unsorted; + struct grub_glyph_info *glyphs_sorted; + int num_glyphs; +}; + +static struct option options[] = +{ + {"output", required_argument, 0, 'o'}, + {"name", required_argument, 0, 'n'}, + {"index", required_argument, 0, 'i'}, + {"range", required_argument, 0, 'r'}, + {"size", required_argument, 0, 's'}, + {"desc", required_argument, 0, 'd'}, + {"asce", required_argument, 0, 'c'}, + {"bold", no_argument, 0, 'b'}, + {"no-bitmap", no_argument, 0, 0x100}, + {"no-hinting", no_argument, 0, 0x101}, + {"force-autohint", no_argument, 0, 'a'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {"ascii-bitmaps", no_argument, 0, 0x102}, + {"width-spec", no_argument, 0, 0x103}, + {0, 0, 0, 0} +}; + +int font_verbosity; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTIONS] FONT_FILES\n\ +\nOptions:\n\ + -o, --output=FILE_NAME set output file name\n\ + --ascii-bitmaps save only the ASCII bitmaps\n\ + --width-spec create width summary file\n\ + -i, --index=N set face index\n\ + -r, --range=A-B[,C-D] set font range\n\ + -n, --name=S set font family name\n\ + -s, --size=N set font size\n\ + -d, --desc=N set font descent\n\ + -c, --asce=N set font ascent\n\ + -b, --bold convert to bold font\n\ + -a, --force-autohint force autohint\n\ + --no-hinting disable hinting\n\ + --no-bitmap ignore bitmap strikes when loading\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print verbose messages\n\ +\n\ +Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); + + exit (status); +} + +void +add_pixel (grub_uint8_t **data, int *mask, int not_blank) +{ + if (*mask == 0) + { + (*data)++; + **data = 0; + *mask = 128; + } + + if (not_blank) + **data |= *mask; + + *mask >>= 1; +} + +static void +add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + grub_uint32_t char_code, int nocut) +{ + struct grub_glyph_info *glyph_info; + int width, height; + int cuttop, cutbottom, cutleft, cutright; + grub_uint8_t *data; + int mask, i, j, bitmap_size; + FT_GlyphSlot glyph; + int flag = FT_LOAD_RENDER | FT_LOAD_MONOCHROME; + FT_Error err; + + if (font_info->flags & GRUB_FONT_FLAG_NOBITMAP) + flag |= FT_LOAD_NO_BITMAP; + + if (font_info->flags & GRUB_FONT_FLAG_NOHINTING) + flag |= FT_LOAD_NO_HINTING; + else if (font_info->flags & GRUB_FONT_FLAG_FORCEHINT) + flag |= FT_LOAD_FORCE_AUTOHINT; + + err = FT_Load_Glyph (face, glyph_idx, flag); + if (err) + { + printf ("Freetype Error %d loading glyph 0x%x for U+0x%x%s", + err, glyph_idx, char_code & GRUB_FONT_CODE_CHAR_MASK, + char_code & GRUB_FONT_CODE_RIGHT_JOINED + ? ((char_code & GRUB_FONT_CODE_LEFT_JOINED) ? " (medial)": + " (leftmost)") + : ((char_code & GRUB_FONT_CODE_LEFT_JOINED) ? " (rightmost)": + "")); + + if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs)) + printf (": %s\n", ft_errmsgs[err]); + else + printf ("\n"); + return; + } + + glyph = face->glyph; + + if (font_info->flags & GRUB_FONT_FLAG_BOLD) + FT_GlyphSlot_Embolden (glyph); + + if (glyph->next) + printf ("%x\n", char_code); + + if (nocut) + cuttop = cutbottom = cutleft = cutright = 0; + else + { + for (cuttop = 0; cuttop < glyph->bitmap.rows; cuttop++) + { + for (j = 0; j < glyph->bitmap.width; j++) + if (glyph->bitmap.buffer[j / 8 + cuttop * glyph->bitmap.pitch] + & (1 << (7 - (j & 7)))) + break; + if (j != glyph->bitmap.width) + break; + } + + for (cutbottom = glyph->bitmap.rows - 1; cutbottom >= 0; cutbottom--) + { + for (j = 0; j < glyph->bitmap.width; j++) + if (glyph->bitmap.buffer[j / 8 + cutbottom * glyph->bitmap.pitch] + & (1 << (7 - (j & 7)))) + break; + if (j != glyph->bitmap.width) + break; + } + cutbottom = glyph->bitmap.rows - 1 - cutbottom; + if (cutbottom + cuttop >= glyph->bitmap.rows) + cutbottom = 0; + + for (cutleft = 0; cutleft < glyph->bitmap.width; cutleft++) + { + for (j = 0; j < glyph->bitmap.rows; j++) + if (glyph->bitmap.buffer[cutleft / 8 + j * glyph->bitmap.pitch] + & (1 << (7 - (cutleft & 7)))) + break; + if (j != glyph->bitmap.rows) + break; + } + for (cutright = glyph->bitmap.width - 1; cutright >= 0; cutright--) + { + for (j = 0; j < glyph->bitmap.rows; j++) + if (glyph->bitmap.buffer[cutright / 8 + j * glyph->bitmap.pitch] + & (1 << (7 - (cutright & 7)))) + break; + if (j != glyph->bitmap.rows) + break; + } + cutright = glyph->bitmap.width - 1 - cutright; + if (cutright + cutleft >= glyph->bitmap.width) + cutright = 0; + } + + width = glyph->bitmap.width - cutleft - cutright; + height = glyph->bitmap.rows - cutbottom - cuttop; + + bitmap_size = ((width * height + 7) / 8); + glyph_info = xmalloc (sizeof (struct grub_glyph_info)); + glyph_info->bitmap = xmalloc (bitmap_size); + glyph_info->bitmap_size = bitmap_size; + + glyph_info->next = font_info->glyphs_unsorted; + font_info->glyphs_unsorted = glyph_info; + font_info->num_glyphs++; + + glyph_info->char_code = char_code; + glyph_info->width = width; + glyph_info->height = height; + glyph_info->x_ofs = glyph->bitmap_left + cutleft; + glyph_info->y_ofs = glyph->bitmap_top - height - cuttop; + glyph_info->device_width = glyph->metrics.horiAdvance / 64; + + if (width > font_info->max_width) + font_info->max_width = width; + + if (height > font_info->max_height) + font_info->max_height = height; + + if (glyph_info->y_ofs < font_info->min_y && glyph_info->y_ofs > -font_info->size) + font_info->min_y = glyph_info->y_ofs; + + if (glyph_info->y_ofs + height > font_info->max_y) + font_info->max_y = glyph_info->y_ofs + height; + + mask = 0; + data = &glyph_info->bitmap[0] - 1; + for (j = cuttop; j < height + cuttop; j++) + for (i = cutleft; i < width + cutleft; i++) + add_pixel (&data, &mask, + glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] & + (1 << (7 - (i & 7)))); +} + +struct glyph_replace *subst_rightjoin, *subst_leftjoin, *subst_medijoin; + +struct glyph_replace +{ + struct glyph_replace *next; + grub_uint32_t from, to; +}; + +/* TODO: sort glyph_replace and use binary search if necessary. */ +static void +add_char (struct grub_font_info *font_info, FT_Face face, + grub_uint32_t char_code, int nocut) +{ + FT_UInt glyph_idx; + struct glyph_replace *cur; + + glyph_idx = FT_Get_Char_Index (face, char_code); + if (!glyph_idx) + return; + add_glyph (font_info, glyph_idx, face, char_code, nocut); + for (cur = subst_rightjoin; cur; cur = cur->next) + if (cur->from == glyph_idx) + { + add_glyph (font_info, cur->to, face, + char_code | GRUB_FONT_CODE_RIGHT_JOINED, nocut); + break; + } + if (!cur && char_code >= GRUB_UNICODE_ARABIC_START + && char_code < GRUB_UNICODE_ARABIC_END) + { + int i; + for (i = 0; grub_unicode_arabic_shapes[i].code; i++) + if (grub_unicode_arabic_shapes[i].code == char_code + && grub_unicode_arabic_shapes[i].right_linked) + { + FT_UInt idx2; + idx2 = FT_Get_Char_Index (face, grub_unicode_arabic_shapes[i] + .right_linked); + if (idx2) + add_glyph (font_info, idx2, face, + char_code | GRUB_FONT_CODE_RIGHT_JOINED, nocut); + break; + } + + } + + for (cur = subst_leftjoin; cur; cur = cur->next) + if (cur->from == glyph_idx) + { + add_glyph (font_info, cur->to, face, + char_code | GRUB_FONT_CODE_LEFT_JOINED, nocut); + break; + } + if (!cur && char_code >= GRUB_UNICODE_ARABIC_START + && char_code < GRUB_UNICODE_ARABIC_END) + { + int i; + for (i = 0; grub_unicode_arabic_shapes[i].code; i++) + if (grub_unicode_arabic_shapes[i].code == char_code + && grub_unicode_arabic_shapes[i].left_linked) + { + FT_UInt idx2; + idx2 = FT_Get_Char_Index (face, grub_unicode_arabic_shapes[i] + .left_linked); + if (idx2) + add_glyph (font_info, idx2, face, + char_code | GRUB_FONT_CODE_LEFT_JOINED, nocut); + break; + } + + } + for (cur = subst_medijoin; cur; cur = cur->next) + if (cur->from == glyph_idx) + { + add_glyph (font_info, cur->to, face, + char_code | GRUB_FONT_CODE_LEFT_JOINED + | GRUB_FONT_CODE_RIGHT_JOINED, nocut); + break; + } + if (!cur && char_code >= GRUB_UNICODE_ARABIC_START + && char_code < GRUB_UNICODE_ARABIC_END) + { + int i; + for (i = 0; grub_unicode_arabic_shapes[i].code; i++) + if (grub_unicode_arabic_shapes[i].code == char_code + && grub_unicode_arabic_shapes[i].both_linked) + { + FT_UInt idx2; + idx2 = FT_Get_Char_Index (face, grub_unicode_arabic_shapes[i] + .both_linked); + if (idx2) + add_glyph (font_info, idx2, face, + char_code | GRUB_FONT_CODE_LEFT_JOINED + | GRUB_FONT_CODE_RIGHT_JOINED, nocut); + break; + } + + } +} + +struct gsub_header +{ + grub_uint32_t version; + grub_uint16_t scripts_off; + grub_uint16_t features_off; + grub_uint16_t lookups_off; +} __attribute__ ((packed)); + +struct gsub_features +{ + grub_uint16_t count; + struct + { +#define FEATURE_FINA 0x66696e61 +#define FEATURE_INIT 0x696e6974 +#define FEATURE_MEDI 0x6d656469 +#define FEATURE_AALT 0x61616c74 +#define FEATURE_LIGA 0x6c696761 +#define FEATURE_RLIG 0x726c6967 + grub_uint32_t feature_tag; + grub_uint16_t offset; + } __attribute__ ((packed)) features[0]; +} __attribute__ ((packed)); + +struct gsub_feature +{ + grub_uint16_t params; + grub_uint16_t lookupcount; + grub_uint16_t lookupindices[0]; +} __attribute__ ((packed)); + +struct gsub_lookup_list +{ + grub_uint16_t count; + grub_uint16_t offsets[0]; +} __attribute__ ((packed)); + +struct gsub_lookup +{ + grub_uint16_t type; + grub_uint16_t flag; + grub_uint16_t subtablecount; + grub_uint16_t subtables[0]; +} __attribute__ ((packed)); + +struct gsub_substitution +{ + grub_uint16_t type; + grub_uint16_t coverage_off; + union + { + grub_int16_t delta; + struct + { + grub_int16_t count; + grub_uint16_t repl[0]; + }; + }; +} __attribute__ ((packed)); + +struct gsub_coverage_list +{ + grub_uint16_t type; + grub_uint16_t count; + grub_uint16_t glyphs[0]; +} __attribute__ ((packed)); + +struct gsub_coverage_ranges +{ + grub_uint16_t type; + grub_uint16_t count; + struct + { + grub_uint16_t start; + grub_uint16_t end; + grub_uint16_t start_index; + } __attribute__ ((packed)) ranges[0]; +} __attribute__ ((packed)); + +#define GSUB_SINGLE_SUBSTITUTION 1 + +#define GSUB_SUBSTITUTION_DELTA 1 +#define GSUB_SUBSTITUTION_MAP 2 + +#define GSUB_COVERAGE_LIST 1 +#define GSUB_COVERAGE_RANGE 2 + +#define GSUB_RTL_CHAR 1 + +static void +add_subst (grub_uint32_t from, grub_uint32_t to, struct glyph_replace **target) +{ + struct glyph_replace *new = xmalloc (sizeof (*new)); + new->next = *target; + new->from = from; + new->to = to; + *target = new; +} + +static void +process_cursive (struct gsub_feature *feature, + struct gsub_lookup_list *lookups, + grub_uint32_t feattag) +{ + int j, k; + int i; + struct glyph_replace **target; + struct gsub_substitution *sub; + + auto inline void subst (grub_uint32_t glyph); + void subst (grub_uint32_t glyph) + { + grub_uint16_t substtype; + substtype = grub_be_to_cpu16 (sub->type); + + if (substtype == GSUB_SUBSTITUTION_DELTA) + add_subst (glyph, glyph + grub_be_to_cpu16 (sub->delta), target); + else if (i >= grub_be_to_cpu16 (sub->count)) + printf ("Out of range substitution (%d, %d)\n", i, + grub_be_to_cpu16 (sub->count)); + else + add_subst (glyph, grub_be_to_cpu16 (sub->repl[i++]), target); + } + + for (j = 0; j < grub_be_to_cpu16 (feature->lookupcount); j++) + { + int lookup_index = grub_be_to_cpu16 (feature->lookupindices[j]); + struct gsub_lookup *lookup; + if (lookup_index >= grub_be_to_cpu16 (lookups->count)) + { + printf ("Out of range lookup: %d\n", lookup_index); + continue; + } + lookup = (struct gsub_lookup *) + ((grub_uint8_t *) lookups + + grub_be_to_cpu16 (lookups->offsets[lookup_index])); + if (grub_be_to_cpu16 (lookup->type) != GSUB_SINGLE_SUBSTITUTION) + { + printf ("Unsupported substitution type: %d\n", + grub_be_to_cpu16 (lookup->type)); + continue; + } + if (grub_be_to_cpu16 (lookup->flag) & ~GSUB_RTL_CHAR) + { + printf ("Unsupported substitution flag: 0x%x\n", + grub_be_to_cpu16 (lookup->flag)); + } + switch (feattag) + { + case FEATURE_INIT: + if (grub_be_to_cpu16 (lookup->flag) & GSUB_RTL_CHAR) + target = &subst_leftjoin; + else + target = &subst_rightjoin; + break; + case FEATURE_FINA: + if (grub_be_to_cpu16 (lookup->flag) & GSUB_RTL_CHAR) + target = &subst_rightjoin; + else + target = &subst_leftjoin; + break; + case FEATURE_MEDI: + target = &subst_medijoin; + break; + } + for (k = 0; k < grub_be_to_cpu16 (lookup->subtablecount); k++) + { + sub = (struct gsub_substitution *) + ((grub_uint8_t *) lookup + grub_be_to_cpu16 (lookup->subtables[k])); + grub_uint16_t substtype; + substtype = grub_be_to_cpu16 (sub->type); + if (substtype != GSUB_SUBSTITUTION_MAP + && substtype != GSUB_SUBSTITUTION_DELTA) + { + printf ("Unsupported substitution specification: %d\n", + substtype); + continue; + } + void *coverage = (grub_uint8_t *) sub + + grub_be_to_cpu16 (sub->coverage_off); + grub_uint32_t covertype; + covertype = grub_be_to_cpu16 (*(grub_uint16_t * __attribute__ ((packed))) coverage); + i = 0; + if (covertype == GSUB_COVERAGE_LIST) + { + struct gsub_coverage_list *cover = coverage; + int l; + for (l = 0; l < grub_be_to_cpu16 (cover->count); l++) + subst (grub_be_to_cpu16 (cover->glyphs[l])); + } + else if (covertype == GSUB_COVERAGE_RANGE) + { + struct gsub_coverage_ranges *cover = coverage; + int l, m; + for (l = 0; l < grub_be_to_cpu16 (cover->count); l++) + for (m = grub_be_to_cpu16 (cover->ranges[l].start); + m <= grub_be_to_cpu16 (cover->ranges[l].end); m++) + subst (m); + } + else + printf ("Unsupported coverage specification: %d\n", covertype); + } + } +} + +void +add_font (struct grub_font_info *font_info, FT_Face face, int nocut) +{ + struct gsub_header *gsub = NULL; + FT_ULong gsub_len = 0; + + if (!FT_Load_Sfnt_Table (face, TTAG_GSUB, 0, NULL, &gsub_len)) + { + gsub = xmalloc (gsub_len); + if (FT_Load_Sfnt_Table (face, TTAG_GSUB, 0, (void *) gsub, &gsub_len)) + { + free (gsub); + gsub = NULL; + gsub_len = 0; + } + } + if (gsub) + { + struct gsub_features *features + = (struct gsub_features *) (((grub_uint8_t *) gsub) + + grub_be_to_cpu16 (gsub->features_off)); + struct gsub_lookup_list *lookups + = (struct gsub_lookup_list *) (((grub_uint8_t *) gsub) + + grub_be_to_cpu16 (gsub->lookups_off)); + int i; + int nfeatures = grub_be_to_cpu16 (features->count); + for (i = 0; i < nfeatures; i++) + { + struct gsub_feature *feature = (struct gsub_feature *) + ((grub_uint8_t *) features + + grub_be_to_cpu16 (features->features[i].offset)); + grub_uint32_t feattag + = grub_be_to_cpu32 (features->features[i].feature_tag); + if (feature->params) + printf ("WARNING: unsupported feature parameters: %x\n", + grub_be_to_cpu16 (feature->params)); + switch (feattag) + { + /* Used for retrieving all possible variants. Useless in grub. */ + case FEATURE_AALT: + break; + + /* FIXME: Add ligature support. */ + case FEATURE_LIGA: + case FEATURE_RLIG: + break; + + /* Cursive form variants. */ + case FEATURE_FINA: + case FEATURE_INIT: + case FEATURE_MEDI: + process_cursive (feature, lookups, feattag); + break; + + default: + { + char str[5]; + int j; + memcpy (str, &features->features[i].feature_tag, + sizeof (features->features[i].feature_tag)); + str[4] = 0; + for (j = 0; j < 4; j++) + if (!grub_isgraph (str[j])) + str[j] = '?'; + printf ("Unknown gsub feature 0x%x (%s)\n", feattag, str); + } + } + } + } + + if (font_info->num_range) + { + int i; + grub_uint32_t j; + + for (i = 0; i < font_info->num_range; i++) + for (j = font_info->ranges[i * 2]; j <= font_info->ranges[i * 2 + 1]; + j++) + add_char (font_info, face, j, nocut); + } + else + { + grub_uint32_t char_code, glyph_index; + + for (char_code = FT_Get_First_Char (face, &glyph_index); + glyph_index; + char_code = FT_Get_Next_Char (face, char_code, &glyph_index)) + add_char (font_info, face, char_code, nocut); + } +} + +void +write_string_section (char *name, char *str, int* offset, FILE* file) +{ + grub_uint32_t leng, leng_be32; + + leng = strlen (str) + 1; + leng_be32 = grub_cpu_to_be32 (leng); + + grub_util_write_image (name, 4, file); + grub_util_write_image ((char *) &leng_be32, 4, file); + grub_util_write_image (str, leng, file); + + *offset += 8 + leng; +} + +void +write_be16_section (char *name, grub_uint16_t data, int* offset, FILE* file) +{ + grub_uint32_t leng; + + leng = grub_cpu_to_be32 (2); + data = grub_cpu_to_be16 (data); + grub_util_write_image (name, 4, file); + grub_util_write_image ((char *) &leng, 4, file); + grub_util_write_image ((char *) &data, 2, file); + + *offset += 10; +} + +void +print_glyphs (struct grub_font_info *font_info) +{ + int num; + struct grub_glyph_info *glyph; + char line[512]; + + for (glyph = font_info->glyphs_sorted, num = 0; num < font_info->num_glyphs; + glyph++, num++) + { + int x, y, xmax, xmin, ymax, ymin; + grub_uint8_t *bitmap, mask; + + printf ("\nGlyph #%d, U+%04x\n", num, glyph->char_code); + printf ("Width %d, Height %d, X offset %d, Y offset %d, Device width %d\n", + glyph->width, glyph->height, glyph->x_ofs, glyph->y_ofs, + glyph->device_width); + + xmax = glyph->x_ofs + glyph->width; + if (xmax < glyph->device_width) + xmax = glyph->device_width; + + xmin = glyph->x_ofs; + if (xmin > 0) + xmin = 0; + + ymax = glyph->y_ofs + glyph->height; + if (ymax < font_info->asce) + ymax = font_info->asce; + + ymin = glyph->y_ofs; + if (ymin > - font_info->desc) + ymin = - font_info->desc; + + bitmap = glyph->bitmap; + mask = 0x80; + for (y = ymax - 1; y >= ymin; y--) + { + int line_pos; + + line_pos = 0; + for (x = xmin; x < xmax; x++) + { + if ((x >= glyph->x_ofs) && + (x < glyph->x_ofs + glyph->width) && + (y >= glyph->y_ofs) && + (y < glyph->y_ofs + glyph->height)) + { + line[line_pos++] = (*bitmap & mask) ? '#' : '_'; + mask >>= 1; + if (mask == 0) + { + mask = 0x80; + bitmap++; + } + } + else if ((x >= 0) && + (x < glyph->device_width) && + (y >= - font_info->desc) && + (y < font_info->asce)) + { + line[line_pos++] = ((x == 0) || (y == 0)) ? '+' : '.'; + } + else + line[line_pos++] = '*'; + } + line[line_pos] = 0; + printf ("%s\n", line); + } + } +} + +void +write_font_ascii_bitmap (struct grub_font_info *font_info, char *output_file) +{ + FILE *file; + struct grub_glyph_info *glyph; + int num; + + file = fopen (output_file, "wb"); + if (! file) + grub_util_error ("Can\'t write to file %s.", output_file); + + int correct_size; + for (glyph = font_info->glyphs_sorted, num = 0; num < font_info->num_glyphs; + glyph++, num++) + { + correct_size = 1; + if (glyph->width != 8 || glyph->height != 16) + { + /* printf ("Width or height from glyph U+%04x not supported, skipping.\n", glyph->char_code); */ + correct_size = 0; + } + int row; + for (row = 0; row < glyph->height; row++) + { + if (correct_size) + fwrite (&glyph->bitmap[row], sizeof(glyph->bitmap[row]), 1, file); + else + fwrite (&correct_size, 1, 1, file); + } + } + fclose (file); +} + +void +write_font_width_spec (struct grub_font_info *font_info, char *output_file) +{ + FILE *file; + struct grub_glyph_info *glyph; + grub_uint8_t *out; + + out = xmalloc (8192); + memset (out, 0, 8192); + + file = fopen (output_file, "wb"); + if (! file) + grub_util_error ("Can\'t write to file %s.", output_file); + + for (glyph = font_info->glyphs_sorted; + glyph < font_info->glyphs_sorted + font_info->num_glyphs; glyph++) + if (glyph->width > 12) + out[glyph->char_code >> 3] |= (1 << (glyph->char_code & 7)); + + fwrite (out, 8192, 1, file); + fclose (file); + free (out); +} + +void +write_font_pf2 (struct grub_font_info *font_info, char *output_file) +{ + FILE *file; + grub_uint32_t leng; + char style_name[20], *font_name; + int offset; + struct grub_glyph_info *cur; + + file = fopen (output_file, "wb"); + if (! file) + grub_util_error ("can\'t write to file %s.", output_file); + + offset = 0; + + leng = grub_cpu_to_be32 (4); + grub_util_write_image (FONT_FORMAT_SECTION_NAMES_FILE, + sizeof(FONT_FORMAT_SECTION_NAMES_FILE) - 1, file); + grub_util_write_image ((char *) &leng, 4, file); + grub_util_write_image (FONT_FORMAT_PFF2_MAGIC, 4, file); + offset += 12; + + if (! font_info->name) + font_info->name = "Unknown"; + + if (font_info->flags & GRUB_FONT_FLAG_BOLD) + font_info->style |= FT_STYLE_FLAG_BOLD; + + style_name[0] = 0; + if (font_info->style & FT_STYLE_FLAG_BOLD) + strcpy (style_name, " Bold"); + + if (font_info->style & FT_STYLE_FLAG_ITALIC) + strcat (style_name, " Italic"); + + if (! style_name[0]) + strcpy (style_name, " Regular"); + + font_name = xasprintf ("%s %s %d", font_info->name, &style_name[1], + font_info->size); + + write_string_section (FONT_FORMAT_SECTION_NAMES_FONT_NAME, + font_name, &offset, file); + write_string_section (FONT_FORMAT_SECTION_NAMES_FAMILY, + font_info->name, &offset, file); + write_string_section (FONT_FORMAT_SECTION_NAMES_WEIGHT, + (font_info->style & FT_STYLE_FLAG_BOLD) ? + "bold" : "normal", + &offset, file); + write_string_section (FONT_FORMAT_SECTION_NAMES_SLAN, + (font_info->style & FT_STYLE_FLAG_ITALIC) ? + "italic" : "normal", + &offset, file); + + write_be16_section (FONT_FORMAT_SECTION_NAMES_POINT_SIZE, + font_info->size, &offset, file); + write_be16_section (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH, + font_info->max_width, &offset, file); + write_be16_section (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT, + font_info->max_height, &offset, file); + + if (! font_info->desc) + { + if (font_info->min_y >= 0) + font_info->desc = 1; + else + font_info->desc = - font_info->min_y; + } + + if (! font_info->asce) + { + if (font_info->max_y <= 0) + font_info->asce = 1; + else + font_info->asce = font_info->max_y; + } + + write_be16_section (FONT_FORMAT_SECTION_NAMES_ASCENT, + font_info->asce, &offset, file); + write_be16_section (FONT_FORMAT_SECTION_NAMES_DESCENT, + font_info->desc, &offset, file); + + if (font_verbosity > 0) + { + printf ("Font name: %s\n", font_name); + printf ("Max width: %d\n", font_info->max_width); + printf ("Max height: %d\n", font_info->max_height); + printf ("Font ascent: %d\n", font_info->asce); + printf ("Font descent: %d\n", font_info->desc); + } + + if (font_verbosity > 0) + printf ("Number of glyph: %d\n", font_info->num_glyphs); + + leng = grub_cpu_to_be32 (font_info->num_glyphs * 9); + grub_util_write_image (FONT_FORMAT_SECTION_NAMES_CHAR_INDEX, + sizeof(FONT_FORMAT_SECTION_NAMES_CHAR_INDEX) - 1, + file); + grub_util_write_image ((char *) &leng, 4, file); + offset += 8 + font_info->num_glyphs * 9 + 8; + + for (cur = font_info->glyphs_sorted; + cur < font_info->glyphs_sorted + font_info->num_glyphs; cur++) + { + grub_uint32_t data32; + grub_uint8_t data8; + data32 = grub_cpu_to_be32 (cur->char_code); + grub_util_write_image ((char *) &data32, 4, file); + data8 = 0; + grub_util_write_image ((char *) &data8, 1, file); + data32 = grub_cpu_to_be32 (offset); + grub_util_write_image ((char *) &data32, 4, file); + offset += 10 + cur->bitmap_size; + } + + leng = 0xffffffff; + grub_util_write_image (FONT_FORMAT_SECTION_NAMES_DATA, + sizeof(FONT_FORMAT_SECTION_NAMES_DATA) - 1, file); + grub_util_write_image ((char *) &leng, 4, file); + + for (cur = font_info->glyphs_sorted; + cur < font_info->glyphs_sorted + font_info->num_glyphs; cur++) + { + grub_uint16_t data; + data = grub_cpu_to_be16 (cur->width); + grub_util_write_image ((char *) &data, 2, file); + data = grub_cpu_to_be16 (cur->height); + grub_util_write_image ((char *) &data, 2, file); + data = grub_cpu_to_be16 (cur->x_ofs); + grub_util_write_image ((char *) &data, 2, file); + data = grub_cpu_to_be16 (cur->y_ofs); + grub_util_write_image ((char *) &data, 2, file); + data = grub_cpu_to_be16 (cur->device_width); + grub_util_write_image ((char *) &data, 2, file); + grub_util_write_image ((char *) &cur->bitmap[0], cur->bitmap_size, file); + } + + fclose (file); +} + +int +main (int argc, char *argv[]) +{ + struct grub_font_info font_info; + FT_Library ft_lib; + int font_index = 0; + int font_size = 0; + char *output_file = NULL; + enum file_formats file_format = PF2; + + memset (&font_info, 0, sizeof (font_info)); + + set_program_name (argv[0]); + + grub_util_init_nls (); + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "bao:n:i:s:d:r:hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'b': + font_info.flags |= GRUB_FONT_FLAG_BOLD; + break; + + case 0x100: + font_info.flags |= GRUB_FONT_FLAG_NOBITMAP; + break; + + case 0x101: + font_info.flags |= GRUB_FONT_FLAG_NOHINTING; + break; + + case 'a': + font_info.flags |= GRUB_FONT_FLAG_FORCEHINT; + break; + + case 'o': + output_file = optarg; + break; + + case 'n': + font_info.name = optarg; + break; + + case 'i': + font_index = strtoul (optarg, NULL, 0); + break; + + case 's': + font_size = strtoul (optarg, NULL, 0); + break; + + case 'r': + { + char *p = optarg; + + while (1) + { + grub_uint32_t a, b; + + a = strtoul (p, &p, 0); + if (*p != '-') + grub_util_error ("invalid font range"); + b = strtoul (p + 1, &p, 0); + if ((font_info.num_range & (GRUB_FONT_RANGE_BLOCK - 1)) == 0) + font_info.ranges = xrealloc (font_info.ranges, + (font_info.num_range + + GRUB_FONT_RANGE_BLOCK) * + sizeof (grub_uint32_t) * 2); + + font_info.ranges[font_info.num_range * 2] = a; + font_info.ranges[font_info.num_range * 2 + 1] = b; + font_info.num_range++; + + if (*p) + { + if (*p != ',') + grub_util_error ("invalid font range"); + else + p++; + } + else + break; + } + break; + } + + case 'd': + font_info.desc = strtoul (optarg, NULL, 0); + break; + + case 'e': + font_info.asce = strtoul (optarg, NULL, 0); + break; + + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + font_verbosity++; + break; + + case 0x102: + file_format = ASCII_BITMAPS; + break; + + case 0x103: + file_format = WIDTH_SPEC; + break; + + default: + usage (1); + break; + } + } + + if (file_format == ASCII_BITMAPS && font_info.num_range > 0) + { + grub_util_error ("Option --ascii-bitmaps doesn't accept ranges (use ASCII)."); + return 1; + } + + else if (file_format == ASCII_BITMAPS) + { + font_info.ranges = xrealloc (font_info.ranges, + GRUB_FONT_RANGE_BLOCK * + sizeof (grub_uint32_t) * 2); + + font_info.ranges[0] = (grub_uint32_t) 0x00; + font_info.ranges[1] = (grub_uint32_t) 0x7f; + font_info.num_range = 1; + } + + if (! output_file) + grub_util_error ("no output file is specified"); + + if (FT_Init_FreeType (&ft_lib)) + grub_util_error ("FT_Init_FreeType fails"); + + for (; optind < argc; optind++) + { + FT_Face ft_face; + int size; + FT_Error err; + + err = FT_New_Face (ft_lib, argv[optind], font_index, &ft_face); + if (err) + { + grub_printf ("can't open file %s, index %d: error %d", argv[optind], + font_index, err); + if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs)) + printf (": %s\n", ft_errmsgs[err]); + else + printf ("\n"); + + continue; + } + + if ((! font_info.name) && (ft_face->family_name)) + font_info.name = xstrdup (ft_face->family_name); + + size = font_size; + if (! size) + { + if ((ft_face->face_flags & FT_FACE_FLAG_SCALABLE) || + (! ft_face->num_fixed_sizes)) + size = GRUB_FONT_DEFAULT_SIZE; + else + size = ft_face->available_sizes[0].height; + } + + font_info.style = ft_face->style_flags; + font_info.size = size; + + if (FT_Set_Pixel_Sizes (ft_face, size, size)) + grub_util_error ("can't set %dx%d font size", size, size); + add_font (&font_info, ft_face, file_format != PF2); + FT_Done_Face (ft_face); + } + + FT_Done_FreeType (ft_lib); + + { + int counter[65537]; + struct grub_glyph_info *tmp, *cur; + int i; + + memset (counter, 0, sizeof (counter)); + + for (cur = font_info.glyphs_unsorted; cur; cur = cur->next) + counter[(cur->char_code & 0xffff) + 1]++; + for (i = 0; i < 0x10000; i++) + counter[i+1] += counter[i]; + tmp = xmalloc (font_info.num_glyphs + * sizeof (tmp[0])); + for (cur = font_info.glyphs_unsorted; cur; cur = cur->next) + tmp[counter[(cur->char_code & 0xffff)]++] = *cur; + + memset (counter, 0, sizeof (counter)); + + for (cur = tmp; cur < tmp + font_info.num_glyphs; cur++) + counter[((cur->char_code & 0xffff0000) >> 16) + 1]++; + for (i = 0; i < 0x10000; i++) + counter[i+1] += counter[i]; + font_info.glyphs_sorted = xmalloc (font_info.num_glyphs + * sizeof (font_info.glyphs_sorted[0])); + for (cur = tmp; cur < tmp + font_info.num_glyphs; cur++) + font_info.glyphs_sorted[counter[(cur->char_code & 0xffff0000) >> 16]++] + = *cur; + free (tmp); + } + + switch (file_format) + { + case PF2: + write_font_pf2 (&font_info, output_file); + break; + + case ASCII_BITMAPS: + write_font_ascii_bitmap (&font_info, output_file); + break; + + case WIDTH_SPEC: + write_font_width_spec (&font_info, output_file); + break; + } + + if (font_verbosity > 1) + print_glyphs (&font_info); + + return 0; +} diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c new file mode 100644 index 0000000..5e964a3 --- /dev/null +++ b/util/grub-mkimage.c @@ -0,0 +1,1620 @@ +/* grub-mkimage.c - make a bootable image */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define _GNU_SOURCE 1 +#include + +#include "progname.h" + +#define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof)) + +#ifdef HAVE_LIBLZMA +#include +#endif + +#define TARGET_NO_FIELD 0xffffffff + +typedef enum { + COMPRESSION_AUTO, COMPRESSION_NONE, COMPRESSION_XZ +} grub_compression_t; + +struct image_target_desc +{ + const char *name; + grub_size_t voidp_sizeof; + int bigendian; + enum { + IMAGE_I386_PC, IMAGE_EFI, IMAGE_COREBOOT, + IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, IMAGE_I386_IEEE1275, + IMAGE_YEELOONG_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH, + IMAGE_I386_PC_PXE + } id; + enum + { + PLATFORM_FLAGS_NONE = 0, + PLATFORM_FLAGS_LZMA = 1, + PLATFORM_FLAGS_DECOMPRESSORS = 2 + } flags; + unsigned prefix; + unsigned prefix_end; + unsigned raw_size; + unsigned total_module_size; + unsigned kernel_image_size; + unsigned compressed_size; + unsigned link_align; + grub_uint16_t elf_target; + unsigned section_align; + signed vaddr_offset; + unsigned install_dos_part, install_bsd_part; + grub_uint64_t link_addr; + unsigned mod_gap, mod_align; + grub_compression_t default_compression; +}; + +struct image_target_desc image_targets[] = + { + { + .name = "i386-coreboot", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_COREBOOT, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_I386_COREBOOT_PREFIX, + .prefix_end = GRUB_KERNEL_I386_COREBOOT_PREFIX_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR, + .elf_target = EM_386, + .link_align = 4, + .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN + }, + { + .name = "i386-multiboot", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_COREBOOT, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_I386_MULTIBOOT_PREFIX, + .prefix_end = GRUB_KERNEL_I386_MULTIBOOT_PREFIX_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR, + .elf_target = EM_386, + .link_align = 4, + .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN + }, + { + .name = "i386-pc", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_PC, + .flags = PLATFORM_FLAGS_LZMA, + .prefix = GRUB_KERNEL_I386_PC_PREFIX, + .prefix_end = GRUB_KERNEL_I386_PC_PREFIX_END, + .raw_size = GRUB_KERNEL_I386_PC_RAW_SIZE, + .total_module_size = GRUB_KERNEL_I386_PC_TOTAL_MODULE_SIZE, + .kernel_image_size = GRUB_KERNEL_I386_PC_KERNEL_IMAGE_SIZE, + .compressed_size = GRUB_KERNEL_I386_PC_COMPRESSED_SIZE, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = GRUB_KERNEL_I386_PC_INSTALL_DOS_PART, + .install_bsd_part = GRUB_KERNEL_I386_PC_INSTALL_BSD_PART, + .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR + }, + { + .name = "i386-pc-pxe", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_PC_PXE, + .flags = PLATFORM_FLAGS_LZMA, + .prefix = GRUB_KERNEL_I386_PC_PREFIX, + .prefix_end = GRUB_KERNEL_I386_PC_PREFIX_END, + .raw_size = GRUB_KERNEL_I386_PC_RAW_SIZE, + .total_module_size = GRUB_KERNEL_I386_PC_TOTAL_MODULE_SIZE, + .kernel_image_size = GRUB_KERNEL_I386_PC_KERNEL_IMAGE_SIZE, + .compressed_size = GRUB_KERNEL_I386_PC_COMPRESSED_SIZE, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = GRUB_KERNEL_I386_PC_INSTALL_DOS_PART, + .install_bsd_part = GRUB_KERNEL_I386_PC_INSTALL_BSD_PART, + .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR + }, + { + .name = "i386-efi", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_I386_EFI_PREFIX, + .prefix_end = GRUB_KERNEL_I386_EFI_PREFIX_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE + + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header) + + sizeof (struct grub_pe32_optional_header) + + 4 * sizeof (struct grub_pe32_section_table), + GRUB_PE32_SECTION_ALIGNMENT), + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + }, + { + .name = "i386-ieee1275", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_IEEE1275, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_I386_IEEE1275_PREFIX, + .prefix_end = GRUB_KERNEL_I386_IEEE1275_PREFIX_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_I386_IEEE1275_LINK_ADDR, + .elf_target = EM_386, + .mod_gap = GRUB_KERNEL_I386_IEEE1275_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN, + .link_align = 4, + }, + { + .name = "i386-qemu", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_QEMU, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_I386_QEMU_PREFIX, + .prefix_end = GRUB_KERNEL_I386_QEMU_PREFIX_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .kernel_image_size = GRUB_KERNEL_I386_QEMU_KERNEL_IMAGE_SIZE, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_I386_QEMU_LINK_ADDR + }, + { + .name = "x86_64-efi", + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_X86_64_EFI_PREFIX, + .prefix_end = GRUB_KERNEL_X86_64_EFI_PREFIX_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE + + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header) + + sizeof (struct grub_pe64_optional_header) + + 4 * sizeof (struct grub_pe32_section_table), + GRUB_PE32_SECTION_ALIGNMENT), + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + }, + { + .name = "mipsel-yeeloong-flash", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_YEELOONG_FLASH, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .prefix = GRUB_KERNEL_MIPS_YEELOONG_PREFIX, + .prefix_end = GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END, + .raw_size = 0, + .total_module_size = GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE, + .compressed_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_MIPS_YEELOONG_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_YEELOONG_LINK_ALIGN, + .default_compression = COMPRESSION_NONE + }, + { + .name = "mipsel-yeeloong-elf", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_YEELOONG_ELF, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .prefix = GRUB_KERNEL_MIPS_YEELOONG_PREFIX, + .prefix_end = GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END, + .raw_size = 0, + .total_module_size = GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE, + .compressed_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_MIPS_YEELOONG_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_YEELOONG_LINK_ALIGN, + .default_compression = COMPRESSION_NONE + }, + { + .name = "powerpc-ieee1275", + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_PPC, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_POWERPC_IEEE1275_PREFIX, + .prefix_end = GRUB_KERNEL_POWERPC_IEEE1275_PREFIX_END, + .raw_size = 0, + .total_module_size = TARGET_NO_FIELD, + .kernel_image_size = TARGET_NO_FIELD, + .compressed_size = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR, + .elf_target = EM_PPC, + .mod_gap = GRUB_KERNEL_POWERPC_IEEE1275_MOD_GAP, + .mod_align = GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN, + .link_align = 4 + }, + { + .name = "sparc64-ieee1275-raw", + .voidp_sizeof = 8, + .bigendian = 1, + .id = IMAGE_SPARC64_RAW, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX, + .prefix_end = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX_END, + .raw_size = GRUB_KERNEL_SPARC64_IEEE1275_RAW_SIZE, + .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, + .kernel_image_size = GRUB_KERNEL_SPARC64_IEEE1275_KERNEL_IMAGE_SIZE, + .compressed_size = GRUB_KERNEL_SPARC64_IEEE1275_COMPRESSED_SIZE, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR + }, + { + .name = "sparc64-ieee1275-aout", + .voidp_sizeof = 8, + .bigendian = 1, + .id = IMAGE_SPARC64_AOUT, + .flags = PLATFORM_FLAGS_NONE, + .prefix = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX, + .prefix_end = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX_END, + .raw_size = GRUB_KERNEL_SPARC64_IEEE1275_RAW_SIZE, + .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, + .kernel_image_size = GRUB_KERNEL_SPARC64_IEEE1275_KERNEL_IMAGE_SIZE, + .compressed_size = GRUB_KERNEL_SPARC64_IEEE1275_COMPRESSED_SIZE, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = TARGET_NO_FIELD, + .install_bsd_part = TARGET_NO_FIELD, + .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR + }, + }; + +#define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x))) +#define grub_host_to_target32(x) (grub_host_to_target32_real (image_target, (x))) +#define grub_target_to_host64(x) (grub_target_to_host64_real (image_target, (x))) +#define grub_host_to_target64(x) (grub_host_to_target64_real (image_target, (x))) +#define grub_host_to_target_addr(x) (grub_host_to_target_addr_real (image_target, (x))) +#define grub_target_to_host16(x) (grub_target_to_host16_real (image_target, (x))) +#define grub_host_to_target16(x) (grub_host_to_target16_real (image_target, (x))) + +static inline grub_uint32_t +grub_target_to_host32_real (struct image_target_desc *image_target, grub_uint32_t in) +{ + if (image_target->bigendian) + return grub_be_to_cpu32 (in); + else + return grub_le_to_cpu32 (in); +} + +static inline grub_uint64_t +grub_target_to_host64_real (struct image_target_desc *image_target, grub_uint64_t in) +{ + if (image_target->bigendian) + return grub_be_to_cpu64 (in); + else + return grub_le_to_cpu64 (in); +} + +static inline grub_uint64_t +grub_host_to_target64_real (struct image_target_desc *image_target, grub_uint64_t in) +{ + if (image_target->bigendian) + return grub_cpu_to_be64 (in); + else + return grub_cpu_to_le64 (in); +} + +static inline grub_uint32_t +grub_host_to_target32_real (struct image_target_desc *image_target, grub_uint32_t in) +{ + if (image_target->bigendian) + return grub_cpu_to_be32 (in); + else + return grub_cpu_to_le32 (in); +} + +static inline grub_uint16_t +grub_target_to_host16_real (struct image_target_desc *image_target, grub_uint16_t in) +{ + if (image_target->bigendian) + return grub_be_to_cpu16 (in); + else + return grub_le_to_cpu16 (in); +} + +static inline grub_uint16_t +grub_host_to_target16_real (struct image_target_desc *image_target, grub_uint16_t in) +{ + if (image_target->bigendian) + return grub_cpu_to_be16 (in); + else + return grub_cpu_to_le16 (in); +} + +static inline grub_uint64_t +grub_host_to_target_addr_real (struct image_target_desc *image_target, grub_uint64_t in) +{ + if (image_target->voidp_sizeof == 8) + return grub_host_to_target64_real (image_target, in); + else + return grub_host_to_target32_real (image_target, in); +} + +static inline grub_uint64_t +grub_target_to_host_real (struct image_target_desc *image_target, grub_uint64_t in) +{ + if (image_target->voidp_sizeof == 8) + return grub_target_to_host64_real (image_target, in); + else + return grub_target_to_host32_real (image_target, in); +} + +#define GRUB_IEEE1275_NOTE_NAME "PowerPC" +#define GRUB_IEEE1275_NOTE_TYPE 0x1275 + +/* These structures are defined according to the CHRP binding to IEEE1275, + "Client Program Format" section. */ + +struct grub_ieee1275_note_hdr +{ + grub_uint32_t namesz; + grub_uint32_t descsz; + grub_uint32_t type; + char name[sizeof (GRUB_IEEE1275_NOTE_NAME)]; +}; + +struct grub_ieee1275_note_desc +{ + grub_uint32_t real_mode; + grub_uint32_t real_base; + grub_uint32_t real_size; + grub_uint32_t virt_base; + grub_uint32_t virt_size; + grub_uint32_t load_base; +}; + +struct grub_ieee1275_note +{ + struct grub_ieee1275_note_hdr header; + struct grub_ieee1275_note_desc descriptor; +}; + +#define grub_target_to_host(val) grub_target_to_host_real(image_target, (val)) + +#include + +static void *SzAlloc(void *p, size_t size) { p = p; return xmalloc(size); } +static void SzFree(void *p, void *address) { p = p; free(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +static void +compress_kernel_lzma (char *kernel_img, size_t kernel_size, + char **core_img, size_t *core_size, size_t raw_size) +{ + CLzmaEncProps props; + unsigned char out_props[5]; + size_t out_props_size = 5; + + LzmaEncProps_Init(&props); + props.dictSize = 1 << 16; + props.lc = 3; + props.lp = 0; + props.pb = 2; + props.numThreads = 1; + + if (kernel_size < raw_size) + grub_util_error (_("the core image is too small")); + + *core_img = xmalloc (kernel_size); + memcpy (*core_img, kernel_img, raw_size); + + *core_size = kernel_size - raw_size; + if (LzmaEncode ((unsigned char *) *core_img + raw_size, core_size, + (unsigned char *) kernel_img + raw_size, + kernel_size - raw_size, + &props, out_props, &out_props_size, + 0, NULL, &g_Alloc, &g_Alloc) != SZ_OK) + grub_util_error (_("cannot compress the kernel image")); + + *core_size += raw_size; +} + +#ifdef HAVE_LIBLZMA +static void +compress_kernel_xz (char *kernel_img, size_t kernel_size, + char **core_img, size_t *core_size, size_t raw_size) +{ + lzma_stream strm = LZMA_STREAM_INIT; + lzma_ret xzret; + lzma_options_lzma lzopts = { + .dict_size = 1 << 16, + .preset_dict = NULL, + .preset_dict_size = 0, + .lc = 3, + .lp = 0, + .pb = 2, + .mode = LZMA_MODE_NORMAL, + .nice_len = 64, + .mf = LZMA_MF_BT4, + .depth = 0, + }; + lzma_filter fltrs[] = { + { .id = LZMA_FILTER_LZMA2, .options = &lzopts}, + { .id = LZMA_VLI_UNKNOWN, .options = NULL} + }; + + if (kernel_size < raw_size) + grub_util_error (_("the core image is too small")); + + xzret = lzma_stream_encoder (&strm, fltrs, LZMA_CHECK_NONE); + if (xzret != LZMA_OK) + grub_util_error (_("cannot compress the kernel image")); + + *core_img = xmalloc (kernel_size); + memcpy (*core_img, kernel_img, raw_size); + + *core_size = kernel_size - raw_size; + strm.next_in = (unsigned char *) kernel_img + raw_size; + strm.avail_in = kernel_size - raw_size; + strm.next_out = (unsigned char *) *core_img + raw_size; + strm.avail_out = *core_size; + + while (1) + { + xzret = lzma_code (&strm, LZMA_FINISH); + if (xzret == LZMA_OK) + continue; + if (xzret == LZMA_STREAM_END) + break; + grub_util_error (_("cannot compress the kernel image")); + } + + *core_size -= strm.avail_out; + + *core_size += raw_size; +} +#endif + +static void +compress_kernel (struct image_target_desc *image_target, char *kernel_img, + size_t kernel_size, char **core_img, size_t *core_size, + grub_compression_t comp) +{ + if (image_target->flags & PLATFORM_FLAGS_LZMA) + { + compress_kernel_lzma (kernel_img, kernel_size, core_img, + core_size, image_target->raw_size); + return; + } + +#ifdef HAVE_LIBLZMA + if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS + && (comp == COMPRESSION_XZ)) + { + compress_kernel_xz (kernel_img, kernel_size, core_img, + core_size, image_target->raw_size); + return; + } +#endif + + if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS + && (comp != COMPRESSION_NONE)) + grub_util_error ("unknown compression %d\n", comp); + + *core_img = xmalloc (kernel_size); + memcpy (*core_img, kernel_img, kernel_size); + *core_size = kernel_size; +} + +struct fixup_block_list +{ + struct fixup_block_list *next; + int state; + struct grub_pe32_fixup_block b; +}; + +#define MKIMAGE_ELF32 1 +#include "grub-mkimagexx.c" +#undef MKIMAGE_ELF32 + +#define MKIMAGE_ELF64 1 +#include "grub-mkimagexx.c" +#undef MKIMAGE_ELF64 + +static void +generate_image (const char *dir, char *prefix, FILE *out, char *mods[], + char *memdisk_path, char *config_path, + struct image_target_desc *image_target, int note, + grub_compression_t comp) +{ + char *kernel_img, *core_img; + size_t kernel_size, total_module_size, core_size, exec_size; + size_t memdisk_size = 0, config_size = 0, config_size_pure = 0; + char *kernel_path; + size_t offset; + struct grub_util_path_list *path_list, *p, *next; + grub_size_t bss_size; + grub_uint64_t start_address; + void *rel_section; + grub_size_t reloc_size, align; + + if (comp == COMPRESSION_AUTO) + comp = image_target->default_compression; + + path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); + + kernel_path = grub_util_get_path (dir, "kernel.img"); + + if (image_target->voidp_sizeof == 8) + total_module_size = sizeof (struct grub_module_info64); + else + total_module_size = sizeof (struct grub_module_info32); + + if (memdisk_path) + { + memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); + grub_util_info ("the size of memory disk is 0x%x", memdisk_size); + total_module_size += memdisk_size + sizeof (struct grub_module_header); + } + + if (config_path) + { + config_size_pure = grub_util_get_image_size (config_path) + 1; + config_size = ALIGN_ADDR (config_size_pure); + grub_util_info ("the size of config file is 0x%x", config_size); + total_module_size += config_size + sizeof (struct grub_module_header); + } + + for (p = path_list; p; p = p->next) + total_module_size += (ALIGN_ADDR (grub_util_get_image_size (p->name)) + + sizeof (struct grub_module_header)); + + grub_util_info ("the total module size is 0x%x", total_module_size); + + if (image_target->voidp_sizeof == 4) + kernel_img = load_image32 (kernel_path, &exec_size, &kernel_size, &bss_size, + total_module_size, &start_address, &rel_section, + &reloc_size, &align, image_target); + else + kernel_img = load_image64 (kernel_path, &exec_size, &kernel_size, &bss_size, + total_module_size, &start_address, &rel_section, + &reloc_size, &align, image_target); + + if (image_target->prefix + strlen (prefix) + 1 > image_target->prefix_end) + grub_util_error (_("prefix is too long")); + strcpy (kernel_img + image_target->prefix, prefix); + + if (image_target->voidp_sizeof == 8) + { + /* Fill in the grub_module_info structure. */ + struct grub_module_info64 *modinfo; + modinfo = (struct grub_module_info64 *) (kernel_img + kernel_size); + memset (modinfo, 0, sizeof (struct grub_module_info64)); + modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC); + modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info64)); + modinfo->size = grub_host_to_target_addr (total_module_size); + offset = kernel_size + sizeof (struct grub_module_info64); + } + else + { + /* Fill in the grub_module_info structure. */ + struct grub_module_info32 *modinfo; + modinfo = (struct grub_module_info32 *) (kernel_img + kernel_size); + memset (modinfo, 0, sizeof (struct grub_module_info32)); + modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC); + modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info32)); + modinfo->size = grub_host_to_target_addr (total_module_size); + offset = kernel_size + sizeof (struct grub_module_info32); + } + + for (p = path_list; p; p = p->next) + { + struct grub_module_header *header; + size_t mod_size, orig_size; + + orig_size = grub_util_get_image_size (p->name); + mod_size = ALIGN_ADDR (orig_size); + + header = (struct grub_module_header *) (kernel_img + offset); + memset (header, 0, sizeof (struct grub_module_header)); + header->type = grub_host_to_target32 (OBJ_TYPE_ELF); + header->size = grub_host_to_target32 (mod_size + sizeof (*header)); + offset += sizeof (*header); + memset (kernel_img + offset + orig_size, 0, mod_size - orig_size); + + grub_util_load_image (p->name, kernel_img + offset); + offset += mod_size; + } + + if (memdisk_path) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + memset (header, 0, sizeof (struct grub_module_header)); + header->type = grub_host_to_target32 (OBJ_TYPE_MEMDISK); + header->size = grub_host_to_target32 (memdisk_size + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (memdisk_path, kernel_img + offset); + offset += memdisk_size; + } + + if (config_path) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + memset (header, 0, sizeof (struct grub_module_header)); + header->type = grub_host_to_target32 (OBJ_TYPE_CONFIG); + header->size = grub_host_to_target32 (config_size + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (config_path, kernel_img + offset); + *(kernel_img + offset + config_size_pure - 1) = 0; + offset += config_size; + } + + if ((image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) + && (image_target->total_module_size != TARGET_NO_FIELD)) + *((grub_uint32_t *) (kernel_img + image_target->total_module_size)) + = grub_host_to_target32 (total_module_size); + + grub_util_info ("kernel_img=%p, kernel_size=0x%x", kernel_img, kernel_size); + compress_kernel (image_target, kernel_img, kernel_size + total_module_size, + &core_img, &core_size, comp); + + grub_util_info ("the core size is 0x%x", core_size); + + if (!(image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) + && image_target->total_module_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (core_img + image_target->total_module_size)) + = grub_host_to_target32 (total_module_size); + if (image_target->kernel_image_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (core_img + image_target->kernel_image_size)) + = grub_host_to_target32 (kernel_size); + if (image_target->compressed_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (core_img + image_target->compressed_size)) + = grub_host_to_target32 (core_size - image_target->raw_size); + + /* If we included a drive in our prefix, let GRUB know it doesn't have to + prepend the drive told by BIOS. */ + if (image_target->install_dos_part != TARGET_NO_FIELD + && image_target->install_bsd_part != TARGET_NO_FIELD && prefix[0] == '(') + { + *((grub_int32_t *) (core_img + image_target->install_dos_part)) + = grub_host_to_target32 (-2); + *((grub_int32_t *) (core_img + image_target->install_bsd_part)) + = grub_host_to_target32 (-2); + } + + if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) + { + char *full_img; + size_t full_size; + char *decompress_path, *decompress_img; + size_t decompress_size; + const char *name; + + switch (comp) + { + case COMPRESSION_XZ: + name = "xz_decompress.img"; + break; + case COMPRESSION_NONE: + name = "none_decompress.img"; + break; + default: + grub_util_error ("unknown compression %d\n", comp); + } + + decompress_path = grub_util_get_path (dir, name); + decompress_size = grub_util_get_image_size (decompress_path); + decompress_img = grub_util_read_image (decompress_path); + + *((grub_uint32_t *) (decompress_img + GRUB_KERNEL_MIPS_YEELOONG_COMPRESSED_SIZE)) + = grub_host_to_target32 (core_size); + + *((grub_uint32_t *) (decompress_img + GRUB_KERNEL_MIPS_YEELOONG_UNCOMPRESSED_SIZE)) + = grub_host_to_target32 (kernel_size + total_module_size); + + full_size = core_size + decompress_size; + + full_img = xmalloc (full_size); + memset (full_img, 0, full_size); + + memcpy (full_img, decompress_img, decompress_size); + + memcpy (full_img + decompress_size, core_img, core_size); + + memset (full_img + decompress_size + core_size, 0, + full_size - (decompress_size + core_size)); + + free (core_img); + core_img = full_img; + core_size = full_size; + } + + switch (image_target->id) + { + case IMAGE_I386_PC: + case IMAGE_I386_PC_PXE: + { + unsigned num; + char *boot_path, *boot_img; + size_t boot_size; + + if (GRUB_KERNEL_I386_PC_LINK_ADDR + core_size > GRUB_MEMORY_I386_PC_UPPER) + grub_util_error (_("core image is too big (%p > %p)"), + GRUB_KERNEL_I386_PC_LINK_ADDR + core_size, + GRUB_MEMORY_I386_PC_UPPER); + + num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); + if (num > 0xffff) + grub_util_error (_("the core image is too big")); + + if (image_target->id == IMAGE_I386_PC_PXE) + { + char *pxeboot_path, *pxeboot_img; + size_t pxeboot_size; + + pxeboot_path = grub_util_get_path (dir, "pxeboot.img"); + pxeboot_size = grub_util_get_image_size (pxeboot_path); + pxeboot_img = grub_util_read_image (pxeboot_path); + + grub_util_write_image (pxeboot_img, pxeboot_size, out); + free (pxeboot_img); + free (pxeboot_path); + } + + boot_path = grub_util_get_path (dir, "diskboot.img"); + boot_size = grub_util_get_image_size (boot_path); + if (boot_size != GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("diskboot.img size must be %u bytes"), + GRUB_DISK_SECTOR_SIZE); + + boot_img = grub_util_read_image (boot_path); + + { + struct grub_pc_bios_boot_blocklist *block; + block = (struct grub_pc_bios_boot_blocklist *) (boot_img + + GRUB_DISK_SECTOR_SIZE + - sizeof (*block)); + block->len = grub_host_to_target16 (num); + + /* This is filled elsewhere. Verify it just in case. */ + assert (block->segment + == grub_host_to_target16 (GRUB_BOOT_I386_PC_KERNEL_SEG + + (GRUB_DISK_SECTOR_SIZE >> 4))); + } + + grub_util_write_image (boot_img, boot_size, out); + free (boot_img); + free (boot_path); + } + break; + case IMAGE_EFI: + { + void *pe_img; + grub_uint8_t *header; + void *sections; + size_t pe_size; + struct grub_pe32_coff_header *c; + struct grub_pe32_section_table *text_section, *data_section; + struct grub_pe32_section_table *mods_section, *reloc_section; + static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB; + int header_size; + int reloc_addr; + + if (image_target->voidp_sizeof == 4) + header_size = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE + + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header) + + sizeof (struct grub_pe32_optional_header) + + 4 * sizeof (struct grub_pe32_section_table), + GRUB_PE32_SECTION_ALIGNMENT); + else + header_size = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE + + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header) + + sizeof (struct grub_pe64_optional_header) + + 4 * sizeof (struct grub_pe32_section_table), + GRUB_PE32_SECTION_ALIGNMENT); + + reloc_addr = ALIGN_UP (header_size + core_size, + image_target->section_align); + + pe_size = ALIGN_UP (reloc_addr + reloc_size, + image_target->section_align); + pe_img = xmalloc (reloc_addr + reloc_size); + memset (pe_img, 0, header_size); + memcpy (pe_img + header_size, core_img, core_size); + memcpy (pe_img + reloc_addr, rel_section, reloc_size); + header = pe_img; + + /* The magic. */ + memcpy (header, stub, GRUB_PE32_MSDOS_STUB_SIZE); + memcpy (header + GRUB_PE32_MSDOS_STUB_SIZE, "PE\0\0", + GRUB_PE32_SIGNATURE_SIZE); + + /* The COFF file header. */ + c = (struct grub_pe32_coff_header *) (header + GRUB_PE32_MSDOS_STUB_SIZE + + GRUB_PE32_SIGNATURE_SIZE); + if (image_target->voidp_sizeof == 4) + c->machine = grub_host_to_target16 (GRUB_PE32_MACHINE_I386); + else + c->machine = grub_host_to_target16 (GRUB_PE32_MACHINE_X86_64); + + c->num_sections = grub_host_to_target16 (4); + c->time = grub_host_to_target32 (time (0)); + c->characteristics = grub_host_to_target16 (GRUB_PE32_EXECUTABLE_IMAGE + | GRUB_PE32_LINE_NUMS_STRIPPED + | ((image_target->voidp_sizeof == 4) + ? GRUB_PE32_32BIT_MACHINE + : 0) + | GRUB_PE32_LOCAL_SYMS_STRIPPED + | GRUB_PE32_DEBUG_STRIPPED); + + /* The PE Optional header. */ + if (image_target->voidp_sizeof == 4) + { + struct grub_pe32_optional_header *o; + + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe32_optional_header)); + + o = (struct grub_pe32_optional_header *) + (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header)); + o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); + o->code_size = grub_host_to_target32 (exec_size); + o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size + - header_size); + o->bss_size = grub_cpu_to_le32 (bss_size); + o->entry_addr = grub_cpu_to_le32 (start_address); + o->code_base = grub_cpu_to_le32 (header_size); + + o->data_base = grub_host_to_target32 (header_size + exec_size); + + o->image_base = 0; + o->section_alignment = grub_host_to_target32 (image_target->section_align); + o->file_alignment = grub_host_to_target32 (image_target->section_align); + o->image_size = grub_host_to_target32 (pe_size); + o->header_size = grub_host_to_target32 (header_size); + o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); + + /* Do these really matter? */ + o->stack_reserve_size = grub_host_to_target32 (0x10000); + o->stack_commit_size = grub_host_to_target32 (0x10000); + o->heap_reserve_size = grub_host_to_target32 (0x10000); + o->heap_commit_size = grub_host_to_target32 (0x10000); + + o->num_data_directories = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); + + o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); + o->base_relocation_table.size = grub_host_to_target32 (reloc_size); + sections = o + 1; + } + else + { + struct grub_pe64_optional_header *o; + + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header)); + + o = (struct grub_pe64_optional_header *) + (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header)); + o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); + o->code_size = grub_host_to_target32 (exec_size); + o->data_size = grub_cpu_to_le32 (reloc_addr - exec_size + - header_size); + o->bss_size = grub_cpu_to_le32 (bss_size); + o->entry_addr = grub_cpu_to_le32 (start_address); + o->code_base = grub_cpu_to_le32 (header_size); + o->image_base = 0; + o->section_alignment = grub_host_to_target32 (image_target->section_align); + o->file_alignment = grub_host_to_target32 (image_target->section_align); + o->image_size = grub_host_to_target32 (pe_size); + o->header_size = grub_host_to_target32 (header_size); + o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); + + /* Do these really matter? */ + o->stack_reserve_size = grub_host_to_target32 (0x10000); + o->stack_commit_size = grub_host_to_target32 (0x10000); + o->heap_reserve_size = grub_host_to_target32 (0x10000); + o->heap_commit_size = grub_host_to_target32 (0x10000); + + o->num_data_directories + = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); + + o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); + o->base_relocation_table.size = grub_host_to_target32 (reloc_size); + sections = o + 1; + } + /* The sections. */ + text_section = sections; + strcpy (text_section->name, ".text"); + text_section->virtual_size = grub_cpu_to_le32 (exec_size); + text_section->virtual_address = grub_cpu_to_le32 (header_size); + text_section->raw_data_size = grub_cpu_to_le32 (exec_size); + text_section->raw_data_offset = grub_cpu_to_le32 (header_size); + text_section->characteristics = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_CODE + | GRUB_PE32_SCN_MEM_EXECUTE + | GRUB_PE32_SCN_MEM_READ); + + data_section = text_section + 1; + strcpy (data_section->name, ".data"); + data_section->virtual_size = grub_cpu_to_le32 (kernel_size - exec_size); + data_section->virtual_address = grub_cpu_to_le32 (header_size + exec_size); + data_section->raw_data_size = grub_cpu_to_le32 (kernel_size - exec_size); + data_section->raw_data_offset = grub_cpu_to_le32 (header_size + exec_size); + data_section->characteristics + = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE); + +#if 0 + bss_section = data_section + 1; + strcpy (bss_section->name, ".bss"); + bss_section->virtual_size = grub_cpu_to_le32 (bss_size); + bss_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size); + bss_section->raw_data_size = 0; + bss_section->raw_data_offset = 0; + bss_section->characteristics + = grub_cpu_to_le32 (GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE + | GRUB_PE32_SCN_ALIGN_64BYTES + | GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | 0x80); +#endif + + mods_section = data_section + 1; + strcpy (mods_section->name, "mods"); + mods_section->virtual_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size); + mods_section->virtual_address = grub_cpu_to_le32 (header_size + kernel_size + bss_size); + mods_section->raw_data_size = grub_cpu_to_le32 (reloc_addr - kernel_size - header_size); + mods_section->raw_data_offset = grub_cpu_to_le32 (header_size + kernel_size); + mods_section->characteristics + = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE); + + reloc_section = mods_section + 1; + strcpy (reloc_section->name, ".reloc"); + reloc_section->virtual_size = grub_cpu_to_le32 (reloc_size); + reloc_section->virtual_address = grub_cpu_to_le32 (reloc_addr + bss_size); + reloc_section->raw_data_size = grub_cpu_to_le32 (reloc_size); + reloc_section->raw_data_offset = grub_cpu_to_le32 (reloc_addr); + reloc_section->characteristics + = grub_cpu_to_le32 (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_DISCARDABLE + | GRUB_PE32_SCN_MEM_READ); + free (core_img); + core_img = pe_img; + core_size = pe_size; + } + break; + case IMAGE_QEMU: + { + char *rom_img; + size_t rom_size; + char *boot_path, *boot_img; + size_t boot_size; + + boot_path = grub_util_get_path (dir, "boot.img"); + boot_size = grub_util_get_image_size (boot_path); + boot_img = grub_util_read_image (boot_path); + + /* Rom sizes must be 64k-aligned. */ + rom_size = ALIGN_UP (core_size + boot_size, 64 * 1024); + + rom_img = xmalloc (rom_size); + memset (rom_img, 0, rom_size); + + *((grub_int32_t *) (core_img + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR)) + = grub_host_to_target32 ((grub_uint32_t) -rom_size); + + memcpy (rom_img, core_img, core_size); + + *((grub_int32_t *) (boot_img + GRUB_BOOT_I386_QEMU_CORE_ENTRY_ADDR)) + = grub_host_to_target32 ((grub_uint32_t) -rom_size); + + memcpy (rom_img + rom_size - boot_size, boot_img, boot_size); + + free (core_img); + core_img = rom_img; + core_size = rom_size; + + free (boot_img); + free (boot_path); + } + break; + case IMAGE_SPARC64_AOUT: + { + void *aout_img; + size_t aout_size; + struct grub_aout32_header *aout_head; + + aout_size = core_size + sizeof (*aout_head); + aout_img = xmalloc (aout_size); + aout_head = aout_img; + aout_head->a_midmag = grub_host_to_target32 ((AOUT_MID_SUN << 16) + | AOUT32_OMAGIC); + aout_head->a_text = grub_host_to_target32 (core_size); + aout_head->a_entry + = grub_host_to_target32 (GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS); + memcpy (aout_img + sizeof (*aout_head), core_img, core_size); + + free (core_img); + core_img = aout_img; + core_size = aout_size; + } + break; + case IMAGE_SPARC64_RAW: + { + unsigned int num; + char *boot_path, *boot_img; + size_t boot_size; + + num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); + num <<= GRUB_DISK_SECTOR_BITS; + + boot_path = grub_util_get_path (dir, "diskboot.img"); + boot_size = grub_util_get_image_size (boot_path); + if (boot_size != GRUB_DISK_SECTOR_SIZE) + grub_util_error ("diskboot.img is not one sector size"); + + boot_img = grub_util_read_image (boot_path); + + *((grub_uint32_t *) (boot_img + GRUB_DISK_SECTOR_SIZE + - GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE + 8)) + = grub_host_to_target32 (num); + + grub_util_write_image (boot_img, boot_size, out); + free (boot_img); + free (boot_path); + } + break; + case IMAGE_YEELOONG_FLASH: + { + char *rom_img; + size_t rom_size; + char *boot_path, *boot_img; + size_t boot_size; + grub_uint8_t context[GRUB_MD_SHA512->contextsize]; + /* fwstart.img is the only part which can't be tested by using *-elf + target. Check it against the checksum. This checksum is obtained with + sha512sum utility after compiling on Gnewsense. + */ + const grub_uint8_t fwstart_good_hash[] = + { + 0x44, 0xce, 0xbc, 0xe7, 0xc2, 0x5e, 0xff, 0x65, + 0xc5, 0xda, 0x29, 0x5a, 0xb9, 0x08, 0x89, 0x42, + 0x83, 0x3f, 0x2b, 0x2e, 0x06, 0xe1, 0x6f, 0x79, + 0x9b, 0x78, 0x6d, 0xe5, 0xd3, 0x64, 0x98, 0x35, + 0xc8, 0x58, 0xac, 0xb8, 0x08, 0x6d, 0x21, 0x51, + 0xcf, 0xe0, 0x76, 0x48, 0x81, 0x6c, 0xed, 0x65, + 0x4a, 0x50, 0xb4, 0x06, 0x38, 0x0b, 0x26, 0x74, + 0x43, 0xbf, 0xc5, 0x2e, 0x07, 0xa6, 0xb8, 0x0e, + }; + + boot_path = grub_util_get_path (dir, "fwstart.img"); + boot_size = grub_util_get_image_size (boot_path); + boot_img = grub_util_read_image (boot_path); + + grub_memset (context, 0, sizeof (context)); + GRUB_MD_SHA512->init (context); + GRUB_MD_SHA512->write (context, boot_img, boot_size); + GRUB_MD_SHA512->final (context); + if (grub_memcmp (GRUB_MD_SHA512->read (context), fwstart_good_hash, + GRUB_MD_SHA512->mdlen) != 0) + grub_util_warn ("fwstart.img doesn't match the known good version. " + "Proceed at your own risk"); + + if (core_size + boot_size > 512 * 1024) + grub_util_error ("firmware image is too big"); + rom_size = 512 * 1024; + + rom_img = xmalloc (rom_size); + memset (rom_img, 0, rom_size); + + memcpy (rom_img, boot_img, boot_size); + + memcpy (rom_img + boot_size, core_img, core_size); + + memset (rom_img + boot_size + core_size, 0, + rom_size - (boot_size + core_size)); + + free (core_img); + core_img = rom_img; + core_size = rom_size; + } + break; + case IMAGE_YEELOONG_ELF: + case IMAGE_PPC: + case IMAGE_COREBOOT: + case IMAGE_I386_IEEE1275: + { + char *elf_img; + size_t program_size; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + grub_uint32_t target_addr; + int header_size, footer_size = 0; + int phnum = 1; + + if (image_target->id != IMAGE_YEELOONG_ELF) + phnum += 2; + + if (note) + { + phnum++; + footer_size += sizeof (struct grub_ieee1275_note); + } + header_size = ALIGN_ADDR (sizeof (*ehdr) + phnum * sizeof (*phdr)); + + program_size = ALIGN_ADDR (core_size); + + elf_img = xmalloc (program_size + header_size + footer_size); + memset (elf_img, 0, program_size + header_size); + memcpy (elf_img + header_size, core_img, core_size); + ehdr = (void *) elf_img; + phdr = (void *) (elf_img + sizeof (*ehdr)); + memcpy (ehdr->e_ident, ELFMAG, SELFMAG); + ehdr->e_ident[EI_CLASS] = ELFCLASS32; + if (!image_target->bigendian) + ehdr->e_ident[EI_DATA] = ELFDATA2LSB; + else + ehdr->e_ident[EI_DATA] = ELFDATA2MSB; + ehdr->e_ident[EI_VERSION] = EV_CURRENT; + ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE; + ehdr->e_type = grub_host_to_target16 (ET_EXEC); + ehdr->e_machine = grub_host_to_target16 (image_target->elf_target); + ehdr->e_version = grub_host_to_target32 (EV_CURRENT); + + ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr); + ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr)); + ehdr->e_phnum = grub_host_to_target16 (phnum); + + /* No section headers. */ + ehdr->e_shoff = grub_host_to_target32 (0); + if (image_target->id == IMAGE_YEELOONG_ELF) + ehdr->e_shentsize = grub_host_to_target16 (0); + else + ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf32_Shdr)); + ehdr->e_shnum = grub_host_to_target16 (0); + ehdr->e_shstrndx = grub_host_to_target16 (0); + + ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr)); + + phdr->p_type = grub_host_to_target32 (PT_LOAD); + phdr->p_offset = grub_host_to_target32 (header_size); + phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); + + if (image_target->id == IMAGE_YEELOONG_ELF) + target_addr = ALIGN_UP (image_target->link_addr + + kernel_size + total_module_size, 32); + else + target_addr = image_target->link_addr; + ehdr->e_entry = grub_host_to_target32 (target_addr); + phdr->p_vaddr = grub_host_to_target32 (target_addr); + phdr->p_paddr = grub_host_to_target32 (target_addr); + phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align); + if (image_target->id == IMAGE_YEELOONG_ELF) + ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER + | EF_MIPS_PIC | EF_MIPS_CPIC); + else + ehdr->e_flags = 0; + if (image_target->id == IMAGE_YEELOONG_ELF) + { + phdr->p_filesz = grub_host_to_target32 (core_size); + phdr->p_memsz = grub_host_to_target32 (core_size); + } + else + { + grub_uint32_t target_addr_mods; + phdr->p_filesz = grub_host_to_target32 (kernel_size); + phdr->p_memsz = grub_host_to_target32 (kernel_size + bss_size); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_GNU_STACK); + phdr->p_offset = grub_host_to_target32 (header_size + kernel_size); + phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0; + phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); + phdr->p_align = grub_host_to_target32 (image_target->link_align); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_LOAD); + phdr->p_offset = grub_host_to_target32 (header_size + kernel_size); + phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); + phdr->p_filesz = phdr->p_memsz + = grub_host_to_target32 (core_size - kernel_size); + + target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size + + image_target->mod_gap, + image_target->mod_align); + phdr->p_vaddr = grub_host_to_target32 (target_addr_mods); + phdr->p_paddr = grub_host_to_target32 (target_addr_mods); + phdr->p_align = grub_host_to_target32 (image_target->link_align); + } + + if (note) + { + int note_size = sizeof (struct grub_ieee1275_note); + struct grub_ieee1275_note *note = (struct grub_ieee1275_note *) + (elf_img + program_size + header_size); + + grub_util_info ("adding CHRP NOTE segment"); + + note->header.namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME)); + note->header.descsz = grub_host_to_target32 (note_size); + note->header.type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE); + strcpy (note->header.name, GRUB_IEEE1275_NOTE_NAME); + note->descriptor.real_mode = grub_host_to_target32 (0xffffffff); + note->descriptor.real_base = grub_host_to_target32 (0x00c00000); + note->descriptor.real_size = grub_host_to_target32 (0xffffffff); + note->descriptor.virt_base = grub_host_to_target32 (0xffffffff); + note->descriptor.virt_size = grub_host_to_target32 (0xffffffff); + note->descriptor.load_base = grub_host_to_target32 (0x00004000); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_NOTE); + phdr->p_flags = grub_host_to_target32 (PF_R); + phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); + phdr->p_vaddr = 0; + phdr->p_paddr = 0; + phdr->p_filesz = grub_host_to_target32 (note_size); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); + } + + free (core_img); + core_img = elf_img; + core_size = program_size + header_size + footer_size; + } + break; + } + + grub_util_write_image (core_img, core_size, out); + free (kernel_img); + free (core_img); + free (kernel_path); + + while (path_list) + { + next = path_list->next; + free ((void *) path_list->name); + free (path_list); + path_list = next; + } +} + + + +static struct option options[] = + { + {"directory", required_argument, 0, 'd'}, + {"prefix", required_argument, 0, 'p'}, + {"memdisk", required_argument, 0, 'm'}, + {"font", required_argument, 0, 'f'}, + {"config", required_argument, 0, 'c'}, + {"output", required_argument, 0, 'o'}, + {"note", no_argument, 0, 'n'}, + {"format", required_argument, 0, 'O'}, + {"compression", required_argument, 0, 'C'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name); + else + { + int format_len = 0; + char *formats; + char *ptr; + unsigned i; + for (i = 0; i < ARRAY_SIZE (image_targets); i++) + format_len += strlen (image_targets[i].name) + 2; + ptr = formats = xmalloc (format_len); + for (i = 0; i < ARRAY_SIZE (image_targets); i++) + { + strcpy (ptr, image_targets[i].name); + ptr += strlen (image_targets[i].name); + *ptr++ = ','; + *ptr++ = ' '; + } + ptr[-2] = 0; + + printf (_("\ +Usage: %s [OPTION]... [MODULES]\n\ +\n\ +Make a bootable image of GRUB.\n\ +\n\ + -d, --directory=DIR use images and modules under DIR [default=%s/@platform@]\n\ + -p, --prefix=DIR set grub_prefix directory [default=%s]\n\ + -m, --memdisk=FILE embed FILE as a memdisk image\n\ + -c, --config=FILE embed FILE as boot config\n\ + -n, --note add NOTE segment for CHRP Open Firmware\n\ + -o, --output=FILE output a generated image to FILE [default=stdout]\n\ + -O, --format=FORMAT generate an image in format\n\ + available formats: %s\n\ + -C, --compression=(xz|none|auto) choose the compression to use\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print verbose messages\n\ +\n\ +Report bugs to <%s>.\n\ +"), + program_name, GRUB_PKGLIBROOTDIR, DEFAULT_DIRECTORY, + formats, + PACKAGE_BUGREPORT); + free (formats); + } + exit (status); +} + +int +main (int argc, char *argv[]) +{ + char *output = NULL; + char *dir = NULL; + char *prefix = NULL; + char *memdisk = NULL; + char *font = NULL; + char *config = NULL; + FILE *fp = stdout; + int note = 0; + struct image_target_desc *image_target = NULL; + grub_compression_t comp = COMPRESSION_AUTO; + + set_program_name (argv[0]); + + grub_util_init_nls (); + + while (1) + { + int c = getopt_long (argc, argv, "d:p:m:c:o:O:f:C:hVvn", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'o': + if (output) + free (output); + + output = xstrdup (optarg); + break; + + case 'O': + { + unsigned i; + for (i = 0; i < ARRAY_SIZE (image_targets); i++) + if (strcmp (optarg, image_targets[i].name) == 0) + image_target = &image_targets[i]; + if (!image_target) + { + printf ("unknown target format %s\n", optarg); + usage (1); + } + break; + } + case 'd': + if (dir) + free (dir); + + dir = xstrdup (optarg); + break; + + case 'n': + note = 1; + break; + + case 'm': + if (memdisk) + free (memdisk); + + memdisk = xstrdup (optarg); + + if (prefix) + free (prefix); + + prefix = xstrdup ("(memdisk)/boot/grub"); + break; + + case 'c': + if (config) + free (config); + + config = xstrdup (optarg); + break; + + case 'C': + if (grub_strcmp (optarg, "xz") == 0) + { +#ifdef HAVE_LIBLZMA + comp = COMPRESSION_XZ; +#else + grub_util_error ("grub-mkimage is compiled without XZ support", + optarg); +#endif + } + else if (grub_strcmp (optarg, "none") == 0) + comp = COMPRESSION_NONE; + else + grub_util_error ("Unknown compression format %s", optarg); + break; + + case 'h': + usage (0); + break; + + case 'p': + if (prefix) + free (prefix); + + prefix = xstrdup (optarg); + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + if (!image_target) + { + printf ("Target format not specified (use the -O option).\n"); + usage (1); + } + + if (output) + { + fp = fopen (output, "wb"); + if (! fp) + grub_util_error (_("cannot open %s"), output); + free (output); + } + + if (!dir) + { + const char *last; + last = strchr (image_target->name, '-'); + if (last) + last = strchr (last + 1, '-'); + if (!last) + last = image_target->name + strlen (image_target->name); + dir = xmalloc (sizeof (GRUB_PKGLIBROOTDIR) + (last - image_target->name) + + 1); + memcpy (dir, GRUB_PKGLIBROOTDIR, sizeof (GRUB_PKGLIBROOTDIR) - 1); + *(dir + sizeof (GRUB_PKGLIBROOTDIR) - 1) = '/'; + if (strncmp (image_target->name, "mipsel-yeeloong", + last - image_target->name) == 0) + { + memcpy (dir + sizeof (GRUB_PKGLIBROOTDIR), "mips-yeeloong", + sizeof ("mips-yeeloong")); + } + else + { + memcpy (dir + sizeof (GRUB_PKGLIBROOTDIR), image_target->name, + last - image_target->name); + *(dir + sizeof (GRUB_PKGLIBROOTDIR) + (last - image_target->name)) + = 0; + } + } + + generate_image (dir, prefix ? : DEFAULT_DIRECTORY, fp, + argv + optind, memdisk, config, + image_target, note, comp); + + fflush (fp); + fsync (fileno (fp)); + fclose (fp); + + if (dir) + free (dir); + + return 0; +} diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c new file mode 100644 index 0000000..ce51f2f --- /dev/null +++ b/util/grub-mkimagexx.c @@ -0,0 +1,756 @@ +/* grub-mkimage.c - make a bootable image */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#undef ELF_R_SYM +#undef ELF_R_TYPE + +#if defined(MKIMAGE_ELF32) +# define SUFFIX(x) x ## 32 +# define ELFCLASSXX ELFCLASS32 +# define Elf_Ehdr Elf32_Ehdr +# define Elf_Phdr Elf32_Phdr +# define Elf_Addr Elf32_Addr +# define Elf_Sym Elf32_Sym +# define Elf_Off Elf32_Off +# define Elf_Shdr Elf32_Shdr +# define Elf_Rela Elf32_Rela +# define Elf_Rel Elf32_Rel +# define ELF_R_SYM(val) ELF32_R_SYM(val) +# define ELF_R_TYPE(val) ELF32_R_TYPE(val) +#elif defined(MKIMAGE_ELF64) +# define SUFFIX(x) x ## 64 +# define ELFCLASSXX ELFCLASS64 +# define Elf_Ehdr Elf64_Ehdr +# define Elf_Phdr Elf64_Phdr +# define Elf_Addr Elf64_Addr +# define Elf_Sym Elf64_Sym +# define Elf_Off Elf64_Off +# define Elf_Shdr Elf64_Shdr +# define Elf_Rela Elf64_Rela +# define Elf_Rel Elf64_Rel +# define ELF_R_SYM(val) ELF64_R_SYM(val) +# define ELF_R_TYPE(val) ELF64_R_TYPE(val) +#else +#error "I'm confused" +#endif + +/* Relocate symbols; note that this function overwrites the symbol table. + Return the address of a start symbol. */ +static Elf_Addr +SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, + Elf_Shdr *symtab_section, Elf_Addr *section_addresses, + Elf_Half section_entsize, Elf_Half num_sections, + struct image_target_desc *image_target) +{ + Elf_Word symtab_size, sym_size, num_syms; + Elf_Off symtab_offset; + Elf_Addr start_address = 0; + Elf_Sym *sym; + Elf_Word i; + Elf_Shdr *strtab_section; + const char *strtab; + + strtab_section + = (Elf_Shdr *) ((char *) sections + + (grub_target_to_host32 (symtab_section->sh_link) + * section_entsize)); + strtab = (char *) e + grub_target_to_host (strtab_section->sh_offset); + + symtab_size = grub_target_to_host (symtab_section->sh_size); + sym_size = grub_target_to_host (symtab_section->sh_entsize); + symtab_offset = grub_target_to_host (symtab_section->sh_offset); + num_syms = symtab_size / sym_size; + + for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset); + i < num_syms; + i++, sym = (Elf_Sym *) ((char *) sym + sym_size)) + { + Elf_Section index; + const char *name; + + name = strtab + grub_target_to_host32 (sym->st_name); + + index = grub_target_to_host16 (sym->st_shndx); + if (index == STN_ABS) + { + continue; + } + else if ((index == STN_UNDEF)) + { + if (sym->st_name) + grub_util_error ("undefined symbol %s", name); + else + continue; + } + else if (index >= num_sections) + grub_util_error ("section %d does not exist", index); + + sym->st_value = (grub_target_to_host32 (sym->st_value) + + section_addresses[index]); + grub_util_info ("locating %s at 0x%x", name, sym->st_value); + + if (! start_address) + if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0) + start_address = sym->st_value; + } + + return start_address; +} + +/* Return the address of a symbol at the index I in the section S. */ +static Elf_Addr +SUFFIX (get_symbol_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i, + struct image_target_desc *image_target) +{ + Elf_Sym *sym; + + sym = (Elf_Sym *) ((char *) e + + grub_target_to_host32 (s->sh_offset) + + i * grub_target_to_host32 (s->sh_entsize)); + return sym->st_value; +} + +/* Return the address of a modified value. */ +static Elf_Addr * +SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset, + struct image_target_desc *image_target) +{ + return (Elf_Addr *) ((char *) e + grub_target_to_host32 (s->sh_offset) + offset); +} + +/* Deal with relocation information. This function relocates addresses + within the virtual address space starting from 0. So only relative + addresses can be fully resolved. Absolute addresses must be relocated + again by a PE32 relocator when loaded. */ +static void +SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, + Elf_Addr *section_addresses, + Elf_Half section_entsize, Elf_Half num_sections, + const char *strtab, struct image_target_desc *image_target) +{ + Elf_Half i; + Elf_Shdr *s; + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if ((s->sh_type == grub_host_to_target32 (SHT_REL)) || + (s->sh_type == grub_host_to_target32 (SHT_RELA))) + { + Elf_Rela *r; + Elf_Word rtab_size, r_size, num_rs; + Elf_Off rtab_offset; + Elf_Shdr *symtab_section; + Elf_Word target_section_index; + Elf_Addr target_section_addr; + Elf_Shdr *target_section; + Elf_Word j; + + symtab_section = (Elf_Shdr *) ((char *) sections + + (grub_target_to_host32 (s->sh_link) + * section_entsize)); + target_section_index = grub_target_to_host32 (s->sh_info); + target_section_addr = section_addresses[target_section_index]; + target_section = (Elf_Shdr *) ((char *) sections + + (target_section_index + * section_entsize)); + + grub_util_info ("dealing with the relocation section %s for %s", + strtab + grub_target_to_host32 (s->sh_name), + strtab + grub_target_to_host32 (target_section->sh_name)); + + rtab_size = grub_target_to_host32 (s->sh_size); + r_size = grub_target_to_host32 (s->sh_entsize); + rtab_offset = grub_target_to_host32 (s->sh_offset); + num_rs = rtab_size / r_size; + + for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset); + j < num_rs; + j++, r = (Elf_Rela *) ((char *) r + r_size)) + { + Elf_Addr info; + Elf_Addr offset; + Elf_Addr sym_addr; + Elf_Addr *target; + Elf_Addr addend; + + offset = grub_target_to_host (r->r_offset); + target = SUFFIX (get_target_address) (e, target_section, + offset, image_target); + info = grub_target_to_host (r->r_info); + sym_addr = SUFFIX (get_symbol_address) (e, symtab_section, + ELF_R_SYM (info), image_target); + + addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? + r->r_addend : 0; + + if (image_target->voidp_sizeof == 4) + switch (ELF_R_TYPE (info)) + { + case R_386_NONE: + break; + + case R_386_32: + /* This is absolute. */ + *target = grub_host_to_target32 (grub_target_to_host32 (*target) + + addend + sym_addr); + grub_util_info ("relocating an R_386_32 entry to 0x%x at the offset 0x%x", + *target, offset); + break; + + case R_386_PC32: + /* This is relative. */ + *target = grub_host_to_target32 (grub_target_to_host32 (*target) + + addend + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + grub_util_info ("relocating an R_386_PC32 entry to 0x%x at the offset 0x%x", + *target, offset); + break; + default: + grub_util_error ("unknown relocation type %d", + ELF_R_TYPE (info)); + break; + } + else + switch (ELF_R_TYPE (info)) + { + + case R_X86_64_NONE: + break; + + case R_X86_64_64: + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr); + grub_util_info ("relocating an R_X86_64_64 entry to 0x%llx at the offset 0x%llx", + *target, offset); + break; + + case R_X86_64_PC32: + { + grub_uint32_t *t32 = (grub_uint32_t *) target; + *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32) + + addend + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + grub_util_info ("relocating an R_X86_64_PC32 entry to 0x%x at the offset 0x%llx", + *t32, offset); + break; + } + + case R_X86_64_32: + case R_X86_64_32S: + { + grub_uint32_t *t32 = (grub_uint32_t *) target; + *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32) + + addend + sym_addr); + grub_util_info ("relocating an R_X86_64_32(S) entry to 0x%x at the offset 0x%llx", + *t32, offset); + break; + } + + default: + grub_util_error ("unknown relocation type %d", + ELF_R_TYPE (info)); + break; + } + } + } +} + +/* Add a PE32's fixup entry for a relocation. Return the resulting address + after having written to the file OUT. */ +static Elf_Addr +SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type, + Elf_Addr addr, int flush, Elf_Addr current_address, + struct image_target_desc *image_target) +{ + struct grub_pe32_fixup_block *b; + + b = &((*cblock)->b); + + /* First, check if it is necessary to write out the current block. */ + if ((*cblock)->state) + { + if (flush || addr < b->page_rva || b->page_rva + 0x1000 <= addr) + { + grub_uint32_t size; + + if (flush) + { + /* Add as much padding as necessary to align the address + with a section boundary. */ + Elf_Addr next_address; + unsigned padding_size; + size_t index; + + next_address = current_address + b->block_size; + padding_size = ((ALIGN_UP (next_address, image_target->section_align) + - next_address) + >> 1); + index = ((b->block_size - sizeof (*b)) >> 1); + grub_util_info ("adding %d padding fixup entries", padding_size); + while (padding_size--) + { + b->entries[index++] = 0; + b->block_size += 2; + } + } + else if (b->block_size & (8 - 1)) + { + /* If not aligned with a 32-bit boundary, add + a padding entry. */ + size_t index; + + grub_util_info ("adding a padding fixup entry"); + index = ((b->block_size - sizeof (*b)) >> 1); + b->entries[index] = 0; + b->block_size += 2; + } + + /* Flush it. */ + grub_util_info ("writing %d bytes of a fixup block starting at 0x%x", + b->block_size, b->page_rva); + size = b->block_size; + current_address += size; + b->page_rva = grub_host_to_target32 (b->page_rva); + b->block_size = grub_host_to_target32 (b->block_size); + (*cblock)->next = xmalloc (sizeof (**cblock) + 2 * 0x1000); + memset ((*cblock)->next, 0, sizeof (**cblock) + 2 * 0x1000); + *cblock = (*cblock)->next; + } + } + + b = &((*cblock)->b); + + if (! flush) + { + grub_uint16_t entry; + size_t index; + + /* If not allocated yet, allocate a block with enough entries. */ + if (! (*cblock)->state) + { + (*cblock)->state = 1; + + /* The spec does not mention the requirement of a Page RVA. + Here, align the address with a 4K boundary for safety. */ + b->page_rva = (addr & ~(0x1000 - 1)); + b->block_size = sizeof (*b); + } + + /* Sanity check. */ + if (b->block_size >= sizeof (*b) + 2 * 0x1000) + grub_util_error ("too many fixup entries"); + + /* Add a new entry. */ + index = ((b->block_size - sizeof (*b)) >> 1); + entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva); + b->entries[index] = grub_host_to_target16 (entry); + b->block_size += 2; + } + + return current_address; +} + +/* Make a .reloc section. */ +static Elf_Addr +SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, + Elf_Addr *section_addresses, Elf_Shdr *sections, + Elf_Half section_entsize, Elf_Half num_sections, + const char *strtab, struct image_target_desc *image_target) +{ + Elf_Half i; + Elf_Shdr *s; + struct fixup_block_list *lst, *lst0; + Elf_Addr current_address = 0; + + lst = lst0 = xmalloc (sizeof (*lst) + 2 * 0x1000); + memset (lst, 0, sizeof (*lst) + 2 * 0x1000); + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) || + (s->sh_type == grub_cpu_to_le32 (SHT_RELA))) + { + Elf_Rel *r; + Elf_Word rtab_size, r_size, num_rs; + Elf_Off rtab_offset; + Elf_Addr section_address; + Elf_Word j; + + grub_util_info ("translating the relocation section %s", + strtab + grub_le_to_cpu32 (s->sh_name)); + + rtab_size = grub_le_to_cpu32 (s->sh_size); + r_size = grub_le_to_cpu32 (s->sh_entsize); + rtab_offset = grub_le_to_cpu32 (s->sh_offset); + num_rs = rtab_size / r_size; + + section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)]; + + for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset); + j < num_rs; + j++, r = (Elf_Rel *) ((char *) r + r_size)) + { + Elf_Addr info; + Elf_Addr offset; + + offset = grub_le_to_cpu32 (r->r_offset); + info = grub_le_to_cpu32 (r->r_info); + + /* Necessary to relocate only absolute addresses. */ + if (image_target->voidp_sizeof == 4) + { + if (ELF_R_TYPE (info) == R_386_32) + { + Elf_Addr addr; + + addr = section_address + offset; + grub_util_info ("adding a relocation entry for 0x%x", addr); + current_address + = SUFFIX (add_fixup_entry) (&lst, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, current_address, + image_target); + } + } + else + { + if ((ELF_R_TYPE (info) == R_X86_64_32) || + (ELF_R_TYPE (info) == R_X86_64_32S)) + { + grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)"); + } + else if (ELF_R_TYPE (info) == R_X86_64_64) + { + Elf_Addr addr; + + addr = section_address + offset; + grub_util_info ("adding a relocation entry for 0x%llx", addr); + current_address + = SUFFIX (add_fixup_entry) (&lst, + GRUB_PE32_REL_BASED_DIR64, + addr, + 0, current_address, + image_target); + } + } + } + } + + current_address = SUFFIX (add_fixup_entry) (&lst, 0, 0, 1, current_address, image_target); + + { + grub_uint8_t *ptr; + ptr = *out = xmalloc (current_address); + for (lst = lst0; lst; lst = lst->next) + if (lst->state) + { + memcpy (ptr, &lst->b, grub_target_to_host32 (lst->b.block_size)); + ptr += grub_target_to_host32 (lst->b.block_size); + } + if (current_address + *out != ptr) + { + grub_util_error ("Bug detected %d != %d\n", ptr - (grub_uint8_t *) *out, + current_address); + } + } + + return current_address; +} + +/* Determine if this section is a text section. Return false if this + section is not allocated. */ +static int +SUFFIX (is_text_section) (Elf_Shdr *s, struct image_target_desc *image_target) +{ + if (image_target->id != IMAGE_EFI + && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS) + return 0; + return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) + == (SHF_EXECINSTR | SHF_ALLOC)); +} + +/* Determine if this section is a data section. This assumes that + BSS is also a data section, since the converter initializes BSS + when producing PE32 to avoid a bug in EFI implementations. */ +static int +SUFFIX (is_data_section) (Elf_Shdr *s, struct image_target_desc *image_target) +{ + if (image_target->id != IMAGE_EFI + && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS) + return 0; + return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) + == SHF_ALLOC); +} + +/* Return if the ELF header is valid. */ +static int +SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, struct image_target_desc *image_target) +{ + if (size < sizeof (*e) + || e->e_ident[EI_MAG0] != ELFMAG0 + || e->e_ident[EI_MAG1] != ELFMAG1 + || e->e_ident[EI_MAG2] != ELFMAG2 + || e->e_ident[EI_MAG3] != ELFMAG3 + || e->e_ident[EI_VERSION] != EV_CURRENT + || e->e_ident[EI_CLASS] != ELFCLASSXX + || e->e_version != grub_host_to_target32 (EV_CURRENT)) + return 0; + + return 1; +} + +/* Locate section addresses by merging code sections and data sections + into .text and .data, respectively. Return the array of section + addresses. */ +static Elf_Addr * +SUFFIX (locate_sections) (Elf_Shdr *sections, Elf_Half section_entsize, + Elf_Half num_sections, const char *strtab, + grub_size_t *exec_size, grub_size_t *kernel_sz, + grub_size_t *all_align, + struct image_target_desc *image_target) +{ + int i; + Elf_Addr current_address; + Elf_Addr *section_addresses; + Elf_Shdr *s; + + *all_align = 1; + + section_addresses = xmalloc (sizeof (*section_addresses) * num_sections); + memset (section_addresses, 0, sizeof (*section_addresses) * num_sections); + + current_address = 0; + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC) + && grub_host_to_target32 (s->sh_addralign) > *all_align) + *all_align = grub_host_to_target32 (s->sh_addralign); + + + /* .text */ + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (SUFFIX (is_text_section) (s, image_target)) + { + Elf_Word align = grub_host_to_target_addr (s->sh_addralign); + const char *name = strtab + grub_host_to_target32 (s->sh_name); + if (align) + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + align) - image_target->vaddr_offset; + grub_util_info ("locating the section %s at 0x%x", + name, current_address); + section_addresses[i] = current_address; + current_address += grub_host_to_target_addr (s->sh_size); + } + + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + image_target->section_align) + - image_target->vaddr_offset; + *exec_size = current_address; + + /* .data */ + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (SUFFIX (is_data_section) (s, image_target)) + { + Elf_Word align = grub_host_to_target_addr (s->sh_addralign); + const char *name = strtab + grub_host_to_target32 (s->sh_name); + + if (align) + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + align) + - image_target->vaddr_offset; + + grub_util_info ("locating the section %s at 0x%x", + name, current_address); + section_addresses[i] = current_address; + current_address += grub_host_to_target_addr (s->sh_size); + } + + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + image_target->section_align) - image_target->vaddr_offset; + *kernel_sz = current_address; + return section_addresses; +} + +static char * +SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size, + grub_size_t *kernel_sz, grub_size_t *bss_size, + grub_size_t total_module_size, grub_uint64_t *start, + void **reloc_section, grub_size_t *reloc_size, + grub_size_t *align, + struct image_target_desc *image_target) +{ + char *kernel_img, *out_img; + const char *strtab; + Elf_Ehdr *e; + Elf_Shdr *sections; + Elf_Addr *section_addresses; + Elf_Addr *section_vaddresses; + int i; + Elf_Shdr *s; + Elf_Half num_sections; + Elf_Off section_offset; + Elf_Half section_entsize; + grub_size_t kernel_size; + Elf_Shdr *symtab_section; + + *start = 0; + + kernel_size = grub_util_get_image_size (kernel_path); + kernel_img = xmalloc (kernel_size); + grub_util_load_image (kernel_path, kernel_img); + + e = (Elf_Ehdr *) kernel_img; + if (! SUFFIX (check_elf_header) (e, kernel_size, image_target)) + grub_util_error ("invalid ELF header"); + + section_offset = grub_target_to_host (e->e_shoff); + section_entsize = grub_target_to_host16 (e->e_shentsize); + num_sections = grub_target_to_host16 (e->e_shnum); + + if (kernel_size < section_offset + section_entsize * num_sections) + grub_util_error ("invalid ELF format"); + + sections = (Elf_Shdr *) (kernel_img + section_offset); + + /* Relocate sections then symbols in the virtual address space. */ + s = (Elf_Shdr *) ((char *) sections + + grub_host_to_target16 (e->e_shstrndx) * section_entsize); + strtab = (char *) e + grub_host_to_target_addr (s->sh_offset); + + section_addresses = SUFFIX (locate_sections) (sections, section_entsize, + num_sections, strtab, + exec_size, kernel_sz, align, + image_target); + + section_vaddresses = xmalloc (sizeof (*section_addresses) * num_sections); + + for (i = 0; i < num_sections; i++) + section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset; + + if (image_target->id != IMAGE_EFI) + { + Elf_Addr current_address = *kernel_sz; + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) + { + Elf_Word align = grub_host_to_target_addr (s->sh_addralign); + const char *name = strtab + grub_host_to_target32 (s->sh_name); + + if (align) + current_address = ALIGN_UP (current_address + + image_target->vaddr_offset, align) + - image_target->vaddr_offset; + + grub_util_info ("locating the section %s at 0x%x", + name, current_address); + section_vaddresses[i] = current_address + + image_target->vaddr_offset; + current_address += grub_host_to_target_addr (s->sh_size); + } + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + image_target->section_align) + - image_target->vaddr_offset; + *bss_size = current_address - *kernel_sz; + } + else + *bss_size = 0; + + if (image_target->id == IMAGE_EFI) + { + symtab_section = NULL; + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB)) + { + symtab_section = s; + break; + } + + if (! symtab_section) + grub_util_error ("no symbol table"); + + *start = SUFFIX (relocate_symbols) (e, sections, symtab_section, + section_vaddresses, section_entsize, + num_sections, image_target); + if (*start == 0) + grub_util_error ("start symbol is not defined"); + + /* Resolve addresses in the virtual address space. */ + SUFFIX (relocate_addresses) (e, sections, section_addresses, section_entsize, + num_sections, strtab, image_target); + + *reloc_size = SUFFIX (make_reloc_section) (e, reloc_section, + section_vaddresses, sections, + section_entsize, num_sections, + strtab, image_target); + } + else + { + *reloc_size = 0; + *reloc_section = NULL; + } + + out_img = xmalloc (*kernel_sz + total_module_size); + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (SUFFIX (is_data_section) (s, image_target) + || SUFFIX (is_text_section) (s, image_target)) + { + if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) + memset (out_img + section_addresses[i], 0, + grub_host_to_target_addr (s->sh_size)); + else + memcpy (out_img + section_addresses[i], + kernel_img + grub_host_to_target_addr (s->sh_offset), + grub_host_to_target_addr (s->sh_size)); + } + free (kernel_img); + + return out_img; +} + + +#undef SUFFIX +#undef ELFCLASSXX +#undef Elf_Ehdr +#undef Elf_Phdr +#undef Elf_Shdr +#undef Elf_Addr +#undef Elf_Sym +#undef Elf_Off +#undef Elf_Rela +#undef Elf_Rel +#undef ELF_R_TYPE +#undef ELF_R_SYM diff --git a/util/grub-mklayout.c b/util/grub-mklayout.c new file mode 100644 index 0000000..04501cb --- /dev/null +++ b/util/grub-mklayout.c @@ -0,0 +1,505 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "progname.h" + +#define CKBCOMP "ckbcomp" + +static struct option options[] = { + {"output", required_argument, 0, 'o'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} +}; + +struct console_grub_equivalence +{ + char *layout; + grub_uint32_t grub; +}; + +static struct console_grub_equivalence console_grub_equivalences_shift[] = { + {"KP_0", '0'}, + {"KP_1", '1'}, + {"KP_2", '2'}, + {"KP_3", '3'}, + {"KP_4", '4'}, + {"KP_5", '5'}, + {"KP_6", '6'}, + {"KP_7", '7'}, + {"KP_8", '8'}, + {"KP_9", '9'}, + {"KP_Period", '.'}, + + {NULL, '\0'} +}; + +static struct console_grub_equivalence console_grub_equivalences_unshift[] = { + {"KP_0", GRUB_TERM_KEY_INSERT}, + {"KP_1", GRUB_TERM_KEY_END}, + {"KP_2", GRUB_TERM_KEY_DOWN}, + {"KP_3", GRUB_TERM_KEY_NPAGE}, + {"KP_4", GRUB_TERM_KEY_LEFT}, + {"KP_5", GRUB_TERM_KEY_CENTER}, + {"KP_6", GRUB_TERM_KEY_RIGHT}, + {"KP_7", GRUB_TERM_KEY_HOME}, + {"KP_8", GRUB_TERM_KEY_UP}, + {"KP_9", GRUB_TERM_KEY_PPAGE}, + {"KP_Period", GRUB_TERM_KEY_DC}, + + {NULL, '\0'} +}; + +static struct console_grub_equivalence console_grub_equivalences_common[] = { + {"Escape", GRUB_TERM_ESC}, + {"Tab", GRUB_TERM_TAB}, + {"Delete", GRUB_TERM_BACKSPACE}, + + {"KP_Enter", '\n'}, + {"Return", '\n'}, + + {"KP_Multiply", '*'}, + {"KP_Subtract", '-'}, + {"KP_Add", '+'}, + {"KP_Divide", '/'}, + + {"F1", GRUB_TERM_KEY_F1}, + {"F2", GRUB_TERM_KEY_F2}, + {"F3", GRUB_TERM_KEY_F3}, + {"F4", GRUB_TERM_KEY_F4}, + {"F5", GRUB_TERM_KEY_F5}, + {"F6", GRUB_TERM_KEY_F6}, + {"F7", GRUB_TERM_KEY_F7}, + {"F8", GRUB_TERM_KEY_F8}, + {"F9", GRUB_TERM_KEY_F9}, + {"F10", GRUB_TERM_KEY_F10}, + {"F11", GRUB_TERM_KEY_F11}, + {"F12", GRUB_TERM_KEY_F12}, + {"F13", GRUB_TERM_KEY_F1 | GRUB_TERM_SHIFT}, + {"F14", GRUB_TERM_KEY_F2 | GRUB_TERM_SHIFT}, + {"F15", GRUB_TERM_KEY_F3 | GRUB_TERM_SHIFT}, + {"F16", GRUB_TERM_KEY_F4 | GRUB_TERM_SHIFT}, + {"F17", GRUB_TERM_KEY_F5 | GRUB_TERM_SHIFT}, + {"F18", GRUB_TERM_KEY_F6 | GRUB_TERM_SHIFT}, + {"F19", GRUB_TERM_KEY_F7 | GRUB_TERM_SHIFT}, + {"F20", GRUB_TERM_KEY_F8 | GRUB_TERM_SHIFT}, + {"F21", GRUB_TERM_KEY_F9 | GRUB_TERM_SHIFT}, + {"F22", GRUB_TERM_KEY_F10 | GRUB_TERM_SHIFT}, + {"F23", GRUB_TERM_KEY_F11 | GRUB_TERM_SHIFT}, + {"F24", GRUB_TERM_KEY_F12 | GRUB_TERM_SHIFT}, + {"Console_13", GRUB_TERM_KEY_F1 | GRUB_TERM_ALT}, + {"Console_14", GRUB_TERM_KEY_F2 | GRUB_TERM_ALT}, + {"Console_15", GRUB_TERM_KEY_F3 | GRUB_TERM_ALT}, + {"Console_16", GRUB_TERM_KEY_F4 | GRUB_TERM_ALT}, + {"Console_17", GRUB_TERM_KEY_F5 | GRUB_TERM_ALT}, + {"Console_18", GRUB_TERM_KEY_F6 | GRUB_TERM_ALT}, + {"Console_19", GRUB_TERM_KEY_F7 | GRUB_TERM_ALT}, + {"Console_20", GRUB_TERM_KEY_F8 | GRUB_TERM_ALT}, + {"Console_21", GRUB_TERM_KEY_F9 | GRUB_TERM_ALT}, + {"Console_22", GRUB_TERM_KEY_F10 | GRUB_TERM_ALT}, + {"Console_23", GRUB_TERM_KEY_F11 | GRUB_TERM_ALT}, + {"Console_24", GRUB_TERM_KEY_F12 | GRUB_TERM_ALT}, + {"Console_25", GRUB_TERM_KEY_F1 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_26", GRUB_TERM_KEY_F2 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_27", GRUB_TERM_KEY_F3 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_28", GRUB_TERM_KEY_F4 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_29", GRUB_TERM_KEY_F5 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_30", GRUB_TERM_KEY_F6 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_31", GRUB_TERM_KEY_F7 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_32", GRUB_TERM_KEY_F8 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_33", GRUB_TERM_KEY_F9 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_34", GRUB_TERM_KEY_F10 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_35", GRUB_TERM_KEY_F11 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_36", GRUB_TERM_KEY_F12 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + + {"Insert", GRUB_TERM_KEY_INSERT}, + {"Down", GRUB_TERM_KEY_DOWN}, + {"Up", GRUB_TERM_KEY_UP}, + {"Home", GRUB_TERM_KEY_HOME}, + {"End", GRUB_TERM_KEY_END}, + {"Right", GRUB_TERM_KEY_RIGHT}, + {"Left", GRUB_TERM_KEY_LEFT}, + {"Next", GRUB_TERM_KEY_NPAGE}, + {"Prior", GRUB_TERM_KEY_PPAGE}, + {"Remove", GRUB_TERM_KEY_DC}, + {"VoidSymbol", 0}, + + /* "Undead" keys since no dead key support in GRUB. */ + {"dead_acute", '\''}, + {"dead_circumflex", '^'}, + {"dead_grave", '`'}, + {"dead_tilde", '~'}, + {"dead_diaeresis", '"'}, + + /* Following ones don't provide any useful symbols for shell. */ + {"dead_cedilla", 0}, + {"dead_ogonek", 0}, + {"dead_caron", 0}, + {"dead_breve", 0}, + {"dead_doubleacute", 0}, + + /* Unused in GRUB. */ + {"Pause", 0}, + {"Scroll_Forward", 0}, + {"Scroll_Backward", 0}, + {"Hex_0", 0}, + {"Hex_1", 0}, + {"Hex_2", 0}, + {"Hex_3", 0}, + {"Hex_4", 0}, + {"Hex_5", 0}, + {"Hex_6", 0}, + {"Hex_7", 0}, + {"Hex_8", 0}, + {"Hex_9", 0}, + {"Hex_A", 0}, + {"Hex_B", 0}, + {"Hex_C", 0}, + {"Hex_D", 0}, + {"Hex_E", 0}, + {"Hex_F", 0}, + {"Scroll_Lock", 0}, + {"Show_Memory", 0}, + {"Show_Registers", 0}, + {"Control_backslash", 0}, + {"Compose", 0}, + + {NULL, '\0'} +}; + +static grub_uint8_t linux_to_usb_map[128] = { + /* 0x00 */ 0 /* Unused */, GRUB_KEYBOARD_KEY_ESCAPE, + /* 0x02 */ GRUB_KEYBOARD_KEY_1, GRUB_KEYBOARD_KEY_2, + /* 0x04 */ GRUB_KEYBOARD_KEY_3, GRUB_KEYBOARD_KEY_4, + /* 0x06 */ GRUB_KEYBOARD_KEY_5, GRUB_KEYBOARD_KEY_6, + /* 0x08 */ GRUB_KEYBOARD_KEY_7, GRUB_KEYBOARD_KEY_8, + /* 0x0a */ GRUB_KEYBOARD_KEY_9, GRUB_KEYBOARD_KEY_0, + /* 0x0c */ GRUB_KEYBOARD_KEY_DASH, GRUB_KEYBOARD_KEY_EQUAL, + /* 0x0e */ GRUB_KEYBOARD_KEY_BACKSPACE, GRUB_KEYBOARD_KEY_TAB, + /* 0x10 */ GRUB_KEYBOARD_KEY_Q, GRUB_KEYBOARD_KEY_W, + /* 0x12 */ GRUB_KEYBOARD_KEY_E, GRUB_KEYBOARD_KEY_R, + /* 0x14 */ GRUB_KEYBOARD_KEY_T, GRUB_KEYBOARD_KEY_Y, + /* 0x16 */ GRUB_KEYBOARD_KEY_U, GRUB_KEYBOARD_KEY_I, + /* 0x18 */ GRUB_KEYBOARD_KEY_O, GRUB_KEYBOARD_KEY_P, + /* 0x1a */ GRUB_KEYBOARD_KEY_LBRACKET, GRUB_KEYBOARD_KEY_RBRACKET, + /* 0x1c */ GRUB_KEYBOARD_KEY_ENTER, GRUB_KEYBOARD_KEY_LEFT_CTRL, + /* 0x1e */ GRUB_KEYBOARD_KEY_A, GRUB_KEYBOARD_KEY_S, + /* 0x20 */ GRUB_KEYBOARD_KEY_D, GRUB_KEYBOARD_KEY_F, + /* 0x22 */ GRUB_KEYBOARD_KEY_G, GRUB_KEYBOARD_KEY_H, + /* 0x24 */ GRUB_KEYBOARD_KEY_J, GRUB_KEYBOARD_KEY_K, + /* 0x26 */ GRUB_KEYBOARD_KEY_L, GRUB_KEYBOARD_KEY_SEMICOLON, + /* 0x28 */ GRUB_KEYBOARD_KEY_DQUOTE, GRUB_KEYBOARD_KEY_RQUOTE, + /* 0x2a */ GRUB_KEYBOARD_KEY_LEFT_SHIFT, GRUB_KEYBOARD_KEY_BACKSLASH, + /* 0x2c */ GRUB_KEYBOARD_KEY_Z, GRUB_KEYBOARD_KEY_X, + /* 0x2e */ GRUB_KEYBOARD_KEY_C, GRUB_KEYBOARD_KEY_V, + /* 0x30 */ GRUB_KEYBOARD_KEY_B, GRUB_KEYBOARD_KEY_N, + /* 0x32 */ GRUB_KEYBOARD_KEY_M, GRUB_KEYBOARD_KEY_COMMA, + /* 0x34 */ GRUB_KEYBOARD_KEY_DOT, GRUB_KEYBOARD_KEY_SLASH, + /* 0x36 */ GRUB_KEYBOARD_KEY_RIGHT_SHIFT, GRUB_KEYBOARD_KEY_NUMMUL, + /* 0x38 */ GRUB_KEYBOARD_KEY_LEFT_ALT, GRUB_KEYBOARD_KEY_SPACE, + /* 0x3a */ GRUB_KEYBOARD_KEY_CAPS_LOCK, GRUB_KEYBOARD_KEY_F1, + /* 0x3c */ GRUB_KEYBOARD_KEY_F2, GRUB_KEYBOARD_KEY_F3, + /* 0x3e */ GRUB_KEYBOARD_KEY_F4, GRUB_KEYBOARD_KEY_F5, + /* 0x40 */ GRUB_KEYBOARD_KEY_F6, GRUB_KEYBOARD_KEY_F7, + /* 0x42 */ GRUB_KEYBOARD_KEY_F8, GRUB_KEYBOARD_KEY_F9, + /* 0x44 */ GRUB_KEYBOARD_KEY_F10, GRUB_KEYBOARD_KEY_NUM_LOCK, + /* 0x46 */ GRUB_KEYBOARD_KEY_SCROLL_LOCK, GRUB_KEYBOARD_KEY_NUM7, + /* 0x48 */ GRUB_KEYBOARD_KEY_NUM8, GRUB_KEYBOARD_KEY_NUM9, + /* 0x4a */ GRUB_KEYBOARD_KEY_NUMMINUS, GRUB_KEYBOARD_KEY_NUM4, + /* 0x4c */ GRUB_KEYBOARD_KEY_NUM5, GRUB_KEYBOARD_KEY_NUM6, + /* 0x4e */ GRUB_KEYBOARD_KEY_NUMPLUS, GRUB_KEYBOARD_KEY_NUM1, + /* 0x50 */ GRUB_KEYBOARD_KEY_NUM2, GRUB_KEYBOARD_KEY_NUM3, + /* 0x52 */ GRUB_KEYBOARD_KEY_NUMDOT, GRUB_KEYBOARD_KEY_NUMDOT, + /* 0x54 */ 0, 0, + /* 0x56 */ GRUB_KEYBOARD_KEY_102ND, GRUB_KEYBOARD_KEY_F11, + /* 0x58 */ GRUB_KEYBOARD_KEY_F12, 0, + /* 0x5a */ 0, 0, + /* 0x5c */ 0, 0, + /* 0x5e */ 0, 0, + /* 0x60 */ GRUB_KEYBOARD_KEY_NUMENTER, GRUB_KEYBOARD_KEY_RIGHT_CTRL, + /* 0x62 */ GRUB_KEYBOARD_KEY_NUMSLASH, 0, + /* 0x64 */ GRUB_KEYBOARD_KEY_RIGHT_ALT, 0, + /* 0x66 */ GRUB_KEYBOARD_KEY_HOME, GRUB_KEYBOARD_KEY_UP, + /* 0x68 */ GRUB_KEYBOARD_KEY_PPAGE, GRUB_KEYBOARD_KEY_LEFT, + /* 0x6a */ GRUB_KEYBOARD_KEY_RIGHT, GRUB_KEYBOARD_KEY_END, + /* 0x6c */ GRUB_KEYBOARD_KEY_DOWN, GRUB_KEYBOARD_KEY_NPAGE, + /* 0x6e */ GRUB_KEYBOARD_KEY_INSERT, GRUB_KEYBOARD_KEY_DELETE +}; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTIONS]\n\ + -i, --input set input filename. Default is STDIN\n\ + -o, --output set output filename. Default is STDOUT\n\ + -h, --help display this message and exit.\n\ + -V, --version print version information and exit.\n\ + -v, --verbose print verbose messages.\n\ +\n\ +Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); + + exit (status); +} + +static void +add_special_keys (struct grub_keyboard_layout *layout) +{ + (void) layout; +} + +static unsigned +lookup (char *code, int shift) +{ + int i; + struct console_grub_equivalence *pr; + + if (shift) + pr = console_grub_equivalences_shift; + else + pr = console_grub_equivalences_unshift; + + for (i = 0; pr[i].layout != NULL; i++) + if (strcmp (code, pr[i].layout) == 0) + return pr[i].grub; + + for (i = 0; console_grub_equivalences_common[i].layout != NULL; i++) + if (strcmp (code, console_grub_equivalences_common[i].layout) == 0) + return console_grub_equivalences_common[i].grub; + + fprintf (stderr, "Unknown key %s\n", code); + + return '\0'; +} + +static unsigned int +get_grub_code (char *layout_code, int shift) +{ + unsigned int code; + + if (strncmp (layout_code, "U+", sizeof ("U+") - 1) == 0) + sscanf (layout_code, "U+%x", &code); + else if (strncmp (layout_code, "+U+", sizeof ("+U+") - 1) == 0) + sscanf (layout_code, "+U+%x", &code); + else + code = lookup (layout_code, shift); + return code; +} + +static void +write_file (FILE *out, struct grub_keyboard_layout *layout) +{ + grub_uint32_t version; + unsigned i; + + version = grub_cpu_to_le32 (GRUB_KEYBOARD_LAYOUTS_VERSION); + + for (i = 0; i < ARRAY_SIZE (layout->keyboard_map); i++) + layout->keyboard_map[i] = grub_cpu_to_le32(layout->keyboard_map[i]); + + for (i = 0; i < ARRAY_SIZE (layout->keyboard_map_shift); i++) + layout->keyboard_map_shift[i] + = grub_cpu_to_le32(layout->keyboard_map_shift[i]); + + for (i = 0; i < ARRAY_SIZE (layout->keyboard_map_l3); i++) + layout->keyboard_map_l3[i] + = grub_cpu_to_le32(layout->keyboard_map_l3[i]); + + for (i = 0; i < ARRAY_SIZE (layout->keyboard_map_shift_l3); i++) + layout->keyboard_map_shift_l3[i] + = grub_cpu_to_le32(layout->keyboard_map_shift_l3[i]); + + fwrite (GRUB_KEYBOARD_LAYOUTS_FILEMAGIC, 1, + GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE, out); + fwrite (&version, sizeof (version), 1, out); + fwrite (layout, 1, sizeof (*layout), out); +} + +static void +write_keymaps (FILE *in, FILE *out) +{ + struct grub_keyboard_layout layout; + char line[2048]; + int ok; + + memset (&layout, 0, sizeof (layout)); + + /* Process the ckbcomp output and prepare the layouts. */ + ok = 0; + while (fgets (line, sizeof (line), in)) + { + if (strncmp (line, "keycode", sizeof ("keycode") - 1) == 0) + { + unsigned keycode_linux; + unsigned keycode_usb; + char normal[64]; + char shift[64]; + char normalalt[64]; + char shiftalt[64]; + + sscanf (line, "keycode %u = %60s %60s %60s %60s", &keycode_linux, + normal, shift, normalalt, shiftalt); + + /* Not used. */ + if (keycode_linux == 0x77 /* Pause */ + /* Some obscure keys */ + || keycode_linux == 0x63 || keycode_linux == 0x7d + || keycode_linux == 0x7e) + continue; + + /* Not remappable. */ + if (keycode_linux == 0x1d /* Left CTRL */ + || keycode_linux == 0x61 /* Right CTRL */ + || keycode_linux == 0x2a /* Left Shift. */ + || keycode_linux == 0x36 /* Right Shift. */ + || keycode_linux == 0x38 /* Left ALT. */ + || keycode_linux == 0x64 /* Right ALT. */ + || keycode_linux == 0x3a /* CapsLock. */ + || keycode_linux == 0x45 /* NumLock. */ + || keycode_linux == 0x46 /* ScrollLock. */) + continue; + + keycode_usb = linux_to_usb_map[keycode_linux]; + if (keycode_usb == 0 + || keycode_usb >= GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) + { + fprintf (stderr, "Unknown keycode 0x%02x\n", keycode_linux); + continue; + } + if (keycode_usb < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) + { + layout.keyboard_map[keycode_usb] = get_grub_code (normal, 0); + layout.keyboard_map_shift[keycode_usb] = get_grub_code (shift, 1); + layout.keyboard_map_l3[keycode_usb] + = get_grub_code (normalalt, 0); + layout.keyboard_map_shift_l3[keycode_usb] + = get_grub_code (shiftalt, 1); + ok = 1; + } + } + } + + if (ok == 0) + { + fprintf (stderr, "ERROR: no keycodes found. Check output of %s.\n", + CKBCOMP); + exit (1); + } + + add_special_keys (&layout); + + write_file (out, &layout); +} + +int +main (int argc, char *argv[]) +{ + int verbosity; + char *infile_name = NULL; + char *outfile_name = NULL; + FILE *in, *out; + + set_program_name (argv[0]); + + verbosity = 0; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "o:i:hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'i': + infile_name = optarg; + break; + + case 'o': + outfile_name = optarg; + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, + PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + if (infile_name) + in = fopen (infile_name, "r"); + else + in = stdin; + + if (!in) + grub_util_error ("Couldn't open input file: %s\n", strerror (errno)); + + if (outfile_name) + out = fopen (outfile_name, "wb"); + else + out = stdout; + + if (!out) + { + if (in != stdin) + fclose (in); + grub_util_error ("Couldn't open output file: %s\n", strerror (errno)); + } + + write_keymaps (in, out); + + if (in != stdin) + fclose (in); + + if (out != stdout) + fclose (out); + + return 0; +} diff --git a/util/grub-mknetdir.in b/util/grub-mknetdir.in new file mode 100644 index 0000000..b353e98 --- /dev/null +++ b/util/grub-mknetdir.in @@ -0,0 +1,230 @@ +#! /bin/sh + +# Install GRUB on your drive. +# Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +# Initialize some variables. +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +sbindir=@sbindir@ +bindir=@bindir@ +libdir=@libdir@ +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_TARNAME=@PACKAGE_TARNAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +target_cpu=@target_cpu@ +platform=@platform@ +host_os=@host_os@ +pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` +localedir=@datadir@/locale +native_platform=@platform@ +pkglib_DATA="moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst terminal.lst" + +self=`basename $0` + +grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` +rootdir=/srv/tftp +grub_prefix=`echo /boot/grub | sed ${transform}` +modules= + +install_device= +no_floppy= +recheck=no +debug=no +debug_image= +subdir=`echo /boot/grub | sed ${transform}` +pc_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-pc + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +argument () { + opt=$1 + shift + + if test $# -eq 0; then + echo "$0: option requires an argument -- '$opt'" 1>&2 + exit 1 + fi + echo $1 +} + +# Check the arguments. +while test $# -gt 0 +do + option=$1 + shift + + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" + exit 0 ;; + + --modules) + modules=`argument $option "$@"`; shift;; + --modules=*) + modules=`echo "$option" | sed 's/--modules=//'` ;; + + --net-directory) + rootdir=`argument $option "$@"`; shift;; + --net-directory=*) + rootdir=`echo "$option" | sed 's/--net-directory=//'` ;; + + --subdir) + subdir=`argument $option "$@"`; shift;; + --subdir=*) + subdir=`echo "$option" | sed 's/--subdir=//'` ;; + + --grub-mkimage) + grub_mkimage=`argument $option "$@"`; shift;; + --grub-mkimage=*) + grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;; + + # This is an undocumented feature... + --debug) + debug=yes ;; + --debug-image) + debug_image=`argument $option "$@"`; shift;; + --debug-image=*) + debug_image=`echo "$option" | sed 's/--debug-image=//'` ;; + + # Intentionally undocumented + --override-directory) + override_dir=`argument $option "$@"` + shift + PATH=${override_dir}:$PATH + export PATH + ;; + --override-directory=*) + override_dir=`echo "${option}/" | sed 's/--override-directory=//'` + PATH=${override_dir}:$PATH + export PATH + ;; + + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + *) + if test "x$install_device" != x; then + echo "More than one install_devices?" 1>&2 + usage + exit 1 + fi + install_device="${option}" ;; + esac +done + +set $grub_mkimage dummy +if test -f "$1"; then + : +else + echo "$1: Not found." 1>&2 + exit 1 +fi + +# Create the GRUB directory if it is not present. +mkdir -p "${rootdir}/${subdir}" || exit 1 + +process_input_dir () +{ + input_dir="$1" + platform="$2" + grubdir="${rootdir}/${subdir}/${platform}" + config_opt= + mkdir -p "$grubdir" || exit 1 + + for file in ${grubdir}/*.mod ${grubdir}/*.lst ${grubdir}/*.img ${grubdir}/efiemu??.o; do + if test -f $file && [ "`basename $file`" != menu.lst ]; then + rm -f $file || exit 1 + fi + done + for file in ${input_dir}/*.mod; do + if test -f "$file"; then + cp -f "$file" "$grubdir/" + fi + done + for file in ${pkglib_DATA}; do + if test -f "${input_dir}/${file}"; then + cp -f "${input_dir}/${file}" "$grubdir/" + fi + done + + mkdir -p "$grubdir/locale" + for file in ${input_dir}/po/*.mo; do + if test -f "$file"; then + cp -f "$file" "$grubdir/locale/" + fi + done + + rm -f ${grubdir}/load.cfg + + if [ "x${debug_image}" != x ]; then + echo "set debug='${debug_image}'" >> ${grubdir}/load.cfg + config_opt="-c ${grubdir}/load.cfg " + fi + + case "${platform}" in + i386-pc) mkimage_target=i386-pc-pxe; + netmodules="pxe"; + prefix="(pxe)/${subdir}/${platform}"; + ext=0 ;; + *) echo Unsupported platform ${platform}; + exit 1;; + esac + + cat << EOF > ${grubdir}/grub.cfg +source ${subdir}/grub.cfg +EOF + + $grub_mkimage ${config_opt} -d "${input_dir}" -O ${mkimage_target} --output=${grubdir}/core.$ext --prefix=$prefix $modules $netmodules || exit 1 + echo "Netboot directory for ${platform} created. Configure your DHCP server to point to ${subdir}/${platform}/core.$ext" +} + +if [ "${override_dir}" = "" ] ; then + if test -e "${pc_dir}" ; then + process_input_dir ${pc_dir} i386-pc + fi +else + process_input_dir ${override_dir} ${target_cpu}-${native_platform} +fi + + +# Bye. +exit 0 diff --git a/util/grub-mkpasswd-pbkdf2.c b/util/grub-mkpasswd-pbkdf2.c new file mode 100644 index 0000000..dc2afdb --- /dev/null +++ b/util/grub-mkpasswd-pbkdf2.c @@ -0,0 +1,314 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1992-1999,2001,2003,2004,2005,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "progname.h" + +static struct option options[] = + { + {"iteration_count", required_argument, 0, 'c'}, + {"buflen", required_argument, 0, 'l'}, + {"saltlen", required_argument, 0, 's'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTIONS]\n\ +\nOptions:\n\ + -c number, --iteration-count=number Number of PBKDF2 iterations\n\ + -l number, --buflen=number Length of generated hash\n\ + -s number, --salt=number Length of salt\n\ +\n\ +Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); + + exit (status); +} + +static void +hexify (char *hex, grub_uint8_t *bin, grub_size_t n) +{ + while (n--) + { + if (((*bin & 0xf0) >> 4) < 10) + *hex = ((*bin & 0xf0) >> 4) + '0'; + else + *hex = ((*bin & 0xf0) >> 4) + 'A' - 10; + hex++; + + if ((*bin & 0xf) < 10) + *hex = (*bin & 0xf) + '0'; + else + *hex = (*bin & 0xf) + 'A' - 10; + hex++; + bin++; + } + *hex = 0; +} + +int +main (int argc, char *argv[]) +{ + unsigned int count = 10000, buflen = 64, saltlen = 64; + char *pass1, *pass2; + char *bufhex, *salthex; + gcry_err_code_t gcry_err; + grub_uint8_t *buf, *salt; + ssize_t nr; + FILE *in, *out; + struct termios s, t; + int tty_changed; + + set_program_name (argv[0]); + + grub_util_init_nls (); + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "c:l:s:hvV", options, 0); + + if (c == -1) + break; + + switch (c) + { + case 'c': + count = strtoul (optarg, NULL, 0); + break; + + case 'l': + buflen = strtoul (optarg, NULL, 0); + break; + + case 's': + saltlen = strtoul (optarg, NULL, 0); + break; + + case 'h': + usage (0); + return 0; + + case 'V': + printf ("%s (%s) %s\n", program_name, + PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + default: + usage (1); + return 1; + } + } + + bufhex = malloc (buflen * 2 + 1); + if (!bufhex) + grub_util_error ("out of memory"); + buf = malloc (buflen); + if (!buf) + { + free (bufhex); + grub_util_error ("out of memory"); + } + + salt = malloc (saltlen); + if (!salt) + { + free (bufhex); + free (buf); + grub_util_error ("out of memory"); + } + salthex = malloc (saltlen * 2 + 1); + if (!salthex) + { + free (salt); + free (bufhex); + free (buf); + grub_util_error ("out of memory"); + } + + /* Disable echoing. Based on glibc. */ + in = fopen ("/dev/tty", "w+c"); + if (in == NULL) + { + in = stdin; + out = stderr; + } + else + out = in; + + if (tcgetattr (fileno (in), &t) == 0) + { + /* Save the old one. */ + s = t; + /* Tricky, tricky. */ + t.c_lflag &= ~(ECHO|ISIG); + tty_changed = (tcsetattr (fileno (in), TCSAFLUSH, &t) == 0); + } + else + tty_changed = 0; + + printf ("Enter password: "); + pass1 = NULL; + { + grub_size_t n; + nr = getline (&pass1, &n, stdin); + } + if (nr < 0 || !pass1) + { + free (buf); + free (bufhex); + free (salthex); + free (salt); + /* Restore the original setting. */ + if (tty_changed) + (void) tcsetattr (fileno (in), TCSAFLUSH, &s); + grub_util_error ("failure to read password"); + } + if (nr >= 1 && pass1[nr-1] == '\n') + pass1[nr-1] = 0; + + printf ("\nReenter password: "); + pass2 = NULL; + { + grub_size_t n; + nr = getline (&pass2, &n, stdin); + } + /* Restore the original setting. */ + if (tty_changed) + (void) tcsetattr (fileno (in), TCSAFLUSH, &s); + printf ("\n"); + + if (nr < 0 || !pass2) + { + memset (pass1, 0, strlen (pass1)); + free (pass1); + free (buf); + free (bufhex); + free (salthex); + free (salt); + grub_util_error ("failure to read password"); + } + if (nr >= 1 && pass2[nr-1] == '\n') + pass2[nr-1] = 0; + + if (strcmp (pass1, pass2) != 0) + { + memset (pass1, 0, strlen (pass1)); + memset (pass2, 0, strlen (pass2)); + free (pass1); + free (pass2); + free (buf); + free (bufhex); + free (salthex); + free (salt); + grub_util_error ("passwords don't match"); + } + memset (pass2, 0, strlen (pass2)); + free (pass2); + +#if ! defined (__linux__) && ! defined (__FreeBSD__) + printf ("WARNING: your random generator isn't known to be secure\n"); +#endif + + { + FILE *f; + size_t rd; + f = fopen ("/dev/urandom", "rb"); + if (!f) + { + memset (pass1, 0, strlen (pass1)); + free (pass1); + free (buf); + free (bufhex); + free (salthex); + free (salt); + fclose (f); + grub_util_error ("couldn't retrieve random data for salt"); + } + rd = fread (salt, 1, saltlen, f); + if (rd != saltlen) + { + fclose (f); + memset (pass1, 0, strlen (pass1)); + free (pass1); + free (buf); + free (bufhex); + free (salthex); + free (salt); + fclose (f); + grub_util_error ("couldn't retrieve random data for salt"); + } + fclose (f); + } + + gcry_err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, + (grub_uint8_t *) pass1, strlen (pass1), + salt, saltlen, + count, buf, buflen); + memset (pass1, 0, strlen (pass1)); + free (pass1); + + if (gcry_err) + { + memset (buf, 0, buflen); + memset (bufhex, 0, 2 * buflen); + free (buf); + free (bufhex); + memset (salt, 0, saltlen); + memset (salthex, 0, 2 * saltlen); + free (salt); + free (salthex); + grub_util_error ("cryptographic error number %d", gcry_err); + } + + hexify (bufhex, buf, buflen); + hexify (salthex, salt, saltlen); + + printf ("Your PBKDF2 is grub.pbkdf2.sha512.%d.%s.%s\n", + count, salthex, bufhex); + memset (buf, 0, buflen); + memset (bufhex, 0, 2 * buflen); + free (buf); + free (bufhex); + memset (salt, 0, saltlen); + memset (salthex, 0, 2 * saltlen); + free (salt); + free (salthex); + + return 0; +} diff --git a/util/grub-mkrelpath.c b/util/grub-mkrelpath.c new file mode 100644 index 0000000..3fe3fe6 --- /dev/null +++ b/util/grub-mkrelpath.c @@ -0,0 +1,109 @@ +/* grub-mkrelpath.c - make a system path relative to its root */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include + +#include +#include +#include +#include +#include + +#include "progname.h" + +static struct option options[] = + { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {0, 0, 0, 0}, + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTIONS] PATH\n\ +\n\ +Make a system path relative to its root.\n\ +\n\ +Options:\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ +\n\ +Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); + + exit (status); +} + +int +main (int argc, char *argv[]) +{ + char *argument, *relpath; + + set_program_name (argv[0]); + + grub_util_init_nls (); + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "hV", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + default: + usage (1); + break; + } + } + + if (optind >= argc) + { + fprintf (stderr, "No path is specified.\n"); + usage (1); + } + + if (optind + 1 != argc) + { + fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]); + usage (1); + } + + argument = argv[optind]; + + relpath = grub_make_system_path_relative_to_its_root (argument); + printf ("%s\n", relpath); + free (relpath); + + return 0; +} diff --git a/util/grub-mkrescue.in b/util/grub-mkrescue.in new file mode 100644 index 0000000..f7f7517 --- /dev/null +++ b/util/grub-mkrescue.in @@ -0,0 +1,315 @@ +#! /bin/sh +set -e + +# Make GRUB rescue image +# Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +# Initialize some variables. +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_TARNAME=@PACKAGE_TARNAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +target_cpu=@target_cpu@ +native_platform=@platform@ +pkglib_DATA="moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst terminal.lst" + +self=`basename $0` + +multiboot_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-multiboot +coreboot_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-coreboot +qemu_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-qemu +pc_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-pc +efi32_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-efi +efi64_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/x86_64-efi +rom_directory= +override_dir= +grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` + +xorriso=xorriso + +# Usage: usage +# Print the usage. +usage () { + cat <. +Mail xorriso support requests to . +EOF +} + +argument () { + opt=$1 + shift + + if test $# -eq 0; then + echo "$0: option requires an argument -- '$opt'" 1>&2 + exit 1 + fi + echo $1 +} + +# Check the arguments. +while test $# -gt 0 +do + option=$1 + shift + + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" + exit 0 ;; + + --modules) + modules=`argument $option "$@"`; shift ;; + --modules=*) + modules=`echo "$option" | sed 's/--modules=//'` ;; + + -o | --output) + output_image=`argument $option "$@"`; shift ;; + --output=*) + output_image=`echo "$option" | sed 's/--output=//'` ;; + + --rom-directory) + rom_directory=`argument $option "$@"`; shift ;; + --rom-directory=*) + rom_directory=`echo "$option" | sed 's/--rom-directory=//'` ;; + + # Intentionally undocumented + --override-directory) + override_dir=`argument $option "$@"` + shift + PATH=${override_dir}:$PATH + export PATH + ;; + --override-directory=*) + override_dir=`echo "${option}/" | sed 's/--override-directory=//'` + PATH=${override_dir}:$PATH + export PATH + ;; + + --grub-mkimage) + grub_mkimage=`argument $option "$@"`; shift ;; + --grub-mkimage=*) + grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;; + + --xorriso) + xorriso=`argument $option "$@"`; shift ;; + --xorriso=*) + xorriso=`echo "${option}/" | sed 's/--xorriso=//'` ;; + + *) + source="${source} ${option} $@"; break ;; + esac +done + +if [ "x${output_image}" = x ] ; then + echo "output file must be given" >&2 + usage + exit 1 +fi + +set $grub_mkimage dummy +if test -f "$1"; then + : +else + echo "$1: Not found." 1>&2 + exit 1 +fi + +iso9660_dir=`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 +mkdir -p ${iso9660_dir}/boot/grub + +process_input_dir () +{ + input_dir="$1" + platform="$2" + mkdir -p ${iso9660_dir}/boot/grub/${platform} + for file in "${input_dir}/"*.mod "${input_dir}/"efiemu32.o "${input_dir}/"efiemu64.o; do + if test -f "$file"; then + cp -f "$file" ${iso9660_dir}/boot/grub/${platform}/ + fi + done + for file in ${pkglib_DATA}; do + if test -f "${input_dir}/${file}"; then + cp -f "${input_dir}/${file}" ${iso9660_dir}/boot/grub/${platform}/ + fi + done + + mkdir -p ${iso9660_dir}/boot/grub/locale + for file in ${input_dir}/po/*.mo; do + if test -f "$file"; then + cp -f "$file" ${iso9660_dir}/boot/grub/locale/ + fi + done +} + +make_image () +{ + source_directory="$1" + platform=$2 + if ! test -e "${source_directory}"; then + return; + fi + + echo "Enabling $2 support ..." + + memdisk_img=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 + memdisk_dir=`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 + mkdir -p ${memdisk_dir}/boot/grub + + cat << EOF > ${memdisk_dir}/boot/grub/grub.cfg +search --fs-uuid --set=root ${iso_uuid} +set prefix=(\${root})/boot/grub/${platform} +source \$prefix/grub.cfg +EOF + (for i in $(cat ${source_directory}/partmap.lst) ${modules} ; do + echo "insmod $i" + done ; \ + echo "source /boot/grub/grub.cfg") \ + > ${iso9660_dir}/boot/grub/${platform}/grub.cfg + + (cd "${memdisk_dir}"; tar -cf - boot) > "${memdisk_img}" + rm -rf ${memdisk_dir} + $grub_mkimage -O ${platform} -d "${source_directory}" -m "${memdisk_img}" -o "$3" --prefix='(memdisk)/boot/grub' \ + search iso9660 configfile normal memdisk tar $4 + rm -rf ${memdisk_img} +} + +if [ "${override_dir}" = "" ] ; then + if test -e "${multiboot_dir}" ; then + process_input_dir ${multiboot_dir} i386-multiboot + fi + if test -e "${coreboot_dir}" ; then + process_input_dir ${coreboot_dir} i386-coreboot + fi + if test -e "${qemu_dir}" ; then + process_input_dir ${qemu_dir} i386-qemu + fi + if test -e "${pc_dir}" ; then + process_input_dir ${pc_dir} i386-pc + fi + if test -e "${efi32_dir}" ; then + process_input_dir ${efi32_dir} i386-efi + fi + if test -e "${efi64_dir}" ; then + process_input_dir ${efi64_dir} x86_64-efi + fi +else + process_input_dir ${override_dir} ${target_cpu}-${native_platform} + multiboot_dir= + pc_dir= + efi32_dir= + efi64_dir= + coreboot_dir= + qemu_dir= + case "${target_cpu}-${native_platform}" in + i386-multiboot) multiboot_dir=${override_dir} ;; + i386-coreboot) coreboot_dir=${override_dir} ;; + i386-qemu) qemu_dir=${override_dir} ;; + i386-pc) pc_dir=${override_dir} ;; + i386-efi) efi32_dir=${override_dir} ;; + x86_64-efi) efi64_dir=${override_dir} ;; + esac +fi + +# obtain date-based UUID +iso_uuid=$(date -u +%Y-%m-%d-%H-%M-%S-00) +grub_mkisofs_arguments="${grub_mkisofs_arguments} --modification-date=$(echo ${iso_uuid} | sed -e s/-//g)" + +# build BIOS core.img +if test -e "${pc_dir}" ; then + echo "Enabling BIOS support ..." + core_img=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 + $grub_mkimage -O i386-pc -d ${pc_dir}/ -o ${core_img} --prefix=/boot/grub/i386-pc \ + iso9660 biosdisk + cat ${pc_dir}/cdboot.img ${core_img} > ${iso9660_dir}/boot/grub/i386-pc/eltorito.img + + embed_img=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 + cat ${pc_dir}/boot.img ${core_img} > ${embed_img} + + rm -f ${core_img} + + (for i in $(cat ${pc_dir}/partmap.lst) ${modules} ; do + echo "insmod $i" + done ; \ + echo "source /boot/grub/grub.cfg") \ + > ${iso9660_dir}/boot/grub/i386-pc/grub.cfg + + grub_mkisofs_arguments="${grub_mkisofs_arguments} -b boot/grub/i386-pc/eltorito.img -no-emul-boot -boot-info-table \ + --embedded-boot ${embed_img}" +fi + +# build multiboot core.img +make_image "${multiboot_dir}" i386-multiboot "${iso9660_dir}/boot/multiboot.img" "ata at_keyboard" + +if test -e "${efi64_dir}" || test -e "${efi32_dir}"; then + efi_dir=`mktemp -d "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 + mkdir -p "${efi_dir}/efi/boot" + + # build bootx64.efi + make_image "${efi64_dir}" x86_64-efi "${efi_dir}"/efi/boot/bootx64.efi "" + # build bootia32.efi + make_image "${efi32_dir}" i386-efi "${efi_dir}"/efi/boot/bootia32.efi "" + if [ -e "${efi_dir}"/efi/boot/bootia32.efi ]; then + # For old macs. Suggested by Peter Jones. + cp "${efi_dir}"/efi/boot/bootia32.efi "${efi_dir}"/efi/boot/boot.efi + fi + + mformat -C -f 2880 -L 16 -i "${iso9660_dir}"/efi.img :: + mcopy -s -i "${iso9660_dir}"/efi.img ${efi_dir}/efi ::/ + rm -rf ${efi_dir} + grub_mkisofs_arguments="${grub_mkisofs_arguments} --efi-boot efi.img" +fi + +make_image "${qemu_dir}" i386-qemu "${iso9660_dir}/boot/qemu.img" "ata at_keyboard" +if [ -e "${iso9660_dir}/boot/qemu.img" ] && [ -d "${rom_directory}" ]; then + cp "${iso9660_dir}/boot/qemu.img" "${rom_directory}/qemu.img" +fi +make_image "${coreboot_dir}" i386-coreboot "${iso9660_dir}/boot/coreboot.elf" "ata at_keyboard" +if [ -e "${iso9660_dir}/boot/coreboot.elf" ] && [ -d "${rom_directory}" ]; then + cp "${iso9660_dir}/boot/coreboot.elf" "${rom_directory}/coreboot.elf" +fi + +# build iso image +"${xorriso}" -as mkisofs -graft-points ${grub_mkisofs_arguments} --protective-msdos-label -o ${output_image} -r ${iso9660_dir} --sort-weight 0 / --sort-weight 1 /boot ${source} +rm -rf ${iso9660_dir} + +rm -f ${embed_img} + +exit 0 diff --git a/util/grub-pe2elf.c b/util/grub-pe2elf.c new file mode 100644 index 0000000..4b93faa --- /dev/null +++ b/util/grub-pe2elf.c @@ -0,0 +1,537 @@ +/* grub-pe2elf.c - tool to convert pe image to elf. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "progname.h" + +static struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} +}; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTIONS] input [output]\n\ +\n\ +Tool to convert pe image to elf.\n\ +\nOptions:\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print verbose messages\n\ +\n\ +Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); + + exit (status); +} + +/* + * Section layout + * + * null + * .text + * .rdata + * .data + * .bss + * .modname + * .moddeps + * .symtab + * .strtab + * relocation sections + */ + +#define TEXT_SECTION 1 +#define RDATA_SECTION 2 +#define DATA_SECTION 3 +#define BSS_SECTION 4 +#define MODNAME_SECTION 5 +#define MODDEPS_SECTION 6 +#define MODLICENSE_SECTION 7 +#define SYMTAB_SECTION 8 +#define STRTAB_SECTION 9 + +#define REL_SECTION 10 +#define MAX_SECTIONS 16 + +#define STRTAB_BLOCK 256 + +static char *strtab; +static int strtab_max, strtab_len; + +Elf32_Ehdr ehdr; +Elf32_Shdr shdr[MAX_SECTIONS]; +int num_sections; +grub_uint32_t offset; + +static int +insert_string (const char *name) +{ + int len, result; + + if (*name == '_') + name++; + + len = strlen (name); + if (strtab_len + len >= strtab_max) + { + strtab_max += STRTAB_BLOCK; + strtab = xrealloc (strtab, strtab_max); + } + + strcpy (strtab + strtab_len, name); + result = strtab_len; + strtab_len += len + 1; + + return result; +} + +static int * +write_section_data (FILE* fp, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr) +{ + int *section_map; + int i; + char *pe_strtab = (image + pe_chdr->symtab_offset + + pe_chdr->num_symbols * sizeof (struct grub_pe32_symbol)); + + section_map = xmalloc ((pe_chdr->num_sections + 1) * sizeof (int)); + section_map[0] = 0; + + for (i = 0; i < pe_chdr->num_sections; i++, pe_shdr++) + { + grub_uint32_t idx; + const char *name = pe_shdr->name; + + if (name[0] == '/' && isdigit (name[1])) + { + char t[sizeof (pe_shdr->name) + 1]; + memcpy (t, name, sizeof (pe_shdr->name)); + t[sizeof (pe_shdr->name)] = 0; + name = pe_strtab + atoi (t + 1); + } + + if (! strcmp (name, ".text")) + { + idx = TEXT_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_EXECINSTR; + } + else if (! strcmp (name, ".rdata")) + { + idx = RDATA_SECTION; + shdr[idx].sh_flags = SHF_ALLOC; + } + else if (! strcmp (name, ".data")) + { + idx = DATA_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; + } + else if (! strcmp (name, ".bss")) + { + idx = BSS_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; + } + else if (! strcmp (name, ".modname")) + idx = MODNAME_SECTION; + else if (! strcmp (name, ".moddeps")) + idx = MODDEPS_SECTION; + else if (strcmp (name, ".module_license") == 0) + idx = MODLICENSE_SECTION; + else + { + section_map[i + 1] = -1; + continue; + } + + section_map[i + 1] = idx; + + shdr[idx].sh_type = (idx == BSS_SECTION) ? SHT_NOBITS : SHT_PROGBITS; + shdr[idx].sh_size = pe_shdr->raw_data_size; + shdr[idx].sh_addralign = 1 << (((pe_shdr->characteristics >> + GRUB_PE32_SCN_ALIGN_SHIFT) & + GRUB_PE32_SCN_ALIGN_MASK) - 1); + + if (idx != BSS_SECTION) + { + shdr[idx].sh_offset = offset; + grub_util_write_image_at (image + pe_shdr->raw_data_offset, + pe_shdr->raw_data_size, offset, fp); + + offset += pe_shdr->raw_data_size; + } + + if (pe_shdr->relocations_offset) + { + char relname[5 + strlen (name)]; + + if (num_sections >= MAX_SECTIONS) + grub_util_error ("too many sections"); + + sprintf (relname, ".rel%s", name); + + shdr[num_sections].sh_name = insert_string (relname); + shdr[num_sections].sh_link = i; + shdr[num_sections].sh_info = idx; + + shdr[idx].sh_name = shdr[num_sections].sh_name + 4; + + num_sections++; + } + else + shdr[idx].sh_name = insert_string (name); + } + + return section_map; +} + +static void +write_reloc_section (FILE* fp, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr, + Elf32_Sym *symtab, + int *symtab_map) +{ + int i; + + for (i = REL_SECTION; i < num_sections; i++) + { + struct grub_pe32_section_table *pe_sec; + struct grub_pe32_reloc *pe_rel; + Elf32_Rel *rel; + int num_rels, j, modified; + + pe_sec = pe_shdr + shdr[i].sh_link; + pe_rel = (struct grub_pe32_reloc *) (image + pe_sec->relocations_offset); + rel = (Elf32_Rel *) xmalloc (pe_sec->num_relocations * sizeof (Elf32_Rel)); + num_rels = 0; + modified = 0; + + for (j = 0; j < pe_sec->num_relocations; j++, pe_rel++) + { + int type; + grub_uint32_t ofs, *addr; + + if ((pe_rel->symtab_index >= pe_chdr->num_symbols) || + (symtab_map[pe_rel->symtab_index] == -1)) + grub_util_error ("invalid symbol"); + + if (pe_rel->type == GRUB_PE32_REL_I386_DIR32) + type = R_386_32; + else if (pe_rel->type == GRUB_PE32_REL_I386_REL32) + type = R_386_PC32; + else + grub_util_error ("unknown pe relocation type %d\n", pe_rel->type); + + ofs = pe_rel->offset - pe_sec->virtual_address; + addr = (grub_uint32_t *)(image + pe_sec->raw_data_offset + ofs); + if (type == R_386_PC32) + { + unsigned char code; + + code = image[pe_sec->raw_data_offset + ofs - 1]; + + if (((code != 0xe8) && (code != 0xe9)) || (*addr)) + grub_util_error ("invalid relocation (%x %x)", code, *addr); + + modified = 1; + if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx) + { + if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx + != shdr[i].sh_info) + grub_util_error ("cross section call is not allowed"); + + *addr = (symtab[symtab_map[pe_rel->symtab_index]].st_value + - ofs - 4); + + continue; + } + else + *addr = -4; + } + + rel[num_rels].r_offset = ofs; + rel[num_rels].r_info = ELF32_R_INFO (symtab_map[pe_rel->symtab_index], + type); + num_rels++; + } + + if (modified) + grub_util_write_image_at (image + pe_sec->raw_data_offset, + shdr[shdr[i].sh_info].sh_size, + shdr[shdr[i].sh_info].sh_offset, + fp); + + shdr[i].sh_type = SHT_REL; + shdr[i].sh_offset = offset; + shdr[i].sh_link = SYMTAB_SECTION; + shdr[i].sh_addralign = 4; + shdr[i].sh_entsize = sizeof (Elf32_Rel); + shdr[i].sh_size = num_rels * sizeof (Elf32_Rel); + + grub_util_write_image_at (rel, shdr[i].sh_size, offset, fp); + offset += shdr[i].sh_size; + free (rel); + } +} + +static void +write_symbol_table (FILE* fp, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr, + int *section_map) +{ + struct grub_pe32_symbol *pe_symtab; + char *pe_strtab; + Elf32_Sym *symtab; + int *symtab_map, num_syms; + int i; + + pe_symtab = (struct grub_pe32_symbol *) (image + pe_chdr->symtab_offset); + pe_strtab = (char *) (pe_symtab + pe_chdr->num_symbols); + + symtab = (Elf32_Sym *) xmalloc ((pe_chdr->num_symbols + 1) * + sizeof (Elf32_Sym)); + memset (symtab, 0, (pe_chdr->num_symbols + 1) * sizeof (Elf32_Sym)); + num_syms = 1; + + symtab_map = (int *) xmalloc (pe_chdr->num_symbols * sizeof (int)); + + for (i = 0; i < (int) pe_chdr->num_symbols; + i += pe_symtab->num_aux + 1, pe_symtab += pe_symtab->num_aux + 1) + { + int bind, type; + + symtab_map[i] = -1; + if ((pe_symtab->section > pe_chdr->num_sections) || + (section_map[pe_symtab->section] == -1)) + continue; + + if (! pe_symtab->section) + type = STT_NOTYPE; + else if (pe_symtab->type == GRUB_PE32_DT_FUNCTION) + type = STT_FUNC; + else + type = STT_OBJECT; + + if (pe_symtab->storage_class == GRUB_PE32_SYM_CLASS_EXTERNAL) + bind = STB_GLOBAL; + else + bind = STB_LOCAL; + + if ((pe_symtab->type != GRUB_PE32_DT_FUNCTION) && (pe_symtab->num_aux)) + { + if (! pe_symtab->value) + type = STT_SECTION; + + symtab[num_syms].st_name = shdr[section_map[pe_symtab->section]].sh_name; + } + else + { + char short_name[9]; + char *name; + + if (pe_symtab->long_name[0]) + { + strncpy (short_name, pe_symtab->short_name, 8); + short_name[8] = 0; + name = short_name; + } + else + name = pe_strtab + pe_symtab->long_name[1]; + + if ((strcmp (name, "_grub_mod_init")) && + (strcmp (name, "_grub_mod_fini")) && + (bind == STB_LOCAL)) + continue; + + symtab[num_syms].st_name = insert_string (name); + } + + symtab[num_syms].st_shndx = section_map[pe_symtab->section]; + symtab[num_syms].st_value = pe_symtab->value; + symtab[num_syms].st_info = ELF32_ST_INFO (bind, type); + + symtab_map[i] = num_syms; + num_syms++; + } + + write_reloc_section (fp, image, pe_chdr, pe_shdr, symtab, symtab_map); + + shdr[SYMTAB_SECTION].sh_name = insert_string (".symtab"); + shdr[SYMTAB_SECTION].sh_type = SHT_SYMTAB; + shdr[SYMTAB_SECTION].sh_offset = offset; + shdr[SYMTAB_SECTION].sh_size = num_syms * sizeof (Elf32_Sym); + shdr[SYMTAB_SECTION].sh_entsize = sizeof (Elf32_Sym); + shdr[SYMTAB_SECTION].sh_link = STRTAB_SECTION; + shdr[SYMTAB_SECTION].sh_addralign = 4; + + grub_util_write_image_at (symtab, shdr[SYMTAB_SECTION].sh_size, + offset, fp); + offset += shdr[SYMTAB_SECTION].sh_size; + + free (symtab); + free (symtab_map); +} + +static void +write_string_table (FILE* fp) +{ + shdr[STRTAB_SECTION].sh_name = insert_string (".strtab"); + shdr[STRTAB_SECTION].sh_type = SHT_STRTAB; + shdr[STRTAB_SECTION].sh_offset = offset; + shdr[STRTAB_SECTION].sh_size = strtab_len; + shdr[STRTAB_SECTION].sh_addralign = 1; + grub_util_write_image_at (strtab, strtab_len, offset, fp); + offset += strtab_len; + + free (strtab); +} + +static void +write_section_header (FILE* fp) +{ + ehdr.e_ident[EI_MAG0] = ELFMAG0; + ehdr.e_ident[EI_MAG1] = ELFMAG1; + ehdr.e_ident[EI_MAG2] = ELFMAG2; + ehdr.e_ident[EI_MAG3] = ELFMAG3; + ehdr.e_ident[EI_VERSION] = EV_CURRENT; + ehdr.e_version = EV_CURRENT; + ehdr.e_type = ET_REL; + + ehdr.e_ident[EI_CLASS] = ELFCLASS32; + ehdr.e_ident[EI_DATA] = ELFDATA2LSB; + ehdr.e_machine = EM_386; + + ehdr.e_ehsize = sizeof (ehdr); + ehdr.e_shentsize = sizeof (Elf32_Shdr); + ehdr.e_shstrndx = STRTAB_SECTION; + + ehdr.e_shoff = offset; + ehdr.e_shnum = num_sections; + grub_util_write_image_at (&shdr, sizeof (Elf32_Shdr) * num_sections, + offset, fp); + + grub_util_write_image_at (&ehdr, sizeof (Elf32_Ehdr), 0, fp); +} + +static void +convert_pe (FILE* fp, char *image) +{ + struct grub_pe32_coff_header *pe_chdr; + struct grub_pe32_section_table *pe_shdr; + int *section_map; + + pe_chdr = (struct grub_pe32_coff_header *) image; + if (grub_le_to_cpu16 (pe_chdr->machine) != GRUB_PE32_MACHINE_I386) + grub_util_error ("invalid coff image"); + + strtab = xmalloc (STRTAB_BLOCK); + strtab_max = STRTAB_BLOCK; + strtab[0] = 0; + strtab_len = 1; + + offset = sizeof (ehdr); + pe_shdr = (struct grub_pe32_section_table *) (pe_chdr + 1); + num_sections = REL_SECTION; + + section_map = write_section_data (fp, image, pe_chdr, pe_shdr); + + write_symbol_table (fp, image, pe_chdr, pe_shdr, section_map); + free (section_map); + + write_string_table (fp); + + write_section_header (fp); +} + +int +main (int argc, char *argv[]) +{ + char *image; + FILE* fp; + + set_program_name (argv[0]); + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + /* Obtain PATH. */ + if (optind >= argc) + { + fprintf (stderr, "Filename not specified.\n"); + usage (1); + } + + image = grub_util_read_image (argv[optind]); + + if (optind + 1 < argc) + optind++; + + fp = fopen (argv[optind], "wb"); + if (! fp) + grub_util_error ("cannot open %s", argv[optind]); + + convert_pe (fp, image); + + fclose (fp); + + return 0; +} diff --git a/util/grub-probe.c b/util/grub-probe.c new file mode 100644 index 0000000..0d5dac9 --- /dev/null +++ b/util/grub-probe.c @@ -0,0 +1,419 @@ +/* grub-probe.c - probe device information for a given path */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define _GNU_SOURCE 1 +#include + +#include "progname.h" + +enum { + PRINT_FS, + PRINT_FS_UUID, + PRINT_FS_LABEL, + PRINT_DRIVE, + PRINT_DEVICE, + PRINT_PARTMAP, + PRINT_ABSTRACTION, +}; + +int print = PRINT_FS; +static unsigned int argument_is_device = 0; + +static void +probe_partmap (grub_disk_t disk) +{ + grub_partition_t part; + + if (disk->partition == NULL) + { + grub_util_info ("no partition map found for %s", disk->name); + return; + } + + for (part = disk->partition; part; part = part->parent) + printf ("%s\n", part->partmap->name); +} + +static int +probe_raid_level (grub_disk_t disk) +{ + /* disk might be NULL in the case of a LVM physical volume with no LVM + signature. Ignore such cases here. */ + if (!disk) + return -1; + + if (disk->dev->id != GRUB_DISK_DEVICE_RAID_ID) + return -1; + + return ((struct grub_raid_array *) disk->data)->level; +} + +static void +probe (const char *path, char *device_name) +{ + char *drive_name = NULL; + char *grub_path = NULL; + char *filebuf_via_grub = NULL, *filebuf_via_sys = NULL; + grub_device_t dev = NULL; + grub_fs_t fs; + + if (path == NULL) + { +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) + if (! grub_util_check_char_device (device_name)) + grub_util_error ("%s is not a character device", device_name); +#else + if (! grub_util_check_block_device (device_name)) + grub_util_error ("%s is not a block device", device_name); +#endif + } + else + device_name = grub_guess_root_device (path); + + if (! device_name) + grub_util_error ("cannot find a device for %s (is /dev mounted?)", path); + + if (print == PRINT_DEVICE) + { + printf ("%s\n", device_name); + goto end; + } + + drive_name = grub_util_get_grub_dev (device_name); + if (! drive_name) + grub_util_error ("cannot find a GRUB drive for %s. Check your device.map", device_name); + + if (print == PRINT_DRIVE) + { + printf ("(%s)\n", drive_name); + goto end; + } + + grub_util_info ("opening %s", drive_name); + dev = grub_device_open (drive_name); + if (! dev) + grub_util_error ("%s", grub_errmsg); + + if (print == PRINT_ABSTRACTION) + { + grub_disk_memberlist_t list = NULL, tmp; + const int is_lvm = (dev->disk->dev->id == GRUB_DISK_DEVICE_LVM_ID); + int is_raid = 0; + int is_raid5 = 0; + int is_raid6 = 0; + int raid_level; + grub_disk_t raid_disk; + + raid_level = probe_raid_level (dev->disk); + if (raid_level >= 0) + { + is_raid = 1; + is_raid5 |= (raid_level == 5); + is_raid6 |= (raid_level == 6); + raid_disk = dev->disk; + } + + if ((is_lvm) && (dev->disk->dev->memberlist)) + list = dev->disk->dev->memberlist (dev->disk); + while (list) + { + raid_level = probe_raid_level (list->disk); + if (raid_level >= 0) + { + is_raid = 1; + is_raid5 |= (raid_level == 5); + is_raid6 |= (raid_level == 6); + raid_disk = list->disk; + } + + tmp = list->next; + free (list); + list = tmp; + } + + if (is_raid) + { + printf ("raid "); + if (is_raid5) + printf ("raid5rec "); + if (is_raid6) + printf ("raid6rec "); + if (raid_disk->dev->raidname) + printf ("%s ", raid_disk->dev->raidname (raid_disk)); + } + + if (is_lvm) + printf ("lvm "); + + printf ("\n"); + + goto end; + } + + if (print == PRINT_PARTMAP) + { + grub_disk_memberlist_t list = NULL, tmp; + + /* Check if dev->disk itself is contained in a partmap. */ + probe_partmap (dev->disk); + + /* In case of LVM/RAID, check the member devices as well. */ + if (dev->disk->dev->memberlist) + list = dev->disk->dev->memberlist (dev->disk); + while (list) + { + probe_partmap (list->disk); + /* LVM on RAID */ + if (list->disk->dev->memberlist) + { + grub_disk_memberlist_t sub_list; + + sub_list = list->disk->dev->memberlist (list->disk); + while (sub_list) + { + probe_partmap (sub_list->disk); + tmp = sub_list->next; + free (sub_list); + sub_list = tmp; + } + } + tmp = list->next; + free (list); + list = tmp; + } + goto end; + } + + fs = grub_fs_probe (dev); + if (! fs) + grub_util_error ("%s", grub_errmsg); + + if (print == PRINT_FS) + { + printf ("%s\n", fs->name); + } + else if (print == PRINT_FS_UUID) + { + char *uuid; + if (! fs->uuid) + grub_util_error ("%s does not support UUIDs", fs->name); + + if (fs->uuid (dev, &uuid) != GRUB_ERR_NONE) + grub_util_error ("%s", grub_errmsg); + + printf ("%s\n", uuid); + } + else if (print == PRINT_FS_LABEL) + { + char *label; + if (! fs->label) + grub_util_error ("%s does not support labels", fs->name); + + if (fs->label (dev, &label) != GRUB_ERR_NONE) + grub_util_error ("%s", grub_errmsg); + + printf ("%s\n", label); + } + + end: + if (dev) + grub_device_close (dev); + free (grub_path); + free (filebuf_via_grub); + free (filebuf_via_sys); + free (drive_name); +} + +static struct option options[] = + { + {"device", no_argument, 0, 'd'}, + {"device-map", required_argument, 0, 'm'}, + {"target", required_argument, 0, 't'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, + "Try `%s --help' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTION]... [PATH|DEVICE]\n\ +\n\ +Probe device information for a given path (or device, if the -d option is given).\n\ +\n\ + -d, --device given argument is a system device, not a path\n\ + -m, --device-map=FILE use FILE as the device map [default=%s]\n\ + -t, --target=(fs|fs_uuid|fs_label|drive|device|partmap|abstraction)\n\ + print filesystem module, GRUB drive, system device, partition map module or abstraction module [default=fs]\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print verbose messages\n\ +\n\ +Report bugs to <%s>.\n\ +", program_name, + DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT); + + exit (status); +} + +int +main (int argc, char *argv[]) +{ + char *dev_map = 0; + char *argument; + + set_program_name (argv[0]); + + grub_util_init_nls (); + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "dm:t:hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'd': + argument_is_device = 1; + break; + + case 'm': + if (dev_map) + free (dev_map); + + dev_map = xstrdup (optarg); + break; + + case 't': + if (!strcmp (optarg, "fs")) + print = PRINT_FS; + else if (!strcmp (optarg, "fs_uuid")) + print = PRINT_FS_UUID; + else if (!strcmp (optarg, "fs_label")) + print = PRINT_FS_LABEL; + else if (!strcmp (optarg, "drive")) + print = PRINT_DRIVE; + else if (!strcmp (optarg, "device")) + print = PRINT_DEVICE; + else if (!strcmp (optarg, "partmap")) + print = PRINT_PARTMAP; + else if (!strcmp (optarg, "abstraction")) + print = PRINT_ABSTRACTION; + else + usage (1); + break; + + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + if (verbosity > 1) + grub_env_set ("debug", "all"); + + /* Obtain ARGUMENT. */ + if (optind >= argc) + { + fprintf (stderr, "No path or device is specified.\n"); + usage (1); + } + + if (optind + 1 != argc) + { + fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]); + usage (1); + } + + argument = argv[optind]; + + /* Initialize the emulated biosdisk driver. */ + grub_util_biosdisk_init (dev_map ? : DEFAULT_DEVICE_MAP); + + /* Initialize all modules. */ + grub_init_all (); + + grub_lvm_fini (); + grub_mdraid09_fini (); + grub_mdraid1x_fini (); + grub_raid_fini (); + grub_raid_init (); + grub_mdraid09_init (); + grub_mdraid1x_init (); + grub_lvm_init (); + + /* Do it. */ + if (argument_is_device) + probe (NULL, argument); + else + probe (argument, NULL); + + /* Free resources. */ + grub_fini_all (); + grub_util_biosdisk_fini (); + + free (dev_map); + + return 0; +} diff --git a/util/grub-reboot.in b/util/grub-reboot.in new file mode 100644 index 0000000..929cf52 --- /dev/null +++ b/util/grub-reboot.in @@ -0,0 +1,135 @@ +#! /bin/sh +# +# Set a default boot entry for GRUB, for the next boot only. +# Copyright (C) 2004,2009 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +# Initialize some variables. +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ + +self=`basename $0` + +grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` +rootdir= +bootdir= +grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +argument () { + opt=$1 + shift + + if test $# -eq 0; then + echo "$0: option requires an argument -- '$opt'" 1>&2 + exit 1 + fi + echo $1 +} + +# Check the arguments. +while test $# -gt 0 +do + option=$1 + shift + + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" + exit 0 ;; + +# Accept for compatibility + --root-directory) + rootdir=`argument $option "$@"`; shift ;; + --root-directory=*) + rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; + + --boot-directory) + bootdir=`argument $option "$@"`; shift;; + --boot-directory=*) + bootdir=`echo "$option" | sed 's/--boot-directory=//'` ;; + + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + *) + if test "x$entry" != x; then + echo "More than one entry?" 1>&2 + usage + exit 1 + fi + entry="${option}" ;; + esac +done + +if test "x$entry" = x; then + echo "entry not specified." 1>&2 + usage + exit 1 +fi + +if [ -z "$bootdir" ]; then + # Default bootdir if bootdir not initialized. + bootdir=/@bootdirname@ + + if [ -n "$rootdir" ] ; then + # Initialize bootdir if rootdir was initialized. + bootdir=${rootdir}/@bootdirname@ + fi +fi + +grubdir=`echo "${bootdir}/@grubdirname@" | sed 's,//*,/,g'` + +prev_saved_entry=`$grub_editenv ${grubdir}/grubenv list | sed -n 's/^saved_entry=//p'` +if [ "$prev_saved_entry" ]; then + $grub_editenv ${grubdir}/grubenv set prev_saved_entry="$prev_saved_entry" +else + # We need some non-empty value for prev_saved_entry so that GRUB will + # recognise that grub-reboot has been used and restore the previous + # saved entry. "0" is the same as an empty value, i.e. the first menu + # entry. + $grub_editenv ${grubdir}/grubenv set prev_saved_entry=0 +fi +$grub_editenv ${grubdir}/grubenv set saved_entry="$entry" + +# Bye. +exit 0 diff --git a/util/grub-script-check.c b/util/grub-script-check.c new file mode 100644 index 0000000..2d1b31c --- /dev/null +++ b/util/grub-script-check.c @@ -0,0 +1,201 @@ +/* grub-script-check.c - check grub script file for syntax errors */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _GNU_SOURCE 1 + +#include +#include +#include +#include +#include +#include + +#include "progname.h" + +static struct option options[] = + { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, + "Try ``%s --help'' for more information.\n", program_name); + else + printf ("\ +Usage: %s [PATH]\n\ +\n\ +Checks GRUB script configuration file for syntax errors.\n\ +\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print the script as it is being processed\n\ +\n\ +Report bugs to <%s>.\n\ +", program_name, + PACKAGE_BUGREPORT); + exit (status); +} + +int +main (int argc, char *argv[]) +{ + char *argument; + char *input; + int lineno = 0; + FILE *file = 0; + int verbose = 0; + int found_input = 0; + struct grub_script *script = NULL; + + auto grub_err_t get_config_line (char **line, int cont); + grub_err_t get_config_line (char **line, int cont __attribute__ ((unused))) + { + int i; + char *cmdline = 0; + size_t len = 0; + ssize_t read; + + read = getline(&cmdline, &len, (file ?: stdin)); + if (read == -1) + { + *line = 0; + grub_errno = GRUB_ERR_READ_ERROR; + + if (cmdline) + free (cmdline); + return grub_errno; + } + + if (verbose) + grub_printf("%s", cmdline); + + for (i = 0; cmdline[i] != '\0'; i++) + { + /* Replace tabs and carriage returns with spaces. */ + if (cmdline[i] == '\t' || cmdline[i] == '\r') + cmdline[i] = ' '; + + /* Replace '\n' with '\0'. */ + if (cmdline[i] == '\n') + cmdline[i] = '\0'; + } + + lineno++; + *line = grub_strdup (cmdline); + + free (cmdline); + return 0; + } + + set_program_name (argv[0]); + grub_util_init_nls (); + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "hvV", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbose = 1; + break; + + default: + usage (1); + break; + } + } + + /* Obtain ARGUMENT. */ + if (optind >= argc) + { + file = 0; /* read from stdin */ + } + else if (optind + 1 != argc) + { + fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]); + usage (1); + } + else + { + argument = argv[optind]; + file = fopen (argument, "r"); + if (! file) + { + fprintf (stderr, "%s: %s: %s\n", program_name, argument, strerror(errno)); + usage (1); + } + } + + do + { + input = 0; + get_config_line(&input, 0); + if (! input) + break; + found_input = 1; + + script = grub_script_parse (input, get_config_line); + if (script) + { + grub_script_execute (script); + grub_script_free (script); + } + + grub_free (input); + } while (script != 0); + + if (file) fclose (file); + + if (found_input && script == 0) + { + fprintf (stderr, "error: line no: %u\n", lineno); + return 1; + } + + return 0; +} diff --git a/util/grub-set-default.in b/util/grub-set-default.in new file mode 100644 index 0000000..b09727d --- /dev/null +++ b/util/grub-set-default.in @@ -0,0 +1,126 @@ +#! /bin/sh +# +# Set a default boot entry for GRUB. +# Copyright (C) 2004,2009 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +# Initialize some variables. +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ + +self=`basename $0` + +grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` +rootdir= +bootdir= +grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +argument () { + opt=$1 + shift + + if test $# -eq 0; then + echo "$0: option requires an argument -- '$opt'" 1>&2 + exit 1 + fi + echo $1 +} + +# Check the arguments. +while test $# -gt 0 +do + option=$1 + shift + + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" + exit 0 ;; + +# Accept for compatibility + --root-directory) + rootdir=`argument $option "$@"`; shift ;; + --root-directory=*) + rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; + + --boot-directory) + bootdir=`argument $option "$@"`; shift;; + --boot-directory=*) + bootdir=`echo "$option" | sed 's/--boot-directory=//'` ;; + + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + *) + if test "x$entry" != x; then + echo "More than one entry?" 1>&2 + usage + exit 1 + fi + entry="${option}" ;; + esac +done + +if test "x$entry" = x; then + echo "entry not specified." 1>&2 + usage + exit 1 +fi + +if [ -z "$bootdir" ]; then + # Default bootdir if bootdir not initialized. + bootdir=/@bootdirname@ + + if [ -n "$rootdir" ] ; then + # Initialize bootdir if rootdir was initialized. + bootdir=${rootdir}/@bootdirname@ + fi +fi + +grubdir=`echo "${bootdir}/@grubdirname@" | sed 's,//*,/,g'` + +$grub_editenv ${grubdir}/grubenv unset prev_saved_entry +$grub_editenv ${grubdir}/grubenv set saved_entry="$entry" + +# Bye. +exit 0 diff --git a/util/grub-setup.c b/util/grub-setup.c new file mode 100644 index 0000000..7d47fa6 --- /dev/null +++ b/util/grub-setup.c @@ -0,0 +1,1017 @@ +/* grub-setup.c - make GRUB usable */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 +#ifdef GRUB_MACHINE_IEEE1275 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "progname.h" +#include +#include + +#define _GNU_SOURCE 1 +#include + +/* On SPARC this program fills in various fields inside of the 'boot' and 'core' + * image files. + * + * The 'boot' image needs to know the OBP path name of the root + * device. It also needs to know the initial block number of + * 'core' (which is 'diskboot' concatenated with 'kernel' and + * all the modules, this is created by grub-mkimage). This resulting + * 'boot' image is 512 bytes in size and is placed in the second block + * of a partition. + * + * The initial 'diskboot' block acts as a loader for the actual GRUB + * kernel. It contains the loading code and then a block list. + * + * The block list of 'core' starts at the end of the 'diskboot' image + * and works it's way backwards towards the end of the code of 'diskboot'. + * + * We patch up the images with the necessary values and write out the + * result. + */ + +#define DEFAULT_BOOT_FILE "boot.img" +#define DEFAULT_CORE_FILE "core.img" + +#ifdef GRUB_MACHINE_SPARC64 +#define grub_target_to_host16(x) grub_be_to_cpu16(x) +#define grub_target_to_host32(x) grub_be_to_cpu32(x) +#define grub_target_to_host64(x) grub_be_to_cpu64(x) +#define grub_host_to_target16(x) grub_cpu_to_be16(x) +#define grub_host_to_target32(x) grub_cpu_to_be32(x) +#define grub_host_to_target64(x) grub_cpu_to_be64(x) +#elif defined (GRUB_MACHINE_PCBIOS) +#define grub_target_to_host16(x) grub_le_to_cpu16(x) +#define grub_target_to_host32(x) grub_le_to_cpu32(x) +#define grub_target_to_host64(x) grub_le_to_cpu64(x) +#define grub_host_to_target16(x) grub_cpu_to_le16(x) +#define grub_host_to_target32(x) grub_cpu_to_le32(x) +#define grub_host_to_target64(x) grub_cpu_to_le64(x) +#else +#error Complete this +#endif + +static void +write_rootdev (char *core_img, grub_device_t root_dev, + char *boot_img, grub_uint64_t first_sector) +{ +#ifdef GRUB_MACHINE_PCBIOS + { + grub_int32_t *install_dos_part, *install_bsd_part; + grub_int32_t dos_part, bsd_part; + grub_uint8_t *boot_drive; + grub_disk_addr_t *kernel_sector; + boot_drive = (grub_uint8_t *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE); + kernel_sector = (grub_disk_addr_t *) (boot_img + + GRUB_BOOT_MACHINE_KERNEL_SECTOR); + + + install_dos_part = (grub_int32_t *) (core_img + GRUB_DISK_SECTOR_SIZE + + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART); + install_bsd_part = (grub_int32_t *) (core_img + GRUB_DISK_SECTOR_SIZE + + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART); + + /* If we hardcoded drive as part of prefix, we don't want to + override the current setting. */ + if (*install_dos_part != -2) + { + /* Embed information about the installed location. */ + if (root_dev->disk->partition) + { + if (root_dev->disk->partition->parent) + { + if (root_dev->disk->partition->parent->parent) + grub_util_error ("Installing on doubly nested partitions is " + "not supported"); + dos_part = root_dev->disk->partition->parent->number; + bsd_part = root_dev->disk->partition->number; + } + else + { + dos_part = root_dev->disk->partition->number; + bsd_part = -1; + } + } + else + dos_part = bsd_part = -1; + } + else + { + dos_part = grub_le_to_cpu32 (*install_dos_part); + bsd_part = grub_le_to_cpu32 (*install_bsd_part); + } + + grub_util_info ("dos partition is %d, bsd partition is %d", + dos_part, bsd_part); + + *install_dos_part = grub_cpu_to_le32 (dos_part); + *install_bsd_part = grub_cpu_to_le32 (bsd_part); + + /* FIXME: can this be skipped? */ + *boot_drive = 0xFF; + + *kernel_sector = grub_cpu_to_le64 (first_sector); + } +#endif +#ifdef GRUB_MACHINE_IEEE1275 + { + grub_disk_addr_t *kernel_byte; + kernel_byte = (grub_disk_addr_t *) (boot_img + + GRUB_BOOT_AOUT_HEADER_SIZE + + GRUB_BOOT_MACHINE_KERNEL_BYTE); + *kernel_byte = grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS); + } +#endif +} + +#ifdef GRUB_MACHINE_IEEE1275 +#define BOOT_SECTOR 1 +#else +#define BOOT_SECTOR 0 +#endif + +static void +setup (const char *dir, + const char *boot_file, const char *core_file, + const char *root, const char *dest, int must_embed, int force, + int fs_probe, int allow_floppy) +{ + char *boot_path, *core_path, *core_path_dev, *core_path_dev_full; + char *boot_img, *core_img; + size_t boot_size, core_size; + grub_uint16_t core_sectors; + grub_device_t root_dev, dest_dev; + struct grub_boot_blocklist *first_block, *block; + char *tmp_img; + int i; + grub_disk_addr_t first_sector; +#ifdef GRUB_MACHINE_PCBIOS + grub_uint16_t current_segment + = GRUB_BOOT_MACHINE_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4); +#endif + grub_uint16_t last_length = GRUB_DISK_SECTOR_SIZE; + grub_file_t file; + FILE *fp; + + auto void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, + unsigned offset, + unsigned length); + auto void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, + unsigned offset, + unsigned length); + + void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, + unsigned offset, + unsigned length) + { + grub_util_info ("the first sector is <%llu,%u,%u>", + sector, offset, length); + + if (offset != 0 || length != GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("the first sector of the core file is not sector-aligned")); + + first_sector = sector; + } + + void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, + unsigned offset, + unsigned length) + { + struct grub_boot_blocklist *prev = block + 1; + + grub_util_info ("saving <%llu,%u,%u>", sector, offset, length); + + if (offset != 0 || last_length != GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("non-sector-aligned data is found in the core file")); + + if (block != first_block + && (grub_target_to_host64 (prev->start) + + grub_target_to_host16 (prev->len)) == sector) + prev->len = grub_host_to_target16 (grub_target_to_host16 (prev->len) + 1); + else + { + block->start = grub_host_to_target64 (sector); + block->len = grub_host_to_target16 (1); +#ifdef GRUB_MACHINE_PCBIOS + block->segment = grub_host_to_target16 (current_segment); +#endif + + block--; + if (block->len) + grub_util_error (_("the sectors of the core file are too fragmented")); + } + + last_length = length; +#ifdef GRUB_MACHINE_PCBIOS + current_segment += GRUB_DISK_SECTOR_SIZE >> 4; +#endif + } + + /* Read the boot image by the OS service. */ + boot_path = grub_util_get_path (dir, boot_file); + boot_size = grub_util_get_image_size (boot_path); + if (boot_size != GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("the size of `%s' is not %u"), + boot_path, GRUB_DISK_SECTOR_SIZE); + boot_img = grub_util_read_image (boot_path); + free (boot_path); + + core_path = grub_util_get_path (dir, core_file); + core_size = grub_util_get_image_size (core_path); + core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) + >> GRUB_DISK_SECTOR_BITS); + if (core_size < GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("the size of `%s' is too small"), core_path); +#ifdef GRUB_MACHINE_PCBIOS + if (core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("the size of `%s' is too large"), core_path); +#endif + + core_img = grub_util_read_image (core_path); + + /* Have FIRST_BLOCK to point to the first blocklist. */ + first_block = (struct grub_boot_blocklist *) (core_img + + GRUB_DISK_SECTOR_SIZE + - sizeof (*block)); + grub_util_info ("root is `%s', dest is `%s'", root, dest); + + /* Open the root device and the destination device. */ + grub_util_info ("Opening root"); + root_dev = grub_device_open (root); + if (! root_dev) + grub_util_error ("%s", grub_errmsg); + + grub_util_info ("Opening dest"); + dest_dev = grub_device_open (dest); + if (! dest_dev) + grub_util_error ("%s", grub_errmsg); + + grub_util_info ("setting the root device to `%s'", root); + if (grub_env_set ("root", root) != GRUB_ERR_NONE) + grub_util_error ("%s", grub_errmsg); + +#ifdef GRUB_MACHINE_PCBIOS + /* Read the original sector from the disk. */ + tmp_img = xmalloc (GRUB_DISK_SECTOR_SIZE); + if (grub_disk_read (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img)) + grub_util_error ("%s", grub_errmsg); +#endif + +#ifdef GRUB_MACHINE_PCBIOS + { + grub_uint16_t *boot_drive_check; + boot_drive_check = (grub_uint16_t *) (boot_img + + GRUB_BOOT_MACHINE_DRIVE_CHECK); + /* Copy the possible DOS BPB. */ + memcpy (boot_img + GRUB_BOOT_MACHINE_BPB_START, + tmp_img + GRUB_BOOT_MACHINE_BPB_START, + GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START); + + /* If DEST_DRIVE is a hard disk, enable the workaround, which is + for buggy BIOSes which don't pass boot drive correctly. Instead, + they pass 0x00 or 0x01 even when booted from 0x80. */ + if (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk)) + /* Replace the jmp (2 bytes) with double nop's. */ + *boot_drive_check = 0x9090; + } +#endif + +#ifdef GRUB_MACHINE_PCBIOS + { + grub_partition_map_t dest_partmap = NULL; + grub_partition_t container = dest_dev->disk->partition; + int multiple_partmaps = 0; + grub_err_t err; + grub_disk_addr_t *sectors; + int i; + grub_fs_t fs; + unsigned int nsec; + + /* Unlike root_dev, with dest_dev we're interested in the partition map even + if dest_dev itself is a whole disk. */ + auto int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk, + const grub_partition_t p); + int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ ((unused)), + const grub_partition_t p) + { + if (p->parent != container) + return 0; + /* NetBSD and OpenBSD subpartitions have metadata inside a partition, + so they are safe to ignore. + */ + if (grub_strcmp (p->partmap->name, "netbsd") == 0 + || grub_strcmp (p->partmap->name, "openbsd") == 0) + return 0; + if (dest_partmap == NULL) + { + dest_partmap = p->partmap; + return 0; + } + if (dest_partmap == p->partmap) + return 0; + multiple_partmaps = 1; + return 1; + } + + grub_partition_iterate (dest_dev->disk, identify_partmap); + + if (container && grub_strcmp (container->partmap->name, "msdos") == 0 + && dest_partmap + && (container->msdostype == GRUB_PC_PARTITION_TYPE_NETBSD + || container->msdostype == GRUB_PC_PARTITION_TYPE_OPENBSD)) + { + grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. This is not supported yet.")); + goto unable_to_embed; + } + + fs = grub_fs_probe (dest_dev); + if (!fs) + grub_errno = GRUB_ERR_NONE; + +#ifdef GRUB_MACHINE_PCBIOS + if (fs_probe) + { + if (!fs && !dest_partmap) + grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"), + dest_dev->disk->name); + if (fs && !fs->reserved_first_sector) + grub_util_error (_("%s appears to contain a %s filesystem which isn't known to " + "reserve space for DOS-style boot. Installing GRUB there could " + "result in FILESYSTEM DESTRUCTION if valuable data is overwritten " + "by grub-setup (--skip-fs-probe disables this " + "check, use at your own risk)"), dest_dev->disk->name, fs->name); + + if (dest_partmap && strcmp (dest_partmap->name, "msdos") != 0 + && strcmp (dest_partmap->name, "gpt") != 0 + && strcmp (dest_partmap->name, "bsd") != 0 + && strcmp (dest_partmap->name, "netbsd") != 0 + && strcmp (dest_partmap->name, "openbsd") != 0 + && strcmp (dest_partmap->name, "sunpc") != 0) + grub_util_error (_("%s appears to contain a %s partition map which isn't known to " + "reserve space for DOS-style boot. Installing GRUB there could " + "result in FILESYSTEM DESTRUCTION if valuable data is overwritten " + "by grub-setup (--skip-fs-probe disables this " + "check, use at your own risk)"), dest_dev->disk->name, dest_partmap->name); + } +#endif + + /* Copy the partition table. */ + if (dest_partmap || + (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk))) + memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, + tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, + GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC); + + free (tmp_img); + + if (! dest_partmap) + { + grub_util_warn (_("Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea.")); + goto unable_to_embed; + } + if (multiple_partmaps || fs) + { + grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. This is not supported yet.")); + goto unable_to_embed; + } + + if (!dest_partmap->embed) + { + grub_util_warn ("Partition style '%s' doesn't support embeding", + dest_partmap->name); + goto unable_to_embed; + } + + nsec = core_sectors; + err = dest_partmap->embed (dest_dev->disk, &nsec, + GRUB_EMBED_PCBIOS, §ors); + if (nsec > 2 * core_sectors) + nsec = 2 * core_sectors; + + if (err) + { + grub_util_warn ("%s", grub_errmsg); + grub_errno = GRUB_ERR_NONE; + goto unable_to_embed; + } + + /* Clean out the blocklists. */ + block = first_block; + while (block->len) + { + grub_memset (block, 0, sizeof (block)); + + block--; + + if ((char *) block <= core_img) + grub_util_error ("No terminator in the core image"); + } + + save_first_sector (sectors[0] + grub_partition_get_start (container), + 0, GRUB_DISK_SECTOR_SIZE); + + block = first_block; + for (i = 1; i < nsec; i++) + save_blocklists (sectors[i] + grub_partition_get_start (container), + 0, GRUB_DISK_SECTOR_SIZE); + + write_rootdev (core_img, root_dev, boot_img, first_sector); + + core_img = realloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE); + first_block = (struct grub_boot_blocklist *) (core_img + + GRUB_DISK_SECTOR_SIZE + - sizeof (*block)); + + *(grub_uint32_t *) (core_img + GRUB_DISK_SECTOR_SIZE + + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY) + = grub_host_to_target32 (nsec * GRUB_DISK_SECTOR_SIZE - core_size); + + grub_reed_solomon_add_redundancy (core_img + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART + GRUB_DISK_SECTOR_SIZE, + core_size - GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_PART - GRUB_DISK_SECTOR_SIZE, + nsec * GRUB_DISK_SECTOR_SIZE + - core_size); + + /* Make sure that the second blocklist is a terminator. */ + block = first_block - 1; + block->start = 0; + block->len = 0; + block->segment = 0; + + /* Write the core image onto the disk. */ + for (i = 0; i < nsec; i++) + grub_disk_write (dest_dev->disk, sectors[i], 0, + GRUB_DISK_SECTOR_SIZE, + core_img + i * GRUB_DISK_SECTOR_SIZE); + + grub_free (sectors); + + goto finish; + } +#endif + +unable_to_embed: + + if (must_embed) + grub_util_error (_("embedding is not possible, but this is required when " + "the root device is on a RAID array or LVM volume")); + +#ifdef GRUB_MACHINE_PCBIOS + if (dest_dev->disk->id != root_dev->disk->id) + grub_util_error (_("embedding is not possible, but this is required for " + "cross-disk install")); +#endif + + grub_util_warn (_("Embedding is not possible. GRUB can only be installed in this " + "setup by using blocklists. However, blocklists are UNRELIABLE and " + "their use is discouraged.")); + if (! force) + grub_util_error (_("will not proceed with blocklists")); + + /* The core image must be put on a filesystem unfortunately. */ + grub_util_info ("will leave the core image on the filesystem"); + + /* Make sure that GRUB reads the identical image as the OS. */ + tmp_img = xmalloc (core_size); + core_path_dev_full = grub_util_get_path (dir, core_file); + core_path_dev = grub_make_system_path_relative_to_its_root (core_path_dev_full); + free (core_path_dev_full); + + grub_util_biosdisk_flush (root_dev->disk); + +#define MAX_TRIES 5 + + for (i = 0; i < MAX_TRIES; i++) + { + grub_util_info ((i == 0) ? _("attempting to read the core image `%s' from GRUB") + : _("attempting to read the core image `%s' from GRUB again"), + core_path_dev); + + grub_disk_cache_invalidate_all (); + + grub_file_filter_disable_compression (); + file = grub_file_open (core_path_dev); + if (file) + { + if (grub_file_size (file) != core_size) + grub_util_info ("succeeded in opening the core image but the size is different (%d != %d)", + (int) grub_file_size (file), (int) core_size); + else if (grub_file_read (file, tmp_img, core_size) + != (grub_ssize_t) core_size) + grub_util_info ("succeeded in opening the core image but cannot read %d bytes", + (int) core_size); + else if (memcmp (core_img, tmp_img, core_size) != 0) + { +#if 0 + FILE *dump; + FILE *dump2; + + dump = fopen ("dump.img", "wb"); + if (dump) + { + fwrite (tmp_img, 1, core_size, dump); + fclose (dump); + } + + dump2 = fopen ("dump2.img", "wb"); + if (dump2) + { + fwrite (core_img, 1, core_size, dump2); + fclose (dump2); + } + +#endif + grub_util_info ("succeeded in opening the core image but the data is different"); + } + else + { + grub_file_close (file); + break; + } + + grub_file_close (file); + } + else + grub_util_info ("couldn't open the core image"); + + if (grub_errno) + grub_util_info ("error message = %s", grub_errmsg); + + grub_errno = GRUB_ERR_NONE; + grub_util_biosdisk_flush (root_dev->disk); + sleep (1); + } + + if (i == MAX_TRIES) + grub_util_error (_("cannot read `%s' correctly"), core_path_dev); + + /* Clean out the blocklists. */ + block = first_block; + while (block->len) + { + block->start = 0; + block->len = 0; +#ifdef GRUB_MACHINE_PCBIOS + block->segment = 0; +#endif + + block--; + + if ((char *) block <= core_img) + grub_util_error (_("no terminator in the core image")); + } + + /* Now read the core image to determine where the sectors are. */ + grub_file_filter_disable_compression (); + file = grub_file_open (core_path_dev); + if (! file) + grub_util_error ("%s", grub_errmsg); + + file->read_hook = save_first_sector; + if (grub_file_read (file, tmp_img, GRUB_DISK_SECTOR_SIZE) + != GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("failed to read the first sector of the core image")); + + block = first_block; + file->read_hook = save_blocklists; + if (grub_file_read (file, tmp_img, core_size - GRUB_DISK_SECTOR_SIZE) + != (grub_ssize_t) core_size - GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("failed to read the rest sectors of the core image")); + +#ifdef GRUB_MACHINE_IEEE1275 + { + char *boot_devpath; + boot_devpath = (char *) (boot_img + + GRUB_BOOT_AOUT_HEADER_SIZE + + GRUB_BOOT_MACHINE_BOOT_DEVPATH); + if (file->device->disk->id != dest_dev->disk->id) + { + const char *dest_ofpath; + dest_ofpath + = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (file->device->disk)); + grub_util_info ("dest_ofpath is `%s'", dest_ofpath); + strncpy (boot_devpath, dest_ofpath, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END + - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1); + boot_devpath[GRUB_BOOT_MACHINE_BOOT_DEVPATH_END + - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1] = 0; + } + else + { + grub_util_info ("non cross-disk install"); + memset (boot_devpath, 0, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END + - GRUB_BOOT_MACHINE_BOOT_DEVPATH); + } + grub_util_info ("boot device path %s", boot_devpath); + } +#endif + + grub_file_close (file); + + free (core_path_dev); + free (tmp_img); + + write_rootdev (core_img, root_dev, boot_img, first_sector); + + /* Write the first two sectors of the core image onto the disk. */ + grub_util_info ("opening the core image `%s'", core_path); + fp = fopen (core_path, "r+b"); + if (! fp) + grub_util_error (_("cannot open `%s'"), core_path); + + grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE * 2, fp); + fclose (fp); + + finish: + + /* Write the boot image onto the disk. */ + if (grub_disk_write (dest_dev->disk, BOOT_SECTOR, + 0, GRUB_DISK_SECTOR_SIZE, boot_img)) + grub_util_error ("%s", grub_errmsg); + + + grub_util_biosdisk_flush (root_dev->disk); + grub_util_biosdisk_flush (dest_dev->disk); + + free (core_path); + free (core_img); + free (boot_img); + grub_device_close (dest_dev); + grub_device_close (root_dev); +} + +static struct argp_option options[] = { + {"boot-image", 'b', N_("FILE"), 0, + N_("Use FILE as the boot image [default=%s]"), 0}, + {"core-image", 'c', N_("FILE"), 0, + N_("Use FILE as the core image [default=%s]"), 0}, + {"directory", 'd', N_("DIR"), 0, + N_("Use GRUB files in the directory DIR [default=%s]"), 0}, + {"device-map", 'm', N_("FILE"), 0, + N_("Use FILE as the device map [default=%s]"), 0}, + {"root-device", 'r', N_("DEV"), 0, + N_("Use DEV as the root device [default=guessed]"), 0}, + {"force", 'f', 0, 0, + N_("Install even if problems are detected"), 0}, + {"skip-fs-probe",'s',0, 0, + N_("Do not probe for filesystems in DEVICE"), 0}, + {"verbose", 'v', 0, 0, + N_("Print verbose messages."), 0}, + {"allow-floppy", 'a', 0, 0, + N_("Make the drive also bootable as floppy (default for fdX devices). May break on some BIOSes."), 0}, + + { 0, 0, 0, 0, 0, 0 } +}; + +static char * +help_filter (int key, const char *text, void *input __attribute__ ((unused))) +{ + switch (key) + { + case 'b': + return xasprintf (text, DEFAULT_BOOT_FILE); + + case 'c': + return xasprintf (text, DEFAULT_CORE_FILE); + + case 'd': + return xasprintf (text, DEFAULT_DIRECTORY); + + case 'm': + return xasprintf (text, DEFAULT_DEVICE_MAP); + + default: + return (char *) text; + } +} + +struct arguments +{ + char *boot_file; + char *core_file; + char *dir; + char *dev_map; + char *root_dev; + int force; + int fs_probe; + int allow_floppy; + char *device; +}; + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state) +{ + fprintf (stream, "%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); +} +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Set the bug report address */ +const char *argp_program_bug_address = "<"PACKAGE_BUGREPORT">"; + +static error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + /* Get the input argument from argp_parse, which we + know is a pointer to our arguments structure. */ + struct arguments *arguments = state->input; + + char *p; + + switch (key) + { + case 'a': + arguments->allow_floppy = 1; + break; + + case 'b': + if (arguments->boot_file) + free (arguments->boot_file); + + arguments->boot_file = xstrdup (arg); + break; + + case 'c': + if (arguments->core_file) + free (arguments->core_file); + + arguments->core_file = xstrdup (arg); + break; + + case 'd': + if (arguments->dir) + free (arguments->dir); + + arguments->dir = xstrdup (arg); + break; + + case 'm': + if (arguments->dev_map) + free (arguments->dev_map); + + arguments->dev_map = xstrdup (arg); + break; + + case 'r': + if (arguments->root_dev) + free (arguments->root_dev); + + arguments->root_dev = xstrdup (arg); + break; + + case 'f': + arguments->force = 1; + break; + + case 's': + arguments->fs_probe = 0; + break; + + case 'v': + verbosity++; + break; + + case ARGP_KEY_ARG: + if (state->arg_num == 0) + arguments->device = xstrdup(arg); + else + { + /* Too many arguments. */ + fprintf (stderr, _("Unknown extra argument `%s'.\n"), arg); + argp_usage (state); + } + break; + + case ARGP_KEY_NO_ARGS: + fprintf (stderr, "%s", _("No device is specified.\n")); + argp_usage (state); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +static struct argp argp = { + options, argp_parser, N_("DEVICE"), + "\n"N_("\ +Set up images to boot from DEVICE.\n\ +\n\ +You should not normally run this program directly. Use grub-install instead.") +"\v"N_("\ +DEVICE must be an OS device (e.g. /dev/sda)."), + NULL, help_filter, NULL +}; + +static char * +get_device_name (char *dev) +{ + size_t len = strlen (dev); + + if (dev[0] != '(' || dev[len - 1] != ')') + return 0; + + dev[len - 1] = '\0'; + return dev + 1; +} + +int +main (int argc, char *argv[]) +{ + char *root_dev = NULL; + char *dest_dev = NULL; + int must_embed = 0; + struct arguments arguments; + + set_program_name (argv[0]); + + grub_util_init_nls (); + + /* Default option values. */ + memset (&arguments, 0, sizeof (struct arguments)); + arguments.fs_probe = 1; + + /* Parse our arguments */ + if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + +#ifdef GRUB_MACHINE_IEEE1275 + arguments.force = 1; +#endif + + if (verbosity > 1) + grub_env_set ("debug", "all"); + + /* Initialize the emulated biosdisk driver. */ + grub_util_biosdisk_init (arguments.dev_map ? : DEFAULT_DEVICE_MAP); + + /* Initialize all modules. */ + grub_init_all (); + + grub_lvm_fini (); + grub_mdraid09_fini (); + grub_mdraid1x_fini (); + grub_raid_fini (); + grub_raid_init (); + grub_mdraid09_init (); + grub_mdraid1x_init (); + grub_lvm_init (); + + dest_dev = get_device_name (arguments.device); + if (! dest_dev) + { + /* Possibly, the user specified an OS device file. */ + dest_dev = grub_util_get_grub_dev (arguments.device); + if (! dest_dev) + { + char *program = xstrdup(program_name); + fprintf (stderr, _("Invalid device `%s'.\n"), arguments.device); + argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program); + free(program); + exit(1); + } + grub_util_info ("transformed OS device `%s' into GRUB device `%s'", + arguments.device, dest_dev); + } + else + { + /* For simplicity. */ + dest_dev = xstrdup (dest_dev); + grub_util_info ("Using `%s' as GRUB device", dest_dev); + } + + if (arguments.root_dev) + { + root_dev = get_device_name (arguments.root_dev); + + if (! root_dev) + grub_util_error (_("invalid root device `%s'"), arguments.root_dev); + + root_dev = xstrdup (root_dev); + } + else + { + char *root_device = + grub_guess_root_device (arguments.dir ? : DEFAULT_DIRECTORY); + + root_dev = grub_util_get_grub_dev (root_device); + if (! root_dev) + { + grub_util_info ("guessing the root device failed, because of `%s'", + grub_errmsg); + grub_util_error (_("cannot guess the root device. Specify the option " + "`--root-device'")); + } + grub_util_info ("guessed root device `%s' and root_dev `%s' from " + "dir `%s'", root_device, root_dev, + arguments.dir ? : DEFAULT_DIRECTORY); + } + +#ifdef __linux__ + if (grub_util_lvm_isvolume (root_dev)) + must_embed = 1; + + if (root_dev[0] == 'm' && root_dev[1] == 'd' + && ((root_dev[2] >= '0' && root_dev[2] <= '9') || root_dev[2] == '/')) + { + /* FIXME: we can avoid this on RAID1. */ + must_embed = 1; + } + + if (dest_dev[0] == 'm' && dest_dev[1] == 'd' + && ((dest_dev[2] >= '0' && dest_dev[2] <= '9') || dest_dev[2] == '/')) + { + char **devicelist; + int i; + + if (arguments.device[0] == '/') + devicelist = grub_util_raid_getmembers (arguments.device); + else + { + char *devname; + devname = xasprintf ("/dev/%s", dest_dev); + devicelist = grub_util_raid_getmembers (dest_dev); + free (devname); + } + + for (i = 0; devicelist[i]; i++) + { + setup (arguments.dir ? : DEFAULT_DIRECTORY, + arguments.boot_file ? : DEFAULT_BOOT_FILE, + arguments.core_file ? : DEFAULT_CORE_FILE, + root_dev, grub_util_get_grub_dev (devicelist[i]), 1, + arguments.force, arguments.fs_probe, + arguments.allow_floppy); + } + } + else +#endif + /* Do the real work. */ + setup (arguments.dir ? : DEFAULT_DIRECTORY, + arguments.boot_file ? : DEFAULT_BOOT_FILE, + arguments.core_file ? : DEFAULT_CORE_FILE, + root_dev, dest_dev, must_embed, arguments.force, + arguments.fs_probe, arguments.allow_floppy); + + /* Free resources. */ + grub_fini_all (); + grub_util_biosdisk_fini (); + + free (arguments.boot_file); + free (arguments.core_file); + free (arguments.dir); + free (arguments.root_dev); + free (arguments.dev_map); + free (arguments.device); + free (root_dev); + free (dest_dev); + + return 0; +} diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in new file mode 100644 index 0000000..9da1511 --- /dev/null +++ b/util/grub.d/00_header.in @@ -0,0 +1,271 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +locale_dir=`echo ${GRUB_PREFIX}/locale | sed ${transform}` +grub_lang=`echo $LANG | cut -d . -f 1` + +. ${libdir}/grub/grub-mkconfig_lib + +# Do this as early as possible, since other commands might depend on it. +# (e.g. the `loadfont' command might need lvm or raid modules) +for i in ${GRUB_PRELOAD_MODULES} ; do + echo "insmod $i" +done + +if [ "x${GRUB_DEFAULT}" = "x" ] ; then GRUB_DEFAULT=0 ; fi +if [ "x${GRUB_DEFAULT}" = "xsaved" ] ; then GRUB_DEFAULT='${saved_entry}' ; fi +if [ "x${GRUB_TIMEOUT}" = "x" ] ; then GRUB_TIMEOUT=5 ; fi +if [ "x${GRUB_GFXMODE}" = "x" ] ; then GRUB_GFXMODE=640x480 ; fi + +if [ "x${GRUB_DEFAULT_BUTTON}" = "x" ] ; then GRUB_DEFAULT_BUTTON="$GRUB_DEFAULT" ; fi +if [ "x${GRUB_DEFAULT_BUTTON}" = "xsaved" ] ; then GRUB_DEFAULT_BUTTON='${saved_entry}' ; fi +if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT" ; fi + +cat << EOF +if [ -s \$prefix/grubenv ]; then + load_env +fi +EOF +if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then + cat <&2 ; exit 1 + fi + + if [ "x${GRUB_SERIAL_COMMAND}" = "x" ] ; then + grub_warn "Requested serial terminal but GRUB_SERIAL_COMMAND is unspecified. Default parameters will be used." + GRUB_SERIAL_COMMAND=serial + fi + echo "${GRUB_SERIAL_COMMAND}" +fi + +if [ "x$gfxterm" = x1 ]; then + # Make the font accessible + prepare_grub_to_access_device `${grub_probe} --target=device "${GRUB_FONT_PATH}"` + + cat << EOF +if loadfont `make_system_path_relative_to_its_root "${GRUB_FONT_PATH}"` ; then + set gfxmode=${GRUB_GFXMODE} + load_video + insmod gfxterm +EOF + +# Gettext variables and module +if [ "x${LANG}" != "xC" ] && [ -d "${locale_dir}" ] ; then + prepare_grub_to_access_device $(${grub_probe} --target=device ${locale_dir}) | sed -e "s/^/ /" + cat << EOF + set locale_dir=(\$root)$(make_system_path_relative_to_its_root ${locale_dir}) + set lang=${grub_lang} + insmod gettext +EOF +fi + +cat <&2 + prepare_grub_to_access_device `${grub_probe} --target=device "$GRUB_THEME"` + cat << EOF +insmod gfxmenu +EOF + themedir="`dirname "$GRUB_THEME"`" + for x in "$themedir"/*.pf2 "$themedir"/f/*.pf2; do + if [ -f "$x" ]; then + cat << EOF +loadfont (\$root)`make_system_path_relative_to_its_root $x` +EOF + fi + done + if [ x"`echo "$themedir"/*.jpg`" != x"$themedir/*.jpg" ] || [ x"`echo "$themedir"/*.jpeg`" != x"$themedir/*.jpeg" ]; then + cat << EOF +insmod jpeg +EOF + fi + if [ x"`echo "$themedir"/*.png`" != x"$themedir/*.png" ]; then + cat << EOF +insmod png +EOF + fi + if [ x"`echo "$themedir"/*.tga`" != x"$themedir/*.tga" ]; then + cat << EOF +insmod tga +EOF + fi + + cat << EOF +set theme=(\$root)`make_system_path_relative_to_its_root $GRUB_THEME` +EOF + elif [ "x$GRUB_BACKGROUND" != x ] && [ -f "$GRUB_BACKGROUND" ] \ + && is_path_readable_by_grub "$GRUB_BACKGROUND"; then + echo "Found background: $GRUB_BACKGROUND" >&2 + case "$GRUB_BACKGROUND" in + *.png) reader=png ;; + *.tga) reader=tga ;; + *.jpg|*.jpeg) reader=jpeg ;; + *) echo "Unsupported image format" >&2; exit 1 ;; + esac + prepare_grub_to_access_device `${grub_probe} --target=device "$GRUB_BACKGROUND"` + cat << EOF +insmod $reader +background_image -m stretch `make_system_path_relative_to_its_root "$GRUB_BACKGROUND"` +EOF + fi +fi + +make_timeout () +{ + if [ "x${1}" != "x" ] ; then + if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then + verbose= + else + verbose=" --verbose" + fi + cat << EOF +if sleep$verbose --interruptible ${1} ; then + set timeout=${2} +fi +EOF + else + cat << EOF +set timeout=${2} +EOF + fi +} + +if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then + cat <. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +. ${libdir}/grub/grub-mkconfig_lib + +CLASS="--class gnu --class os" + +if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=GNU +else + OS="${GRUB_DISTRIBUTOR} GNU/Hurd" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}" +fi + +at_least_one=false +all_of_them=true + +# FIXME: add l4 here? +kernel= +for i in /boot/gnumach* ; do + if test -e $i ; then + basename=`basename $i` + dirname=`dirname $i` + rel_dirname=`make_system_path_relative_to_its_root $dirname` + echo "Found GNU Mach: $i" >&2 + kernels="${kernels} ${rel_dirname}/${basename}" + at_least_one=true + fi +done + +# FIXME: This works for ext2. For other filesystems we might need special-casing +case "${GRUB_FS}" in + *fs) hurd_fs="${GRUB_FS}" ;; + *) hurd_fs="${GRUB_FS}fs" ;; +esac + +for i in /hurd/${hurd_fs}.static /hurd/exec ; do + if test -e "$i" ; then + echo "Found Hurd module: $i" >&2 + at_least_one=true + else + all_of_them=false + fi +done + +if ${at_least_one} ; then : ; else + # no hurd here, aborting silently + exit 0 +fi + +if ${all_of_them} && test -e /lib/ld.so.1 ; then : ; else + echo "Some Hurd stuff found, but not enough to boot." >&2 + exit 1 +fi + +for kernel in ${kernels} +do + kernel_base="`basename "${kernel}"`" + KERNEL="using ${kernel_base}" + + cat << EOF +menuentry "${OS} ${KERNEL}" ${CLASS} { +EOF + prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" + message="$(gettext_printf "Loading GNU Mach ...")" + cat << EOF + echo '$message' + multiboot ${kernel} root=device:${GRUB_DEVICE#/dev/} +EOF + save_default_entry | sed -e "s/^/\t/" + prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/" + message="$(gettext_printf "Loading the Hurd ...")" + cat << EOF + echo '$message' + module /hurd/${hurd_fs}.static ${hurd_fs} --readonly \\ + --multiboot-command-line='\${kernel-command-line}' \\ + --host-priv-port='\${host-port}' \\ + --device-master-port='\${device-port}' \\ + --exec-server-task='\${exec-task}' -T typed '\${root}' \\ + '\$(task-create)' '\$(task-resume)' + module /lib/ld.so.1 exec /hurd/exec '\$(exec-task=task-create)' +} +EOF + + cat << EOF +menuentry "${OS} ${KERNEL} (recovery mode)" ${CLASS} { +EOF + prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/" + message="$(gettext_printf "Loading GNU Mach ...")" + cat << EOF + echo '$message' + multiboot ${kernel} root=device:${GRUB_DEVICE#/dev/} -s +EOF + prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/" + message="$(gettext_printf "Loading the Hurd ...")" + cat << EOF + echo '$message' + module /hurd/${hurd_fs}.static ${hurd_fs} \\ + --multiboot-command-line='\${kernel-command-line}' \\ + --host-priv-port='\${host-port}' \\ + --device-master-port='\${device-port}' \\ + --exec-server-task='\${exec-task}' -T typed '\${root}' \\ + '\$(task-create)' '\$(task-resume)' + module /lib/ld.so.1 exec /hurd/exec '\$(exec-task=task-create)' +} +EOF + +done diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in new file mode 100644 index 0000000..3600c74 --- /dev/null +++ b/util/grub.d/10_kfreebsd.in @@ -0,0 +1,192 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +. ${libdir}/grub/grub-mkconfig_lib + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR=@localedir@ + +CLASS="--class os" + +case "${GRUB_DISTRIBUTOR}" in + Debian) + OS="${GRUB_DISTRIBUTOR} GNU/kFreeBSD" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) --class gnu-kfreebsd --class gnu ${CLASS}" + ;; + *) + OS="FreeBSD" + CLASS="--class freebsd --class bsd ${CLASS}" + ;; +esac + +load_kfreebsd_module () +{ + mod="$1" + allow_fail="$2" + + if ! test -e "${module_dir}/${mod}.ko" ; then + if [ "${allow_fail}" = "true" ] ; then + # Return silently + return + else + # Print an error and fail. + ls "${module_dir}/${mod}.ko" > /dev/null + fi + fi + + if [ -z "${prepare_module_dir_cache}" ]; then + prepare_module_dir_cache="$(prepare_grub_to_access_device $(grub-probe -t device "${module_dir}") | sed -e "s/^/\t/")" + fi + + printf '%s\n' "${prepare_module_dir_cache}" + cat << EOF + kfreebsd_module_elf ${module_dir_rel}/${mod}.ko +EOF +} + +kfreebsd_entry () +{ + os="$1" + version="$2" + recovery="$3" + args="$4" + if ${recovery} ; then + title="$(gettext_quoted "%s, with kFreeBSD %s (recovery mode)")" + else + title="$(gettext_quoted "%s, with kFreeBSD %s")" + fi + printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${version}" + if ! ${recovery} ; then + save_default_entry | sed -e "s/^/\t/" + fi + if [ -z "${prepare_boot_cache}" ]; then + prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" + fi + + printf '%s\n' "${prepare_boot_cache}" + message="$(gettext_printf "Loading kernel of FreeBSD %s ..." ${version})" + cat << EOF + echo '$message' + kfreebsd ${rel_dirname}/${basename} ${args} +EOF + + if test -n "${devices}" ; then + cat << EOF + kfreebsd_loadenv ${devices_rel_dirname}/${devices_basename} +EOF + fi + + load_kfreebsd_module acpi true + + case "${kfreebsd_fs}" in + zfs) + load_kfreebsd_module opensolaris false + + ls "${dirname}/zfs/zpool.cache" > /dev/null + printf '%s\n' "${prepare_boot_cache}" + cat << EOF + kfreebsd_module ${rel_dirname}/zfs/zpool.cache type=/boot/zfs/zpool.cache +EOF + ;; + esac + + if [ x${kfreebsd_fs} = xufs ]; then + load_kfreebsd_module ${kfreebsd_fs} true + else + load_kfreebsd_module ${kfreebsd_fs} false + fi + + cat << EOF + set kFreeBSD.vfs.root.mountfrom=${kfreebsd_fs}:${kfreebsd_device} + set kFreeBSD.vfs.root.mountfrom.options=rw +} +EOF +} + +list=`for i in /boot/kfreebsd-* /boot/kernel/kernel ; do + if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi + done` +prepare_boot_cache= + +while [ "x$list" != "x" ] ; do + kfreebsd=`version_find_latest $list` + echo "Found kernel of FreeBSD: $kfreebsd" >&2 + basename=`basename $kfreebsd` + dirname=`dirname $kfreebsd` + rel_dirname=`make_system_path_relative_to_its_root $dirname` + + if [ -f /boot/device.hints ] ; then + devices=/boot/device.hints + devices_basename=`basename $devices` + devices_dirname=`dirname $devices` + devices_rel_dirname=`make_system_path_relative_to_its_root $devices_dirname` + fi + + case ${GRUB_FS} in + ufs1 | ufs2) kfreebsd_fs=ufs ;; + ext2) kfreebsd_fs=ext2fs ;; + *) kfreebsd_fs=${GRUB_FS} ;; + esac + + case ${GRUB_FS} in + zfs) + # zpool name + kfreebsd_device=$(grub-probe -t fs_label --device ${GRUB_DEVICE}) + # filesystem name (empty string for the main filesystem) + kfreebsd_device="${kfreebsd_device}$(grub-mkrelpath / | sed -e "s,/*@$,,")" + ;; + *) + kfreebsd_device=${kfreebsd_fs}id/${GRUB_DEVICE_UUID} + # Debian GNU/kFreeBSD can't remount root if it's supplied as UUID but + # as an UUID + if [ "x${GRUB_DISTRIBUTOR}" = "xDebian" ] \ + && ! (cat /etc/fstab | awk '!/^[[:space:]]*#/ && $2=="/" { print $1; }' \ + | grep "${kfreebsd_fs}id/${GRUB_DEVICE_UUID}" > /dev/null); then + kfreebsd_device=${GRUB_DEVICE} + fi + ;; + esac + + version=`echo $basename | sed -e "s,^[^0-9]*-,,g;s/\.gz$//g"` + alt_version=`echo $version | sed -e "s,\.old$,,g"` + + module_dir= + for i in "/lib/modules/${version}" "/lib/modules/${alt_version}" \ + "/boot/kernel"; do + if test -e "$i" ; then + module_dir="$i" + break + fi + done + if test -n "${module_dir}" ; then + echo "Found kernel module directory: ${module_dir}" >&2 + module_dir_rel=$(make_system_path_relative_to_its_root $module_dir) + fi + + kfreebsd_entry "${OS}" "${version}" false + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then + kfreebsd_entry "${OS}" "${version}" true "-s" + fi + + list=`echo $list | tr ' ' '\n' | grep -vx $kfreebsd | tr '\n' ' '` +done diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in new file mode 100644 index 0000000..1d1eb40 --- /dev/null +++ b/util/grub.d/10_linux.in @@ -0,0 +1,199 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +. ${libdir}/grub/grub-mkconfig_lib + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR=@localedir@ + +CLASS="--class gnu-linux --class gnu --class os" + +if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=GNU/Linux +else + OS="${GRUB_DISTRIBUTOR} GNU/Linux" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}" +fi + +# loop-AES arranges things so that /dev/loop/X can be our root device, but +# the initrds that Linux uses don't like that. +case ${GRUB_DEVICE} in + /dev/loop/*|/dev/loop[0-9]) + GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` + ;; +esac + +if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ + || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \ + || uses_abstraction "${GRUB_DEVICE}" lvm; then + LINUX_ROOT_DEVICE=${GRUB_DEVICE} +else + LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} +fi + +if [ "x`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`" = xbtrfs ]; then + rootsubvol="`make_system_path_relative_to_its_root /`" + rootsubvol="${rootsubvol#/}" + if [ "x${rootsubvol}" != x ]; then + GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" + fi +fi + +linux_entry () +{ + os="$1" + version="$2" + recovery="$3" + args="$4" + if ${recovery} ; then + title="$(gettext_quoted "%s, with Linux %s (recovery mode)")" + else + title="$(gettext_quoted "%s, with Linux %s")" + fi + printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${version}" + if ! ${recovery} ; then + save_default_entry | sed -e "s/^/\t/" + fi + + # Use ELILO's generic "efifb" when it's known to be available. + # FIXME: We need an interface to select vesafb in case efifb can't be used. + if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then + cat << EOF + load_video +EOF + if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \ + && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then + cat << EOF + set gfxpayload=keep +EOF + fi + else + if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then + cat << EOF + load_video +EOF + fi + cat << EOF + set gfxpayload=$GRUB_GFXPAYLOAD_LINUX +EOF + fi + + cat << EOF + insmod gzio +EOF + + if [ x$dirname = x/ ]; then + if [ -z "${prepare_root_cache}" ]; then + prepare_root_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/")" + fi + printf '%s\n' "${prepare_root_cache}" + else + if [ -z "${prepare_boot_cache}" ]; then + prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" + fi + printf '%s\n' "${prepare_boot_cache}" + fi + message="$(gettext_printf "Loading Linux %s ..." ${version})" + cat << EOF + echo '$message' + linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args} +EOF + if test -n "${initrd}" ; then + message="$(gettext_printf "Loading initial ramdisk ...")" + cat << EOF + echo '$message' + initrd ${rel_dirname}/${initrd} +EOF + fi + cat << EOF +} +EOF +} + +case x`uname -m` in + xi?86 | xx86_64) + list=`for i in /boot/vmlinuz-* /vmlinuz-* /boot/kernel-* ; do + if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi + done` ;; + *) + list=`for i in /boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* /boot/kernel-* ; do + if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi + done` ;; +esac + +prepare_boot_cache= +prepare_root_cache= + +while [ "x$list" != "x" ] ; do + linux=`version_find_latest $list` + echo "Found linux image: $linux" >&2 + basename=`basename $linux` + dirname=`dirname $linux` + rel_dirname=`make_system_path_relative_to_its_root $dirname` + version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` + alt_version=`echo $version | sed -e "s,\.old$,,g"` + linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" + + initrd= + for i in "initrd.img-${version}" "initrd-${version}.img" \ + "initrd-${version}" "initramfs-${version}.img" \ + "initrd.img-${alt_version}" "initrd-${alt_version}.img" \ + "initrd-${alt_version}" "initramfs-${alt_version}.img" \ + "initramfs-genkernel-${version}" \ + "initramfs-genkernel-${alt_version}"; do + if test -e "${dirname}/${i}" ; then + initrd="$i" + break + fi + done + + config= + for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do + if test -e "${i}" ; then + config="${i}" + break + fi + done + + initramfs= + if test -n "${config}" ; then + initramfs=`grep CONFIG_INITRAMFS_SOURCE= "${config}" | cut -f2 -d= | tr -d \"` + fi + + if test -n "${initrd}" ; then + echo "Found initrd image: ${dirname}/${initrd}" >&2 + elif test -z "${initramfs}" ; then + # "UUID=" magic is parsed by initrd or initramfs. Since there's + # no initrd or builtin initramfs, it can't work here. + linux_root_device_thisversion=${GRUB_DEVICE} + fi + + linux_entry "${OS}" "${version}" false \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then + linux_entry "${OS}" "${version}" true \ + "single ${GRUB_CMDLINE_LINUX}" + fi + + list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '` +done diff --git a/util/grub.d/10_netbsd.in b/util/grub.d/10_netbsd.in new file mode 100644 index 0000000..ffd31ad --- /dev/null +++ b/util/grub.d/10_netbsd.in @@ -0,0 +1,143 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +. ${libdir}/grub/grub-mkconfig_lib + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR=@localedir@ + +if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS="NetBSD" +else + OS="${GRUB_DISTRIBUTOR} NetBSD" +fi + +netbsd_load_fs_module () +{ + loader="$1" # "knetbsd" or "multiboot" + kernel="$2" # absolute path to the kernel file + + case $(zcat -f "${kernel}" | file -bL - | cut -d , -f 2 | tr -d ' ') in + Intel80386) + karch="i386" + ;; + x86-64) + karch="amd64" + ;; + *) + return + ;; + esac + + case $(${grub_probe} --target=fs -d ${GRUB_DEVICE}) in + ext2) + kmod="ext2fs" + ;; + fat) + kmod="msdosfs" + ;; + ntfs) + kmod="ntfs" + ;; + ufs*) + kmod="ffs" + ;; + *) + return + ;; + esac + + kversion=$(zcat -f "${kernel}" | strings | sed -n -e '/^@(#)NetBSD/ { s/^@(#)NetBSD \([0-9\.]*\) .*$/\1/g ; p ; q ; }') + kmodule="/stand/${karch}/${kversion}/modules/${kmod}/${kmod}.kmod" + + if test -z "$karch" -o -z "$kversion" -o ! -f "${kmodule}"; then + return + fi + + kmodule_rel=$(make_system_path_relative_to_its_root "$kmodule") || return + prepare_grub_to_access_device $(${grub_probe} -t device "${kmodule}") | sed -e 's,^, ,' + case "${loader}" in + knetbsd) + printf "\tknetbsd_module_elf %s\n" "${kmodule_rel}" + ;; + multiboot) + printf "\tmodule %s\n" "${kmodule_rel}" + ;; + esac +} + +netbsd_entry () +{ + loader="$1" # "knetbsd" or "multiboot" + kernel="$2" # absolute path to the kernel file + recovery="$3" # is this is a recovery entry? + args="$4" # extra arguments appended to loader command + + kroot_device="$(echo ${GRUB_DEVICE} | sed -e 's,^/dev/r,,')" + if ${recovery} ; then + title="$(gettext_quoted "%s, with kernel %s (via %s, recovery mode)")" + else + title="$(gettext_quoted "%s, with kernel %s (via %s)")" + fi + + printf "menuentry \"${title}\" {\n" \ + "${OS}" "$(echo ${kernel} | sed -e 's,^.*/,,')" "${loader}" + printf "%s\n" "${prepare_boot_cache}" + case "${loader}" in + knetbsd) + printf "\tknetbsd %s -r %s %s\n" \ + "${kernel}" "${kroot_device}" "${GRUB_CMDLINE_NETBSD} ${args}" + ;; + multiboot) + printf "\tmultiboot %s %s root=%s %s\n" \ + "${kernel}" "${kernel}" "${kroot_device}" "${GRUB_CMDLINE_NETBSD} ${args}" + ;; + esac + + netbsd_load_fs_module "${loader}" "${kernel}" + + printf "}\n" +} + +prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e 's,^, ,')" + +# We look for NetBSD kernels in / but not in subdirectories. We simply +# pick all statically linked ELF executable files (or links) in / with a +# name that starts with `netbsd'. +pattern="^ELF[^,]*executable.*statically linked" +for k in $(ls -t /netbsd*) ; do + if ! grub_file_is_not_garbage "$k" ; then + continue + fi + if ! (zcat -f "$k" | file -bL - | grep -q "${pattern}") 2>/dev/null ; then + continue + fi + + echo "Found NetBSD kernel: $k" >&2 + netbsd_entry "knetbsd" "$k" false "${GRUB_CMDLINE_NETBSD_DEFAULT}" + netbsd_entry "multiboot" "$k" false "${GRUB_CMDLINE_NETBSD_DEFAULT}" + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then + netbsd_entry "knetbsd" "$k" true "-s" + netbsd_entry "multiboot" "$k" true "-s" + fi +done diff --git a/util/grub.d/10_windows.in b/util/grub.d/10_windows.in new file mode 100644 index 0000000..fd068dd --- /dev/null +++ b/util/grub.d/10_windows.in @@ -0,0 +1,94 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +. ${libdir}/grub/grub-mkconfig_lib + +case "`uname 2>/dev/null`" in + CYGWIN*) ;; + *) exit 0 ;; +esac + +# Try C: even if current system is on other partition. +case "$SYSTEMDRIVE" in + [Cc]:) drives="C:" ;; + [D-Zd-z]:) drives="C: $SYSTEMDRIVE" ;; + *) exit 0 ;; +esac + +get_os_name_from_boot_ini () +{ + # Fail if no or more than one partition. + test "`sed -n 's,^\(\(multi\|scsi\)[^=]*\)=.*$,\1,p' "$1" 2>/dev/null | \ + sort | uniq | wc -l`" = 1 || return 1 + + # Search 'default=PARTITION' + local part=`sed -n 's,^default=,,p' "$1" | sed 's,\\\\,/,g;s,[ \t\r]*$,,;1q'` + test -n "$part" || return 1 + + # Search 'PARTITION="NAME" ...' + local name=`sed -n 's,\\\\,/,g;s,^'"$part"'="\([^"]*\)".*$,\1,p' "$1" | sed 1q` + test -n "$name" || return 1 + + echo "$name" +} + + +for drv in $drives ; do + + # Convert to Cygwin path. + dir=`cygpath "$drv"` + test -n "$dir" || continue + + needmap= + + # Check for Vista bootmgr. + if [ -f "$dir"/bootmgr -a -f "$dir"/boot/bcd ] ; then + OS="Windows Vista bootmgr" + + # Check for NTLDR. + elif [ -f "$dir"/ntldr -a -f "$dir"/ntdetect.com -a -f "$dir"/boot.ini ] ; then + OS=`get_os_name_from_boot_ini "$dir"/boot.ini` || OS="Windows NT/2000/XP loader" + needmap=t + + else + continue + fi + + # Get boot /dev/ice. + dev=`${grub_probe} -t device "$dir" 2>/dev/null` || continue + + echo "Found $OS on $drv ($dev)" >&2 + cat << EOF +menuentry "$OS" { +EOF + + save_default_entry | sed -e 's,^,\t,' + prepare_grub_to_access_device "$dev" | sed 's,^,\t,' + test -z "$needmap" || cat <. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +. ${libdir}/grub/grub-mkconfig_lib + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR=@localedir@ + +CLASS="--class gnu-linux --class gnu --class os --class xen" + +if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=GNU/Linux +else + OS="${GRUB_DISTRIBUTOR} GNU/Linux" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1) ${CLASS}" +fi + +# loop-AES arranges things so that /dev/loop/X can be our root device, but +# the initrds that Linux uses don't like that. +case ${GRUB_DEVICE} in + /dev/loop/*|/dev/loop[0-9]) + GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` + ;; +esac + +if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ + || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \ + || uses_abstraction "${GRUB_DEVICE}" lvm; then + LINUX_ROOT_DEVICE=${GRUB_DEVICE} +else + LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} +fi + +if [ "x`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`" = xbtrfs ]; then + rootsubvol="`make_system_path_relative_to_its_root /`" + rootsubvol="${rootsubvol#/}" + if [ "x${rootsubvol}" != x ]; then + GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" + fi +fi + +linux_entry () +{ + os="$1" + version="$2" + xen_version="$3" + recovery="$4" + args="$5" + xen_args="$6" + if ${recovery} ; then + title="$(gettext_quoted "%s, with Xen %s and Linux %s (recovery mode)")" + else + title="$(gettext_quoted "%s, with Xen %s and Linux %s")" + fi + printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${xen_version}" "${version}" + if ! ${recovery} ; then + save_default_entry | sed -e "s/^/\t/" + fi + + if [ -z "${prepare_boot_cache}" ]; then + prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" + fi + printf '%s\n' "${prepare_boot_cache}" + xmessage="$(gettext_printf "Loading Xen %s ..." ${xen_version})" + lmessage="$(gettext_printf "Loading Linux %s ..." ${version})" + cat << EOF + echo '$xmessage' + multiboot ${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} + echo '$lmessage' + module ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args} +EOF + if test -n "${initrd}" ; then + message="$(gettext_printf "Loading initial ramdisk ...")" + cat << EOF + echo '$message' + module ${rel_dirname}/${initrd} +EOF + fi + cat << EOF +} +EOF +} + +linux_list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* /boot/kernel-*; do + if grub_file_is_not_garbage "$i"; then + basename=$(basename $i) + version=$(echo $basename | sed -e "s,^[^0-9]*-,,g") + dirname=$(dirname $i) + config= + for j in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do + if test -e "${j}" ; then + config="${j}" + break + fi + done + if (grep -qx "CONFIG_XEN_DOM0=y" "${config}" 2> /dev/null || grep -qx "CONFIG_XEN_PRIVILEGED_GUEST=y" "${config}" 2> /dev/null); then echo -n "$i " ; fi + fi + done` +if [ "x${linux_list}" = "x" ] ; then + exit 0 +fi +xen_list=`for i in /boot/xen*; do + if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi + done` +prepare_boot_cache= + +while [ "x${xen_list}" != "x" ] ; do + list="${linux_list}" + current_xen=`version_find_latest $xen_list` + xen_basename=`basename ${current_xen}` + xen_dirname=`dirname ${current_xen}` + rel_xen_dirname=`make_system_path_relative_to_its_root $xen_dirname` + xen_version=`echo $xen_basename | sed -e "s,.gz$,,g;s,^xen-,,g"` + echo "submenu \"Xen ${xen_version}\" {" + while [ "x$list" != "x" ] ; do + linux=`version_find_latest $list` + echo "Found linux image: $linux" >&2 + basename=`basename $linux` + dirname=`dirname $linux` + rel_dirname=`make_system_path_relative_to_its_root $dirname` + version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` + alt_version=`echo $version | sed -e "s,\.old$,,g"` + linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" + + initrd= + for i in "initrd.img-${version}" "initrd-${version}.img" \ + "initrd-${version}" "initrd.img-${alt_version}" \ + "initrd-${alt_version}.img" "initrd-${alt_version}" \ + "initramfs-genkernel-${version}" \ + "initramfs-genkernel-${alt_version}" ; do + if test -e "${dirname}/${i}" ; then + initrd="$i" + break + fi + done + if test -n "${initrd}" ; then + echo "Found initrd image: ${dirname}/${initrd}" >&2 + else + # "UUID=" magic is parsed by initrds. Since there's no initrd, it can't work here. + linux_root_device_thisversion=${GRUB_DEVICE} + fi + + linux_entry "${OS}" "${version}" "${xen_version}" false \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" "${GRUB_CMDLINE_XEN} ${GRUB_CMDLINE_XEN_DEFAULT}" + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then + linux_entry "${OS}" "${version}" "${xen_version}" true \ + "single ${GRUB_CMDLINE_LINUX}" "${GRUB_CMDLINE_XEN}" + fi + + list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '` + done + echo "}" + xen_list=`echo $xen_list | tr ' ' '\n' | grep -vx $current_xen | tr '\n' ' '` +done diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in new file mode 100644 index 0000000..d9d4b0a --- /dev/null +++ b/util/grub.d/30_os-prober.in @@ -0,0 +1,204 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ + +. ${libdir}/grub/grub-mkconfig_lib + +if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then + exit 0 +fi + +if [ -z "`which os-prober 2> /dev/null`" -o -z "`which linux-boot-prober 2> /dev/null`" ] ; then + # missing os-prober and/or linux-boot-prober + exit 0 +fi + +OSPROBED="`os-prober | tr ' ' '^' | paste -s -d ' '`" +if [ -z "${OSPROBED}" ] ; then + # empty os-prober output, nothing doing + exit 0 +fi + +osx_entry() { + cat << EOF +menuentry "${LONGNAME} (${2}-bit) (on ${DEVICE})" --class osx --class darwin --class os { +EOF + save_default_entry | sed -e "s/^/\t/" + prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/" + cat << EOF + load_video + set do_resume=0 + if [ /var/vm/sleepimage -nt10 / ]; then + if xnu_resume /var/vm/sleepimage; then + set do_resume=1 + fi + fi + if [ \$do_resume = 0 ]; then + xnu_uuid ${OSXUUID} uuid + if [ -f /Extra/DSDT.aml ]; then + acpi -e /Extra/DSDT.aml + fi + $1 /mach_kernel boot-uuid=\${uuid} rd=*uuid + if [ /System/Library/Extensions.mkext -nt /System/Library/Extensions ]; then + xnu_mkext /System/Library/Extensions.mkext + else + xnu_kextdir /System/Library/Extensions + fi + if [ -f /Extra/Extensions.mkext ]; then + xnu_mkext /Extra/Extensions.mkext + fi + if [ -d /Extra/Extensions ]; then + xnu_kextdir /Extra/Extensions + fi + if [ -f /Extra/devprop.bin ]; then + xnu_devprop_load /Extra/devprop.bin + fi + if [ -f /Extra/splash.jpg ]; then + insmod jpeg + xnu_splash /Extra/splash.jpg + fi + if [ -f /Extra/splash.png ]; then + insmod png + xnu_splash /Extra/splash.png + fi + if [ -f /Extra/splash.tga ]; then + insmod tga + xnu_splash /Extra/splash.tga + fi + fi +} +EOF +} + +for OS in ${OSPROBED} ; do + DEVICE="`echo ${OS} | cut -d ':' -f 1`" + LONGNAME="`echo ${OS} | cut -d ':' -f 2 | tr '^' ' '`" + LABEL="`echo ${OS} | cut -d ':' -f 3 | tr '^' ' '`" + BOOT="`echo ${OS} | cut -d ':' -f 4`" + + if [ -z "${LONGNAME}" ] ; then + LONGNAME="${LABEL}" + fi + + echo "Found ${LONGNAME} on ${DEVICE}" >&2 + + case ${BOOT} in + chain) + + cat << EOF +menuentry "${LONGNAME} (on ${DEVICE})" --class windows --class os { +EOF + save_default_entry | sed -e "s/^/\t/" + prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/" + + case ${LONGNAME} in + Windows\ Vista*|Windows\ 7*|Windows\ Server\ 2008*) + ;; + *) + cat << EOF + drivemap -s (hd0) \${root} +EOF + ;; + esac + + cat <&2 + ;; + esac +done diff --git a/util/grub.d/40_custom.in b/util/grub.d/40_custom.in new file mode 100644 index 0000000..48068de --- /dev/null +++ b/util/grub.d/40_custom.in @@ -0,0 +1,5 @@ +#!/bin/sh +exec tail -n +3 $0 +# This file provides an easy way to add custom menu entries. Simply type the +# menu entries you want to add after this comment. Be careful not to change +# the 'exec tail' line above. diff --git a/util/grub.d/41_custom.in b/util/grub.d/41_custom.in new file mode 100644 index 0000000..64d691c --- /dev/null +++ b/util/grub.d/41_custom.in @@ -0,0 +1,7 @@ +#!/bin/sh +cat <. + +if [ "x$1" = "x" ]; then + echo "Filename required". +fi + +ioreg -lw0 -p IODeviceTree -n efi -r -x |grep device-properties | sed 's/.*.*//;' | xxd -r -p > $1 diff --git a/util/ieee1275/devicemap.c b/util/ieee1275/devicemap.c new file mode 100644 index 0000000..19ab746 --- /dev/null +++ b/util/ieee1275/devicemap.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include + +/* Since OF path names can have "," characters in them, and GRUB + internally uses "," to indicate partitions (unlike OF which uses + ":" for this purpose) we escape such commas. */ + +static char * +escape_of_path (const char *orig_path) +{ + char *new_path, *d, c; + const char *p; + + if (!strchr (orig_path, ',')) + return (char *) orig_path; + + new_path = xmalloc (strlen (orig_path) * 2); + + p = orig_path; + d = new_path; + while ((c = *p++) != '\0') + { + if (c == ',') + *d++ = '\\'; + *d++ = c; + } + + free ((char *) orig_path); + + return new_path; +} + +void +grub_util_emit_devicemap_entry (FILE *fp, char *name, + int is_floppy __attribute__((unused)), + int *num_fd __attribute__((unused)), + int *num_hd __attribute__((unused))) +{ + const char *orig_path = grub_util_devname_to_ofpath (name); + char *ofpath = escape_of_path (orig_path); + + fprintf(fp, "(%s)\t%s\n", ofpath, name); + + free (ofpath); +} diff --git a/util/ieee1275/grub-ofpathname.c b/util/ieee1275/grub-ofpathname.c new file mode 100644 index 0000000..3ac6fce --- /dev/null +++ b/util/ieee1275/grub-ofpathname.c @@ -0,0 +1,47 @@ +/* grub-ofpathname.c - Find OpenBOOT path for a given device */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include + +#include + +#include "progname.h" + +int main(int argc, char **argv) +{ + char *of_path; + + set_program_name (argv[0]); + + grub_util_init_nls (); + + if (argc != 2) + { + printf("Usage: %s DEVICE\n", program_name); + return 1; + } + + of_path = grub_util_devname_to_ofpath (argv[1]); + printf("%s\n", of_path); + + free (of_path); + + return 0; +} diff --git a/util/ieee1275/ofpath.c b/util/ieee1275/ofpath.c new file mode 100644 index 0000000..1a43334 --- /dev/null +++ b/util/ieee1275/ofpath.c @@ -0,0 +1,425 @@ +/* ofpath.c - calculate OpenFirmware path names given an OS device */ +/* + * 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 . + */ + +#undef OFPATH_STANDALONE + +#ifndef OFPATH_STANDALONE +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef OFPATH_STANDALONE +#define xmalloc malloc +void +grub_util_error (const char *fmt, ...) +{ + va_list ap; + + fprintf (stderr, "ofpath: error: "); + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + fputc ('\n', stderr); + exit (1); +} + +#endif + +static void +kill_trailing_dir(char *path) +{ + char *end = path + strlen(path) - 1; + + while (end >= path) + { + if (*end != '/') + { + end--; + continue; + } + *end = '\0'; + break; + } +} + +static void +trim_newline (char *path) +{ + char *end = path + strlen(path) - 1; + + while (*end == '\n') + *end-- = '\0'; +} + +#define OF_PATH_MAX 256 + +static void +find_obppath(char *of_path, const char *sysfs_path_orig) +{ + char *sysfs_path, *path; + + sysfs_path = xmalloc (PATH_MAX); + path = xmalloc (PATH_MAX); + + strcpy(sysfs_path, sysfs_path_orig); + while (1) + { + int fd; + + snprintf(path, PATH_MAX, "%s/obppath", sysfs_path); +#if 0 + printf("Trying %s\n", path); +#endif + + fd = open(path, O_RDONLY); + if (fd < 0) + { + kill_trailing_dir(sysfs_path); + if (!strcmp(sysfs_path, "/sys")) + grub_util_error("'obppath' not found in parent dirs of %s", + sysfs_path_orig); + continue; + } + memset(of_path, 0, OF_PATH_MAX); + read(fd, of_path, OF_PATH_MAX); + close(fd); + + trim_newline(of_path); + break; + } + + free (path); + free (sysfs_path); +} + +static void +block_device_get_sysfs_path_and_link(const char *devicenode, + char *sysfs_path, int sysfs_path_len) +{ + char *rpath = xmalloc (PATH_MAX); + + snprintf(sysfs_path, sysfs_path_len, "/sys/block/%s", devicenode); + + if (!realpath (sysfs_path, rpath)) + grub_util_error ("cannot get the real path of `%s'", sysfs_path); + + strcat(rpath, "/device"); + + if (!realpath (rpath, sysfs_path)) + grub_util_error ("cannot get the real path of `%s'", rpath); + + free (rpath); +} + +static const char * +trailing_digits (const char *p) +{ + const char *end; + + end = p + strlen(p) - 1; + while (end >= p) + { + if (! isdigit(*end)) + break; + end--; + } + + return end + 1; +} + +static void +__of_path_common(char *of_path, char *sysfs_path, + const char *device, int devno) +{ + const char *digit_string; + char disk[64]; + + find_obppath(of_path, sysfs_path); + + digit_string = trailing_digits (device); + if (*digit_string == '\0') + { + sprintf(disk, "/disk@%d", devno); + } + else + { + int part; + + sscanf(digit_string, "%d", &part); + sprintf(disk, "/disk@%d:%c", devno, 'a' + (part - 1)); + } + strcat(of_path, disk); +} + +static char * +get_basename(char *p) +{ + char *ret = p; + + while (*p) + { + if (*p == '/') + ret = p + 1; + p++; + } + + return ret; +} + +static void +of_path_of_vdisk(char *of_path, + const char *devname __attribute__((unused)), + const char *device, + const char *devnode __attribute__((unused)), + const char *devicenode) +{ + char *sysfs_path, *p; + int devno, junk; + + sysfs_path = xmalloc (PATH_MAX); + block_device_get_sysfs_path_and_link(devicenode, + sysfs_path, PATH_MAX); + p = get_basename (sysfs_path); + sscanf(p, "vdc-port-%d-%d", &devno, &junk); + __of_path_common(of_path, sysfs_path, device, devno); + + free (sysfs_path); +} + +static void +of_path_of_ide(char *of_path, + const char *devname __attribute__((unused)), const char *device, + const char *devnode __attribute__((unused)), + const char *devicenode) +{ + char *sysfs_path, *p; + int chan, devno; + + sysfs_path = xmalloc (PATH_MAX); + block_device_get_sysfs_path_and_link(devicenode, + sysfs_path, PATH_MAX); + p = get_basename (sysfs_path); + sscanf(p, "%d.%d", &chan, &devno); + + __of_path_common(of_path, sysfs_path, device, devno); + + free (sysfs_path); +} + +static int +vendor_is_ATA(const char *path) +{ + int fd, err; + char *buf; + + buf = xmalloc (PATH_MAX); + + snprintf(buf, PATH_MAX, "%s/vendor", path); + fd = open(buf, O_RDONLY); + if (fd < 0) + grub_util_error ("cannot open 'vendor' node of `%s'", path); + + memset(buf, 0, PATH_MAX); + err = read(fd, buf, PATH_MAX); + if (err < 0) + grub_util_error ("cannot read 'vendor' node of `%s'", path); + + close(fd); + + free (buf); + + if (!strncmp(buf, "ATA", 3)) + return 1; + return 0; +} + +static void +check_sas (char *sysfs_path, int *tgt) +{ + char *ed = strstr (sysfs_path, "end_device"); + char *p, *q, *path; + char phy[16]; + int fd; + + if (!ed) + return; + + /* SAS devices are identified using disk@$PHY_ID */ + p = strdup (sysfs_path); + ed = strstr(p, "end_device"); + + q = ed; + while (*q && *q != '/') + q++; + *q = '\0'; + + path = xmalloc (PATH_MAX); + sprintf (path, "%s/sas_device:%s/phy_identifier", p, ed); + + fd = open(path, O_RDONLY); + if (fd < 0) + grub_util_error("cannot open SAS PHY ID `%s'\n", path); + + memset (phy, 0, sizeof (phy)); + read (fd, phy, sizeof (phy)); + + sscanf (phy, "%d", tgt); + + free (path); + free (p); +} + +static void +of_path_of_scsi(char *of_path, + const char *devname __attribute__((unused)), const char *device, + const char *devnode __attribute__((unused)), + const char *devicenode) +{ + const char *p, *digit_string, *disk_name; + int host, bus, tgt, lun; + char *sysfs_path, disk[64]; + + sysfs_path = xmalloc (PATH_MAX); + + block_device_get_sysfs_path_and_link(devicenode, + sysfs_path, PATH_MAX); + p = get_basename (sysfs_path); + sscanf(p, "%d:%d:%d:%d", &host, &bus, &tgt, &lun); + check_sas (sysfs_path, &tgt); + + if (vendor_is_ATA(sysfs_path)) + { + __of_path_common(of_path, sysfs_path, device, tgt); + free (sysfs_path); + return; + } + + find_obppath(of_path, sysfs_path); + free (sysfs_path); + + if (strstr (of_path, "qlc")) + strcat (of_path, "/fp@0,0"); + + if (strstr (of_path, "sbus")) + disk_name = "sd"; + else + disk_name = "disk"; + + digit_string = trailing_digits (device); + if (*digit_string == '\0') + { + sprintf(disk, "/%s@%x,%d", disk_name, tgt, lun); + } + else + { + int part; + + sscanf(digit_string, "%d", &part); + sprintf(disk, "/%s@%x,%d:%c", disk_name, tgt, lun, 'a' + (part - 1)); + } + strcat(of_path, disk); +} + +static char * +strip_trailing_digits (const char *p) +{ + char *new, *end; + + new = strdup (p); + end = new + strlen(new) - 1; + while (end >= new) + { + if (! isdigit(*end)) + break; + *end-- = '\0'; + } + + return new; +} + +char * +grub_util_devname_to_ofpath (const char *devname) +{ + char *name_buf, *device, *devnode, *devicenode, *ofpath; + + name_buf = xmalloc (PATH_MAX); + name_buf = realpath (devname, name_buf); + if (! name_buf) + grub_util_error ("cannot get the real path of `%s'", devname); + + device = get_basename (name_buf); + devnode = strip_trailing_digits (name_buf); + devicenode = strip_trailing_digits (device); + + ofpath = xmalloc (OF_PATH_MAX); + + if (device[0] == 'h' && device[1] == 'd') + of_path_of_ide(ofpath, name_buf, device, devnode, devicenode); + else if (device[0] == 's' + && (device[1] == 'd' || device[1] == 'r')) + of_path_of_scsi(ofpath, name_buf, device, devnode, devicenode); + else if (device[0] == 'v' && device[1] == 'd' && device[2] == 'i' + && device[3] == 's' && device[4] == 'k') + of_path_of_vdisk(ofpath, name_buf, device, devnode, devicenode); + else if (device[0] == 'f' && device[1] == 'd' + && device[2] == '0' && device[3] == '\0') + /* All the models I've seen have a devalias "floppy". + New models have no floppy at all. */ + strcpy (ofpath, "floppy"); + else + grub_util_error ("unknown device type %s\n", device); + + free (devnode); + free (devicenode); + free (name_buf); + + return ofpath; +} + +#ifdef OFPATH_STANDALONE +int main(int argc, char **argv) +{ + char *of_path; + + if (argc != 2) + { + printf("Usage: grub-ofpathname DEVICE\n"); + return 1; + } + + of_path = grub_util_devname_to_ofpath (argv[1]); + printf("%s\n", of_path); + + return 0; +} +#endif diff --git a/util/import_gcry.py b/util/import_gcry.py new file mode 100644 index 0000000..b2a0a54 --- /dev/null +++ b/util/import_gcry.py @@ -0,0 +1,346 @@ +#* +#* 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 . +#* + +import re +import sys +import os +import datetime + +if len (sys.argv) < 3: + print ("Usage: %s SOURCE DESTINATION" % sys.argv[0]) + exit (0) +indir = sys.argv[1] +outdir = sys.argv[2] + +basedir = os.path.join (outdir, "lib/libgcrypt-grub") +try: + os.makedirs (basedir) +except: + print ("WARNING: %s already exists" % basedir) +cipher_dir_in = os.path.join (indir, "cipher") +cipher_dir_out = os.path.join (basedir, "cipher") +try: + os.makedirs (cipher_dir_out) +except: + print ("WARNING: %s already exists" % cipher_dir_out) + +cipher_files = os.listdir (cipher_dir_in) +conf = open (os.path.join ("grub-core", "Makefile.gcry.def"), "w") +conf.write ("AutoGen definitions Makefile.tpl;\n\n") +chlog = "" + +# Strictly speaking CRC32/CRC24 work on bytes so this value should be 1 +# But libgcrypt uses 64. Let's keep the value for compatibility. Since +# noone uses CRC24/CRC32 for HMAC this is no problem +mdblocksizes = {"_gcry_digest_spec_crc32" : 64, + "_gcry_digest_spec_crc32_rfc1510" : 64, + "_gcry_digest_spec_crc24_rfc2440" : 64, + "_gcry_digest_spec_md4" : 64, + "_gcry_digest_spec_md5" : 64, + "_gcry_digest_spec_rmd160" : 64, + "_gcry_digest_spec_sha1" : 64, + "_gcry_digest_spec_sha224" : 64, + "_gcry_digest_spec_sha256" : 64, + "_gcry_digest_spec_sha384" : 128, + "_gcry_digest_spec_sha512" : 128, + "_gcry_digest_spec_tiger" : 64, + "_gcry_digest_spec_whirlpool" : 64} + +cryptolist = open (os.path.join (cipher_dir_out, "crypto.lst"), "w") + +# rijndael is the only cipher using aliases. So no need for mangling, just +# hardcode it +cryptolist.write ("RIJNDAEL: gcry_rijndael\n"); +cryptolist.write ("RIJNDAEL192: gcry_rijndael\n"); +cryptolist.write ("RIJNDAEL256: gcry_rijndael\n"); +cryptolist.write ("AES128: gcry_rijndael\n"); +cryptolist.write ("AES-128: gcry_rijndael\n"); +cryptolist.write ("AES-192: gcry_rijndael\n"); +cryptolist.write ("AES-256: gcry_rijndael\n"); + +for cipher_file in cipher_files: + infile = os.path.join (cipher_dir_in, cipher_file) + outfile = os.path.join (cipher_dir_out, cipher_file) + if cipher_file == "ChangeLog": + continue + chlognew = " * %s" % cipher_file + if re.match ("(Manifest|Makefile\.am|ac\.c|cipher\.c|hash-common\.c|hmac-tests\.c|md\.c|pubkey\.c)$", cipher_file): + chlog = "%s%s: Removed\n" % (chlog, chlognew) + continue + # Autogenerated files. Not even worth mentionning in ChangeLog + if re.match ("Makefile\.in$", cipher_file): + continue + nch = False + if re.match (".*\.[ch]$", cipher_file): + isc = re.match (".*\.c$", cipher_file) + f = open (infile, "r") + fw = open (outfile, "w") + fw.write ("/* This file was automatically imported with \n") + fw.write (" import_gcry.py. Please don't modify it */\n") + fw.write ("#include \n") + # Whole libgcrypt is distributed under GPLv3+ or compatible + if isc: + fw.write ("GRUB_MOD_LICENSE (\"GPLv3+\");\n") + + ciphernames = [] + mdnames = [] + hold = False + skip = False + skip2 = False + ismd = False + iscryptostart = False + iscomma = False + isglue = False + skip_statement = False + if isc: + modname = cipher_file [0:len(cipher_file) - 2] + if re.match (".*-glue$", modname): + modname = modname.replace ("-glue", "") + isglue = True + modname = "gcry_%s" % modname + for line in f: + if skip_statement: + if not re.search (";", line) is None: + skip_statement = False + continue + if skip: + if line[0] == "}": + skip = False + continue + if skip2: + if not re.search (" *};", line) is None: + skip2 = False + continue + if iscryptostart: + s = re.search (" *\"([A-Z0-9_a-z]*)\"", line) + if not s is None: + sg = s.groups()[0] + cryptolist.write (("%s: %s\n") % (sg, modname)) + iscryptostart = False + if ismd: + if not re.search (" *};", line) is None: + if not mdblocksizes.has_key (mdname): + print ("ERROR: Unknown digest blocksize: %s\n" % mdname) + exit (1) + if not iscomma: + fw.write (" ,\n") + fw.write (" .blocksize = %s\n" % mdblocksizes [mdname]) + ismd = False + iscomma = not re.search (",$", line) is None + # Used only for selftests. + m = re.match ("(static byte|static unsigned char) (weak_keys_chksum)\[[0-9]*\] =", line) + if not m is None: + skip = True + fname = m.groups ()[1] + chmsg = "(%s): Removed." % fname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue + if hold: + hold = False + # We're optimising for size. + if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer|tripledes_set2keys|do_tripledes_set_extra_info)", line) is None: + skip = True + fname = re.match ("[a-zA-Z0-9_]*", line).group () + chmsg = "(%s): Removed." % fname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue + else: + fw.write (holdline) + m = re.match ("#include <.*>", line) + if not m is None: + chmsg = "Removed including of %s" % \ + m.group () [len ("#include <"):len (m.group ()) - 1] + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s: %s" % (chlognew, chmsg) + nch = True + continue + m = re.match ("gcry_cipher_spec_t", line) + if isc and not m is None: + assert (not iscryptostart) + ciphername = line [len ("gcry_cipher_spec_t"):].strip () + ciphername = re.match("[a-zA-Z0-9_]*",ciphername).group () + ciphernames.append (ciphername) + iscryptostart = True + m = re.match ("gcry_md_spec_t", line) + if isc and not m is None: + assert (not ismd) + assert (not iscryptostart) + mdname = line [len ("gcry_md_spec_t"):].strip () + mdname = re.match("[a-zA-Z0-9_]*",mdname).group () + mdnames.append (mdname) + ismd = True + iscryptostart = True + m = re.match ("static const char \*selftest.*;$", line) + if not m is None: + fname = line[len ("static const char \*"):] + fname = re.match ("[a-zA-Z0-9_]*", fname).group () + chmsg = "(%s): Removed declaration." % fname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue + m = re.match ("(static const char( |)\*|static gpg_err_code_t|void|static int|static gcry_err_code_t)$", line) + if not m is None: + hold = True + holdline = line + continue + m = re.match ("static int tripledes_set2keys \(.*\);", line) + if not m is None: + continue + m = re.match ("static int tripledes_set2keys \(", line) + if not m is None: + skip_statement = True + continue + m = re.match ("cipher_extra_spec_t", line) + if isc and not m is None: + skip2 = True + fname = line[len ("cipher_extra_spec_t "):] + fname = re.match ("[a-zA-Z0-9_]*", fname).group () + chmsg = "(%s): Removed." % fname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue + m = re.match ("md_extra_spec_t", line) + if isc and not m is None: + skip2 = True + fname = line[len ("md_extra_spec_t "):] + fname = re.match ("[a-zA-Z0-9_]*", fname).group () + chmsg = "(%s): Removed." % fname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue + fw.write (line) + if len (ciphernames) > 0 or len (mdnames) > 0: + if isglue: + modfiles = "lib/libgcrypt-grub/cipher/%s lib/libgcrypt-grub/cipher/%s" \ + % (cipher_file, cipher_file.replace ("-glue.c", ".c")) + else: + modfiles = "lib/libgcrypt-grub/cipher/%s" % cipher_file + chmsg = "(GRUB_MOD_INIT(%s)): New function\n" % modname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s%s" % (chlognew, chmsg) + nch = True + fw.write ("\n\nGRUB_MOD_INIT(%s)\n" % modname) + fw.write ("{\n") + for ciphername in ciphernames: + chmsg = "Register cipher %s" % ciphername + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write (" grub_cipher_register (&%s);\n" % ciphername) + for mdname in mdnames: + chmsg = "Register digest %s" % mdname + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write (" grub_md_register (&%s);\n" % mdname) + fw.write ("}") + chmsg = "(GRUB_MOD_FINI(%s)): New function\n" % modname + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write ("\n\nGRUB_MOD_FINI(%s)\n" % modname) + fw.write ("{\n") + for ciphername in ciphernames: + chmsg = "Unregister cipher %s" % ciphername + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write (" grub_cipher_unregister (&%s);\n" % ciphername) + for mdname in mdnames: + chmsg = "Unregister MD %s" % mdname + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write (" grub_md_unregister (&%s);\n" % mdname) + fw.write ("}\n") + conf.write ("module = {\n") + conf.write (" name = %s;\n" % modname) + for src in modfiles.split(): + conf.write (" common = %s;\n" % src) + conf.write (" cflags = '$(CFLAGS_GCRY)';\n"); + conf.write (" cppflags = '$(CPPFLAGS_GCRY)';\n"); + conf.write ("};\n\n") + elif isc and cipher_file != "camellia.c": + print ("WARNING: C file isn't a module: %s" % cipher_file) + f.close () + fw.close () + if nch: + chlog = "%s%s\n" % (chlog, chlognew) + continue + chlog = "%s%sSkipped unknown file\n" % (chlog, chlognew) + print ("WARNING: unknown file %s" % cipher_file) + +cryptolist.close () +chlog = "%s * crypto.lst: New file.\n" % chlog + +outfile = os.path.join (cipher_dir_out, "types.h") +fw=open (outfile, "w") +fw.write ("#include \n") +fw.write ("#include \n") +chlog = "%s * types.h: New file.\n" % chlog +fw.close () + +outfile = os.path.join (cipher_dir_out, "memory.h") +fw=open (outfile, "w") +fw.write ("#include \n") +chlog = "%s * memory.h: New file.\n" % chlog +fw.close () + + +outfile = os.path.join (cipher_dir_out, "cipher.h") +fw=open (outfile, "w") +fw.write ("#include \n") +fw.write ("#include \n") +chlog = "%s * cipher.h: Likewise.\n" % chlog +fw.close () + +outfile = os.path.join (cipher_dir_out, "g10lib.h") +fw=open (outfile, "w") +fw.write ("#include \n") +chlog = "%s * g10lib.h: Likewise.\n" % chlog +fw.close () + +infile = os.path.join (cipher_dir_in, "ChangeLog") +outfile = os.path.join (cipher_dir_out, "ChangeLog") + + +f=open (infile, "r") +fw=open (outfile, "w") +dt = datetime.date.today () +fw.write ("%04d-%02d-%02d Automatic import tool\n" % \ + (dt.year,dt.month, dt.day)) +fw.write ("\n") +fw.write (" Imported ciphers to GRUB\n") +fw.write ("\n") +fw.write (chlog) +fw.write ("\n") +for line in f: + fw.write (line) +f.close () +fw.close () diff --git a/util/import_unicode.py b/util/import_unicode.py new file mode 100644 index 0000000..8d17e7e --- /dev/null +++ b/util/import_unicode.py @@ -0,0 +1,189 @@ +#* +#* 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 . +#* + +import re +import sys + +if len (sys.argv) < 3: + print ("Usage: %s SOURCE DESTINATION" % sys.argv[0]) + exit (0) +infile = open (sys.argv[3], "r") +joining = {} +for line in infile: + line = re.sub ("#.*$", "", line) + line = line.replace ("\n", "") + line = line.replace (" ", "") + if len (line) == 0 or line[0] == '\n': + continue + sp = line.split (";") + curcode = int (sp[0], 16) + if sp[2] == "U": + joining[curcode] = "NONJOINING" + elif sp[2] == "L": + joining[curcode] = "LEFT" + elif sp[2] == "R": + joining[curcode] = "RIGHT" + elif sp[2] == "D": + joining[curcode] = "DUAL" + elif sp[2] == "C": + joining[curcode] = "CAUSING" + else: + print ("Unknown joining type '%s'" % sp[2]) + exit (1) +infile.close () + +infile = open (sys.argv[1], "r") +outfile = open (sys.argv[4], "w") +outfile.write ("#include \n") +outfile.write ("\n") +outfile.write ("struct grub_unicode_compact_range grub_unicode_compact[] = {\n") + +begincode = -2 +lastcode = -2 +lastbiditype = "X" +lastmirrortype = False +lastcombtype = -1 +arabicsubst = {} +for line in infile: + sp = line.split (";") + curcode = int (sp[0], 16) + curcombtype = int (sp[3], 10) + curbiditype = sp[4] + curmirrortype = (sp[9] == "Y") + if curcombtype <= 255 and curcombtype >= 253: + print ("UnicodeData.txt uses combination type %d. Conflict." \ + % curcombtype) + raise + if sp[2] != "Lu" and sp[2] != "Ll" and sp[2] != "Lt" and sp[2] != "Lm" \ + and sp[2] != "Lo"\ + and sp[2] != "Me" and sp[2] != "Mc" and sp[2] != "Mn" \ + and sp[2] != "Nd" and sp[2] != "Nl" and sp[2] != "No" \ + and sp[2] != "Pc" and sp[2] != "Pd" and sp[2] != "Ps" \ + and sp[2] != "Pe" and sp[2] != "Pi" and sp[2] != "Pf" \ + and sp[2] != "Po" \ + and sp[2] != "Sm" and sp[2] != "Sc" and sp[2] != "Sk" \ + and sp[2] != "So"\ + and sp[2] != "Zs" and sp[2] != "Zl" and sp[2] != "Zp" \ + and sp[2] != "Cc" and sp[2] != "Cf" and sp[2] != "Cs" \ + and sp[2] != "Co": + print ("WARNING: Unknown type %s" % sp[2]) + if curcombtype == 0 and sp[2] == "Me": + curcombtype = 253 + if curcombtype == 0 and sp[2] == "Mc": + curcombtype = 254 + if curcombtype == 0 and sp[2] == "Mn": + curcombtype = 255 + if (curcombtype >= 2 and curcombtype <= 6) \ + or (curcombtype >= 37 and curcombtype != 84 and curcombtype != 91 and curcombtype != 103 and curcombtype != 107 and curcombtype != 118 and curcombtype != 122 and curcombtype != 129 and curcombtype != 130 and curcombtype != 132 and curcombtype != 202 and \ + curcombtype != 214 and curcombtype != 216 and \ + curcombtype != 218 and curcombtype != 220 and \ + curcombtype != 222 and curcombtype != 224 and curcombtype != 226 and curcombtype != 228 and \ + curcombtype != 230 and curcombtype != 232 and curcombtype != 233 and \ + curcombtype != 234 and \ + curcombtype != 240 and curcombtype != 253 and \ + curcombtype != 254 and curcombtype != 255): + print ("WARNING: Unknown combining type %d" % curcombtype) + if curcode in joining: + curjoin = joining[curcode] + elif sp[2] == "Me" or sp[2] == "Mn" or sp[2] == "Cf": + curjoin = "TRANSPARENT" + else: + curjoin = "NONJOINING" + if sp[1].startswith ("ARABIC LETTER "): + arabname = sp[1][len ("ARABIC LETTER "):] + form = 0 + if arabname.endswith (" ISOLATED FORM"): + arabname = arabname[0:len (arabname) - len (" ISOLATED FORM")] + form = 1 + if arabname.endswith (" FINAL FORM"): + arabname = arabname[0:len (arabname) - len (" FINAL FORM")] + form = 2 + if arabname.endswith (" MEDIAL FORM"): + arabname = arabname[0:len (arabname) - len (" MEDIAL FORM")] + form = 3 + if arabname.endswith (" INITIAL FORM"): + arabname = arabname[0:len (arabname) - len (" INITIAL FORM")] + form = 4 + if arabname not in arabicsubst: + arabicsubst[arabname]={} + arabicsubst[arabname][form] = curcode; + if form == 0: + arabicsubst[arabname]['join'] = curjoin + if lastcode + 1 != curcode or curbiditype != lastbiditype \ + or curcombtype != lastcombtype or curmirrortype != lastmirrortype \ + or curjoin != lastjoin: + if begincode != -2 and (lastbiditype != "L" or lastcombtype != 0 or \ + lastmirrortype): + outfile.write (("{0x%x, 0x%x, GRUB_BIDI_TYPE_%s, %d, %d, GRUB_JOIN_TYPE_%s},\n" \ + % (begincode, lastcode, lastbiditype, \ + lastcombtype, lastmirrortype, \ + lastjoin))) + begincode = curcode + lastcode = curcode + lastjoin = curjoin + lastbiditype = curbiditype + lastcombtype = curcombtype + lastmirrortype = curmirrortype +if lastbiditype != "L" or lastcombtype != 0 or lastmirrortype: + outfile.write (("{0x%x, 0x%x, GRUB_BIDI_TYPE_%s, %d, %d, GRUB_JOIN_TYPE_%s},\n" \ + % (begincode, lastcode, lastbiditype, lastcombtype, \ + lastmirrortype, lastjoin))) +outfile.write ("{0, 0, 0, 0, 0, 0},\n") + +outfile.write ("};\n") + +infile.close () + +infile = open (sys.argv[2], "r") + +outfile.write ("struct grub_unicode_bidi_pair grub_unicode_bidi_pairs[] = {\n") + +for line in infile: + line = re.sub ("#.*$", "", line) + line = line.replace ("\n", "") + line = line.replace (" ", "") + if len (line) == 0 or line[0] == '\n': + continue + sp = line.split (";") + code1 = int (sp[0], 16) + code2 = int (sp[1], 16) + outfile.write ("{0x%x, 0x%x},\n" % (code1, code2)) +outfile.write ("{0, 0},\n") +outfile.write ("};\n") + +infile.close () + +outfile.write ("struct grub_unicode_arabic_shape grub_unicode_arabic_shapes[] = {\n ") + +for x in arabicsubst: + try: + if arabicsubst[x]['join'] == "DUAL": + outfile.write ("{0x%x, 0x%x, 0x%x, 0x%x, 0x%x},\n " % (arabicsubst[x][0], arabicsubst[x][1], arabicsubst[x][2], arabicsubst[x][3], arabicsubst[x][4])) + elif arabicsubst[x]['join'] == "RIGHT": + outfile.write ("{0x%x, 0x%x, 0x%x, 0x%x, 0x%x},\n " % (arabicsubst[x][0], arabicsubst[x][1], arabicsubst[x][2], 0, 0)) + elif arabicsubst[x]['join'] == "LEFT": + outfile.write ("{0x%x, 0x%x, 0x%x, 0x%x, 0x%x},\n " % (arabicsubst[x][0], arabicsubst[x][1], 0, 0, arabicsubst[x][4])) + except: + pass + +outfile.write ("{0, 0, 0, 0, 0},\n") +outfile.write ("};\n") + + +outfile.close () + diff --git a/util/lvm.c b/util/lvm.c new file mode 100644 index 0000000..bb2c19f --- /dev/null +++ b/util/lvm.c @@ -0,0 +1,52 @@ +/* lvm.c - LVM support for GRUB utils. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +/* We only support LVM on Linux. */ +#ifdef __linux__ +#include +#include +#include + +#include +#include + +#define LVM_DEV_MAPPER_STRING "/dev/mapper/" + +int +grub_util_lvm_isvolume (char *name) +{ + char *devname; + struct stat st; + int err; + + devname = xmalloc (strlen (name) + sizeof (LVM_DEV_MAPPER_STRING)); + + strcpy (devname, LVM_DEV_MAPPER_STRING); + strcpy (devname + sizeof(LVM_DEV_MAPPER_STRING) - 1, name); + + err = stat (devname, &st); + free (devname); + + if (err) + return 0; + else + return 1; +} + +#endif /* ! __linux__ */ diff --git a/util/misc.c b/util/misc.c new file mode 100644 index 0000000..cfbae60 --- /dev/null +++ b/util/misc.c @@ -0,0 +1,379 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include + +#include +#include +#include +#include +#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" + +/* Include malloc.h, only if memalign is available. It is known that + memalign is declared in malloc.h in all systems, if present. */ +#ifdef HAVE_MEMALIGN +# include +#endif + +#ifdef __MINGW32__ +#include +#include +#endif + +#ifdef GRUB_UTIL +int +grub_err_printf (const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start (ap, fmt); + ret = vfprintf (stderr, fmt, ap); + va_end (ap); + + return ret; +} +#endif + +char * +grub_util_get_path (const char *dir, const char *file) +{ + char *path; + + path = (char *) xmalloc (strlen (dir) + 1 + strlen (file) + 1); + sprintf (path, "%s/%s", dir, file); + return path; +} + +size_t +grub_util_get_fp_size (FILE *fp) +{ + struct stat st; + + if (fflush (fp) == EOF) + grub_util_error ("fflush failed"); + + if (fstat (fileno (fp), &st) == -1) + grub_util_error ("fstat failed"); + + return st.st_size; +} + +size_t +grub_util_get_image_size (const char *path) +{ + struct stat st; + + grub_util_info ("getting the size of %s", path); + + if (stat (path, &st) == -1) + grub_util_error ("cannot stat %s", path); + + return st.st_size; +} + +void +grub_util_read_at (void *img, size_t size, off_t offset, FILE *fp) +{ + if (fseeko (fp, offset, SEEK_SET) == -1) + grub_util_error ("seek failed"); + + if (fread (img, 1, size, fp) != size) + grub_util_error ("read failed"); +} + +char * +grub_util_read_image (const char *path) +{ + char *img; + FILE *fp; + size_t size; + + grub_util_info ("reading %s", path); + + size = grub_util_get_image_size (path); + img = (char *) xmalloc (size); + + fp = fopen (path, "rb"); + if (! fp) + grub_util_error ("cannot open %s", path); + + grub_util_read_at (img, size, 0, fp); + + fclose (fp); + + return img; +} + +void +grub_util_load_image (const char *path, char *buf) +{ + FILE *fp; + size_t size; + + grub_util_info ("reading %s", path); + + size = grub_util_get_image_size (path); + + fp = fopen (path, "rb"); + if (! fp) + grub_util_error ("cannot open %s", path); + + if (fread (buf, 1, size, fp) != size) + grub_util_error ("cannot read %s", path); + + fclose (fp); +} + +void +grub_util_write_image_at (const void *img, size_t size, off_t offset, FILE *out) +{ + grub_util_info ("writing 0x%x bytes at offset 0x%x", size, offset); + if (fseeko (out, offset, SEEK_SET) == -1) + grub_util_error ("seek failed"); + if (fwrite (img, 1, size, out) != size) + grub_util_error ("write failed"); +} + +void +grub_util_write_image (const char *img, size_t size, FILE *out) +{ + grub_util_info ("writing 0x%x bytes", size); + if (fwrite (img, 1, size, out) != size) + grub_util_error ("write failed"); +} + +char * +grub_script_execute_argument_to_string (struct grub_script_arg *arg __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute_cmdline (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute_cmdlist (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute_cmdif (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute_cmdfor (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute_cmdwhile (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute_menuentry (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + +grub_err_t +grub_script_execute (struct grub_script *script) +{ + if (script == 0 || script->cmd == 0) + return 0; + + return script->cmd->exec (script->cmd); +} + +void +grub_putchar (int c) +{ + putchar (c); +} + +int +grub_getkey (void) +{ + return -1; +} + +void +grub_refresh (void) +{ + fflush (stdout); +} + +static void +grub_xputs_real (const char *str) +{ + fputs (str, stdout); +} + +void (*grub_xputs) (const char *str) = grub_xputs_real; + +int +grub_dl_ref (grub_dl_t mod) +{ + (void) mod; + return 0; +} + +int +grub_dl_unref (grub_dl_t mod) +{ + (void) mod; + return 0; +} + +/* Some functions that we don't use. */ +void +grub_mm_init_region (void *addr __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused))) +{ +} + +void +grub_register_exported_symbols (void) +{ +} + +#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 + +#ifdef __MINGW32__ + +void sync (void) +{ +} + +int fsync (int fno __attribute__ ((unused))) +{ + return 0; +} + +void sleep (int s) +{ + Sleep (s * 1000); +} + +grub_int64_t +grub_util_get_disk_size (char *name) +{ + HANDLE hd; + grub_int64_t size = -1LL; + + hd = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, OPEN_EXISTING, 0, 0); + + if (hd == INVALID_HANDLE_VALUE) + return size; + + if (((name[0] == '/') || (name[0] == '\\')) && + ((name[1] == '/') || (name[1] == '\\')) && + (name[2] == '.') && + ((name[3] == '/') || (name[3] == '\\')) && + (! strncasecmp (name + 4, "PHYSICALDRIVE", 13))) + { + DWORD nr; + DISK_GEOMETRY g; + + if (! DeviceIoControl (hd, IOCTL_DISK_GET_DRIVE_GEOMETRY, + 0, 0, &g, sizeof (g), &nr, 0)) + goto fail; + + size = g.Cylinders.QuadPart; + size *= g.TracksPerCylinder * g.SectorsPerTrack * g.BytesPerSector; + } + else + { + LARGE_INTEGER s; + + s.LowPart = GetFileSize (hd, &s.HighPart); + size = s.QuadPart; + } + +fail: + + CloseHandle (hd); + + return size; +} + +#endif /* __MINGW32__ */ + +#ifdef GRUB_UTIL +void +grub_util_init_nls (void) +{ +#if (defined(ENABLE_NLS) && ENABLE_NLS) + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); +#endif /* (defined(ENABLE_NLS) && ENABLE_NLS) */ +} +#endif diff --git a/util/powerpc/ieee1275/grub-mkrescue.in b/util/powerpc/ieee1275/grub-mkrescue.in new file mode 100644 index 0000000..d688431 --- /dev/null +++ b/util/powerpc/ieee1275/grub-mkrescue.in @@ -0,0 +1,143 @@ +#! /bin/sh +set -e + +# Make GRUB rescue image +# Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +# Initialize some variables. +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +libdir=@libdir@ +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_TARNAME=@PACKAGE_TARNAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +target_cpu=@target_cpu@ +platform=@platform@ +pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` + +self=`basename $0` + +grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +argument () { + opt=$1 + shift + + if test $# -eq 0; then + echo "$0: option requires an argument -- '$opt'" 1>&2 + exit 1 + fi + echo $1 +} + +input_dir=${pkglibdir} + +# Check the arguments. +while test $# -gt 0 +do + option=$1 + shift + + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" + exit 0 ;; + + --modules) + modules=`argument $option "$@"`; shift ;; + --modules=*) + modules=`echo "$option" | sed 's/--modules=//'` ;; + + --pkglibdir) + input_dir=`argument $option "$@"`; shift ;; + --pkglibdir=*) + input_dir=`echo "$option" | sed 's/--pkglibdir=//'` ;; + + --grub-mkimage) + grub_mkimage=`argument $option "$@"`; shift ;; + --grub-mkimage=*) + grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;; + + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + *) + if test "x$output_image" != x; then + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + fi + output_image="${option}" ;; + esac +done + +if test "x$output_image" = x; then + usage + exit 1 +fi + +if [ "x${modules}" = "x" ] ; then + modules=`cd ${input_dir}/ && ls *.mod` +fi + +map_file=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 1 +cat >${map_file} <. + */ + +/* We only support RAID on Linux. */ +#ifdef __linux__ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +char ** +grub_util_raid_getmembers (const char *name) +{ + int fd, ret, i, j; + char **devicelist; + mdu_version_t version; + mdu_array_info_t info; + mdu_disk_info_t disk; + + fd = open (name, O_RDONLY); + + if (fd == -1) + grub_util_error ("can't open %s: %s", name, strerror (errno)); + + ret = ioctl (fd, RAID_VERSION, &version); + if (ret != 0) + grub_util_error ("ioctl RAID_VERSION error: %s", strerror (errno)); + + if (version.major != 0 || version.minor != 90) + grub_util_error ("unsupported RAID version: %d.%d", + version.major, version.minor); + + ret = ioctl (fd, GET_ARRAY_INFO, &info); + if (ret != 0) + grub_util_error ("ioctl GET_ARRAY_INFO error: %s", strerror (errno)); + + devicelist = xmalloc ((info.nr_disks + 1) * sizeof (char *)); + + for (i = 0, j = 0; i . + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +/* Module. */ +struct mod_list +{ + const char *name; + struct mod_list *next; +}; + +/* Dependency. */ +struct dep_list +{ + const char *name; + struct mod_list *list; + struct dep_list *next; +}; + +static char buf[1024]; + +static void +free_mod_list (struct mod_list *head) +{ + while (head) + { + struct mod_list *next; + + next = head->next; + free ((void *) head->name); + free (head); + head = next; + } +} + +static void +free_dep_list (struct dep_list *head) +{ + while (head) + { + struct dep_list *next; + + next = head->next; + free ((void *) head->name); + free_mod_list (head->list); + free (head); + head = next; + } +} + +/* Read the list of dependencies. */ +static struct dep_list * +read_dep_list (FILE *fp) +{ + struct dep_list *dep_list = 0; + + while (fgets (buf, sizeof (buf), fp)) + { + char *p; + struct dep_list *dep; + + /* Get the target name. */ + p = strchr (buf, ':'); + if (! p) + grub_util_error ("invalid line format: %s", buf); + + *p++ = '\0'; + + dep = xmalloc (sizeof (*dep)); + dep->name = xstrdup (buf); + dep->list = 0; + + dep->next = dep_list; + dep_list = dep; + + /* Add dependencies. */ + while (*p) + { + struct mod_list *mod; + char *name; + + /* Skip whitespace. */ + while (*p && isspace (*p)) + p++; + + if (! *p) + break; + + name = p; + + /* Skip non-whitespace. */ + while (*p && ! isspace (*p)) + p++; + + *p++ = '\0'; + + mod = (struct mod_list *) xmalloc (sizeof (*mod)); + mod->name = xstrdup (name); + mod->next = dep->list; + dep->list = mod; + } + } + + return dep_list; +} + +static char * +get_module_name (const char *str) +{ + char *base; + char *ext; + + base = strrchr (str, '/'); + if (! base) + base = (char *) str; + else + base++; + + ext = strrchr (base, '.'); + if (ext && strcmp (ext, ".mod") == 0) + { + char *name; + + name = xmalloc (ext - base + 1); + memcpy (name, base, ext - base); + name[ext - base] = '\0'; + return name; + } + + return xstrdup (base); +} + +static char * +get_module_path (const char *prefix, const char *str) +{ + char *dir; + char *base; + char *ext; + char *ret; + + ext = strrchr (str, '.'); + if (ext && strcmp (ext, ".mod") == 0) + base = xstrdup (str); + else + { + base = xmalloc (strlen (str) + 4 + 1); + sprintf (base, "%s.mod", str); + } + + dir = strchr (str, '/'); + if (dir) + return base; + + ret = grub_util_get_path (prefix, base); + free (base); + return ret; +} + +static void +add_module (const char *dir, + struct dep_list *dep_list, + struct mod_list **mod_head, + struct grub_util_path_list **path_head, + const char *name) +{ + char *mod_name; + struct grub_util_path_list *path; + struct mod_list *mod; + struct dep_list *dep; + + mod_name = get_module_name (name); + + /* Check if the module has already been added. */ + for (mod = *mod_head; mod; mod = mod->next) + if (strcmp (mod->name, mod_name) == 0) + { + free (mod_name); + return; + } + + /* Resolve dependencies. */ + for (dep = dep_list; dep; dep = dep->next) + if (strcmp (dep->name, mod_name) == 0) + { + for (mod = dep->list; mod; mod = mod->next) + add_module (dir, dep_list, mod_head, path_head, mod->name); + + break; + } + + /* Add this module. */ + mod = (struct mod_list *) xmalloc (sizeof (*mod)); + mod->name = mod_name; + mod->next = *mod_head; + *mod_head = mod; + + /* Add this path. */ + path = (struct grub_util_path_list *) xmalloc (sizeof (*path)); + path->name = get_module_path (dir, name); + path->next = *path_head; + *path_head = path; +} + +struct grub_util_path_list * +grub_util_resolve_dependencies (const char *prefix, + const char *dep_list_file, + char *modules[]) +{ + char *path; + FILE *fp; + struct dep_list *dep_list; + struct mod_list *mod_list = 0; + struct grub_util_path_list *path_list = 0; + + path = grub_util_get_path (prefix, dep_list_file); + fp = fopen (path, "r"); + if (! fp) + grub_util_error ("cannot open %s", path); + + free (path); + dep_list = read_dep_list (fp); + fclose (fp); + + while (*modules) + { + add_module (prefix, dep_list, &mod_list, &path_list, *modules); + modules++; + } + + free_dep_list (dep_list); + free_mod_list (mod_list); + + { /* Reverse the path_list */ + struct grub_util_path_list *p, *prev, *next; + + for (p = path_list, prev = NULL; p; p = next) + { + next = p->next; + p->next = prev; + prev = p; + } + + return prev; + } +} diff --git a/util/update-grub_lib.in b/util/update-grub_lib.in new file mode 100644 index 0000000..998452e --- /dev/null +++ b/util/update-grub_lib.in @@ -0,0 +1,23 @@ +# stub for new grub-mkconfig_lib +# Copyright (C) 2007,2008 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ + +. ${libdir}/grub/grub-mkconfig_lib + +grub_warn "update-grub_lib is deprecated, use grub-mkconfig_lib instead" -- cgit v1.2.3