diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:29:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:29:51 +0000 |
commit | 6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e (patch) | |
tree | 32451fa3cdd9321fb2591fada9891b2cb70a9cd1 /util | |
parent | Initial commit. (diff) | |
download | grub2-upstream.tar.xz grub2-upstream.zip |
Adding upstream version 2.06.upstream/2.06upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
75 files changed, 26697 insertions, 0 deletions
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..0cad59b --- /dev/null +++ b/util/bash-completion.d/Makefile.in @@ -0,0 +1,1443 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 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@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +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 +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/00gnulib.m4 \ + $(top_srcdir)/m4/__inline.m4 \ + $(top_srcdir)/m4/absolute-header.m4 $(top_srcdir)/m4/alloca.m4 \ + $(top_srcdir)/m4/argp.m4 $(top_srcdir)/m4/base64.m4 \ + $(top_srcdir)/m4/btowc.m4 $(top_srcdir)/m4/builtin-expect.m4 \ + $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/close.m4 \ + $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/dirent_h.m4 \ + $(top_srcdir)/m4/dirfd.m4 $(top_srcdir)/m4/dirname.m4 \ + $(top_srcdir)/m4/double-slash-root.m4 $(top_srcdir)/m4/dup2.m4 \ + $(top_srcdir)/m4/eealloc.m4 $(top_srcdir)/m4/errno_h.m4 \ + $(top_srcdir)/m4/error.m4 $(top_srcdir)/m4/exponentd.m4 \ + $(top_srcdir)/m4/extensions.m4 \ + $(top_srcdir)/m4/extern-inline.m4 $(top_srcdir)/m4/fchdir.m4 \ + $(top_srcdir)/m4/fcntl-o.m4 $(top_srcdir)/m4/fcntl.m4 \ + $(top_srcdir)/m4/fcntl_h.m4 $(top_srcdir)/m4/filenamecat.m4 \ + $(top_srcdir)/m4/flexmember.m4 $(top_srcdir)/m4/float_h.m4 \ + $(top_srcdir)/m4/fnmatch.m4 $(top_srcdir)/m4/fnmatch_h.m4 \ + $(top_srcdir)/m4/fstat.m4 $(top_srcdir)/m4/getcwd.m4 \ + $(top_srcdir)/m4/getdelim.m4 $(top_srcdir)/m4/getdtablesize.m4 \ + $(top_srcdir)/m4/getline.m4 $(top_srcdir)/m4/getopt.m4 \ + $(top_srcdir)/m4/getprogname.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/host-cpu-c-abi.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/largefile.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libunistring-base.m4 \ + $(top_srcdir)/m4/limits-h.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/locale_h.m4 \ + $(top_srcdir)/m4/localeconv.m4 $(top_srcdir)/m4/lock.m4 \ + $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/lstat.m4 \ + $(top_srcdir)/m4/malloc.m4 $(top_srcdir)/m4/malloca.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/mbswidth.m4 $(top_srcdir)/m4/mbtowc.m4 \ + $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/mempcpy.m4 \ + $(top_srcdir)/m4/memrchr.m4 $(top_srcdir)/m4/mmap-anon.m4 \ + $(top_srcdir)/m4/mode_t.m4 $(top_srcdir)/m4/msvc-inval.m4 \ + $(top_srcdir)/m4/msvc-nothrow.m4 $(top_srcdir)/m4/multiarch.m4 \ + $(top_srcdir)/m4/nl_langinfo.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/nocrash.m4 $(top_srcdir)/m4/off_t.m4 \ + $(top_srcdir)/m4/open-cloexec.m4 $(top_srcdir)/m4/open.m4 \ + $(top_srcdir)/m4/openat.m4 $(top_srcdir)/m4/pathmax.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/printf.m4 \ + $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/m4/pthread_rwlock_rdlock.m4 \ + $(top_srcdir)/m4/rawmemchr.m4 $(top_srcdir)/m4/realloc.m4 \ + $(top_srcdir)/m4/regex.m4 $(top_srcdir)/m4/save-cwd.m4 \ + $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/sleep.m4 \ + $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-time.m4 \ + $(top_srcdir)/m4/stat.m4 $(top_srcdir)/m4/stdalign.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/strdup.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_socket_h.m4 \ + $(top_srcdir)/m4/sys_stat_h.m4 $(top_srcdir)/m4/sys_types_h.m4 \ + $(top_srcdir)/m4/sysexits.m4 $(top_srcdir)/m4/threadlib.m4 \ + $(top_srcdir)/m4/time_h.m4 $(top_srcdir)/m4/unistd-safer.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/wcwidth.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) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config-util.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(bashcompletiondir)" +DATA = $(bashcompletion_DATA) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +ALLOCA_H = @ALLOCA_H@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +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@ +BOOT_TIME_STATS = @BOOT_TIME_STATS@ +BSS_START_SYMBOL = @BSS_START_SYMBOL@ +BUILD_CC = @BUILD_CC@ +BUILD_CFLAGS = @BUILD_CFLAGS@ +BUILD_CPPFLAGS = @BUILD_CPPFLAGS@ +BUILD_EXEEXT = @BUILD_EXEEXT@ +BUILD_FREETYPE_CFLAGS = @BUILD_FREETYPE_CFLAGS@ +BUILD_FREETYPE_LIBS = @BUILD_FREETYPE_LIBS@ +BUILD_LDFLAGS = @BUILD_LDFLAGS@ +BUILD_LIBM = @BUILD_LIBM@ +BUILD_SHEBANG = @BUILD_SHEBANG@ +BUILD_SIZEOF_LONG = @BUILD_SIZEOF_LONG@ +BUILD_SIZEOF_VOID_P = @BUILD_SIZEOF_VOID_P@ +BUILD_WORDS_BIGENDIAN = @BUILD_WORDS_BIGENDIAN@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CMP = @CMP@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISK_CACHE_STATS = @DISK_CACHE_STATS@ +DJVU_FONT_SOURCE = @DJVU_FONT_SOURCE@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EFIEMU64_LINK_FORMAT = @EFIEMU64_LINK_FORMAT@ +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_CFLAGS = @FREETYPE_CFLAGS@ +FREETYPE_LIBS = @FREETYPE_LIBS@ +GETOPT_CDEFS_H = @GETOPT_CDEFS_H@ +GETOPT_H = @GETOPT_H@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLIBC21 = @GLIBC21@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNULIB_ALPHASORT = @GNULIB_ALPHASORT@ +GNULIB_ATOLL = @GNULIB_ATOLL@ +GNULIB_BTOWC = @GNULIB_BTOWC@ +GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@ +GNULIB_CANONICALIZE_FILE_NAME = @GNULIB_CANONICALIZE_FILE_NAME@ +GNULIB_CHDIR = @GNULIB_CHDIR@ +GNULIB_CHOWN = @GNULIB_CHOWN@ +GNULIB_CLOSE = @GNULIB_CLOSE@ +GNULIB_CLOSEDIR = @GNULIB_CLOSEDIR@ +GNULIB_CTIME = @GNULIB_CTIME@ +GNULIB_DIRFD = @GNULIB_DIRFD@ +GNULIB_DPRINTF = @GNULIB_DPRINTF@ +GNULIB_DUP = @GNULIB_DUP@ +GNULIB_DUP2 = @GNULIB_DUP2@ +GNULIB_DUP3 = @GNULIB_DUP3@ +GNULIB_DUPLOCALE = @GNULIB_DUPLOCALE@ +GNULIB_ENVIRON = @GNULIB_ENVIRON@ +GNULIB_EUIDACCESS = @GNULIB_EUIDACCESS@ +GNULIB_EXPLICIT_BZERO = @GNULIB_EXPLICIT_BZERO@ +GNULIB_FACCESSAT = @GNULIB_FACCESSAT@ +GNULIB_FCHDIR = @GNULIB_FCHDIR@ +GNULIB_FCHMODAT = @GNULIB_FCHMODAT@ +GNULIB_FCHOWNAT = @GNULIB_FCHOWNAT@ +GNULIB_FCLOSE = @GNULIB_FCLOSE@ +GNULIB_FCNTL = @GNULIB_FCNTL@ +GNULIB_FDATASYNC = @GNULIB_FDATASYNC@ +GNULIB_FDOPEN = @GNULIB_FDOPEN@ +GNULIB_FDOPENDIR = @GNULIB_FDOPENDIR@ +GNULIB_FFLUSH = @GNULIB_FFLUSH@ +GNULIB_FFS = @GNULIB_FFS@ +GNULIB_FFSL = @GNULIB_FFSL@ +GNULIB_FFSLL = @GNULIB_FFSLL@ +GNULIB_FGETC = @GNULIB_FGETC@ +GNULIB_FGETS = @GNULIB_FGETS@ +GNULIB_FNMATCH = @GNULIB_FNMATCH@ +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_FREAD = @GNULIB_FREAD@ +GNULIB_FREOPEN = @GNULIB_FREOPEN@ +GNULIB_FSCANF = @GNULIB_FSCANF@ +GNULIB_FSEEK = @GNULIB_FSEEK@ +GNULIB_FSEEKO = @GNULIB_FSEEKO@ +GNULIB_FSTAT = @GNULIB_FSTAT@ +GNULIB_FSTATAT = @GNULIB_FSTATAT@ +GNULIB_FSYNC = @GNULIB_FSYNC@ +GNULIB_FTELL = @GNULIB_FTELL@ +GNULIB_FTELLO = @GNULIB_FTELLO@ +GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@ +GNULIB_FUTIMENS = @GNULIB_FUTIMENS@ +GNULIB_FWRITE = @GNULIB_FWRITE@ +GNULIB_GETC = @GNULIB_GETC@ +GNULIB_GETCHAR = @GNULIB_GETCHAR@ +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_GETPASS = @GNULIB_GETPASS@ +GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@ +GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@ +GNULIB_GETUSERSHELL = @GNULIB_GETUSERSHELL@ +GNULIB_GL_UNISTD_H_GETOPT = @GNULIB_GL_UNISTD_H_GETOPT@ +GNULIB_GRANTPT = @GNULIB_GRANTPT@ +GNULIB_GROUP_MEMBER = @GNULIB_GROUP_MEMBER@ +GNULIB_ISATTY = @GNULIB_ISATTY@ +GNULIB_ISWBLANK = @GNULIB_ISWBLANK@ +GNULIB_ISWCTYPE = @GNULIB_ISWCTYPE@ +GNULIB_LCHMOD = @GNULIB_LCHMOD@ +GNULIB_LCHOWN = @GNULIB_LCHOWN@ +GNULIB_LINK = @GNULIB_LINK@ +GNULIB_LINKAT = @GNULIB_LINKAT@ +GNULIB_LOCALECONV = @GNULIB_LOCALECONV@ +GNULIB_LOCALENAME = @GNULIB_LOCALENAME@ +GNULIB_LOCALTIME = @GNULIB_LOCALTIME@ +GNULIB_LSEEK = @GNULIB_LSEEK@ +GNULIB_LSTAT = @GNULIB_LSTAT@ +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_MBTOWC = @GNULIB_MBTOWC@ +GNULIB_MEMCHR = @GNULIB_MEMCHR@ +GNULIB_MEMMEM = @GNULIB_MEMMEM@ +GNULIB_MEMPCPY = @GNULIB_MEMPCPY@ +GNULIB_MEMRCHR = @GNULIB_MEMRCHR@ +GNULIB_MKDIRAT = @GNULIB_MKDIRAT@ +GNULIB_MKDTEMP = @GNULIB_MKDTEMP@ +GNULIB_MKFIFO = @GNULIB_MKFIFO@ +GNULIB_MKFIFOAT = @GNULIB_MKFIFOAT@ +GNULIB_MKNOD = @GNULIB_MKNOD@ +GNULIB_MKNODAT = @GNULIB_MKNODAT@ +GNULIB_MKOSTEMP = @GNULIB_MKOSTEMP@ +GNULIB_MKOSTEMPS = @GNULIB_MKOSTEMPS@ +GNULIB_MKSTEMP = @GNULIB_MKSTEMP@ +GNULIB_MKSTEMPS = @GNULIB_MKSTEMPS@ +GNULIB_MKTIME = @GNULIB_MKTIME@ +GNULIB_NANOSLEEP = @GNULIB_NANOSLEEP@ +GNULIB_NL_LANGINFO = @GNULIB_NL_LANGINFO@ +GNULIB_NONBLOCKING = @GNULIB_NONBLOCKING@ +GNULIB_OBSTACK_PRINTF = @GNULIB_OBSTACK_PRINTF@ +GNULIB_OBSTACK_PRINTF_POSIX = @GNULIB_OBSTACK_PRINTF_POSIX@ +GNULIB_OPEN = @GNULIB_OPEN@ +GNULIB_OPENAT = @GNULIB_OPENAT@ +GNULIB_OPENDIR = @GNULIB_OPENDIR@ +GNULIB_OVERRIDES_STRUCT_STAT = @GNULIB_OVERRIDES_STRUCT_STAT@ +GNULIB_OVERRIDES_WINT_T = @GNULIB_OVERRIDES_WINT_T@ +GNULIB_PCLOSE = @GNULIB_PCLOSE@ +GNULIB_PERROR = @GNULIB_PERROR@ +GNULIB_PIPE = @GNULIB_PIPE@ +GNULIB_PIPE2 = @GNULIB_PIPE2@ +GNULIB_POPEN = @GNULIB_POPEN@ +GNULIB_POSIX_OPENPT = @GNULIB_POSIX_OPENPT@ +GNULIB_PREAD = @GNULIB_PREAD@ +GNULIB_PRINTF = @GNULIB_PRINTF@ +GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@ +GNULIB_PTSNAME = @GNULIB_PTSNAME@ +GNULIB_PTSNAME_R = @GNULIB_PTSNAME_R@ +GNULIB_PUTC = @GNULIB_PUTC@ +GNULIB_PUTCHAR = @GNULIB_PUTCHAR@ +GNULIB_PUTENV = @GNULIB_PUTENV@ +GNULIB_PUTS = @GNULIB_PUTS@ +GNULIB_PWRITE = @GNULIB_PWRITE@ +GNULIB_QSORT_R = @GNULIB_QSORT_R@ +GNULIB_RANDOM = @GNULIB_RANDOM@ +GNULIB_RANDOM_R = @GNULIB_RANDOM_R@ +GNULIB_RAWMEMCHR = @GNULIB_RAWMEMCHR@ +GNULIB_READ = @GNULIB_READ@ +GNULIB_READDIR = @GNULIB_READDIR@ +GNULIB_READLINK = @GNULIB_READLINK@ +GNULIB_READLINKAT = @GNULIB_READLINKAT@ +GNULIB_REALLOCARRAY = @GNULIB_REALLOCARRAY@ +GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@ +GNULIB_REALPATH = @GNULIB_REALPATH@ +GNULIB_REMOVE = @GNULIB_REMOVE@ +GNULIB_RENAME = @GNULIB_RENAME@ +GNULIB_RENAMEAT = @GNULIB_RENAMEAT@ +GNULIB_REWINDDIR = @GNULIB_REWINDDIR@ +GNULIB_RMDIR = @GNULIB_RMDIR@ +GNULIB_RPMATCH = @GNULIB_RPMATCH@ +GNULIB_SCANDIR = @GNULIB_SCANDIR@ +GNULIB_SCANF = @GNULIB_SCANF@ +GNULIB_SECURE_GETENV = @GNULIB_SECURE_GETENV@ +GNULIB_SETENV = @GNULIB_SETENV@ +GNULIB_SETHOSTNAME = @GNULIB_SETHOSTNAME@ +GNULIB_SETLOCALE = @GNULIB_SETLOCALE@ +GNULIB_SLEEP = @GNULIB_SLEEP@ +GNULIB_SNPRINTF = @GNULIB_SNPRINTF@ +GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@ +GNULIB_STAT = @GNULIB_STAT@ +GNULIB_STDIO_H_NONBLOCKING = @GNULIB_STDIO_H_NONBLOCKING@ +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_STRERROR_R = @GNULIB_STRERROR_R@ +GNULIB_STRFTIME = @GNULIB_STRFTIME@ +GNULIB_STRNCAT = @GNULIB_STRNCAT@ +GNULIB_STRNDUP = @GNULIB_STRNDUP@ +GNULIB_STRNLEN = @GNULIB_STRNLEN@ +GNULIB_STRPBRK = @GNULIB_STRPBRK@ +GNULIB_STRPTIME = @GNULIB_STRPTIME@ +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_SYSTEM_POSIX = @GNULIB_SYSTEM_POSIX@ +GNULIB_TIMEGM = @GNULIB_TIMEGM@ +GNULIB_TIME_R = @GNULIB_TIME_R@ +GNULIB_TIME_RZ = @GNULIB_TIME_RZ@ +GNULIB_TMPFILE = @GNULIB_TMPFILE@ +GNULIB_TOWCTRANS = @GNULIB_TOWCTRANS@ +GNULIB_TRUNCATE = @GNULIB_TRUNCATE@ +GNULIB_TTYNAME_R = @GNULIB_TTYNAME_R@ +GNULIB_TZSET = @GNULIB_TZSET@ +GNULIB_UNISTD_H_NONBLOCKING = @GNULIB_UNISTD_H_NONBLOCKING@ +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_UTIMENSAT = @GNULIB_UTIMENSAT@ +GNULIB_VASPRINTF = @GNULIB_VASPRINTF@ +GNULIB_VDPRINTF = @GNULIB_VDPRINTF@ +GNULIB_VFPRINTF = @GNULIB_VFPRINTF@ +GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@ +GNULIB_VFSCANF = @GNULIB_VFSCANF@ +GNULIB_VPRINTF = @GNULIB_VPRINTF@ +GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@ +GNULIB_VSCANF = @GNULIB_VSCANF@ +GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@ +GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@ +GNULIB_WCPCPY = @GNULIB_WCPCPY@ +GNULIB_WCPNCPY = @GNULIB_WCPNCPY@ +GNULIB_WCRTOMB = @GNULIB_WCRTOMB@ +GNULIB_WCSCASECMP = @GNULIB_WCSCASECMP@ +GNULIB_WCSCAT = @GNULIB_WCSCAT@ +GNULIB_WCSCHR = @GNULIB_WCSCHR@ +GNULIB_WCSCMP = @GNULIB_WCSCMP@ +GNULIB_WCSCOLL = @GNULIB_WCSCOLL@ +GNULIB_WCSCPY = @GNULIB_WCSCPY@ +GNULIB_WCSCSPN = @GNULIB_WCSCSPN@ +GNULIB_WCSDUP = @GNULIB_WCSDUP@ +GNULIB_WCSFTIME = @GNULIB_WCSFTIME@ +GNULIB_WCSLEN = @GNULIB_WCSLEN@ +GNULIB_WCSNCASECMP = @GNULIB_WCSNCASECMP@ +GNULIB_WCSNCAT = @GNULIB_WCSNCAT@ +GNULIB_WCSNCMP = @GNULIB_WCSNCMP@ +GNULIB_WCSNCPY = @GNULIB_WCSNCPY@ +GNULIB_WCSNLEN = @GNULIB_WCSNLEN@ +GNULIB_WCSNRTOMBS = @GNULIB_WCSNRTOMBS@ +GNULIB_WCSPBRK = @GNULIB_WCSPBRK@ +GNULIB_WCSRCHR = @GNULIB_WCSRCHR@ +GNULIB_WCSRTOMBS = @GNULIB_WCSRTOMBS@ +GNULIB_WCSSPN = @GNULIB_WCSSPN@ +GNULIB_WCSSTR = @GNULIB_WCSSTR@ +GNULIB_WCSTOK = @GNULIB_WCSTOK@ +GNULIB_WCSWIDTH = @GNULIB_WCSWIDTH@ +GNULIB_WCSXFRM = @GNULIB_WCSXFRM@ +GNULIB_WCTOB = @GNULIB_WCTOB@ +GNULIB_WCTOMB = @GNULIB_WCTOMB@ +GNULIB_WCTRANS = @GNULIB_WCTRANS@ +GNULIB_WCTYPE = @GNULIB_WCTYPE@ +GNULIB_WCWIDTH = @GNULIB_WCWIDTH@ +GNULIB_WMEMCHR = @GNULIB_WMEMCHR@ +GNULIB_WMEMCMP = @GNULIB_WMEMCMP@ +GNULIB_WMEMCPY = @GNULIB_WMEMCPY@ +GNULIB_WMEMMOVE = @GNULIB_WMEMMOVE@ +GNULIB_WMEMSET = @GNULIB_WMEMSET@ +GNULIB_WRITE = @GNULIB_WRITE@ +GNULIB__EXIT = @GNULIB__EXIT@ +GREP = @GREP@ +GRUB_BOOT_MACHINE_LINK_ADDR = @GRUB_BOOT_MACHINE_LINK_ADDR@ +GRUB_PLATFORM = @GRUB_PLATFORM@ +GRUB_TARGET_CPU = @GRUB_TARGET_CPU@ +HAVE_ALPHASORT = @HAVE_ALPHASORT@ +HAVE_ASM_USCORE = @HAVE_ASM_USCORE@ +HAVE_ATOLL = @HAVE_ATOLL@ +HAVE_BTOWC = @HAVE_BTOWC@ +HAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@ +HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@ +HAVE_CHOWN = @HAVE_CHOWN@ +HAVE_CLOSEDIR = @HAVE_CLOSEDIR@ +HAVE_CRTDEFS_H = @HAVE_CRTDEFS_H@ +HAVE_CXX = @HAVE_CXX@ +HAVE_DECL_DIRFD = @HAVE_DECL_DIRFD@ +HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@ +HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@ +HAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@ +HAVE_DECL_FDOPENDIR = @HAVE_DECL_FDOPENDIR@ +HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@ +HAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@ +HAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@ +HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@ +HAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@ +HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@ +HAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@ +HAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@ +HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@ +HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@ +HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@ +HAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@ +HAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@ +HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@ +HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@ +HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@ +HAVE_DECL_SETENV = @HAVE_DECL_SETENV@ +HAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@ +HAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@ +HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@ +HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@ +HAVE_DECL_STRERROR_R = @HAVE_DECL_STRERROR_R@ +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_TRUNCATE = @HAVE_DECL_TRUNCATE@ +HAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@ +HAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@ +HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@ +HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@ +HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@ +HAVE_DIRENT_H = @HAVE_DIRENT_H@ +HAVE_DPRINTF = @HAVE_DPRINTF@ +HAVE_DUP2 = @HAVE_DUP2@ +HAVE_DUP3 = @HAVE_DUP3@ +HAVE_DUPLOCALE = @HAVE_DUPLOCALE@ +HAVE_EUIDACCESS = @HAVE_EUIDACCESS@ +HAVE_EXPLICIT_BZERO = @HAVE_EXPLICIT_BZERO@ +HAVE_FACCESSAT = @HAVE_FACCESSAT@ +HAVE_FCHDIR = @HAVE_FCHDIR@ +HAVE_FCHMODAT = @HAVE_FCHMODAT@ +HAVE_FCHOWNAT = @HAVE_FCHOWNAT@ +HAVE_FCNTL = @HAVE_FCNTL@ +HAVE_FDATASYNC = @HAVE_FDATASYNC@ +HAVE_FDOPENDIR = @HAVE_FDOPENDIR@ +HAVE_FEATURES_H = @HAVE_FEATURES_H@ +HAVE_FFS = @HAVE_FFS@ +HAVE_FFSL = @HAVE_FFSL@ +HAVE_FFSLL = @HAVE_FFSLL@ +HAVE_FNMATCH = @HAVE_FNMATCH@ +HAVE_FNMATCH_H = @HAVE_FNMATCH_H@ +HAVE_FONT_SOURCE = @HAVE_FONT_SOURCE@ +HAVE_FREELOCALE = @HAVE_FREELOCALE@ +HAVE_FSEEKO = @HAVE_FSEEKO@ +HAVE_FSTATAT = @HAVE_FSTATAT@ +HAVE_FSYNC = @HAVE_FSYNC@ +HAVE_FTELLO = @HAVE_FTELLO@ +HAVE_FTRUNCATE = @HAVE_FTRUNCATE@ +HAVE_FUTIMENS = @HAVE_FUTIMENS@ +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_GETPASS = @HAVE_GETPASS@ +HAVE_GETSUBOPT = @HAVE_GETSUBOPT@ +HAVE_GRANTPT = @HAVE_GRANTPT@ +HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@ +HAVE_INTTYPES_H = @HAVE_INTTYPES_H@ +HAVE_ISWBLANK = @HAVE_ISWBLANK@ +HAVE_ISWCNTRL = @HAVE_ISWCNTRL@ +HAVE_LANGINFO_ALTMON = @HAVE_LANGINFO_ALTMON@ +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_LCHMOD = @HAVE_LCHMOD@ +HAVE_LCHOWN = @HAVE_LCHOWN@ +HAVE_LINK = @HAVE_LINK@ +HAVE_LINKAT = @HAVE_LINKAT@ +HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@ +HAVE_LSTAT = @HAVE_LSTAT@ +HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@ +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_MKDIRAT = @HAVE_MKDIRAT@ +HAVE_MKDTEMP = @HAVE_MKDTEMP@ +HAVE_MKFIFO = @HAVE_MKFIFO@ +HAVE_MKFIFOAT = @HAVE_MKFIFOAT@ +HAVE_MKNOD = @HAVE_MKNOD@ +HAVE_MKNODAT = @HAVE_MKNODAT@ +HAVE_MKOSTEMP = @HAVE_MKOSTEMP@ +HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@ +HAVE_MKSTEMP = @HAVE_MKSTEMP@ +HAVE_MKSTEMPS = @HAVE_MKSTEMPS@ +HAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@ +HAVE_NANOSLEEP = @HAVE_NANOSLEEP@ +HAVE_NEWLOCALE = @HAVE_NEWLOCALE@ +HAVE_NL_LANGINFO = @HAVE_NL_LANGINFO@ +HAVE_OPENAT = @HAVE_OPENAT@ +HAVE_OPENDIR = @HAVE_OPENDIR@ +HAVE_OS_H = @HAVE_OS_H@ +HAVE_PCLOSE = @HAVE_PCLOSE@ +HAVE_PIPE = @HAVE_PIPE@ +HAVE_PIPE2 = @HAVE_PIPE2@ +HAVE_POPEN = @HAVE_POPEN@ +HAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@ +HAVE_PREAD = @HAVE_PREAD@ +HAVE_PTSNAME = @HAVE_PTSNAME@ +HAVE_PTSNAME_R = @HAVE_PTSNAME_R@ +HAVE_PWRITE = @HAVE_PWRITE@ +HAVE_QSORT_R = @HAVE_QSORT_R@ +HAVE_RANDOM = @HAVE_RANDOM@ +HAVE_RANDOM_H = @HAVE_RANDOM_H@ +HAVE_RANDOM_R = @HAVE_RANDOM_R@ +HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@ +HAVE_READDIR = @HAVE_READDIR@ +HAVE_READLINK = @HAVE_READLINK@ +HAVE_READLINKAT = @HAVE_READLINKAT@ +HAVE_REALLOCARRAY = @HAVE_REALLOCARRAY@ +HAVE_REALPATH = @HAVE_REALPATH@ +HAVE_RENAMEAT = @HAVE_RENAMEAT@ +HAVE_REWINDDIR = @HAVE_REWINDDIR@ +HAVE_RPMATCH = @HAVE_RPMATCH@ +HAVE_SCANDIR = @HAVE_SCANDIR@ +HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@ +HAVE_SETENV = @HAVE_SETENV@ +HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@ +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_STRINGS_H = @HAVE_STRINGS_H@ +HAVE_STRPBRK = @HAVE_STRPBRK@ +HAVE_STRPTIME = @HAVE_STRPTIME@ +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_CDEFS_H = @HAVE_SYS_CDEFS_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_TIMEGM = @HAVE_TIMEGM@ +HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@ +HAVE_TZSET = @HAVE_TZSET@ +HAVE_UNISTD_H = @HAVE_UNISTD_H@ +HAVE_UNLINKAT = @HAVE_UNLINKAT@ +HAVE_UNLOCKPT = @HAVE_UNLOCKPT@ +HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@ +HAVE_USLEEP = @HAVE_USLEEP@ +HAVE_UTIMENSAT = @HAVE_UTIMENSAT@ +HAVE_VASPRINTF = @HAVE_VASPRINTF@ +HAVE_VDPRINTF = @HAVE_VDPRINTF@ +HAVE_WCHAR_H = @HAVE_WCHAR_H@ +HAVE_WCHAR_T = @HAVE_WCHAR_T@ +HAVE_WCPCPY = @HAVE_WCPCPY@ +HAVE_WCPNCPY = @HAVE_WCPNCPY@ +HAVE_WCRTOMB = @HAVE_WCRTOMB@ +HAVE_WCSCASECMP = @HAVE_WCSCASECMP@ +HAVE_WCSCAT = @HAVE_WCSCAT@ +HAVE_WCSCHR = @HAVE_WCSCHR@ +HAVE_WCSCMP = @HAVE_WCSCMP@ +HAVE_WCSCOLL = @HAVE_WCSCOLL@ +HAVE_WCSCPY = @HAVE_WCSCPY@ +HAVE_WCSCSPN = @HAVE_WCSCSPN@ +HAVE_WCSDUP = @HAVE_WCSDUP@ +HAVE_WCSFTIME = @HAVE_WCSFTIME@ +HAVE_WCSLEN = @HAVE_WCSLEN@ +HAVE_WCSNCASECMP = @HAVE_WCSNCASECMP@ +HAVE_WCSNCAT = @HAVE_WCSNCAT@ +HAVE_WCSNCMP = @HAVE_WCSNCMP@ +HAVE_WCSNCPY = @HAVE_WCSNCPY@ +HAVE_WCSNLEN = @HAVE_WCSNLEN@ +HAVE_WCSNRTOMBS = @HAVE_WCSNRTOMBS@ +HAVE_WCSPBRK = @HAVE_WCSPBRK@ +HAVE_WCSRCHR = @HAVE_WCSRCHR@ +HAVE_WCSRTOMBS = @HAVE_WCSRTOMBS@ +HAVE_WCSSPN = @HAVE_WCSSPN@ +HAVE_WCSSTR = @HAVE_WCSSTR@ +HAVE_WCSTOK = @HAVE_WCSTOK@ +HAVE_WCSWIDTH = @HAVE_WCSWIDTH@ +HAVE_WCSXFRM = @HAVE_WCSXFRM@ +HAVE_WCTRANS_T = @HAVE_WCTRANS_T@ +HAVE_WCTYPE_H = @HAVE_WCTYPE_H@ +HAVE_WCTYPE_T = @HAVE_WCTYPE_T@ +HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ +HAVE_WINT_T = @HAVE_WINT_T@ +HAVE_WMEMCHR = @HAVE_WMEMCHR@ +HAVE_WMEMCMP = @HAVE_WMEMCMP@ +HAVE_WMEMCPY = @HAVE_WMEMCPY@ +HAVE_WMEMMOVE = @HAVE_WMEMMOVE@ +HAVE_WMEMSET = @HAVE_WMEMSET@ +HAVE_XLOCALE_H = @HAVE_XLOCALE_H@ +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@ +LIBDEVMAPPER = @LIBDEVMAPPER@ +LIBGEOM = @LIBGEOM@ +LIBGNU_LIBDEPS = @LIBGNU_LIBDEPS@ +LIBGNU_LTLIBDEPS = @LIBGNU_LTLIBDEPS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBLZMA = @LIBLZMA@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBNVPAIR = @LIBNVPAIR@ +LIBOBJS = @LIBOBJS@ +LIBPCIACCESS = @LIBPCIACCESS@ +LIBPTH = @LIBPTH@ +LIBPTH_PREFIX = @LIBPTH_PREFIX@ +LIBS = @LIBS@ +LIBSDL = @LIBSDL@ +LIBTHREAD = @LIBTHREAD@ +LIBUNISTRING_UNITYPES_H = @LIBUNISTRING_UNITYPES_H@ +LIBUNISTRING_UNIWIDTH_H = @LIBUNISTRING_UNIWIDTH_H@ +LIBUTIL = @LIBUTIL@ +LIBZFS = @LIBZFS@ +LIMITS_H = @LIMITS_H@ +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@ +LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBPTH = @LTLIBPTH@ +LTLIBTHREAD = @LTLIBTHREAD@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NEXT_AS_FIRST_DIRECTIVE_DIRENT_H = @NEXT_AS_FIRST_DIRECTIVE_DIRENT_H@ +NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@ +NEXT_AS_FIRST_DIRECTIVE_FCNTL_H = @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@ +NEXT_AS_FIRST_DIRECTIVE_FLOAT_H = @NEXT_AS_FIRST_DIRECTIVE_FLOAT_H@ +NEXT_AS_FIRST_DIRECTIVE_FNMATCH_H = @NEXT_AS_FIRST_DIRECTIVE_FNMATCH_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_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@ +NEXT_AS_FIRST_DIRECTIVE_LOCALE_H = @NEXT_AS_FIRST_DIRECTIVE_LOCALE_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_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@ +NEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_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_DIRENT_H = @NEXT_DIRENT_H@ +NEXT_ERRNO_H = @NEXT_ERRNO_H@ +NEXT_FCNTL_H = @NEXT_FCNTL_H@ +NEXT_FLOAT_H = @NEXT_FLOAT_H@ +NEXT_FNMATCH_H = @NEXT_FNMATCH_H@ +NEXT_GETOPT_H = @NEXT_GETOPT_H@ +NEXT_LANGINFO_H = @NEXT_LANGINFO_H@ +NEXT_LIMITS_H = @NEXT_LIMITS_H@ +NEXT_LOCALE_H = @NEXT_LOCALE_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_STAT_H = @NEXT_SYS_STAT_H@ +NEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@ +NEXT_TIME_H = @NEXT_TIME_H@ +NEXT_UNISTD_H = @NEXT_UNISTD_H@ +NEXT_WCHAR_H = @NEXT_WCHAR_H@ +NEXT_WCTYPE_H = @NEXT_WCTYPE_H@ +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@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POSUB = @POSUB@ +PRAGMA_COLUMNS = @PRAGMA_COLUMNS@ +PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@ +PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@ +PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +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_CLOSEDIR = @REPLACE_CLOSEDIR@ +REPLACE_CTIME = @REPLACE_CTIME@ +REPLACE_DIRFD = @REPLACE_DIRFD@ +REPLACE_DPRINTF = @REPLACE_DPRINTF@ +REPLACE_DUP = @REPLACE_DUP@ +REPLACE_DUP2 = @REPLACE_DUP2@ +REPLACE_DUPLOCALE = @REPLACE_DUPLOCALE@ +REPLACE_FACCESSAT = @REPLACE_FACCESSAT@ +REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@ +REPLACE_FCLOSE = @REPLACE_FCLOSE@ +REPLACE_FCNTL = @REPLACE_FCNTL@ +REPLACE_FDOPEN = @REPLACE_FDOPEN@ +REPLACE_FDOPENDIR = @REPLACE_FDOPENDIR@ +REPLACE_FFLUSH = @REPLACE_FFLUSH@ +REPLACE_FNMATCH = @REPLACE_FNMATCH@ +REPLACE_FOPEN = @REPLACE_FOPEN@ +REPLACE_FPRINTF = @REPLACE_FPRINTF@ +REPLACE_FPURGE = @REPLACE_FPURGE@ +REPLACE_FREELOCALE = @REPLACE_FREELOCALE@ +REPLACE_FREOPEN = @REPLACE_FREOPEN@ +REPLACE_FSEEK = @REPLACE_FSEEK@ +REPLACE_FSEEKO = @REPLACE_FSEEKO@ +REPLACE_FSTAT = @REPLACE_FSTAT@ +REPLACE_FSTATAT = @REPLACE_FSTATAT@ +REPLACE_FTELL = @REPLACE_FTELL@ +REPLACE_FTELLO = @REPLACE_FTELLO@ +REPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@ +REPLACE_FUTIMENS = @REPLACE_FUTIMENS@ +REPLACE_GETCWD = @REPLACE_GETCWD@ +REPLACE_GETDELIM = @REPLACE_GETDELIM@ +REPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@ +REPLACE_GETDTABLESIZE = @REPLACE_GETDTABLESIZE@ +REPLACE_GETGROUPS = @REPLACE_GETGROUPS@ +REPLACE_GETLINE = @REPLACE_GETLINE@ +REPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@ +REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@ +REPLACE_GETPASS = @REPLACE_GETPASS@ +REPLACE_GMTIME = @REPLACE_GMTIME@ +REPLACE_ISATTY = @REPLACE_ISATTY@ +REPLACE_ISWBLANK = @REPLACE_ISWBLANK@ +REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@ +REPLACE_ITOLD = @REPLACE_ITOLD@ +REPLACE_LCHOWN = @REPLACE_LCHOWN@ +REPLACE_LINK = @REPLACE_LINK@ +REPLACE_LINKAT = @REPLACE_LINKAT@ +REPLACE_LOCALECONV = @REPLACE_LOCALECONV@ +REPLACE_LOCALTIME = @REPLACE_LOCALTIME@ +REPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@ +REPLACE_LSEEK = @REPLACE_LSEEK@ +REPLACE_LSTAT = @REPLACE_LSTAT@ +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_MBTOWC = @REPLACE_MBTOWC@ +REPLACE_MEMCHR = @REPLACE_MEMCHR@ +REPLACE_MEMMEM = @REPLACE_MEMMEM@ +REPLACE_MKDIR = @REPLACE_MKDIR@ +REPLACE_MKFIFO = @REPLACE_MKFIFO@ +REPLACE_MKNOD = @REPLACE_MKNOD@ +REPLACE_MKSTEMP = @REPLACE_MKSTEMP@ +REPLACE_MKTIME = @REPLACE_MKTIME@ +REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@ +REPLACE_NEWLOCALE = @REPLACE_NEWLOCALE@ +REPLACE_NL_LANGINFO = @REPLACE_NL_LANGINFO@ +REPLACE_NULL = @REPLACE_NULL@ +REPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@ +REPLACE_OPEN = @REPLACE_OPEN@ +REPLACE_OPENAT = @REPLACE_OPENAT@ +REPLACE_OPENDIR = @REPLACE_OPENDIR@ +REPLACE_PERROR = @REPLACE_PERROR@ +REPLACE_POPEN = @REPLACE_POPEN@ +REPLACE_PREAD = @REPLACE_PREAD@ +REPLACE_PRINTF = @REPLACE_PRINTF@ +REPLACE_PTSNAME = @REPLACE_PTSNAME@ +REPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@ +REPLACE_PUTENV = @REPLACE_PUTENV@ +REPLACE_PWRITE = @REPLACE_PWRITE@ +REPLACE_QSORT_R = @REPLACE_QSORT_R@ +REPLACE_RANDOM_R = @REPLACE_RANDOM_R@ +REPLACE_READ = @REPLACE_READ@ +REPLACE_READLINK = @REPLACE_READLINK@ +REPLACE_READLINKAT = @REPLACE_READLINKAT@ +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_SETLOCALE = @REPLACE_SETLOCALE@ +REPLACE_SLEEP = @REPLACE_SLEEP@ +REPLACE_SNPRINTF = @REPLACE_SNPRINTF@ +REPLACE_SPRINTF = @REPLACE_SPRINTF@ +REPLACE_STAT = @REPLACE_STAT@ +REPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@ +REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@ +REPLACE_STPNCPY = @REPLACE_STPNCPY@ +REPLACE_STRCASESTR = @REPLACE_STRCASESTR@ +REPLACE_STRCHRNUL = @REPLACE_STRCHRNUL@ +REPLACE_STRDUP = @REPLACE_STRDUP@ +REPLACE_STRERROR = @REPLACE_STRERROR@ +REPLACE_STRERROR_R = @REPLACE_STRERROR_R@ +REPLACE_STRFTIME = @REPLACE_STRFTIME@ +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_STRUCT_LCONV = @REPLACE_STRUCT_LCONV@ +REPLACE_SYMLINK = @REPLACE_SYMLINK@ +REPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@ +REPLACE_TIMEGM = @REPLACE_TIMEGM@ +REPLACE_TMPFILE = @REPLACE_TMPFILE@ +REPLACE_TOWLOWER = @REPLACE_TOWLOWER@ +REPLACE_TRUNCATE = @REPLACE_TRUNCATE@ +REPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@ +REPLACE_TZSET = @REPLACE_TZSET@ +REPLACE_UNLINK = @REPLACE_UNLINK@ +REPLACE_UNLINKAT = @REPLACE_UNLINKAT@ +REPLACE_UNSETENV = @REPLACE_UNSETENV@ +REPLACE_USLEEP = @REPLACE_USLEEP@ +REPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@ +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_WCSFTIME = @REPLACE_WCSFTIME@ +REPLACE_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@ +REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@ +REPLACE_WCSWIDTH = @REPLACE_WCSWIDTH@ +REPLACE_WCTOB = @REPLACE_WCTOB@ +REPLACE_WCTOMB = @REPLACE_WCTOMB@ +REPLACE_WCWIDTH = @REPLACE_WCWIDTH@ +REPLACE_WRITE = @REPLACE_WRITE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@ +SIZE_T_SUFFIX = @SIZE_T_SUFFIX@ +STDALIGN_H = @STDALIGN_H@ +STDBOOL_H = @STDBOOL_H@ +STDDEF_H = @STDDEF_H@ +STDINT_H = @STDINT_H@ +STRIP = @STRIP@ +SYSEXITS_H = @SYSEXITS_H@ +SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@ +TARGET_APPLE_LINKER = @TARGET_APPLE_LINKER@ +TARGET_CC = @TARGET_CC@ +TARGET_CCAS = @TARGET_CCAS@ +TARGET_CCASFLAGS = @TARGET_CCASFLAGS@ +TARGET_CC_VERSION = @TARGET_CC_VERSION@ +TARGET_CFLAGS = @TARGET_CFLAGS@ +TARGET_CPP = @TARGET_CPP@ +TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ +TARGET_DECOMPRESSOR_LINK_ADDR = @TARGET_DECOMPRESSOR_LINK_ADDR@ +TARGET_IMG_BASE_LDOPT = @TARGET_IMG_BASE_LDOPT@ +TARGET_IMG_CFLAGS = @TARGET_IMG_CFLAGS@ +TARGET_IMG_LDFLAGS = @TARGET_IMG_LDFLAGS@ +TARGET_LDFLAGS = @TARGET_LDFLAGS@ +TARGET_LDFLAGS_OLDMAGIC = @TARGET_LDFLAGS_OLDMAGIC@ +TARGET_LINK_ADDR = @TARGET_LINK_ADDR@ +TARGET_MODULE_FORMAT = @TARGET_MODULE_FORMAT@ +TARGET_NM = @TARGET_NM@ +TARGET_NMFLAGS_DEFINED_ONLY = @TARGET_NMFLAGS_DEFINED_ONLY@ +TARGET_NMFLAGS_MINUS_P = @TARGET_NMFLAGS_MINUS_P@ +TARGET_OBJ2ELF = @TARGET_OBJ2ELF@ +TARGET_OBJCONV = @TARGET_OBJCONV@ +TARGET_OBJCOPY = @TARGET_OBJCOPY@ +TARGET_RANLIB = @TARGET_RANLIB@ +TARGET_STRIP = @TARGET_STRIP@ +TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@ +UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@ +UNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@ +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_NLS = @USE_NLS@ +VERSION = @VERSION@ +WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@ +WINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@ +WINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@ +WINDOWS_STAT_INODES = @WINDOWS_STAT_INODES@ +WINDOWS_STAT_TIMESPEC = @WINDOWS_STAT_TIMESPEC@ +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_CXX = @ac_ct_CXX@ +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_mkfont = @enable_grub_mkfont@ +enable_grub_mount = @enable_grub_mount@ +exec_prefix = @exec_prefix@ +gl_LIBOBJS = @gl_LIBOBJS@ +gl_LTLIBOBJS = @gl_LTLIBOBJS@ +gltests_LIBOBJS = @gltests_LIBOBJS@ +gltests_LTLIBOBJS = @gltests_LTLIBOBJS@ +gltests_WITNESS = @gltests_WITNESS@ +grub_bios_setup = @grub_bios_setup@ +grub_editenv = @grub_editenv@ +grub_file = @grub_file@ +grub_glue_efi = @grub_glue_efi@ +grub_install = @grub_install@ +grub_mkconfig = @grub_mkconfig@ +grub_mkfont = @grub_mkfont@ +grub_mkimage = @grub_mkimage@ +grub_mklayout = @grub_mklayout@ +grub_mkpasswd_pbkdf2 = @grub_mkpasswd_pbkdf2@ +grub_mkrelpath = @grub_mkrelpath@ +grub_mkrescue = @grub_mkrescue@ +grub_probe = @grub_probe@ +grub_reboot = @grub_reboot@ +grub_render_label = @grub_render_label@ +grub_script_check = @grub_script_check@ +grub_set_default = @grub_set_default@ +grub_sparc64_setup = @grub_sparc64_setup@ +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@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +platform = @platform@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +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 +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) + @list='$(bashcompletion_DATA)'; test -n "$(bashcompletiondir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bashcompletiondir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bashcompletiondir)" || exit 1; \ + fi; \ + 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|^.*/||'`; \ + dir='$(DESTDIR)$(bashcompletiondir)'; $(am__uninstall_files_from_dir) +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +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 cscopelist-am \ + ctags-am 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 tags-am \ + uninstall uninstall-am uninstall-bashcompletionDATA + +.PRECIOUS: Makefile + + +$(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..44bf135 --- /dev/null +++ b/util/bash-completion.d/grub-completion.bash.in @@ -0,0 +1,495 @@ +# +# 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 <http://www.gnu.org/licenses/>. +# 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="@grub_set_default@" +have ${__grub_set_default_program} && \ + complete -F _grub_set_entry -o filenames ${__grub_set_default_program} +unset __grub_set_default_program + +__grub_reboot_program="@grub_reboot@" +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="@grub_editenv@" +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="@grub_mkconfig@" +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_bios_setup_program="@grub_bios_setup@" +have ${__grub_bios_setup_program} && \ + complete -F _grub_setup -o filenames ${__grub_bios_setup_program} +unset __grub_bios_setup_program + +__grub_sparc64_setup_program="@grub_sparc64_setup@" +have ${__grub_sparc64_setup_program} && \ + complete -F _grub_setup -o filenames ${__grub_sparc64_setup_program} +unset __grub_sparc64_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="@grub_install@" +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="@grub_mkfont@" +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="@grub_mkrescue@" +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="@grub_mkimage@" +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="@grub_mkpasswd_pbkdf2@" +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="@grub_probe@" +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="@grub_script_check@" +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..dd75fb8 --- /dev/null +++ b/util/bin2h.c @@ -0,0 +1,64 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> + +int +main (int argc, char *argv[]) +{ + int b, i; + char *sym; + + if (2 != argc) + return 1; + + sym = argv[1]; + + 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/config.c b/util/config.c new file mode 100644 index 0000000..ebcdd8f --- /dev/null +++ b/util/config.c @@ -0,0 +1,121 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <string.h> + +#include <grub/emu/config.h> +#include <grub/util/misc.h> + +void +grub_util_parse_config (FILE *f, struct grub_util_config *cfg, int simple) +{ + char *buffer = NULL; + size_t sz = 0; + while (getline (&buffer, &sz, f) >= 0) + { + const char *ptr; + for (ptr = buffer; *ptr && grub_isspace (*ptr); ptr++); + if (grub_strncmp (ptr, "GRUB_ENABLE_CRYPTODISK=", + sizeof ("GRUB_ENABLE_CRYPTODISK=") - 1) == 0) + { + ptr += sizeof ("GRUB_ENABLE_CRYPTODISK=") - 1; + if (*ptr == '"' || *ptr == '\'') + ptr++; + if (*ptr == 'y') + cfg->is_cryptodisk_enabled = 1; + continue; + } + if (grub_strncmp (ptr, "GRUB_DISTRIBUTOR=", + sizeof ("GRUB_DISTRIBUTOR=") - 1) == 0) + { + char *optr; + enum { NONE, SNGLQUOT, DBLQUOT } state; + + ptr += sizeof ("GRUB_DISTRIBUTOR=") - 1; + + if (simple) + { + char *ptr2; + free (cfg->grub_distributor); + cfg->grub_distributor = xstrdup (ptr); + for (ptr2 = cfg->grub_distributor + + grub_strlen (cfg->grub_distributor) - 1; + ptr2 >= cfg->grub_distributor + && (*ptr2 == '\r' || *ptr2 == '\n'); ptr2--); + ptr2[1] = '\0'; + continue; + } + free (cfg->grub_distributor); + cfg->grub_distributor = xmalloc (strlen (ptr) + 1); + optr = cfg->grub_distributor; + state = NONE; + + for (; *ptr; ptr++) + switch (*ptr) + { + case '\\': + if (state == SNGLQUOT) + { + *optr++ = *ptr; + continue; + } + if (ptr[1]) + { + *optr++ = ptr[1]; + ptr++; + continue; + } + ptr++; + break; + case '"': + if (state == NONE) + { + state = DBLQUOT; + continue; + } + if (state == DBLQUOT) + { + state = NONE; + continue; + } + *optr++ = *ptr; + continue; + case '\'': + if (state == SNGLQUOT) + { + state = NONE; + continue; + } + if (state == NONE) + { + state = SNGLQUOT; + continue; + } + *optr++ = *ptr; + continue; + default: + *optr++ = *ptr; + continue; + } + *optr = '\0'; + } + } +} + diff --git a/util/editenv.c b/util/editenv.c new file mode 100644 index 0000000..c532b04 --- /dev/null +++ b/util/editenv.c @@ -0,0 +1,135 @@ +/* editenv.c - tool to edit environment block. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009,2010,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/util/install.h> +#include <grub/lib/envblk.h> +#include <grub/i18n.h> +#include <grub/emu/hostfile.h> + +#include <errno.h> +#include <string.h> +#if !defined(_WIN32) +#include <libgen.h> +#endif + +#define DEFAULT_ENVBLK_SIZE 1024 +#define GRUB_ENVBLK_MESSAGE "# WARNING: Do not edit this file by tools other than "PACKAGE"-editenv!!!\n" + +void +grub_util_create_envblk_file (const char *name) +{ + FILE *fp; + char *buf, *pbuf, *namenew; +#if !defined(_WIN32) + ssize_t size = 1; + char *rename_target = xstrdup (name); + int rc; +#endif + + buf = xmalloc (DEFAULT_ENVBLK_SIZE); + + namenew = xasprintf ("%s.new", name); + fp = grub_util_fopen (namenew, "wb"); + if (! fp) + grub_util_error (_("cannot open `%s': %s"), namenew, + strerror (errno)); + + pbuf = buf; + memcpy (pbuf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1); + pbuf += sizeof (GRUB_ENVBLK_SIGNATURE) - 1; + memcpy (pbuf, GRUB_ENVBLK_MESSAGE, sizeof (GRUB_ENVBLK_MESSAGE) - 1); + pbuf += sizeof (GRUB_ENVBLK_MESSAGE) - 1; + memset (pbuf , '#', + DEFAULT_ENVBLK_SIZE - sizeof (GRUB_ENVBLK_SIGNATURE) - sizeof (GRUB_ENVBLK_MESSAGE) + 2); + + if (fwrite (buf, 1, DEFAULT_ENVBLK_SIZE, fp) != DEFAULT_ENVBLK_SIZE) + grub_util_error (_("cannot write to `%s': %s"), namenew, + strerror (errno)); + + + if (grub_util_file_sync (fp) < 0) + grub_util_error (_("cannot sync `%s': %s"), namenew, strerror (errno)); + free (buf); + fclose (fp); + +#if defined(_WIN32) + if (grub_util_rename (namenew, name) < 0) + grub_util_error (_("cannot rename the file %s to %s"), namenew, name); +#else + while (1) + { + char *linkbuf; + ssize_t retsize; + + linkbuf = xmalloc (size + 1); + retsize = grub_util_readlink (rename_target, linkbuf, size); + if (retsize < 0 && (errno == ENOENT || errno == EINVAL)) + { + free (linkbuf); + break; + } + else if (retsize < 0) + { + free (linkbuf); + grub_util_error (_("cannot rename the file %s to %s: %m"), namenew, name); + } + else if (retsize == size) + { + free (linkbuf); + size += 128; + continue; + } + + linkbuf[retsize] = '\0'; + if (linkbuf[0] == '/') + { + free (rename_target); + rename_target = linkbuf; + } + else + { + char *dbuf = xstrdup (rename_target); + const char *dir = dirname (dbuf); + + free (rename_target); + rename_target = xasprintf ("%s/%s", dir, linkbuf); + free (dbuf); + free (linkbuf); + } + } + + rc = grub_util_rename (namenew, rename_target); + if (rc < 0 && errno == EXDEV) + { + rc = grub_install_copy_file (namenew, rename_target, 1); + grub_util_unlink (namenew); + } + + free (rename_target); + + if (rc < 0) + grub_util_error (_("cannot rename the file %s to %s: %m"), namenew, name); +#endif + + free (namenew); +} diff --git a/util/garbage-gen.c b/util/garbage-gen.c new file mode 100644 index 0000000..ccba1bf --- /dev/null +++ b/util/garbage-gen.c @@ -0,0 +1,67 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +/* Standard random generator is slow. For FS testing we need just some + garbage files, we don't need them to be high-quality random. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> + +static unsigned long long buffer[1048576]; + +int +main (int argc, char **argv) +{ + unsigned long long high = 0, low = 1; + unsigned long i, j; + unsigned long long cnt = strtoull (argv[1], 0, 0); + struct timeval tv; + gettimeofday (&tv, NULL); + high = tv.tv_sec; + low = tv.tv_usec; + if (!high) + high = 1; + if (!low) + low = 2; + + for (j = 0; j < (cnt + sizeof (buffer) - 1) / sizeof (buffer); j++) + { + for (i = 0; i < sizeof (buffer) / sizeof (buffer[0]); i += 2) + { + int c1 = 0, c2 = 0; + buffer[i] = low; + buffer[i+1] = high; + if (low & (1ULL << 63)) + c1 = 1; + low <<= 1; + if (high & (1ULL << 63)) + c2 = 1; + high = (high << 1) | c1; + if (c2) + low ^= 0x87; + } + if (sizeof (buffer) < cnt - sizeof (buffer) * j) + fwrite (buffer, 1, sizeof (buffer), stdout); + else + fwrite (buffer, 1, cnt - sizeof (buffer) * j, stdout); + } + return 0; +} diff --git a/util/getroot.c b/util/getroot.c new file mode 100644 index 0000000..a5eaa64 --- /dev/null +++ b/util/getroot.c @@ -0,0 +1,482 @@ +/* getroot.c - Get root device */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config-util.h> +#include <config.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <assert.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <dirent.h> +#include <errno.h> +#include <error.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif +#include <grub/util/misc.h> + +#include <grub/cryptodisk.h> +#include <grub/i18n.h> + +#ifdef __linux__ +#include <sys/ioctl.h> /* ioctl */ +#include <sys/mount.h> +#endif + +#include <sys/types.h> + +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) +# include <grub/util/libzfs.h> +# include <grub/util/libnvpair.h> +#endif + +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/emu/misc.h> +#include <grub/emu/hostdisk.h> +#include <grub/emu/getroot.h> + +#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) +#include <sys/mount.h> +#endif + +#if defined(__NetBSD__) || defined(__OpenBSD__) +# include <sys/ioctl.h> +# include <sys/disklabel.h> /* struct disklabel */ +# include <sys/disk.h> /* struct dkwedge_info */ +#include <sys/param.h> +#include <sys/mount.h> +#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */ + +#if defined(__NetBSD__) +# include <sys/fdio.h> +#endif + +grub_disk_addr_t +grub_util_find_partition_start (const char *dev) +{ +#if GRUB_UTIL_FD_STAT_IS_FUNCTIONAL + struct stat st; + grub_disk_addr_t partition_start; + + if (stat (dev, &st) >= 0 + && grub_util_device_is_mapped_stat (&st) + && grub_util_get_dm_node_linear_info (st.st_rdev, 0, 0, &partition_start)) + return partition_start; +#endif + + return grub_util_find_partition_start_os (dev); +} + +void +grub_util_pull_device (const char *os_dev) +{ + enum grub_dev_abstraction_types ab; + ab = grub_util_get_dev_abstraction (os_dev); + switch (ab) + { + case GRUB_DEV_ABSTRACTION_LVM: + grub_util_pull_lvm_by_command (os_dev); + /* Fallthrough - in case that lvm-tools are unavailable. */ + case GRUB_DEV_ABSTRACTION_LUKS: + grub_util_pull_devmapper (os_dev); + return; + + default: + if (grub_util_pull_device_os (os_dev, ab)) + return; + /* Fallthrough. */ + case GRUB_DEV_ABSTRACTION_NONE: + free (grub_util_biosdisk_get_grub_dev (os_dev)); + return; + } +} + +char * +grub_util_get_grub_dev (const char *os_dev) +{ + char *ret; + + grub_util_pull_device (os_dev); + + ret = grub_util_get_devmapper_grub_dev (os_dev); + if (ret) + return ret; + ret = grub_util_get_grub_dev_os (os_dev); + if (ret) + return ret; + return grub_util_biosdisk_get_grub_dev (os_dev); +} + +int +grub_util_get_dev_abstraction (const char *os_dev) +{ + enum grub_dev_abstraction_types ret; + + /* User explicitly claims that this drive is visible by BIOS. */ + if (grub_util_biosdisk_is_present (os_dev)) + return GRUB_DEV_ABSTRACTION_NONE; + + /* Check for LVM and LUKS. */ + ret = grub_util_get_dm_abstraction (os_dev); + + if (ret != GRUB_DEV_ABSTRACTION_NONE) + return ret; + + return grub_util_get_dev_abstraction_os (os_dev); +} + +static char * +convert_system_partition_to_system_disk (const char *os_dev, int *is_part) +{ +#if GRUB_UTIL_FD_STAT_IS_FUNCTIONAL + struct stat st; + + if (stat (os_dev, &st) < 0) + { + const char *errstr = strerror (errno); + grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot stat `%s': %s"), + os_dev, errstr); + grub_util_info (_("cannot stat `%s': %s"), os_dev, errstr); + return 0; + } + + *is_part = 0; + + if (grub_util_device_is_mapped_stat (&st)) + return grub_util_devmapper_part_to_disk (&st, is_part, os_dev); + + *is_part = 0; + + return grub_util_part_to_disk (os_dev, &st, is_part); +#else + *is_part = 0; + + return grub_util_part_to_disk (os_dev, NULL, is_part); +#endif +} + +static const char * +find_system_device (const char *os_dev) +{ + char *os_disk; + const char *drive; + int is_part; + + os_disk = convert_system_partition_to_system_disk (os_dev, &is_part); + if (! os_disk) + return NULL; + + drive = grub_hostdisk_os_dev_to_grub_drive (os_disk, 0); + free (os_disk); + return drive; +} + +static char * +make_device_name (const char *drive) +{ + char *ret, *ptr; + const char *iptr; + + ret = xcalloc (2, strlen (drive)); + ptr = ret; + for (iptr = drive; *iptr; iptr++) + { + if (*iptr == ',' || *iptr == '\\') + *ptr++ = '\\'; + *ptr++ = *iptr; + } + *ptr = 0; + + return ret; +} + +char * +grub_util_get_os_disk (const char *os_dev) +{ + int is_part; + + grub_util_info ("Looking for %s", os_dev); + + return convert_system_partition_to_system_disk (os_dev, &is_part); +} + +#if !defined(__APPLE__) +/* Context for grub_util_biosdisk_get_grub_dev. */ +struct grub_util_biosdisk_get_grub_dev_ctx +{ + char *partname; + grub_disk_addr_t start; +}; + +/* Helper for grub_util_biosdisk_get_grub_dev. */ +static int +find_partition (grub_disk_t dsk __attribute__ ((unused)), + const grub_partition_t partition, void *data) +{ + struct grub_util_biosdisk_get_grub_dev_ctx *ctx = data; + grub_disk_addr_t part_start = 0; + grub_util_info ("Partition %d starts from %" GRUB_HOST_PRIuLONG_LONG, + partition->number, (unsigned long long) partition->start); + + part_start = grub_partition_get_start (partition); + + if (ctx->start == part_start) + { + ctx->partname = grub_partition_get_name (partition); + return 1; + } + + return 0; +} +#endif + +char * +grub_util_biosdisk_get_grub_dev (const char *os_dev) +{ + const char *drive; + char *sys_disk; + int is_part; + + grub_util_info ("Looking for %s", os_dev); + + sys_disk = convert_system_partition_to_system_disk (os_dev, &is_part); + + if (!sys_disk) + return 0; + + drive = grub_hostdisk_os_dev_to_grub_drive (sys_disk, 1); + + grub_util_info ("%s is a parent of %s", sys_disk, os_dev); + if (!is_part) + { + free (sys_disk); + return make_device_name (drive); + } + free (sys_disk); + +#if defined(__APPLE__) + /* Apple uses "/dev/r?disk[0-9]+(s[0-9]+)?". */ + /* + * Note: we do not use the new partition naming scheme as dos_part does not + * necessarily correspond to an msdos partition. + */ + { + const char *p; + char *dri, *ret; + int part; + int disk = (grub_memcmp (os_dev, "/dev/disk", sizeof ("/dev/disk") - 1) + == 0); + int rdisk = (grub_memcmp (os_dev, "/dev/rdisk", sizeof ("/dev/rdisk") - 1) + == 0); + + dri = make_device_name (drive); + + if (!disk && !rdisk) + return dri; + + p = os_dev + sizeof ("/dev/disk") + rdisk - 1; + while (*p >= '0' && *p <= '9') + p++; + if (*p != 's') + return dri; + p++; + + part = strtol (p, NULL, 10); + if (part == 0) + return dri; + + ret = xasprintf ("%s,%d", dri, part); + free (dri); + + return ret; + } + +#else + + /* Linux counts partitions uniformly, whether a BSD partition or a DOS + partition, so mapping them to GRUB devices is not trivial. + Here, get the start sector of a partition by HDIO_GETGEO, and + compare it with each partition GRUB recognizes. + + Cygwin /dev/sdXN emulation uses Windows partition mapping. It + does not count the extended partition and missing primary + partitions. Use same method as on Linux here. + + For NetBSD and FreeBSD, proceed as for Linux, except that the start + sector is obtained from the disk label. */ + { + char *name; + grub_disk_t disk; + struct grub_util_biosdisk_get_grub_dev_ctx ctx; + + name = make_device_name (drive); + + ctx.start = grub_util_find_partition_start (os_dev); + if (grub_errno != GRUB_ERR_NONE) + { + free (name); + return 0; + } + +#if defined(__GNU__) + /* Some versions of Hurd use badly glued Linux code to handle partitions + resulting in partitions being promoted to disks. */ + /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */ + /* + * Note: we do not use the new partition naming scheme as dos_part does not + * necessarily correspond to an msdos partition. + */ + if (ctx.start == (grub_disk_addr_t) -1) + { + char *p; + char *dri; + + dri = make_device_name (drive); + + p = strrchr (os_dev + sizeof ("/dev/hd") - 1, 's'); + if (p) + { + long int n; + char *q; + + p++; + n = strtol (p, &q, 10); + if (p != q && n > 0 && n != GRUB_LONG_MAX) + { + char *t; + t = dri; + if (*q >= 'a' && *q <= 'g') + dri = xasprintf ("%s,%ld,%d", t, n, *q - 'a' + 1); + else + dri = xasprintf ("%s,%ld", t, n); + free (t); + } + } + + return dri; + } +#endif + + grub_util_info ("%s starts from %" GRUB_HOST_PRIuLONG_LONG, + os_dev, (unsigned long long) ctx.start); + + grub_util_info ("opening the device %s", name); + disk = grub_disk_open (name); + free (name); + + if (! disk) + { + /* We already know that the partition exists. Given that we already + checked the device map above, we can only get + GRUB_ERR_UNKNOWN_DEVICE at this point if the disk does not exist. + This can happen on Xen, where disk images in the host can be + assigned to devices that have partition-like names in the guest + but are really more like disks. */ + if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE) + { + char *canon; + grub_util_warn + (_("disk does not exist, so falling back to partition device %s"), + os_dev); + grub_errno = GRUB_ERR_NONE; + + canon = grub_canonicalize_file_name (os_dev); + drive = grub_hostdisk_os_dev_to_grub_drive (canon ? : os_dev, 1); + if (canon) + free (canon); + return make_device_name (drive); + } + else + return 0; + } + + name = grub_util_get_ldm (disk, ctx.start); + if (name) + { + grub_disk_close (disk); + return name; + } + + ctx.partname = NULL; + + grub_partition_iterate (disk, find_partition, &ctx); + if (grub_errno != GRUB_ERR_NONE) + { + grub_disk_close (disk); + return 0; + } + + if (ctx.partname == NULL) + { + grub_disk_close (disk); + grub_util_info ("cannot find the partition of `%s'", os_dev); + grub_error (GRUB_ERR_BAD_DEVICE, + "cannot find the partition of `%s'", os_dev); + return 0; + } + + name = grub_xasprintf ("%s,%s", disk->name, ctx.partname); + free (ctx.partname); + grub_disk_close (disk); + return name; + } + +#endif +} + +int +grub_util_biosdisk_is_present (const char *os_dev) +{ + int ret = (find_system_device (os_dev) != NULL); + grub_util_info ((ret ? "%s is present" : "%s is not present"), + os_dev); + return ret; +} + +#ifdef HAVE_LIBZFS +static libzfs_handle_t *__libzfs_handle; + +static void +fini_libzfs (void) +{ + libzfs_fini (__libzfs_handle); +} + +libzfs_handle_t * +grub_get_libzfs_handle (void) +{ + if (! __libzfs_handle) + { + __libzfs_handle = libzfs_init (); + + if (__libzfs_handle) + atexit (fini_libzfs); + } + + return __libzfs_handle; +} +#endif /* HAVE_LIBZFS */ + diff --git a/util/glue-efi.c b/util/glue-efi.c new file mode 100644 index 0000000..de0fa6d --- /dev/null +++ b/util/glue-efi.c @@ -0,0 +1,153 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2012,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <grub/util/misc.h> +#include <grub/util/install.h> +#include <grub/i18n.h> +#include <grub/term.h> +#include <grub/macho.h> + +#define _GNU_SOURCE 1 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +static void +write_fat (FILE *in32, FILE *in64, FILE *out, const char *out_filename, + const char *name32, const char *name64) +{ + struct grub_macho_fat_header head; + struct grub_macho_fat_arch arch32, arch64; + grub_uint32_t size32, size64; + long size; + char *buf; + + fseek (in32, 0, SEEK_END); + size = ftell (in32); + if (size < 0) + grub_util_error ("cannot get end of input file '%s': %s", + name32, strerror (errno)); + size32 = (grub_uint32_t) size; + fseek (in32, 0, SEEK_SET); + + fseek (in64, 0, SEEK_END); + size = ftell (in64); + if (size < 0) + grub_util_error ("cannot get end of input file '%s': %s", + name64, strerror (errno)); + size64 = (grub_uint64_t) size; + fseek (in64, 0, SEEK_SET); + + head.magic = grub_cpu_to_le32_compile_time (GRUB_MACHO_FAT_EFI_MAGIC); + head.nfat_arch = grub_cpu_to_le32_compile_time (2); + arch32.cputype = grub_cpu_to_le32_compile_time (GRUB_MACHO_CPUTYPE_IA32); + arch32.cpusubtype = grub_cpu_to_le32_compile_time (3); + arch32.offset = grub_cpu_to_le32_compile_time (sizeof (head) + + sizeof (arch32) + + sizeof (arch64)); + arch32.size = grub_cpu_to_le32 (size32); + arch32.align = 0; + + arch64.cputype = grub_cpu_to_le32_compile_time (GRUB_MACHO_CPUTYPE_AMD64); + arch64.cpusubtype = grub_cpu_to_le32_compile_time (3); + arch64.offset = grub_cpu_to_le32 (sizeof (head) + sizeof (arch32) + + sizeof (arch64) + size32); + arch64.size = grub_cpu_to_le32 (size64); + arch64.align = 0; + if (fwrite (&head, 1, sizeof (head), out) != sizeof (head) + || fwrite (&arch32, 1, sizeof (arch32), out) != sizeof (arch32) + || fwrite (&arch64, 1, sizeof (arch64), out) != sizeof (arch64)) + { + if (out_filename) + grub_util_error ("cannot write to `%s': %s", + out_filename, strerror (errno)); + else + grub_util_error ("cannot write to the stdout: %s", strerror (errno)); + } + + buf = xmalloc (size32); + if (fread (buf, 1, size32, in32) != size32) + grub_util_error (_("cannot read `%s': %s"), name32, + strerror (errno)); + if (fwrite (buf, 1, size32, out) != size32) + { + if (out_filename) + grub_util_error ("cannot write to `%s': %s", + out_filename, strerror (errno)); + else + grub_util_error ("cannot write to the stdout: %s", strerror (errno)); + } + free (buf); + + buf = xmalloc (size64); + if (fread (buf, 1, size64, in64) != size64) + grub_util_error (_("cannot read `%s': %s"), name64, + strerror (errno)); + if (fwrite (buf, 1, size64, out) != size64) + { + if (out_filename) + grub_util_error ("cannot write to `%s': %s", + out_filename, strerror (errno)); + else + grub_util_error ("cannot write to the stdout: %s", strerror (errno)); + } + free (buf); +} + +void +grub_util_glue_efi (const char *file32, const char *file64, const char *outname) +{ + FILE *in32, *in64, *out; + + in32 = grub_util_fopen (file32, "r"); + + if (!in32) + grub_util_error (_("cannot open `%s': %s"), file32, + strerror (errno)); + + in64 = grub_util_fopen (file64, "r"); + if (!in64) + grub_util_error (_("cannot open `%s': %s"), file64, + strerror (errno)); + + if (outname) + out = grub_util_fopen (outname, "wb"); + else + out = stdout; + + if (!out) + { + grub_util_error (_("cannot open `%s': %s"), outname ? : "stdout", + strerror (errno)); + } + + write_fat (in32, in64, out, outname, + file32, file64); + + fclose (in32); + fclose (in64); + + if (out != stdout) + fclose (out); +} + diff --git a/util/grub-editenv.c b/util/grub-editenv.c new file mode 100644 index 0000000..db6f187 --- /dev/null +++ b/util/grub-editenv.c @@ -0,0 +1,305 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/lib/envblk.h> +#include <grub/i18n.h> +#include <grub/emu/hostfile.h> +#include <grub/util/install.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + + +#include "progname.h" + +#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}, + /* TRANSLATORS: "set" is a keyword. It's a summary of "set" subcommand. */ + {N_("set [NAME=VALUE ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE, + N_("Set variables."), 0}, + /* TRANSLATORS: "unset" is a keyword. It's a summary of "unset" subcommand. */ + {N_("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">"; + +static 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; +} + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +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_ENVBLK_PATH); + + default: + return (char *) text; + } +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +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.\n\n\ +There is no `delete' command; if you want to delete the whole environment\n\ +block, use `rm %s'."), + NULL, help_filter, NULL +}; + +static grub_envblk_t +open_envblk_file (const char *name) +{ + FILE *fp; + char *buf; + long loc; + size_t size; + grub_envblk_t envblk; + + fp = grub_util_fopen (name, "rb"); + if (! fp) + { + /* Create the file implicitly. */ + grub_util_create_envblk_file (name); + fp = grub_util_fopen (name, "rb"); + if (! fp) + grub_util_error (_("cannot open `%s': %s"), name, + strerror (errno)); + } + + if (fseek (fp, 0, SEEK_END) < 0) + grub_util_error (_("cannot seek `%s': %s"), name, + strerror (errno)); + + loc = ftell (fp); + if (loc < 0) + grub_util_error (_("cannot get file location `%s': %s"), name, + strerror (errno)); + + size = (size_t) loc; + + if (fseek (fp, 0, SEEK_SET) < 0) + grub_util_error (_("cannot seek `%s': %s"), name, + strerror (errno)); + + buf = xmalloc (size); + + if (fread (buf, 1, size, fp) != size) + grub_util_error (_("cannot read `%s': %s"), name, + strerror (errno)); + + fclose (fp); + + envblk = grub_envblk_open (buf, size); + if (! envblk) + grub_util_error ("%s", _("invalid environment block")); + + return envblk; +} + +static int +print_var (const char *varname, const char *value, + void *hook_data __attribute__ ((unused))) +{ + printf ("%s=%s\n", varname, value); + return 0; +} + +static void +list_variables (const char *name) +{ + grub_envblk_t envblk; + + envblk = open_envblk_file (name); + grub_envblk_iterate (envblk, NULL, print_var); + grub_envblk_close (envblk); +} + +static void +write_envblk (const char *name, grub_envblk_t envblk) +{ + FILE *fp; + + fp = grub_util_fopen (name, "wb"); + if (! fp) + grub_util_error (_("cannot open `%s': %s"), name, + strerror (errno)); + + if (fwrite (grub_envblk_buffer (envblk), 1, grub_envblk_size (envblk), fp) + != grub_envblk_size (envblk)) + grub_util_error (_("cannot write to `%s': %s"), name, + strerror (errno)); + + if (grub_util_file_sync (fp) < 0) + grub_util_error (_("cannot sync `%s': %s"), name, strerror (errno)); + 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 ("%s", _("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[]) +{ + const char *filename; + char *command; + int curindex, arg_count; + + grub_util_host_init (&argc, &argv); + + /* Parse our arguments */ + if (argp_parse (&argp, argc, argv, 0, &curindex, 0) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + arg_count = argc - curindex; + + if (arg_count == 1) + { + filename = DEFAULT_ENVBLK_PATH; + command = argv[curindex++]; + } + else + { + filename = argv[curindex++]; + if (strcmp (filename, "-") == 0) + filename = DEFAULT_ENVBLK_PATH; + command = argv[curindex++]; + } + + if (strcmp (command, "create") == 0) + grub_util_create_envblk_file (filename); + else if (strcmp (command, "list") == 0) + list_variables (filename); + else if (strcmp (command, "set") == 0) + set_variables (filename, argc - curindex, argv + curindex); + else if (strcmp (command, "unset") == 0) + unset_variables (filename, argc - curindex, argv + curindex); + 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-file.c b/util/grub-file.c new file mode 100644 index 0000000..b2e7dd6 --- /dev/null +++ b/util/grub-file.c @@ -0,0 +1,106 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2012,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include <config.h> + +#include <grub/util/misc.h> +#include <grub/i18n.h> +#include <grub/term.h> +#include <grub/font.h> +#include <grub/gfxmenu_view.h> +#include <grub/color.h> +#include <grub/util/install.h> +#include <grub/command.h> +#include <grub/env.h> + +#define _GNU_SOURCE 1 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "progname.h" + +void grub_file_init (void); +void grub_host_init (void); +void grub_hostfs_init (void); + +int +main (int argc, char *argv[]) +{ + char **argv2; + int i; + int had_file = 0, had_separator = 0; + grub_command_t cmd; + grub_err_t err; + + grub_util_host_init (&argc, &argv); + + argv2 = xcalloc (argc, sizeof (argv2[0])); + + if (argc == 2 && strcmp (argv[1], "--version") == 0) + { + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); + } + + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-' && argv[i][1] == '-' + && argv[i][2] == '\0' && !had_separator) + { + had_separator = 1; + argv2[i - 1] = xstrdup (argv[i]); + continue; + } + if (argv[i][0] == '-' && !had_separator) + { + argv2[i - 1] = xstrdup (argv[i]); + continue; + } + if (had_file) + grub_util_error ("one argument expected"); + argv2[i - 1] = grub_canonicalize_file_name (argv[i]); + if (!argv2[i - 1]) + { + grub_util_error (_("cannot open `%s': %s"), argv[i], + strerror (errno)); + } + had_file = 1; + } + argv2[i - 1] = NULL; + + /* Initialize all modules. */ + grub_init_all (); + grub_file_init (); + grub_hostfs_init (); + grub_host_init (); + + grub_env_set ("root", "host"); + + cmd = grub_command_find ("file"); + if (! cmd) + grub_util_error (_("can't find command `%s'"), "file"); + + err = (cmd->func) (cmd, argc - 1, argv2); + if (err && err != GRUB_ERR_TEST_FAILURE) + grub_print_error (); + return err; +} diff --git a/util/grub-fstest.c b/util/grub-fstest.c new file mode 100644 index 0000000..8386564 --- /dev/null +++ b/util/grub-fstest.c @@ -0,0 +1,776 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/misc.h> +#include <grub/device.h> +#include <grub/disk.h> +#include <grub/file.h> +#include <grub/fs.h> +#include <grub/env.h> +#include <grub/term.h> +#include <grub/mm.h> +#include <grub/lib/hexdump.h> +#include <grub/crypto.h> +#include <grub/command.h> +#include <grub/i18n.h> +#include <grub/zfs/zfs.h> +#include <grub/emu/hostfile.h> + +#include <stdio.h> +#include <errno.h> +#include <string.h> + +#include "progname.h" +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include "argp.h" +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +static grub_err_t +execute_command (const 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); +} + +enum { + CMD_LS = 1, + CMD_CP, + CMD_CAT, + CMD_CMP, + CMD_HEX, + CMD_CRC, + CMD_BLOCKLIST, + CMD_TESTLOAD, + CMD_ZFSINFO, + CMD_XNU_UUID +}; +#define BUF_SIZE 32256 + +static grub_disk_addr_t skip, leng; +static int uncompress = 0; + +static void +read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len, void *hook_arg), void *hook_arg) +{ + static char buf[BUF_SIZE]; + grub_file_t file; + + if ((pathname[0] == '-') && (pathname[1] == 0)) + { + grub_device_t dev; + + dev = grub_device_open (0); + if ((! dev) || (! dev->disk)) + grub_util_error ("%s", grub_errmsg); + + grub_util_info ("total sectors : %" GRUB_HOST_PRIuLONG_LONG, + (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)) + { + char *msg = grub_xasprintf (_("disk read fails at offset %lld, length %lld"), + (long long) skip, (long long) len); + grub_util_error ("%s", msg); + } + + if (hook (skip, buf, len, hook_arg)) + break; + + skip += len; + leng -= len; + } + + grub_device_close (dev); + return; + } + + file = grub_file_open (pathname, ((uncompress == 0) + ? GRUB_FILE_TYPE_NO_DECOMPRESS : GRUB_FILE_TYPE_NONE) + | GRUB_FILE_TYPE_FSTEST); + if (!file) + { + grub_util_error (_("cannot open `%s': %s"), pathname, + grub_errmsg); + return; + } + + grub_util_info ("file size : %" GRUB_HOST_PRIuLONG_LONG, + (unsigned long long) file->size); + + if (skip > file->size) + { + char *msg = grub_xasprintf (_("invalid skip value %lld"), + (unsigned long long) skip); + grub_util_error ("%s", msg); + return; + } + + { + grub_off_t ofs, len; + 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) + { + char *msg = grub_xasprintf (_("read error at offset %llu: %s"), + (unsigned long long) ofs, grub_errmsg); + grub_util_error ("%s", msg); + break; + } + + if ((sz == 0) || (hook (ofs, buf, sz, hook_arg))) + break; + + ofs += sz; + len -= sz; + } + } + + grub_file_close (file); +} + +struct cp_hook_ctx +{ + FILE *ff; + const char *dest; +}; + +static int +cp_hook (grub_off_t ofs, char *buf, int len, void *_ctx) +{ + struct cp_hook_ctx *ctx = _ctx; + (void) ofs; + + if ((int) fwrite (buf, 1, len, ctx->ff) != len) + { + grub_util_error (_("cannot write to `%s': %s"), + ctx->dest, strerror (errno)); + return 1; + } + + return 0; +} + +static void +cmd_cp (char *src, const char *dest) +{ + struct cp_hook_ctx ctx = + { + .dest = dest + }; + + ctx.ff = grub_util_fopen (dest, "wb"); + if (ctx.ff == NULL) + { + grub_util_error (_("cannot open OS file `%s': %s"), dest, + strerror (errno)); + return; + } + read_file (src, cp_hook, &ctx); + fclose (ctx.ff); +} + +static int +cat_hook (grub_off_t ofs, char *buf, int len, void *_arg __attribute__ ((unused))) +{ + (void) ofs; + + if ((int) fwrite (buf, 1, len, stdout) != len) + { + grub_util_error (_("cannot write to the stdout: %s"), + strerror (errno)); + return 1; + } + + return 0; +} + +static void +cmd_cat (char *src) +{ + read_file (src, cat_hook, 0); +} + +static int +cmp_hook (grub_off_t ofs, char *buf, int len, void *ff_in) +{ + FILE *ff = ff_in; + static char buf_1[BUF_SIZE]; + if ((int) fread (buf_1, 1, len, ff) != len) + { + char *msg = grub_xasprintf (_("read error at offset %llu: %s"), + (unsigned long long) ofs, grub_errmsg); + grub_util_error ("%s", msg); + return 1; + } + + if (grub_memcmp (buf, buf_1, len) != 0) + { + int i; + + for (i = 0; i < len; i++, ofs++) + if (buf_1[i] != buf[i]) + { + char *msg = grub_xasprintf (_("compare fail at offset %llu"), + (unsigned long long) ofs); + grub_util_error ("%s", msg); + return 1; + } + } + return 0; +} + + +static void +cmd_cmp (char *src, char *dest) +{ + FILE *ff; + + if (grub_util_is_directory (dest)) + { + grub_util_fd_dir_t dir = grub_util_fd_opendir (dest); + grub_util_fd_dirent_t entry; + if (dir == NULL) + { + grub_util_error (_("OS file %s open error: %s"), dest, + grub_util_fd_strerror ()); + return; + } + while ((entry = grub_util_fd_readdir (dir))) + { + char *srcnew, *destnew; + char *ptr; + if (strcmp (entry->d_name, ".") == 0 + || strcmp (entry->d_name, "..") == 0) + continue; + srcnew = xmalloc (strlen (src) + sizeof ("/") + + strlen (entry->d_name)); + destnew = xmalloc (strlen (dest) + sizeof ("/") + + strlen (entry->d_name)); + ptr = grub_stpcpy (srcnew, src); + *ptr++ = '/'; + strcpy (ptr, entry->d_name); + ptr = grub_stpcpy (destnew, dest); + *ptr++ = '/'; + strcpy (ptr, entry->d_name); + + if (grub_util_is_special_file (destnew)) + continue; + + cmd_cmp (srcnew, destnew); + } + grub_util_fd_closedir (dir); + return; + } + + ff = grub_util_fopen (dest, "rb"); + if (ff == NULL) + { + grub_util_error (_("OS file %s open error: %s"), dest, + strerror (errno)); + return; + } + + if ((skip) && (fseeko (ff, skip, SEEK_SET))) + grub_util_error (_("cannot seek `%s': %s"), dest, + strerror (errno)); + + read_file (src, cmp_hook, ff); + + { + grub_uint64_t pre; + pre = ftell (ff); + fseek (ff, 0, SEEK_END); + if (pre != ftell (ff)) + grub_util_error ("%s", _("unexpected end of file")); + } + fclose (ff); +} + +static int +hex_hook (grub_off_t ofs, char *buf, int len, void *arg __attribute__ ((unused))) +{ + hexdump (ofs, buf, len); + return 0; +} + +static void +cmd_hex (char *pathname) +{ + read_file (pathname, hex_hook, 0); +} + +static int +crc_hook (grub_off_t ofs, char *buf, int len, void *crc_ctx) +{ + (void) ofs; + + GRUB_MD_CRC32->write(crc_ctx, buf, len); + return 0; +} + +static void +cmd_crc (char *pathname) +{ + grub_uint8_t *crc32_context = xmalloc (GRUB_MD_CRC32->contextsize); + GRUB_MD_CRC32->init(crc32_context); + + read_file (pathname, crc_hook, crc32_context); + GRUB_MD_CRC32->final(crc32_context); + printf ("%08x\n", + grub_be_to_cpu32 (grub_get_unaligned32 (GRUB_MD_CRC32->read (crc32_context)))); + free (crc32_context); +} + +static const 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 int mount_crypt = 0; + +static void +fstest (int n) +{ + 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 ("%s", grub_errmsg); + + host_file = grub_xasprintf ("(host)%s", images[i]); + if (!host_file) + grub_util_error ("%s", grub_errmsg); + + argv[0] = loop_name; + argv[1] = host_file; + + if (execute_command ("loopback", 2, argv)) + grub_util_error (_("`loopback' command fails: %s"), grub_errmsg); + + grub_free (loop_name); + grub_free (host_file); + } + + { + if (mount_crypt) + { + char *argv[2] = { xstrdup ("-a"), NULL}; + if (execute_command ("cryptomount", 1, argv)) + grub_util_error (_("`cryptomount' command fails: %s"), + grub_errmsg); + free (argv[0]); + } + } + + grub_ldm_fini (); + grub_lvm_fini (); + grub_mdraid09_fini (); + grub_mdraid1x_fini (); + grub_diskfilter_fini (); + grub_diskfilter_init (); + grub_mdraid09_init (); + grub_mdraid1x_init (); + grub_lvm_init (); + grub_ldm_init (); + + switch (cmd) + { + case CMD_LS: + execute_command ("ls", n, args); + break; + case CMD_ZFSINFO: + execute_command ("zfsinfo", n, args); + break; + case CMD_CP: + cmd_cp (args[0], args[1]); + break; + case CMD_CAT: + cmd_cat (args[0]); + 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"); + break; + case CMD_TESTLOAD: + execute_command ("testload", n, args); + grub_printf ("\n"); + break; + case CMD_XNU_UUID: + { + grub_device_t dev; + grub_fs_t fs; + char *uuid = 0; + char *argv[3] = { xstrdup ("-l"), NULL, NULL}; + dev = grub_device_open (n ? args[0] : 0); + if (!dev) + grub_util_error ("%s", grub_errmsg); + fs = grub_fs_probe (dev); + if (!fs) + grub_util_error ("%s", grub_errmsg); + if (!fs->fs_uuid) + grub_util_error ("%s", _("couldn't retrieve UUID")); + if (fs->fs_uuid (dev, &uuid)) + grub_util_error ("%s", grub_errmsg); + if (!uuid) + grub_util_error ("%s", _("couldn't retrieve UUID")); + argv[1] = uuid; + execute_command ("xnu_uuid", 2, argv); + grub_free (argv[0]); + grub_free (uuid); + grub_device_close (dev); + } + } + + for (i = 0; i < num_disks; i++) + { + char *argv[2]; + + loop_name = grub_xasprintf ("loop%d", i); + if (!loop_name) + grub_util_error ("%s", grub_errmsg); + + argv[0] = xstrdup ("-d"); + argv[1] = loop_name; + + execute_command ("loopback", 2, argv); + + grub_free (loop_name); + grub_free (argv[0]); + } +} + +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_("cat FILE"), 0, 0 , OPTION_DOC, N_("Copy FILE to standard output."), 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_("Show contents of FILE in hex."), 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}, + {N_("xnu_uuid DEVICE"), 0, 0, OPTION_DOC, N_("Compute XNU UUID of the device."), 1}, + + {"root", 'r', N_("DEVICE_NAME"), 0, N_("Set root device."), 2}, + {"skip", 's', N_("NUM"), 0, N_("Skip N bytes from output file."), 2}, + {"length", 'n', N_("NUM"), 0, N_("Handle N bytes in output file."), 2}, + {"diskcount", 'c', N_("NUM"), 0, N_("Specify the number of input files."), 2}, + {"debug", 'd', N_("STRING"), 0, N_("Set debug environment variable."), 2}, + {"crypto", 'C', NULL, 0, N_("Mount crypto devices."), 2}, + {"zfs-key", 'K', + /* TRANSLATORS: "prompt" is a keyword. */ + N_("FILE|prompt"), 0, N_("Load zfs crypto key."), 2}, + {"verbose", 'v', NULL, 0, N_("print verbose messages."), 2}, + {"uncompress", 'u', NULL, 0, N_("Uncompress data."), 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; + +static error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + const char *p; + + switch (key) + { + case 'r': + root = arg; + return 0; + + case 'K': + if (strcmp (arg, "prompt") == 0) + { + char buf[1024]; + grub_puts_ (N_("Enter ZFS password: ")); + if (grub_password_get (buf, 1023)) + { + grub_zfs_add_key ((grub_uint8_t *) buf, grub_strlen (buf), 1); + } + } + else + { + FILE *f; + ssize_t real_size; + grub_uint8_t buf[1024]; + f = grub_util_fopen (arg, "rb"); + if (!f) + { + printf (_("%s: error:"), program_name); + printf (_("cannot open `%s': %s"), arg, strerror (errno)); + printf ("\n"); + return 0; + } + real_size = fread (buf, 1, 1024, f); + fclose (f); + if (real_size < 0) + { + printf (_("%s: error:"), program_name); + printf (_("cannot read `%s': %s"), arg, strerror (errno)); + printf ("\n"); + return 0; + } + grub_zfs_add_key (buf, real_size, 0); + } + return 0; + + case 'C': + mount_crypt = 1; + 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) + { + /* TRANSLATORS: disk count is optional but if it's there it must + be before disk list. So please don't imply disk count as mandatory. + */ + 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 'u': + uncompress = 1; + 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 (args_count == 0) + images = xcalloc (num_disks, sizeof (images[0])); + images[args_count] = grub_canonicalize_file_name (arg); + args_count++; + return 0; + } + + if (args_count == num_disks) + { + if (!grub_strcmp (arg, "ls")) + { + cmd = CMD_LS; + } + else if (!grub_strcmp (arg, "zfsinfo")) + { + cmd = CMD_ZFSINFO; + } + else if (!grub_strcmp (arg, "cp")) + { + cmd = CMD_CP; + nparm = 2; + } + else if (!grub_strcmp (arg, "cat")) + { + cmd = CMD_CAT; + nparm = 1; + } + 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 if (!grub_strcmp (arg, "testload")) + { + cmd = CMD_TESTLOAD; + nparm = 1; + } + else if (grub_strcmp (arg, "xnu_uuid") == 0) + { + cmd = CMD_XNU_UUID; + nparm = 0; + } + 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[]) +{ + const char *default_root; + char *alloc_root; + + grub_util_host_init (&argc, &argv); + + args = xcalloc (argc, sizeof (args[0])); + + argp_parse (&argp, argc, argv, 0, 0, 0); + + /* Initialize all modules. */ + grub_init_all (); + grub_gcry_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); + + /* Free resources. */ + grub_gcry_fini_all (); + grub_fini_all (); + + return 0; +} diff --git a/util/grub-gen-asciih.c b/util/grub-gen-asciih.c new file mode 100644 index 0000000..e35dcb7 --- /dev/null +++ b/util/grub-gen-asciih.c @@ -0,0 +1,256 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <errno.h> + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TRUETYPE_TAGS_H +#include FT_TRUETYPE_TABLES_H +#include FT_SYNTHESIS_H + +#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 + +#define GRUB_FONT_DEFAULT_SIZE 16 + +#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) + +struct grub_glyph_info +{ + int width; + int height; + int x_ofs; + int y_ofs; + int device_width; + int bitmap_size; + unsigned char *bitmap; +}; + +static void +add_pixel (unsigned char **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 (FT_UInt glyph_idx, FT_Face face, + unsigned int char_code, + struct grub_glyph_info *glyph_info) +{ + int width, height; + int cuttop, cutbottom, cutleft, cutright; + unsigned char *data; + int mask, i, j, bitmap_size; + FT_GlyphSlot glyph; + int flag = FT_LOAD_RENDER | FT_LOAD_MONOCHROME; + FT_Error err; + + err = FT_Load_Glyph (face, glyph_idx, flag); + if (err) + { + fprintf (stderr, "Freetype Error %d loading glyph 0x%x for U+0x%x", + err, glyph_idx, char_code); + + if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs)) + fprintf (stderr, ": %s\n", ft_errmsgs[err]); + else + fprintf (stderr, "\n"); + exit (1); + } + + glyph = face->glyph; + + if (glyph->next) + printf ("%x\n", char_code); + + cuttop = cutbottom = cutleft = cutright = 0; + + width = glyph->bitmap.width; + height = glyph->bitmap.rows; + + bitmap_size = ((width * height + 7) / 8); + glyph_info->bitmap = malloc (bitmap_size); + if (!glyph_info->bitmap) + { + fprintf (stderr, "grub-gen-asciih: error: out of memory"); + exit (1); + } + glyph_info->bitmap_size = bitmap_size; + + glyph_info->width = width; + glyph_info->height = height; + glyph_info->x_ofs = glyph->bitmap_left; + glyph_info->y_ofs = glyph->bitmap_top - height; + glyph_info->device_width = glyph->metrics.horiAdvance / 64; + + 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)))); +} + +static void +write_font_ascii_bitmap (FILE *file, FT_Face face) +{ + int char_code; + + fprintf (file, "/* THIS CHUNK OF BYTES IS AUTOMATICALLY GENERATED */\n"); + fprintf (file, "unsigned char ascii_bitmaps[] =\n"); + fprintf (file, "{\n"); + + for (char_code = 0; char_code <= 0x7f; char_code++) + { + FT_UInt glyph_idx; + struct grub_glyph_info glyph; + + glyph_idx = FT_Get_Char_Index (face, char_code); + if (!glyph_idx) + return; + + memset (&glyph, 0, sizeof(glyph)); + + add_glyph (glyph_idx, face, char_code, &glyph); + + if (glyph.width == 8 && glyph.height == 16 + && glyph.x_ofs == 0 && glyph.y_ofs == 0) + { + int row; + for (row = 0; row < 16; row++) + fprintf (file, "0x%02x, ", glyph.bitmap[row]); + } + else + { + unsigned char glph[16]; + int p = 0, mask = 0x80; + int row, col; + int dy = 12 - glyph.height - glyph.y_ofs; + for (row = 0; row < 16; row++) + glph[row] = 0; + for (row = 0; row < glyph.height; row++) + for (col = 0; col < glyph.width; col++) + { + int val = glyph.bitmap[p] & mask; + mask >>= 1; + if (mask == 0) + { + mask = 0x80; + p++; + } + if (val && dy + row >= 0 + && dy + row < 16 + && glyph.x_ofs + col >= 0 + && glyph.x_ofs + col < 8) + glph[dy + row] |= 1 << (7 - (glyph.x_ofs + col)); + } + for (row = 0; row < 16; row++) + fprintf (file, "0x%02x, ", glph[row]); + } + fprintf (file, "\n"); + free (glyph.bitmap); + } + fprintf (file, "};\n"); +} + +int +main (int argc, char *argv[]) +{ + FT_Library ft_lib; + FT_Face ft_face; + FILE *file; + + if (argc != 3) + { + fprintf (stderr, "grub-gen-asciih: usage: INPUT OUTPUT"); + return 1; + } + + if (FT_Init_FreeType (&ft_lib)) + { + fprintf (stderr, "grub-gen-asciih: error: FT_Init_FreeType fails"); + return 1; + } + + { + int size; + FT_Error err; + + err = FT_New_Face (ft_lib, argv[1], 0, &ft_face); + if (err) + { + fprintf (stderr, "can't open file %s, index %d: error %d", + argv[1], 0, err); + if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs)) + fprintf (stderr, ": %s\n", ft_errmsgs[err]); + else + fprintf (stderr, "\n"); + + return 1; + } + + 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; + + if (FT_Set_Pixel_Sizes (ft_face, size, size)) + { + fprintf (stderr, "grub-gen-asciih: error: can't set %dx%d font size", size, size); + return 1; + } + } + + file = fopen (argv[2], "w"); + if (! file) + { + fprintf (stderr, "grub-gen-asciih: error: cannot write to `%s': %s", argv[2], + strerror (errno)); + return 1; + } + + write_font_ascii_bitmap (file, ft_face); + + fclose (file); + + FT_Done_Face (ft_face); + + FT_Done_FreeType (ft_lib); + + return 0; +} diff --git a/util/grub-gen-widthspec.c b/util/grub-gen-widthspec.c new file mode 100644 index 0000000..33bc8cb --- /dev/null +++ b/util/grub-gen-widthspec.c @@ -0,0 +1,153 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <errno.h> + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TRUETYPE_TAGS_H +#include FT_TRUETYPE_TABLES_H +#include FT_SYNTHESIS_H + +#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 + +#define GRUB_FONT_DEFAULT_SIZE 16 + +#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) + +#define MAX_CODE 65536 +static unsigned char result[MAX_CODE / 8]; + +static void +add_glyph (FT_Face face, + unsigned int char_code) +{ + int flag = FT_LOAD_RENDER | FT_LOAD_MONOCHROME; + FT_Error err; + FT_UInt glyph_idx; + + glyph_idx = FT_Get_Char_Index (face, char_code); + if (!glyph_idx) + return; + + err = FT_Load_Glyph (face, glyph_idx, flag); + if (err) + { + printf ("Freetype Error %d loading glyph 0x%x for U+0x%x", + err, glyph_idx, char_code); + + if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs)) + printf (": %s\n", ft_errmsgs[err]); + else + printf ("\n"); + return; + } + + if (face->glyph->bitmap.width > 12 && char_code < MAX_CODE) + result[char_code >> 3] |= (1 << (char_code & 7)); +} + +int +main (int argc, char *argv[]) +{ + FT_Library ft_lib; + FILE *file; + int i; + + if (argc != 3) + { + fprintf (stderr, "grub-gen-widthspec: usage: INPUT OUTPUT"); + return 1; + } + + if (FT_Init_FreeType (&ft_lib)) + { + fprintf (stderr, "grub-gen-widthspec: error: FT_Init_FreeType fails"); + return 1; + } + + { + FT_Face ft_face; + int size; + FT_Error err; + unsigned int char_code, glyph_index; + + err = FT_New_Face (ft_lib, argv[1], 0, &ft_face); + if (err) + { + fprintf (stderr, "can't open file %s, index %d: error %d", + argv[1], 0, err); + if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs)) + fprintf (stderr, ": %s\n", ft_errmsgs[err]); + else + fprintf (stderr, "\n"); + + return 1; + } + + 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; + + if (FT_Set_Pixel_Sizes (ft_face, size, size)) + { + fprintf (stderr, "grub-gen-widthspec: error: can't set %dx%d font size", size, size); + return 1; + } + + for (char_code = FT_Get_First_Char (ft_face, &glyph_index); + glyph_index; + char_code = FT_Get_Next_Char (ft_face, char_code, &glyph_index)) + add_glyph (ft_face, char_code); + + FT_Done_Face (ft_face); + } + + FT_Done_FreeType (ft_lib); + + file = fopen (argv[2], "w"); + if (! file) + { + fprintf (stderr, "grub-gen-asciih: error: cannot write to `%s': %s", argv[2], + strerror (errno)); + return 1; + } + + fprintf (file, "/* THIS CHUNK OF BYTES IS AUTOMATICALLY GENERATED */\n"); + fprintf (file, "unsigned char widthspec[] =\n"); + fprintf (file, "{\n"); + + for (i = 0; i < MAX_CODE / 8; i++) + fprintf (file, "0x%02x,%c", result[i], ((i & 0xf) == 0xf) ? '\n' : ' '); + + fprintf (file, "};\n"); + + fclose (file); + + return 0; +} diff --git a/util/grub-glue-efi.c b/util/grub-glue-efi.c new file mode 100644 index 0000000..07fa430 --- /dev/null +++ b/util/grub-glue-efi.c @@ -0,0 +1,125 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2012,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <grub/util/misc.h> +#include <grub/i18n.h> +#include <grub/term.h> +#include <grub/macho.h> +#include <grub/util/install.h> + +#define _GNU_SOURCE 1 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include "progname.h" + +struct arguments +{ + char *input32; + char *input64; + char *output; + int verbosity; +}; + +static struct argp_option options[] = { + {"input32", '3', N_("FILE"), 0, + N_("set input filename for 32-bit part."), 0}, + {"input64", '6', N_("FILE"), 0, + N_("set input filename for 64-bit part."), 0}, + {"output", 'o', N_("FILE"), 0, + N_("set output filename. Default is STDOUT"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + { 0, 0, 0, 0, 0, 0 } +}; + +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; + + switch (key) + { + case '6': + arguments->input64 = xstrdup (arg); + break; + case '3': + arguments->input32 = xstrdup (arg); + break; + + case 'o': + arguments->output = xstrdup (arg); + break; + + case 'v': + arguments->verbosity++; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +static struct argp argp = { + options, argp_parser, N_("[OPTIONS]"), + N_("Glue 32-bit and 64-bit binary into Apple universal one."), + NULL, NULL, NULL +}; + +int +main (int argc, char *argv[]) +{ + struct arguments arguments; + + grub_util_host_init (&argc, &argv); + + /* Check for options. */ + memset (&arguments, 0, sizeof (struct arguments)); + if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + if (!arguments.input32 || !arguments.input64) + { + fprintf (stderr, "%s", _("Missing input file\n")); + exit(1); + } + + grub_util_glue_efi (arguments.input32, + arguments.input64, + arguments.output); + + return 0; +} diff --git a/util/grub-install-common.c b/util/grub-install-common.c new file mode 100644 index 0000000..4e212e6 --- /dev/null +++ b/util/grub-install-common.c @@ -0,0 +1,1164 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/misc.h> +#include <grub/device.h> +#include <grub/disk.h> +#include <grub/file.h> +#include <grub/fs.h> +#include <grub/env.h> +#include <grub/term.h> +#include <grub/mm.h> +#include <grub/lib/hexdump.h> +#include <grub/crypto.h> +#include <grub/command.h> +#include <grub/i18n.h> +#include <grub/zfs/zfs.h> +#include <grub/util/install.h> +#include <grub/util/resolve.h> +#include <grub/emu/hostfile.h> +#include <grub/emu/config.h> +#include <grub/emu/hostfile.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +char * +grub_install_help_filter (int key, const char *text, + void *input __attribute__ ((unused))) +{ + switch (key) + { + case GRUB_INSTALL_OPTIONS_INSTALL_THEMES: + return xasprintf(text, "starfield"); + case GRUB_INSTALL_OPTIONS_INSTALL_FONTS: + return xasprintf(text, "unicode"); + case GRUB_INSTALL_OPTIONS_DIRECTORY: + case GRUB_INSTALL_OPTIONS_DIRECTORY2: + return xasprintf(text, grub_util_get_pkglibdir ()); + case GRUB_INSTALL_OPTIONS_LOCALE_DIRECTORY: + return xasprintf(text, grub_util_get_localedir ()); + case GRUB_INSTALL_OPTIONS_THEMES_DIRECTORY: + return grub_util_path_concat (2, grub_util_get_pkgdatadir (), "themes"); + default: + return (char *) text; + } +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +static int (*compress_func) (const char *src, const char *dest) = NULL; +char *grub_install_copy_buffer; +static char *dtb; + +int +grub_install_copy_file (const char *src, + const char *dst, + int is_needed) +{ + grub_util_fd_t in, out; + ssize_t r; + + grub_util_info ("copying `%s' -> `%s'", src, dst); + + in = grub_util_fd_open (src, GRUB_UTIL_FD_O_RDONLY); + if (!GRUB_UTIL_FD_IS_VALID (in)) + { + if (is_needed) + grub_util_error (_("cannot open `%s': %s"), src, grub_util_fd_strerror ()); + else + grub_util_info (_("cannot open `%s': %s"), src, grub_util_fd_strerror ()); + return 0; + } + out = grub_util_fd_open (dst, GRUB_UTIL_FD_O_WRONLY + | GRUB_UTIL_FD_O_CREATTRUNC); + if (!GRUB_UTIL_FD_IS_VALID (out)) + { + grub_util_error (_("cannot open `%s': %s"), dst, + grub_util_fd_strerror ()); + grub_util_fd_close (in); + return 0; + } + + if (!grub_install_copy_buffer) + grub_install_copy_buffer = xmalloc (GRUB_INSTALL_COPY_BUFFER_SIZE); + + while (1) + { + r = grub_util_fd_read (in, grub_install_copy_buffer, GRUB_INSTALL_COPY_BUFFER_SIZE); + if (r <= 0) + break; + r = grub_util_fd_write (out, grub_install_copy_buffer, r); + if (r <= 0) + break; + } + if (grub_util_fd_sync (out) < 0) + r = -1; + if (grub_util_fd_close (in) < 0) + r = -1; + if (grub_util_fd_close (out) < 0) + r = -1; + + if (r < 0) + grub_util_error (_("cannot copy `%s' to `%s': %s"), + src, dst, grub_util_fd_strerror ()); + + return 1; +} + +static int +grub_install_compress_file (const char *in_name, + const char *out_name, + int is_needed) +{ + int ret; + + if (!compress_func) + ret = grub_install_copy_file (in_name, out_name, is_needed); + else + { + grub_util_info ("compressing `%s' -> `%s'", in_name, out_name); + ret = !compress_func (in_name, out_name); + if (!ret && is_needed) + grub_util_warn (_("can't compress `%s' to `%s'"), in_name, out_name); + } + + if (!ret && is_needed) + grub_util_error (_("cannot copy `%s' to `%s': %s"), + in_name, out_name, grub_util_fd_strerror ()); + + return ret; +} + +static int +is_path_separator (char c) +{ +#if defined (__MINGW32__) || defined (__CYGWIN__) + if (c == '\\') + return 1; +#endif + if (c == '/') + return 1; + return 0; +} + +void +grub_install_mkdir_p (const char *dst) +{ + char *t = xstrdup (dst); + char *p; + for (p = t; *p; p++) + { + if (is_path_separator (*p)) + { + char s = *p; + *p = '\0'; + grub_util_mkdir (t); + *p = s; + } + } + grub_util_mkdir (t); + free (t); +} + +static int +strcmp_ext (const char *a, const char *b, const char *ext) +{ + char *bsuffix = grub_util_path_concat_ext (1, b, ext); + int r = strcmp (a, bsuffix); + + free (bsuffix); + return r; +} + +enum clean_grub_dir_mode +{ + CLEAN_NEW, + CLEAN_BACKUP, + CREATE_BACKUP, + RESTORE_BACKUP +}; + +#ifdef HAVE_ATEXIT +static size_t backup_dirs_size = 0; +static char **backup_dirs = NULL; +static pid_t backup_process = 0; +static int grub_install_backup_ponr = 0; + +void +grub_set_install_backup_ponr (void) +{ + grub_install_backup_ponr = 1; +} +#endif + +static void +clean_grub_dir_real (const char *di, enum clean_grub_dir_mode mode) +{ + grub_util_fd_dir_t d; + grub_util_fd_dirent_t de; + const char *suffix = ""; + + if ((mode == CLEAN_BACKUP) || (mode == RESTORE_BACKUP)) + suffix = "~"; + + d = grub_util_fd_opendir (di); + if (!d) + { + if (mode == CLEAN_BACKUP) + return; + grub_util_error (_("cannot open directory `%s': %s"), + di, grub_util_fd_strerror ()); + } + + while ((de = grub_util_fd_readdir (d))) + { + const char *ext = strrchr (de->d_name, '.'); + + if ((ext && (strcmp_ext (ext, ".mod", suffix) == 0 + || strcmp_ext (ext, ".lst", suffix) == 0 + || strcmp_ext (ext, ".img", suffix) == 0 + || strcmp_ext (ext, ".efi", suffix) == 0 + || strcmp_ext (ext, ".mo", suffix) == 0) + && strcmp_ext (de->d_name, "menu.lst", suffix) != 0) + || strcmp_ext (de->d_name, "modinfo.sh", suffix) == 0 + || strcmp_ext (de->d_name, "efiemu32.o", suffix) == 0 + || strcmp_ext (de->d_name, "efiemu64.o", suffix) == 0) + { + char *srcf = grub_util_path_concat (2, di, de->d_name); + + if (mode == CREATE_BACKUP) + { + char *dstf = grub_util_path_concat_ext (2, di, de->d_name, "~"); + + if (grub_util_rename (srcf, dstf) < 0) + grub_util_error (_("cannot backup `%s': %s"), srcf, + grub_util_fd_strerror ()); + free (dstf); + } + else if (mode == RESTORE_BACKUP) + { + char *dstf = grub_util_path_concat (2, di, de->d_name); + + dstf[strlen (dstf) - 1] = '\0'; + if (grub_util_rename (srcf, dstf) < 0) + grub_util_error (_("cannot restore `%s': %s"), dstf, + grub_util_fd_strerror ()); + free (dstf); + } + else + { + if (grub_util_unlink (srcf) < 0) + grub_util_error (_("cannot delete `%s': %s"), srcf, + grub_util_fd_strerror ()); + } + free (srcf); + } + } + grub_util_fd_closedir (d); +} + +#ifdef HAVE_ATEXIT +static void +restore_backup_atexit (void) +{ + size_t i; + + /* + * Some child inherited atexit() handler, did not clear it, and called it. + * Thus skip clean or restore logic. + */ + if (backup_process != getpid ()) + return; + + for (i = 0; i < backup_dirs_size; i++) + { + /* + * If past point of no return simply clean the backups. Otherwise + * cleanup newly installed files, and restore the backups. + */ + if (grub_install_backup_ponr) + clean_grub_dir_real (backup_dirs[i], CLEAN_BACKUP); + else + { + clean_grub_dir_real (backup_dirs[i], CLEAN_NEW); + clean_grub_dir_real (backup_dirs[i], RESTORE_BACKUP); + } + free (backup_dirs[i]); + } + + backup_dirs_size = 0; + + free (backup_dirs); +} + +static void +append_to_backup_dirs (const char *dir) +{ + backup_dirs = xrealloc (backup_dirs, sizeof (char *) * (backup_dirs_size + 1)); + backup_dirs[backup_dirs_size] = xstrdup (dir); + backup_dirs_size++; + if (!backup_process) + { + atexit (restore_backup_atexit); + backup_process = getpid (); + } +} +#else +static void +append_to_backup_dirs (const char *dir __attribute__ ((unused))) +{ +} +#endif + +static void +clean_grub_dir (const char *di) +{ + clean_grub_dir_real (di, CLEAN_BACKUP); + clean_grub_dir_real (di, CREATE_BACKUP); + append_to_backup_dirs (di); +} + +struct install_list +{ + int is_default; + char **entries; + size_t n_entries; + size_t n_alloc; +}; + +struct install_list install_modules = { 1, 0, 0, 0 }; +struct install_list modules = { 1, 0, 0, 0 }; +struct install_list install_locales = { 1, 0, 0, 0 }; +struct install_list install_fonts = { 1, 0, 0, 0 }; +struct install_list install_themes = { 1, 0, 0, 0 }; +char *grub_install_source_directory = NULL; +char *grub_install_locale_directory = NULL; +char *grub_install_themes_directory = NULL; + +int +grub_install_is_short_mbrgap_supported (void) +{ + int i, j; + static const char *whitelist[] = + { + "part_msdos", "biosdisk", "affs", "afs", "bfs", "archelp", + "cpio", "cpio_be", "newc", "odc", "ext2", "fat", "exfat", + "f2fs", "fshelp", "hfs", "hfsplus", "iso9660", "jfs", "minix", + "minix2", "minix3", "minix_be", "minix2_be", "nilfs2", "ntfs", + "ntfscomp", "reiserfs", "romfs", "sfs", "tar", "udf", "ufs1", + "ufs1_be", "ufs2", "xfs" + }; + + for (i = 0; i < modules.n_entries; i++) { + for (j = 0; j < ARRAY_SIZE (whitelist); j++) + if (strcmp(modules.entries[i], whitelist[j]) == 0) + break; + if (j == ARRAY_SIZE (whitelist)) + return 0; + } + + return 1; +} + +void +grub_install_push_module (const char *val) +{ + modules.is_default = 0; + if (modules.n_entries + 1 >= modules.n_alloc) + { + modules.n_alloc <<= 1; + if (modules.n_alloc < 16) + modules.n_alloc = 16; + modules.entries = xrealloc (modules.entries, + modules.n_alloc * sizeof (*modules.entries)); + } + modules.entries[modules.n_entries++] = xstrdup (val); + modules.entries[modules.n_entries] = NULL; +} + +void +grub_install_pop_module (void) +{ + modules.n_entries--; + free (modules.entries[modules.n_entries]); + modules.entries[modules.n_entries] = NULL; +} + + +static void +handle_install_list (struct install_list *il, const char *val, + int default_all) +{ + const char *ptr; + char **ce; + il->is_default = 0; + free (il->entries); + il->entries = NULL; + il->n_entries = 0; + if (strcmp (val, "all") == 0 && default_all) + { + il->is_default = 1; + return; + } + ptr = val; + while (1) + { + while (*ptr && grub_isspace (*ptr)) + ptr++; + if (!*ptr) + break; + while (*ptr && !grub_isspace (*ptr)) + ptr++; + il->n_entries++; + } + il->n_alloc = il->n_entries + 1; + il->entries = xcalloc (il->n_alloc, sizeof (il->entries[0])); + ptr = val; + for (ce = il->entries; ; ce++) + { + const char *bptr; + while (*ptr && grub_isspace (*ptr)) + ptr++; + if (!*ptr) + break; + bptr = ptr; + while (*ptr && !grub_isspace (*ptr)) + ptr++; + *ce = xmalloc (ptr - bptr + 1); + memcpy (*ce, bptr, ptr - bptr); + (*ce)[ptr - bptr] = '\0'; + } + *ce = NULL; +} + +static char **pubkeys; +static size_t npubkeys; +static char *sbat; +static int disable_shim_lock; +static grub_compression_t compression; + +int +grub_install_parse (int key, char *arg) +{ + switch (key) + { + case 'C': + if (grub_strcmp (arg, "xz") == 0) + { +#ifdef HAVE_LIBLZMA + compression = GRUB_COMPRESSION_XZ; +#else + grub_util_error ("%s", + _("grub-mkimage is compiled without XZ support")); +#endif + } + else if (grub_strcmp (arg, "none") == 0) + compression = GRUB_COMPRESSION_NONE; + else if (grub_strcmp (arg, "auto") == 0) + compression = GRUB_COMPRESSION_AUTO; + else + grub_util_error (_("Unknown compression format %s"), arg); + return 1; + case 'k': + pubkeys = xrealloc (pubkeys, + sizeof (pubkeys[0]) + * (npubkeys + 1)); + pubkeys[npubkeys++] = xstrdup (arg); + return 1; + case GRUB_INSTALL_OPTIONS_SBAT: + if (sbat) + free (sbat); + + sbat = xstrdup (arg); + return 1; + case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: + disable_shim_lock = 1; + return 1; + + case GRUB_INSTALL_OPTIONS_VERBOSITY: + verbosity++; + return 1; + + case GRUB_INSTALL_OPTIONS_DIRECTORY: + case GRUB_INSTALL_OPTIONS_DIRECTORY2: + free (grub_install_source_directory); + grub_install_source_directory = xstrdup (arg); + return 1; + case GRUB_INSTALL_OPTIONS_LOCALE_DIRECTORY: + free (grub_install_locale_directory); + grub_install_locale_directory = xstrdup (arg); + return 1; + case GRUB_INSTALL_OPTIONS_THEMES_DIRECTORY: + free (grub_install_themes_directory); + grub_install_themes_directory = xstrdup (arg); + return 1; + case GRUB_INSTALL_OPTIONS_INSTALL_MODULES: + handle_install_list (&install_modules, arg, 0); + return 1; + case GRUB_INSTALL_OPTIONS_MODULES: + handle_install_list (&modules, arg, 0); + return 1; + case GRUB_INSTALL_OPTIONS_INSTALL_LOCALES: + handle_install_list (&install_locales, arg, 0); + return 1; + case GRUB_INSTALL_OPTIONS_INSTALL_THEMES: + handle_install_list (&install_themes, arg, 0); + return 1; + case GRUB_INSTALL_OPTIONS_INSTALL_FONTS: + handle_install_list (&install_fonts, arg, 0); + return 1; + case GRUB_INSTALL_OPTIONS_DTB: + if (dtb) + free (dtb); + dtb = xstrdup (arg); + return 1; + case GRUB_INSTALL_OPTIONS_INSTALL_COMPRESS: + if (strcmp (arg, "no") == 0 + || strcmp (arg, "none") == 0) + { + compress_func = NULL; + return 1; + } + if (strcmp (arg, "gz") == 0) + { + compress_func = grub_install_compress_gzip; + return 1; + } + if (strcmp (arg, "xz") == 0) + { + compress_func = grub_install_compress_xz; + return 1; + } + if (strcmp (arg, "lzo") == 0) + { + compress_func = grub_install_compress_lzop; + return 1; + } + grub_util_error (_("Unrecognized compression `%s'"), arg); + case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE: + return 1; + default: + return 0; + } +} + +static int +decompressors (void) +{ + if (compress_func == grub_install_compress_gzip) + { + grub_install_push_module ("gzio"); + return 1; + } + if (compress_func == grub_install_compress_xz) + { + grub_install_push_module ("xzio"); + grub_install_push_module ("gcry_crc"); + return 2; + } + if (compress_func == grub_install_compress_lzop) + { + grub_install_push_module ("lzopio"); + grub_install_push_module ("adler32"); + grub_install_push_module ("gcry_crc"); + return 3; + } + return 0; +} + +void +grub_install_make_image_wrap_file (const char *dir, const char *prefix, + FILE *fp, const char *outname, + char *memdisk_path, + char *config_path, + const char *mkimage_target, int note) +{ + const struct grub_install_image_target_desc *tgt; + const char *const compnames[] = + { + [GRUB_COMPRESSION_AUTO] = "auto", + [GRUB_COMPRESSION_NONE] = "none", + [GRUB_COMPRESSION_XZ] = "xz", + [GRUB_COMPRESSION_LZMA] = "lzma", + }; + grub_size_t slen = 1; + char *s, *p; + char **pk, **md; + int dc = decompressors (); + + if (memdisk_path) + slen += 20 + grub_strlen (memdisk_path); + if (config_path) + slen += 20 + grub_strlen (config_path); + + for (pk = pubkeys; pk < pubkeys + npubkeys; pk++) + slen += 20 + grub_strlen (*pk); + + for (md = modules.entries; *md; md++) + { + slen += 10 + grub_strlen (*md); + } + + p = s = xmalloc (slen); + if (memdisk_path) + { + p = grub_stpcpy (p, "--memdisk '"); + p = grub_stpcpy (p, memdisk_path); + *p++ = '\''; + *p++ = ' '; + } + if (config_path) + { + p = grub_stpcpy (p, "--config '"); + p = grub_stpcpy (p, config_path); + *p++ = '\''; + *p++ = ' '; + } + for (pk = pubkeys; pk < pubkeys + npubkeys; pk++) + { + p = grub_stpcpy (p, "--pubkey '"); + p = grub_stpcpy (p, *pk); + *p++ = '\''; + *p++ = ' '; + } + + for (md = modules.entries; *md; md++) + { + *p++ = '\''; + p = grub_stpcpy (p, *md); + *p++ = '\''; + *p++ = ' '; + } + + *p = '\0'; + + grub_util_info ("grub-mkimage --directory '%s' --prefix '%s'" + " --output '%s' " + " --dtb '%s' " + "--sbat '%s' " + "--format '%s' --compression '%s' %s %s %s\n", + dir, prefix, + outname, dtb ? : "", sbat ? : "", mkimage_target, + compnames[compression], note ? "--note" : "", + disable_shim_lock ? "--disable-shim-lock" : "", s); + free (s); + + tgt = grub_install_get_image_target (mkimage_target); + if (!tgt) + grub_util_error (_("unknown target format %s"), mkimage_target); + + grub_install_generate_image (dir, prefix, fp, outname, + modules.entries, memdisk_path, + pubkeys, npubkeys, config_path, tgt, + note, compression, dtb, sbat, + disable_shim_lock); + while (dc--) + grub_install_pop_module (); +} + +void +grub_install_make_image_wrap (const char *dir, const char *prefix, + const char *outname, char *memdisk_path, + char *config_path, + const char *mkimage_target, int note) +{ + FILE *fp; + + fp = grub_util_fopen (outname, "wb"); + if (! fp) + grub_util_error (_("cannot open `%s': %s"), outname, + strerror (errno)); + grub_install_make_image_wrap_file (dir, prefix, fp, outname, + memdisk_path, config_path, + mkimage_target, note); + if (grub_util_file_sync (fp) < 0) + grub_util_error (_("cannot sync `%s': %s"), outname, strerror (errno)); + fclose (fp); +} + +static void +copy_by_ext (const char *srcd, + const char *dstd, + const char *extf, + int req) +{ + grub_util_fd_dir_t d; + grub_util_fd_dirent_t de; + + d = grub_util_fd_opendir (srcd); + if (!d && !req) + return; + if (!d) + grub_util_error (_("cannot open directory `%s': %s"), + srcd, grub_util_fd_strerror ()); + + while ((de = grub_util_fd_readdir (d))) + { + const char *ext = strrchr (de->d_name, '.'); + if (ext && strcmp (ext, extf) == 0) + { + char *srcf = grub_util_path_concat (2, srcd, de->d_name); + char *dstf = grub_util_path_concat (2, dstd, de->d_name); + grub_install_compress_file (srcf, dstf, 1); + free (srcf); + free (dstf); + } + } + grub_util_fd_closedir (d); +} + +static void +copy_all (const char *srcd, + const char *dstd) +{ + grub_util_fd_dir_t d; + grub_util_fd_dirent_t de; + + d = grub_util_fd_opendir (srcd); + if (!d) + grub_util_error (_("cannot open directory `%s': %s"), + srcd, grub_util_fd_strerror ()); + + while ((de = grub_util_fd_readdir (d))) + { + char *srcf; + char *dstf; + if (strcmp (de->d_name, ".") == 0 + || strcmp (de->d_name, "..") == 0) + continue; + srcf = grub_util_path_concat (2, srcd, de->d_name); + if (grub_util_is_special_file (srcf) + || grub_util_is_directory (srcf)) + continue; + dstf = grub_util_path_concat (2, dstd, de->d_name); + grub_install_compress_file (srcf, dstf, 1); + free (srcf); + free (dstf); + } + grub_util_fd_closedir (d); +} + +#if (defined (GRUB_UTIL) && defined(ENABLE_NLS) && ENABLE_NLS) +static const char * +get_localedir (void) +{ + if (grub_install_locale_directory) + return grub_install_locale_directory; + else + return grub_util_get_localedir (); +} + +static void +copy_locales (const char *dstd) +{ + grub_util_fd_dir_t d; + grub_util_fd_dirent_t de; + const char *locale_dir = get_localedir (); + + d = grub_util_fd_opendir (locale_dir); + if (!d) + { + grub_util_warn (_("cannot open directory `%s': %s"), + locale_dir, grub_util_fd_strerror ()); + return; + } + + while ((de = grub_util_fd_readdir (d))) + { + char *srcf; + char *dstf; + char *ext; + if (strcmp (de->d_name, ".") == 0) + continue; + if (strcmp (de->d_name, "..") == 0) + continue; + ext = grub_strrchr (de->d_name, '.'); + if (ext && (grub_strcmp (ext, ".mo") == 0 + || grub_strcmp (ext, ".gmo") == 0)) + { + srcf = grub_util_path_concat (2, locale_dir, de->d_name); + dstf = grub_util_path_concat (2, dstd, de->d_name); + ext = grub_strrchr (dstf, '.'); + grub_strcpy (ext, ".mo"); + } + else + { + srcf = grub_util_path_concat_ext (4, locale_dir, de->d_name, + "LC_MESSAGES", PACKAGE, ".mo"); + dstf = grub_util_path_concat_ext (2, dstd, de->d_name, ".mo"); + } + grub_install_compress_file (srcf, dstf, 0); + free (srcf); + free (dstf); + } + grub_util_fd_closedir (d); +} +#endif + +static void +grub_install_copy_nls(const char *src __attribute__ ((unused)), + const char *dst __attribute__ ((unused))) +{ +#if (defined (GRUB_UTIL) && defined(ENABLE_NLS) && ENABLE_NLS) + char *dst_locale; + + dst_locale = grub_util_path_concat (2, dst, "locale"); + grub_install_mkdir_p (dst_locale); + clean_grub_dir (dst_locale); + + if (install_locales.is_default) + { + char *srcd = grub_util_path_concat (2, src, "po"); + copy_by_ext (srcd, dst_locale, ".mo", 0); + copy_locales (dst_locale); + free (srcd); + } + else + { + size_t i; + const char *locale_dir = get_localedir (); + + for (i = 0; i < install_locales.n_entries; i++) + { + char *srcf = grub_util_path_concat_ext (3, src, "po", + install_locales.entries[i], + ".mo"); + char *dstf = grub_util_path_concat_ext (2, dst_locale, + install_locales.entries[i], + ".mo"); + if (grub_install_compress_file (srcf, dstf, 0)) + { + free (srcf); + free (dstf); + continue; + } + free (srcf); + srcf = grub_util_path_concat_ext (4, locale_dir, + install_locales.entries[i], + "LC_MESSAGES", PACKAGE, ".mo"); + if (grub_install_compress_file (srcf, dstf, 0) == 0) + grub_util_error (_("cannot find locale `%s'"), + install_locales.entries[i]); + free (srcf); + free (dstf); + } + } + free (dst_locale); +#endif +} + +static struct +{ + const char *cpu; + const char *platform; +} platforms[GRUB_INSTALL_PLATFORM_MAX] = + { + [GRUB_INSTALL_PLATFORM_I386_PC] = { "i386", "pc" }, + [GRUB_INSTALL_PLATFORM_I386_EFI] = { "i386", "efi" }, + [GRUB_INSTALL_PLATFORM_I386_QEMU] = { "i386", "qemu" }, + [GRUB_INSTALL_PLATFORM_I386_COREBOOT] = { "i386", "coreboot" }, + [GRUB_INSTALL_PLATFORM_I386_MULTIBOOT] = { "i386", "multiboot" }, + [GRUB_INSTALL_PLATFORM_I386_IEEE1275] = { "i386", "ieee1275" }, + [GRUB_INSTALL_PLATFORM_X86_64_EFI] = { "x86_64", "efi" }, + [GRUB_INSTALL_PLATFORM_I386_XEN] = { "i386", "xen" }, + [GRUB_INSTALL_PLATFORM_X86_64_XEN] = { "x86_64", "xen" }, + [GRUB_INSTALL_PLATFORM_I386_XEN_PVH] = { "i386", "xen_pvh" }, + [GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON] = { "mipsel", "loongson" }, + [GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS] = { "mipsel", "qemu_mips" }, + [GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS] = { "mips", "qemu_mips" }, + [GRUB_INSTALL_PLATFORM_MIPSEL_ARC] = { "mipsel", "arc" }, + [GRUB_INSTALL_PLATFORM_MIPS_ARC] = { "mips", "arc" }, + [GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275] = { "sparc64", "ieee1275" }, + [GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275] = { "powerpc", "ieee1275" }, + [GRUB_INSTALL_PLATFORM_IA64_EFI] = { "ia64", "efi" }, + [GRUB_INSTALL_PLATFORM_ARM_EFI] = { "arm", "efi" }, + [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64", "efi" }, + [GRUB_INSTALL_PLATFORM_ARM_UBOOT] = { "arm", "uboot" }, + [GRUB_INSTALL_PLATFORM_ARM_COREBOOT] = { "arm", "coreboot" }, + [GRUB_INSTALL_PLATFORM_RISCV32_EFI] = { "riscv32", "efi" }, + [GRUB_INSTALL_PLATFORM_RISCV64_EFI] = { "riscv64", "efi" }, + }; + +char * +grub_install_get_platforms_string (void) +{ + char **arr = xmalloc (sizeof (char *) * ARRAY_SIZE (platforms)); + int platform_strins_len = 0; + char *platforms_string; + char *ptr; + unsigned i; + for (i = 0; i < ARRAY_SIZE (platforms); i++) + { + arr[i] = xasprintf ("%s-%s", platforms[i].cpu, + platforms[i].platform); + platform_strins_len += strlen (arr[i]) + 2; + } + ptr = platforms_string = xmalloc (platform_strins_len); + qsort (arr, ARRAY_SIZE (platforms), sizeof (char *), grub_qsort_strcmp); + for (i = 0; i < ARRAY_SIZE (platforms); i++) + { + strcpy (ptr, arr[i]); + ptr += strlen (arr[i]); + *ptr++ = ','; + *ptr++ = ' '; + free (arr[i]); + } + ptr[-2] = 0; + free (arr); + + return platforms_string; +} + +char * +grub_install_get_platform_name (enum grub_install_plat platid) +{ + return xasprintf ("%s-%s", platforms[platid].cpu, + platforms[platid].platform); +} + +const char * +grub_install_get_platform_cpu (enum grub_install_plat platid) +{ + return platforms[platid].cpu; +} + +const char * +grub_install_get_platform_platform (enum grub_install_plat platid) +{ + return platforms[platid].platform; +} + + +void +grub_install_copy_files (const char *src, + const char *dst, + enum grub_install_plat platid) +{ + char *dst_platform, *dst_fonts; + const char *pkgdatadir = grub_util_get_pkgdatadir (); + char *themes_dir; + + { + char *platform; + platform = xasprintf ("%s-%s", platforms[platid].cpu, + platforms[platid].platform); + dst_platform = grub_util_path_concat (2, dst, platform); + free (platform); + } + dst_fonts = grub_util_path_concat (2, dst, "fonts"); + grub_install_mkdir_p (dst_platform); + clean_grub_dir (dst); + clean_grub_dir (dst_platform); + + grub_install_copy_nls(src, dst); + + if (install_modules.is_default) + copy_by_ext (src, dst_platform, ".mod", 1); + else + { + struct grub_util_path_list *path_list, *p; + + path_list = grub_util_resolve_dependencies (src, "moddep.lst", + install_modules.entries); + for (p = path_list; p; p = p->next) + { + const char *srcf = p->name; + const char *dir; + char *dstf; + + dir = grub_strrchr (srcf, '/'); + if (dir) + dir++; + else + dir = srcf; + dstf = grub_util_path_concat (2, dst_platform, dir); + grub_install_compress_file (srcf, dstf, 1); + free (dstf); + } + + grub_util_free_path_list (path_list); + } + + const char *pkglib_DATA[] = {"efiemu32.o", "efiemu64.o", + "moddep.lst", "command.lst", + "fs.lst", "partmap.lst", + "parttool.lst", + "video.lst", "crypto.lst", + "terminal.lst", "modinfo.sh" }; + size_t i; + + for (i = 0; i < ARRAY_SIZE (pkglib_DATA); i++) + { + char *srcf = grub_util_path_concat (2, src, pkglib_DATA[i]); + char *dstf = grub_util_path_concat (2, dst_platform, pkglib_DATA[i]); + if (i == 0 || i == 1) + grub_install_compress_file (srcf, dstf, 0); + else + grub_install_compress_file (srcf, dstf, 1); + free (srcf); + free (dstf); + } + + if (install_themes.is_default) + { + install_themes.is_default = 0; + install_themes.n_entries = 1; + install_themes.entries = xmalloc (2 * sizeof (install_themes.entries[0])); + install_themes.entries[0] = xstrdup ("starfield"); + install_themes.entries[1] = NULL; + } + + if (grub_install_themes_directory) + themes_dir = xstrdup (grub_install_themes_directory); + else + themes_dir = grub_util_path_concat (2, grub_util_get_pkgdatadir (), + "themes"); + + for (i = 0; i < install_themes.n_entries; i++) + { + char *srcf = grub_util_path_concat (3, themes_dir, + install_themes.entries[i], + "theme.txt"); + if (grub_util_is_regular (srcf)) + { + char *srcd = grub_util_path_concat (2, themes_dir, + install_themes.entries[i]); + char *dstd = grub_util_path_concat (3, dst, "themes", + install_themes.entries[i]); + grub_install_mkdir_p (dstd); + copy_all (srcd, dstd); + free (srcd); + free (dstd); + } + free (srcf); + } + + free (themes_dir); + + if (install_fonts.is_default) + { + install_fonts.is_default = 0; + install_fonts.n_entries = 1; + install_fonts.entries = xmalloc (2 * sizeof (install_fonts.entries[0])); + install_fonts.entries[0] = xstrdup ("unicode"); + install_fonts.entries[1] = NULL; + } + + grub_install_mkdir_p (dst_fonts); + + for (i = 0; i < install_fonts.n_entries; i++) + { + char *srcf = grub_util_path_concat_ext (2, pkgdatadir, + install_fonts.entries[i], + ".pf2"); + char *dstf = grub_util_path_concat_ext (2, dst_fonts, + install_fonts.entries[i], + ".pf2"); + + grub_install_compress_file (srcf, dstf, 0); + free (srcf); + free (dstf); + } + + free (dst_platform); + free (dst_fonts); +} + +enum grub_install_plat +grub_install_get_target (const char *src) +{ + char *fn; + grub_util_fd_t f; + char buf[8192]; + ssize_t r; + char *c, *pl, *p; + size_t i; + fn = grub_util_path_concat (2, src, "modinfo.sh"); + f = grub_util_fd_open (fn, GRUB_UTIL_FD_O_RDONLY); + if (!GRUB_UTIL_FD_IS_VALID (f)) + grub_util_error (_("%s doesn't exist. Please specify --target or --directory"), + fn); + r = grub_util_fd_read (f, buf, sizeof (buf) - 1); + if (r < 0) + grub_util_error (_("cannot read `%s': %s"), fn, strerror (errno)); + grub_util_fd_close (f); + buf[r] = '\0'; + c = strstr (buf, "grub_modinfo_target_cpu="); + if (!c || (c != buf && !grub_isspace (*(c-1)))) + grub_util_error (_("invalid modinfo file `%s'"), fn); + pl = strstr (buf, "grub_modinfo_platform="); + if (!pl || (pl != buf && !grub_isspace (*(pl-1)))) + grub_util_error (_("invalid modinfo file `%s'"), fn); + c += sizeof ("grub_modinfo_target_cpu=") - 1; + pl += sizeof ("grub_modinfo_platform=") - 1; + for (p = c; *p && !grub_isspace (*p); p++); + *p = '\0'; + for (p = pl; *p && !grub_isspace (*p); p++); + *p = '\0'; + + for (i = 0; i < ARRAY_SIZE (platforms); i++) + if (strcmp (platforms[i].cpu, c) == 0 + && strcmp (platforms[i].platform, pl) == 0) + { + free (fn); + return i; + } + grub_util_error (_("Unknown platform `%s-%s'"), c, pl); +} + + +void +grub_util_unlink_recursive (const char *name) +{ + grub_util_fd_dir_t d; + grub_util_fd_dirent_t de; + + d = grub_util_fd_opendir (name); + + while ((de = grub_util_fd_readdir (d))) + { + char *fp; + if (strcmp (de->d_name, ".") == 0) + continue; + if (strcmp (de->d_name, "..") == 0) + continue; + fp = grub_util_path_concat (2, name, de->d_name); + if (grub_util_is_special_file (fp)) + { + free (fp); + continue; + } + if (grub_util_is_regular (fp)) + grub_util_unlink (fp); + else if (grub_util_is_directory (fp)) + grub_util_unlink_recursive (fp); + free (fp); + } + grub_util_rmdir (name); + grub_util_fd_closedir (d); +} diff --git a/util/grub-install.c b/util/grub-install.c new file mode 100644 index 0000000..0fbe7f7 --- /dev/null +++ b/util/grub-install.c @@ -0,0 +1,2000 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/misc.h> +#include <grub/device.h> +#include <grub/disk.h> +#include <grub/file.h> +#include <grub/fs.h> +#include <grub/env.h> +#include <grub/term.h> +#include <grub/mm.h> +#include <grub/lib/hexdump.h> +#include <grub/crypto.h> +#include <grub/command.h> +#include <grub/i18n.h> +#include <grub/zfs/zfs.h> +#include <grub/util/install.h> +#include <grub/emu/getroot.h> +#include <grub/diskfilter.h> +#include <grub/cryptodisk.h> +#include <grub/legacy_parse.h> +#include <grub/gpt_partition.h> +#include <grub/emu/config.h> +#include <grub/util/ofpath.h> +#include <grub/hfsplus.h> + +#include <string.h> + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include "progname.h" + +static char *target; +static int removable = 0; +static int recheck = 0; +static int update_nvram = 1; +static char *install_device = NULL; +static char *debug_image = NULL; +static char *rootdir = NULL; +static char *bootdir = NULL; +static int allow_floppy = 0; +static int force_file_id = 0; +static char *disk_module = NULL; +static char *efidir = NULL; +static char *macppcdir = NULL; +static int force = 0; +static int have_abstractions = 0; +static int have_cryptodisk = 0; +static char * bootloader_id; +static int have_load_cfg = 0; +static FILE * load_cfg_f = NULL; +static char *load_cfg; +static int install_bootsector = 1; +static char *label_font; +static char *label_color; +static char *label_bgcolor; +static char *product_version; +static int add_rs_codes = 1; + +enum + { + OPTION_BOOT_DIRECTORY = 0x301, + OPTION_ROOT_DIRECTORY, + OPTION_TARGET, + OPTION_SETUP, + OPTION_MKRELPATH, + OPTION_MKDEVICEMAP, + OPTION_PROBE, + OPTION_EDITENV, + OPTION_ALLOW_FLOPPY, + OPTION_RECHECK, + OPTION_FORCE, + OPTION_FORCE_FILE_ID, + OPTION_NO_NVRAM, + OPTION_REMOVABLE, + OPTION_BOOTLOADER_ID, + OPTION_EFI_DIRECTORY, + OPTION_FONT, + OPTION_DEBUG, + OPTION_DEBUG_IMAGE, + OPTION_NO_FLOPPY, + OPTION_DISK_MODULE, + OPTION_NO_BOOTSECTOR, + OPTION_NO_RS_CODES, + OPTION_MACPPC_DIRECTORY, + OPTION_LABEL_FONT, + OPTION_LABEL_COLOR, + OPTION_LABEL_BGCOLOR, + OPTION_PRODUCT_VERSION + }; + +static int fs_probe = 1; + +static error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + if (grub_install_parse (key, arg)) + return 0; + switch (key) + { + case OPTION_FORCE_FILE_ID: + force_file_id = 1; + return 0; + case 's': + fs_probe = 0; + return 0; + + case OPTION_SETUP: + if (!grub_strstr (arg, "setup")) + install_bootsector = 0; + return 0; + + case OPTION_PRODUCT_VERSION: + free (product_version); + product_version = xstrdup (arg); + return 0; + case OPTION_LABEL_FONT: + free (label_font); + label_font = xstrdup (arg); + return 0; + + case OPTION_LABEL_COLOR: + free (label_color); + label_color = xstrdup (arg); + return 0; + + case OPTION_LABEL_BGCOLOR: + free (label_bgcolor); + label_bgcolor = xstrdup (arg); + return 0; + + /* Accept and ignore for compatibility. */ + case OPTION_FONT: + case OPTION_MKRELPATH: + case OPTION_PROBE: + case OPTION_EDITENV: + case OPTION_MKDEVICEMAP: + case OPTION_NO_FLOPPY: + return 0; + case OPTION_ROOT_DIRECTORY: + /* Accept for compatibility. */ + free (rootdir); + rootdir = xstrdup (arg); + return 0; + + case OPTION_BOOT_DIRECTORY: + free (bootdir); + bootdir = xstrdup (arg); + return 0; + + case OPTION_MACPPC_DIRECTORY: + free (macppcdir); + macppcdir = xstrdup (arg); + return 0; + + case OPTION_EFI_DIRECTORY: + free (efidir); + efidir = xstrdup (arg); + return 0; + + case OPTION_DISK_MODULE: + free (disk_module); + disk_module = xstrdup (arg); + return 0; + + case OPTION_TARGET: + free (target); + target = xstrdup (arg); + return 0; + + case OPTION_DEBUG_IMAGE: + free (debug_image); + debug_image = xstrdup (arg); + return 0; + + case OPTION_NO_NVRAM: + update_nvram = 0; + return 0; + + case OPTION_FORCE: + force = 1; + return 0; + + case OPTION_RECHECK: + recheck = 1; + return 0; + + case OPTION_REMOVABLE: + removable = 1; + return 0; + + case OPTION_ALLOW_FLOPPY: + allow_floppy = 1; + return 0; + + case OPTION_NO_BOOTSECTOR: + install_bootsector = 0; + return 0; + + case OPTION_NO_RS_CODES: + add_rs_codes = 0; + return 0; + + case OPTION_DEBUG: + verbosity++; + return 0; + + case OPTION_BOOTLOADER_ID: + free (bootloader_id); + bootloader_id = xstrdup (arg); + return 0; + + case ARGP_KEY_ARG: + if (install_device) + grub_util_error ("%s", _("More than one install device?")); + install_device = xstrdup (arg); + return 0; + + default: + return ARGP_ERR_UNKNOWN; + } +} + + +static struct argp_option options[] = { + GRUB_INSTALL_OPTIONS, + {"boot-directory", OPTION_BOOT_DIRECTORY, N_("DIR"), + 0, N_("install GRUB images under the directory DIR/%s instead of the %s directory"), 2}, + {"root-directory", OPTION_ROOT_DIRECTORY, N_("DIR"), + OPTION_HIDDEN, 0, 2}, + {"font", OPTION_FONT, N_("FILE"), + OPTION_HIDDEN, 0, 2}, + {"target", OPTION_TARGET, N_("TARGET"), + /* TRANSLATORS: "TARGET" as in "target platform". */ + 0, N_("install GRUB for TARGET platform [default=%s]; available targets: %s"), 2}, + {"grub-setup", OPTION_SETUP, "FILE", OPTION_HIDDEN, 0, 2}, + {"grub-mkrelpath", OPTION_MKRELPATH, "FILE", OPTION_HIDDEN, 0, 2}, + {"grub-mkdevicemap", OPTION_MKDEVICEMAP, "FILE", OPTION_HIDDEN, 0, 2}, + {"grub-probe", OPTION_PROBE, "FILE", OPTION_HIDDEN, 0, 2}, + {"grub-editenv", OPTION_EDITENV, "FILE", OPTION_HIDDEN, 0, 2}, + {"allow-floppy", OPTION_ALLOW_FLOPPY, 0, 0, + /* TRANSLATORS: "may break" doesn't just mean that option wouldn't have any + effect but that it will make the resulting install unbootable from HDD. */ + N_("make the drive also bootable as floppy (default for fdX devices)." + " May break on some BIOSes."), 2}, + {"recheck", OPTION_RECHECK, 0, 0, + N_("delete device map if it already exists"), 2}, + {"force", OPTION_FORCE, 0, 0, + N_("install even if problems are detected"), 2}, + {"force-file-id", OPTION_FORCE_FILE_ID, 0, 0, + N_("use identifier file even if UUID is available"), 2}, + {"disk-module", OPTION_DISK_MODULE, N_("MODULE"), 0, + N_("disk module to use (biosdisk or native). " + "This option is only available on BIOS target."), 2}, + {"no-nvram", OPTION_NO_NVRAM, 0, 0, + N_("don't update the `boot-device'/`Boot*' NVRAM variables. " + "This option is only available on EFI and IEEE1275 targets."), 2}, + {"skip-fs-probe",'s',0, 0, + N_("do not probe for filesystems in DEVICE"), 0}, + {"no-bootsector", OPTION_NO_BOOTSECTOR, 0, 0, + N_("do not install bootsector"), 0}, + {"no-rs-codes", OPTION_NO_RS_CODES, 0, 0, + N_("Do not apply any reed-solomon codes when embedding core.img. " + "This option is only available on x86 BIOS targets."), 0}, + + {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2}, + {"no-floppy", OPTION_NO_FLOPPY, 0, OPTION_HIDDEN, 0, 2}, + {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2}, + {"removable", OPTION_REMOVABLE, 0, 0, + N_("the installation device is removable. " + "This option is only available on EFI."), 2}, + {"bootloader-id", OPTION_BOOTLOADER_ID, N_("ID"), 0, + N_("the ID of bootloader. This option is only available on EFI and Macs."), 2}, + {"efi-directory", OPTION_EFI_DIRECTORY, N_("DIR"), 0, + N_("use DIR as the EFI System Partition root."), 2}, + {"macppc-directory", OPTION_MACPPC_DIRECTORY, N_("DIR"), 0, + N_("use DIR for PPC MAC install."), 2}, + {"label-font", OPTION_LABEL_FONT, N_("FILE"), 0, N_("use FILE as font for label"), 2}, + {"label-color", OPTION_LABEL_COLOR, N_("COLOR"), 0, N_("use COLOR for label"), 2}, + {"label-bgcolor", OPTION_LABEL_BGCOLOR, N_("COLOR"), 0, N_("use COLOR for label background"), 2}, + {"product-version", OPTION_PRODUCT_VERSION, N_("STRING"), 0, N_("use STRING as product version"), 2}, + {0, 0, 0, 0, 0, 0} +}; + +static const char * +get_default_platform (void) +{ +#ifdef __powerpc__ + return "powerpc-ieee1275"; +#elif defined (__sparc__) || defined (__sparc64__) + return "sparc64-ieee1275"; +#elif defined (__MIPSEL__) + return "mipsel-loongson"; +#elif defined (__MIPSEB__) + return "mips-arc"; +#elif defined (__ia64__) + return "ia64-efi"; +#elif defined (__arm__) + return grub_install_get_default_arm_platform (); +#elif defined (__aarch64__) + return "arm64-efi"; +#elif defined (__amd64__) || defined (__x86_64__) || defined (__i386__) + return grub_install_get_default_x86_platform (); +#elif defined (__riscv) +#if __riscv_xlen == 32 + return "riscv32-efi"; +#elif __riscv_xlen == 64 + return "riscv64-efi"; +#else + return NULL; +#endif +#else + return NULL; +#endif +} + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +static char * +help_filter (int key, const char *text, void *input __attribute__ ((unused))) +{ + switch (key) + { + case OPTION_BOOT_DIRECTORY: + return xasprintf (text, GRUB_DIR_NAME, GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME); + case OPTION_TARGET: + { + char *plats = grub_install_get_platforms_string (); + char *ret; + ret = xasprintf (text, get_default_platform (), plats); + free (plats); + return ret; + } + case ARGP_KEY_HELP_POST_DOC: + return xasprintf (text, program_name, GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME); + default: + return grub_install_help_filter (key, text, input); + } +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +/* TRANSLATORS: INSTALL_DEVICE isn't an identifier and is the DEVICE you + install to. */ +struct argp argp = { + options, argp_parser, N_("[OPTION] [INSTALL_DEVICE]"), + N_("Install GRUB on your drive.")"\v" + N_("INSTALL_DEVICE must be system device filename.\n" + "%s copies GRUB images into %s. On some platforms, it" + " may also install GRUB into the boot sector."), + NULL, help_filter, NULL +}; + +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_DISKFILTER_ID) + return -1; + + if (disk->name[0] != 'm' || disk->name[1] != 'd') + return -1; + + if (!((struct grub_diskfilter_lv *) disk->data)->segments) + return -1; + return ((struct grub_diskfilter_lv *) disk->data)->segments->type; +} + +static void +push_partmap_module (const char *map, void *data __attribute__ ((unused))) +{ + char buf[50]; + + if (strcmp (map, "openbsd") == 0 || strcmp (map, "netbsd") == 0) + { + grub_install_push_module ("part_bsd"); + return; + } + + snprintf (buf, sizeof (buf), "part_%s", map); + grub_install_push_module (buf); +} + +static void +push_cryptodisk_module (const char *mod, void *data __attribute__ ((unused))) +{ + grub_install_push_module (mod); +} + +static void +probe_mods (grub_disk_t disk) +{ + grub_partition_t part; + grub_disk_memberlist_t list = NULL, tmp; + int raid_level; + + if (disk->partition == NULL) + grub_util_info ("no partition map found for %s", disk->name); + + for (part = disk->partition; part; part = part->parent) + push_partmap_module (part->partmap->name, NULL); + + if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID) + { + grub_diskfilter_get_partmap (disk, push_partmap_module, NULL); + have_abstractions = 1; + } + + if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID + && (grub_memcmp (disk->name, "lvm/", sizeof ("lvm/") - 1) == 0 || + grub_memcmp (disk->name, "lvmid/", sizeof ("lvmid/") - 1) == 0)) + grub_install_push_module ("lvm"); + + if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID + && grub_memcmp (disk->name, "ldm/", sizeof ("ldm/") - 1) == 0) + grub_install_push_module ("ldm"); + + if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) + { + grub_util_cryptodisk_get_abstraction (disk, + push_cryptodisk_module, NULL); + have_abstractions = 1; + have_cryptodisk = 1; + } + + raid_level = probe_raid_level (disk); + if (raid_level >= 0) + { + grub_install_push_module ("diskfilter"); + if (disk->dev->disk_raidname) + grub_install_push_module (disk->dev->disk_raidname (disk)); + } + if (raid_level == 5) + grub_install_push_module ("raid5rec"); + if (raid_level == 6) + grub_install_push_module ("raid6rec"); + + /* In case of LVM/RAID, check the member devices as well. */ + if (disk->dev->disk_memberlist) + list = disk->dev->disk_memberlist (disk); + while (list) + { + probe_mods (list->disk); + tmp = list->next; + free (list); + list = tmp; + } +} + +static int +have_bootdev (enum grub_install_plat pl) +{ + switch (pl) + { + case GRUB_INSTALL_PLATFORM_I386_PC: + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + return 1; + + case GRUB_INSTALL_PLATFORM_I386_QEMU: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + return 0; + + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + return 0; + } + return 0; +} + +static void +probe_cryptodisk_uuid (grub_disk_t disk) +{ + grub_disk_memberlist_t list = NULL, tmp; + + /* In case of LVM/RAID, check the member devices as well. */ + if (disk->dev->disk_memberlist) + { + list = disk->dev->disk_memberlist (disk); + } + while (list) + { + probe_cryptodisk_uuid (list->disk); + tmp = list->next; + free (list); + list = tmp; + } + if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) + { + const char *uuid = grub_util_cryptodisk_get_uuid (disk); + if (!load_cfg_f) + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + have_load_cfg = 1; + + fprintf (load_cfg_f, "cryptomount -u %s\n", + uuid); + } +} + +static int +is_same_disk (const char *a, const char *b) +{ + while (1) + { + if ((*a == ',' || *a == '\0') && (*b == ',' || *b == '\0')) + return 1; + if (*a != *b) + return 0; + if (*a == '\\') + { + if (a[1] != b[1]) + return 0; + a += 2; + b += 2; + continue; + } + a++; + b++; + } +} + +static char * +get_rndstr (void) +{ + grub_uint8_t rnd[15]; + const size_t sz = sizeof (rnd) * GRUB_CHAR_BIT / 5; + char * ret = xmalloc (sz + 1); + size_t i; + if (grub_get_random (rnd, sizeof (rnd))) + grub_util_error ("%s", _("couldn't retrieve random data")); + for (i = 0; i < sz; i++) + { + grub_size_t b = i * 5; + grub_uint8_t r; + grub_size_t f1 = GRUB_CHAR_BIT - b % GRUB_CHAR_BIT; + grub_size_t f2; + if (f1 > 5) + f1 = 5; + f2 = 5 - f1; + r = (rnd[b / GRUB_CHAR_BIT] >> (b % GRUB_CHAR_BIT)) & ((1 << f1) - 1); + if (f2) + r |= (rnd[b / GRUB_CHAR_BIT + 1] & ((1 << f2) - 1)) << f1; + if (r < 10) + ret[i] = '0' + r; + else + ret[i] = 'a' + (r - 10); + } + ret[sz] = '\0'; + return ret; +} + +static char * +escape (const char *in) +{ + char *ptr; + char *ret; + int overhead = 0; + + for (ptr = (char*)in; *ptr; ptr++) + if (*ptr == '\'') + overhead += 3; + ret = grub_malloc (ptr - in + overhead + 1); + if (!ret) + return NULL; + + grub_strchrsub (ret, in, '\'', "'\\''"); + return ret; +} + +static struct grub_util_config config; + +static void +device_map_check_duplicates (const char *dev_map) +{ + FILE *fp; + char buf[1024]; /* XXX */ + size_t alloced = 8; + size_t filled = 0; + char **d; + size_t i; + + if (dev_map[0] == '\0') + return; + + fp = grub_util_fopen (dev_map, "r"); + if (! fp) + return; + + d = xcalloc (alloced, sizeof (d[0])); + + while (fgets (buf, sizeof (buf), fp)) + { + char *p = buf; + char *e; + + /* Skip leading spaces. */ + while (*p && grub_isspace (*p)) + p++; + + /* If the first character is `#' or NUL, skip this line. */ + if (*p == '\0' || *p == '#') + continue; + + if (*p != '(') + continue; + + p++; + + e = p; + p = strchr (p, ')'); + if (! p) + continue; + + if (filled >= alloced) + { + alloced *= 2; + d = xrealloc (d, alloced * sizeof (d[0])); + } + + *p = '\0'; + + d[filled++] = xstrdup (e); + } + + fclose (fp); + + qsort (d, filled, sizeof (d[0]), grub_qsort_strcmp); + + for (i = 0; i + 1 < filled; i++) + if (strcmp (d[i], d[i+1]) == 0) + { + grub_util_error (_("the drive %s is defined multiple times in the device map %s"), + d[i], dev_map); + } + + for (i = 0; i < filled; i++) + free (d[i]); + + free (d); +} + +static grub_err_t +write_to_disk (grub_device_t dev, const char *fn) +{ + char *core_img; + size_t core_size; + grub_err_t err; + + core_size = grub_util_get_image_size (fn); + + core_img = grub_util_read_image (fn); + + grub_util_info ("writing `%s' to `%s'", fn, dev->disk->name); + err = grub_disk_write (dev->disk, 0, 0, + core_size, core_img); + free (core_img); + return err; +} + +static int +is_prep_partition (grub_device_t dev) +{ + if (!dev->disk) + return 0; + if (!dev->disk->partition) + return 0; + if (strcmp(dev->disk->partition->partmap->name, "msdos") == 0) + return (dev->disk->partition->msdostype == 0x41); + + if (strcmp (dev->disk->partition->partmap->name, "gpt") == 0) + { + struct grub_gpt_partentry gptdata; + grub_partition_t p = dev->disk->partition; + int ret = 0; + dev->disk->partition = dev->disk->partition->parent; + + if (grub_disk_read (dev->disk, p->offset, p->index, + sizeof (gptdata), &gptdata) == 0) + { + const grub_gpt_part_guid_t template = { + grub_cpu_to_le32_compile_time (0x9e1a2d38), + grub_cpu_to_le16_compile_time (0xc612), + grub_cpu_to_le16_compile_time (0x4316), + { 0xaa, 0x26, 0x8b, 0x49, 0x52, 0x1e, 0x5a, 0x8b } + }; + + ret = grub_memcmp (&template, &gptdata.type, + sizeof (template)) == 0; + } + dev->disk->partition = p; + return ret; + } + + return 0; +} + +static int +is_prep_empty (grub_device_t dev) +{ + grub_disk_addr_t dsize, addr; + grub_uint32_t buffer[32768]; + + dsize = grub_disk_native_sectors (dev->disk); + for (addr = 0; addr < dsize; + addr += sizeof (buffer) / GRUB_DISK_SECTOR_SIZE) + { + grub_size_t sz = sizeof (buffer); + grub_uint32_t *ptr; + + if (sizeof (buffer) / GRUB_DISK_SECTOR_SIZE > dsize - addr) + sz = (dsize - addr) * GRUB_DISK_SECTOR_SIZE; + grub_disk_read (dev->disk, addr, 0, sz, buffer); + + if (addr == 0 && grub_memcmp (buffer, ELFMAG, SELFMAG) == 0) + return 1; + + for (ptr = buffer; ptr < buffer + sz / sizeof (*buffer); ptr++) + if (*ptr) + return 0; + } + + return 1; +} + +static void +bless (grub_device_t dev, const char *path, int x86) +{ + struct stat st; + grub_err_t err; + + grub_util_info ("blessing %s", path); + + if (stat (path, &st) < 0) + grub_util_error (N_("cannot stat `%s': %s"), + path, strerror (errno)); + + err = grub_mac_bless_inode (dev, st.st_ino, S_ISDIR (st.st_mode), x86); + if (err) + grub_util_error ("%s", grub_errmsg); + grub_util_info ("blessed"); +} + +static void +fill_core_services (const char *core_services) +{ + char *label; + FILE *f; + char *label_text; + char *label_string = xasprintf ("%s %s", bootloader_id, product_version); + char *sysv_plist; + + label = grub_util_path_concat (2, core_services, ".disk_label"); + grub_util_info ("rendering label %s", label_string); + grub_util_render_label (label_font, label_bgcolor ? : "white", + label_color ? : "black", label_string, label); + grub_util_info ("label rendered"); + free (label); + label_text = grub_util_path_concat (2, core_services, ".disk_label.contentDetails"); + f = grub_util_fopen (label_text, "wb"); + fprintf (f, "%s\n", label_string); + fclose (f); + free (label_string); + free (label_text); + + sysv_plist = grub_util_path_concat (2, core_services, "SystemVersion.plist"); + f = grub_util_fopen (sysv_plist, "wb"); + fprintf (f, + "<plist version=\"1.0\">\n" + "<dict>\n" + " <key>ProductBuildVersion</key>\n" + " <string></string>\n" + " <key>ProductName</key>\n" + " <string>%s</string>\n" + " <key>ProductVersion</key>\n" + " <string>%s</string>\n" + "</dict>\n" + "</plist>\n", bootloader_id, product_version); + fclose (f); + free (sysv_plist); +} + +int +main (int argc, char *argv[]) +{ + int is_efi = 0; + const char *efi_distributor = NULL; + const char *efi_file = NULL; + char **grub_devices; + grub_fs_t grub_fs; + grub_device_t grub_dev = NULL; + enum grub_install_plat platform; + char *grubdir, *device_map; + char **curdev, **curdrive; + char **grub_drives; + char *relative_grubdir; + char **efidir_device_names = NULL; + grub_device_t efidir_grub_dev = NULL; + char *efidir_grub_devname; + int efidir_is_mac = 0; + int is_prep = 0; + const char *pkgdatadir; + + grub_util_host_init (&argc, &argv); + product_version = xstrdup (PACKAGE_VERSION); + pkgdatadir = grub_util_get_pkgdatadir (); + label_font = grub_util_path_concat (2, pkgdatadir, "unicode.pf2"); + + argp_parse (&argp, argc, argv, 0, 0, 0); + + if (verbosity > 1) + grub_env_set ("debug", "all"); + + grub_util_load_config (&config); + + if (!bootloader_id && config.grub_distributor) + { + char *ptr; + bootloader_id = xstrdup (config.grub_distributor); + for (ptr = bootloader_id; *ptr && *ptr != ' '; ptr++) + if (*ptr >= 'A' && *ptr <= 'Z') + *ptr = *ptr - 'A' + 'a'; + *ptr = '\0'; + } + if (!bootloader_id || bootloader_id[0] == '\0') + { + free (bootloader_id); + bootloader_id = xstrdup ("grub"); + } + + if (!grub_install_source_directory) + { + if (!target) + { + const char * t; + t = get_default_platform (); + if (!t) + grub_util_error ("%s", + _("Unable to determine your platform." + " Use --target.") + ); + target = xstrdup (t); + } + grub_install_source_directory + = grub_util_path_concat (2, grub_util_get_pkglibdir (), target); + } + + platform = grub_install_get_target (grub_install_source_directory); + + { + char *platname = grub_install_get_platform_name (platform); + fprintf (stderr, _("Installing for %s platform.\n"), platname); + free (platname); + } + + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_PC: + if (!disk_module) + disk_module = xstrdup ("biosdisk"); + break; + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + break; + + case GRUB_INSTALL_PLATFORM_I386_QEMU: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + disk_module = xstrdup ("native"); + break; + + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_PC: + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + if (!install_device) + grub_util_error ("%s", _("install device isn't specified")); + break; + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + if (install_device) + is_prep = 1; + break; + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + break; + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_QEMU: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + free (install_device); + install_device = NULL; + break; + + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + + if (!bootdir) + bootdir = grub_util_path_concat (3, "/", rootdir, GRUB_BOOT_DIR_NAME); + + { + char * t = grub_util_path_concat (2, bootdir, GRUB_DIR_NAME); + grub_install_mkdir_p (t); + grubdir = grub_canonicalize_file_name (t); + if (!grubdir) + grub_util_error (_("failed to get canonical path of `%s'"), t); + free (t); + } + device_map = grub_util_path_concat (2, grubdir, "device.map"); + + if (recheck) + grub_util_unlink (device_map); + + device_map_check_duplicates (device_map); + grub_util_biosdisk_init (device_map); + + /* Initialize all modules. */ + grub_init_all (); + grub_gcry_init_all (); + grub_hostfs_init (); + grub_host_init (); + + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + is_efi = 1; + break; + default: + is_efi = 0; + break; + + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + + /* Find the EFI System Partition. */ + + if (is_efi) + { + grub_fs_t fs; + free (install_device); + install_device = NULL; + if (!efidir) + { + char *d = grub_util_path_concat (2, bootdir, "efi"); + char *dr = NULL; + if (!grub_util_is_directory (d)) + { + free (d); + d = grub_util_path_concat (2, bootdir, "EFI"); + } + /* + The EFI System Partition may have been given directly using + --root-directory. + */ + if (!grub_util_is_directory (d) + && rootdir && grub_strcmp (rootdir, "/") != 0) + { + free (d); + d = xstrdup (rootdir); + } + if (grub_util_is_directory (d)) + dr = grub_make_system_path_relative_to_its_root (d); + /* Is it a mount point? */ + if (dr && dr[0] == '\0') + efidir = d; + else + free (d); + free (dr); + } + if (!efidir) + grub_util_error ("%s", _("cannot find EFI directory")); + efidir_device_names = grub_guess_root_devices (efidir); + if (!efidir_device_names || !efidir_device_names[0]) + grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), + efidir); + install_device = efidir_device_names[0]; + + for (curdev = efidir_device_names; *curdev; curdev++) + grub_util_pull_device (*curdev); + + efidir_grub_devname = grub_util_get_grub_dev (efidir_device_names[0]); + if (!efidir_grub_devname) + grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), + efidir_device_names[0]); + + efidir_grub_dev = grub_device_open (efidir_grub_devname); + if (! efidir_grub_dev) + grub_util_error ("%s", grub_errmsg); + + fs = grub_fs_probe (efidir_grub_dev); + if (! fs) + grub_util_error ("%s", grub_errmsg); + + efidir_is_mac = 0; + + if (grub_strcmp (fs->name, "hfs") == 0 + || grub_strcmp (fs->name, "hfsplus") == 0) + efidir_is_mac = 1; + + if (!efidir_is_mac && grub_strcmp (fs->name, "fat") != 0) + grub_util_error (_("%s doesn't look like an EFI partition"), efidir); + + /* 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. + */ + char *t; + efi_distributor = bootloader_id; + if (removable) + { + /* 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"; + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_EFI: + efi_file = "BOOTIA32.EFI"; + break; + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + efi_file = "BOOTX64.EFI"; + break; + case GRUB_INSTALL_PLATFORM_IA64_EFI: + efi_file = "BOOTIA64.EFI"; + break; + case GRUB_INSTALL_PLATFORM_ARM_EFI: + efi_file = "BOOTARM.EFI"; + break; + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + efi_file = "BOOTAA64.EFI"; + break; + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + efi_file = "BOOTRISCV32.EFI"; + break; + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + efi_file = "BOOTRISCV64.EFI"; + break; + default: + grub_util_error ("%s", _("You've found a bug")); + break; + } + } + else + { + /* It is convenient for each architecture to have a different + efi_file, so that different versions can be installed in parallel. + */ + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_EFI: + efi_file = "grubia32.efi"; + break; + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + efi_file = "grubx64.efi"; + break; + case GRUB_INSTALL_PLATFORM_IA64_EFI: + efi_file = "grubia64.efi"; + break; + case GRUB_INSTALL_PLATFORM_ARM_EFI: + efi_file = "grubarm.efi"; + break; + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + efi_file = "grubaa64.efi"; + break; + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + efi_file = "grubriscv32.efi"; + break; + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + efi_file = "grubriscv64.efi"; + break; + default: + efi_file = "grub.efi"; + break; + } + } + t = grub_util_path_concat (3, efidir, "EFI", efi_distributor); + free (efidir); + efidir = t; + grub_install_mkdir_p (efidir); + } + + if (platform == GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275) + { + int is_guess = 0; + if (!macppcdir) + { + char *d; + + is_guess = 1; + d = grub_util_path_concat (2, bootdir, "macppc"); + if (!grub_util_is_directory (d)) + { + free (d); + d = grub_util_path_concat (2, bootdir, "efi"); + } + /* Find the Mac HFS(+) System Partition. */ + if (!grub_util_is_directory (d)) + { + free (d); + d = grub_util_path_concat (2, bootdir, "EFI"); + } + if (!grub_util_is_directory (d)) + { + free (d); + d = 0; + } + if (d) + macppcdir = d; + } + if (macppcdir) + { + char **macppcdir_device_names = NULL; + grub_device_t macppcdir_grub_dev = NULL; + char *macppcdir_grub_devname; + grub_fs_t fs; + + macppcdir_device_names = grub_guess_root_devices (macppcdir); + if (!macppcdir_device_names || !macppcdir_device_names[0]) + grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), + macppcdir); + + for (curdev = macppcdir_device_names; *curdev; curdev++) + grub_util_pull_device (*curdev); + + macppcdir_grub_devname = grub_util_get_grub_dev (macppcdir_device_names[0]); + if (!macppcdir_grub_devname) + grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), + macppcdir_device_names[0]); + + macppcdir_grub_dev = grub_device_open (macppcdir_grub_devname); + if (! macppcdir_grub_dev) + grub_util_error ("%s", grub_errmsg); + + fs = grub_fs_probe (macppcdir_grub_dev); + if (! fs) + grub_util_error ("%s", grub_errmsg); + + if (grub_strcmp (fs->name, "hfs") != 0 + && grub_strcmp (fs->name, "hfsplus") != 0 + && !is_guess) + grub_util_error (_("filesystem on %s is neither HFS nor HFS+"), + macppcdir); + if (grub_strcmp (fs->name, "hfs") == 0 + || grub_strcmp (fs->name, "hfsplus") == 0) + { + install_device = macppcdir_device_names[0]; + is_prep = 0; + } + } + } + + grub_install_copy_files (grub_install_source_directory, + grubdir, platform); + + char *envfile = grub_util_path_concat (2, grubdir, "grubenv"); + if (!grub_util_is_regular (envfile)) + grub_util_create_envblk_file (envfile); + + size_t ndev = 0; + + /* Write device to a variable so we don't have to traverse /dev every time. */ + grub_devices = grub_guess_root_devices (grubdir); + if (!grub_devices || !grub_devices[0]) + grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), + grubdir); + + for (curdev = grub_devices; *curdev; curdev++) + { + grub_util_pull_device (*curdev); + ndev++; + } + + grub_drives = xcalloc (ndev + 1, sizeof (grub_drives[0])); + + for (curdev = grub_devices, curdrive = grub_drives; *curdev; curdev++, + curdrive++) + { + *curdrive = grub_util_get_grub_dev (*curdev); + if (! *curdrive) + grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), + *curdev); + } + *curdrive = 0; + + grub_dev = grub_device_open (grub_drives[0]); + if (! grub_dev) + grub_util_error ("%s", grub_errmsg); + + grub_fs = grub_fs_probe (grub_dev); + if (! grub_fs) + grub_util_error ("%s", grub_errmsg); + + grub_install_push_module (grub_fs->name); + + if (grub_dev->disk) + probe_mods (grub_dev->disk); + + for (curdrive = grub_drives + 1; *curdrive; curdrive++) + { + grub_device_t dev = grub_device_open (*curdrive); + if (!dev) + continue; + if (dev->disk) + probe_mods (dev->disk); + grub_device_close (dev); + } + + if (!config.is_cryptodisk_enabled && have_cryptodisk) + grub_util_error (_("attempt to install to encrypted disk without cryptodisk enabled. " + "Set `%s' in file `%s'"), "GRUB_ENABLE_CRYPTODISK=y", + grub_util_get_config_filename ()); + + if (disk_module && grub_strcmp (disk_module, "ata") == 0) + grub_install_push_module ("pata"); + else if (disk_module && grub_strcmp (disk_module, "native") == 0) + { + grub_install_push_module ("pata"); + grub_install_push_module ("ahci"); + grub_install_push_module ("ohci"); + grub_install_push_module ("uhci"); + grub_install_push_module ("ehci"); + grub_install_push_module ("usbms"); + } + else if (disk_module && disk_module[0]) + grub_install_push_module (disk_module); + + relative_grubdir = grub_make_system_path_relative_to_its_root (grubdir); + if (relative_grubdir[0] == '\0') + { + free (relative_grubdir); + relative_grubdir = xstrdup ("/"); + } + + char *platname = grub_install_get_platform_name (platform); + char *platdir; + { + char *t = grub_util_path_concat (2, grubdir, + platname); + platdir = grub_canonicalize_file_name (t); + if (!platdir) + grub_util_error (_("failed to get canonical path of `%s'"), + t); + free (t); + } + load_cfg = grub_util_path_concat (2, platdir, + "load.cfg"); + + grub_util_unlink (load_cfg); + + if (debug_image && debug_image[0]) + { + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + have_load_cfg = 1; + fprintf (load_cfg_f, "set debug='%s'\n", + debug_image); + } + char *prefix_drive = NULL; + char *install_drive = NULL; + + if (install_device) + { + if (install_device[0] == '(' + && install_device[grub_strlen (install_device) - 1] == ')') + { + size_t len = grub_strlen (install_device) - 2; + install_drive = xmalloc (len + 1); + memcpy (install_drive, install_device + 1, len); + install_drive[len] = '\0'; + } + else + { + grub_util_pull_device (install_device); + install_drive = grub_util_get_grub_dev (install_device); + if (!install_drive) + grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), + install_device); + } + } + + if (!have_abstractions) + { + if ((disk_module && grub_strcmp (disk_module, "biosdisk") != 0) + || grub_drives[1] + || (!install_drive + && platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275) + || (install_drive && !is_same_disk (grub_drives[0], install_drive)) + || !have_bootdev (platform)) + { + char *uuid = NULL; + /* generic method (used on coreboot and ata mod). */ + if (!force_file_id + && grub_fs->fs_uuid && grub_fs->fs_uuid (grub_dev, &uuid)) + { + grub_print_error (); + grub_errno = 0; + uuid = NULL; + } + + if (!load_cfg_f) + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + have_load_cfg = 1; + if (uuid) + { + fprintf (load_cfg_f, "search.fs_uuid %s root ", + uuid); + grub_install_push_module ("search_fs_uuid"); + } + else + { + char *rndstr = get_rndstr (); + char *fl = grub_util_path_concat (3, grubdir, + "uuid", rndstr); + char *fldir = grub_util_path_concat (2, grubdir, + "uuid"); + char *relfl; + FILE *flf; + grub_install_mkdir_p (fldir); + flf = grub_util_fopen (fl, "w"); + if (!flf) + grub_util_error (_("Can't create file: %s"), strerror (errno)); + fclose (flf); + relfl = grub_make_system_path_relative_to_its_root (fl); + fprintf (load_cfg_f, "search.file %s root ", + relfl); + grub_install_push_module ("search_fs_file"); + } + for (curdev = grub_devices, curdrive = grub_drives; *curdev; curdev++, + curdrive++) + { + const char *map; + char *g = NULL; + grub_device_t dev; + if (curdrive == grub_drives) + dev = grub_dev; + else + dev = grub_device_open (*curdrive); + if (!dev) + continue; + + if (dev->disk->dev->id != GRUB_DISK_DEVICE_HOSTDISK_ID) + { + grub_util_fprint_full_disk_name (load_cfg_f, + dev->disk->name, + dev); + fprintf (load_cfg_f, " "); + if (dev != grub_dev) + grub_device_close (dev); + continue; + } + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + + if (map) + { + grub_util_fprint_full_disk_name (load_cfg_f, map, dev); + fprintf (load_cfg_f, " "); + } + + + if (disk_module && disk_module[0] + && grub_strcmp (disk_module, "biosdisk") != 0) + g = grub_util_guess_baremetal_drive (*curdev); + else + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_PC: + g = grub_util_guess_bios_drive (*curdev); + break; + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + g = grub_util_guess_efi_drive (*curdev); + break; + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + { + const char * ofpath = grub_util_devname_to_ofpath (*curdev); + g = xasprintf ("ieee1275/%s", ofpath); + break; + } + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_I386_QEMU: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + g = grub_util_guess_baremetal_drive (*curdev); + break; + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + grub_util_warn ("%s", _("no hints available for your platform. Expect reduced performance")); + break; + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + if (g) + { + grub_util_fprint_full_disk_name (load_cfg_f, g, dev); + fprintf (load_cfg_f, " "); + free (g); + } + if (dev != grub_dev) + grub_device_close (dev); + } + fprintf (load_cfg_f, "\n"); + char *escaped_relpath = escape (relative_grubdir); + fprintf (load_cfg_f, "set prefix=($root)'%s'\n", + escaped_relpath); + } + else + { + /* We need to hardcode the partition number in the core image's prefix. */ + char *p; + for (p = grub_drives[0]; *p; ) + { + if (*p == '\\' && p[1]) + { + p += 2; + continue; + } + if (*p == ',' || *p == '\0') + break; + p++; + } + prefix_drive = xasprintf ("(%s)", p); + } + } + else + { + if (config.is_cryptodisk_enabled) + { + if (grub_dev->disk) + probe_cryptodisk_uuid (grub_dev->disk); + + for (curdrive = grub_drives + 1; *curdrive; curdrive++) + { + grub_device_t dev = grub_device_open (*curdrive); + if (!dev) + continue; + if (dev->disk) + probe_cryptodisk_uuid (dev->disk); + grub_device_close (dev); + } + } + prefix_drive = xasprintf ("(%s)", grub_drives[0]); + } + + char mkimage_target[200]; + const char *core_name = NULL; + + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + core_name = "core.efi"; + snprintf (mkimage_target, sizeof (mkimage_target), + "%s-%s", + grub_install_get_platform_cpu (platform), + grub_install_get_platform_platform (platform)); + break; + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + core_name = "core.elf"; + snprintf (mkimage_target, sizeof (mkimage_target), + "%s-%s-elf", + grub_install_get_platform_cpu (platform), + grub_install_get_platform_platform (platform)); + break; + + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + core_name = "core.elf"; + snprintf (mkimage_target, sizeof (mkimage_target), + "%s-%s", + grub_install_get_platform_cpu (platform), + grub_install_get_platform_platform (platform)); + break; + + + case GRUB_INSTALL_PLATFORM_I386_PC: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_QEMU: + snprintf (mkimage_target, sizeof (mkimage_target), + "%s-%s", + grub_install_get_platform_cpu (platform), + grub_install_get_platform_platform (platform)); + core_name = "core.img"; + break; + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + strcpy (mkimage_target, "sparc64-ieee1275-raw"); + core_name = "core.img"; + break; + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + + if (!core_name) + grub_util_error ("%s", _("You've found a bug")); + + if (load_cfg_f) + fclose (load_cfg_f); + + char *imgfile = grub_util_path_concat (2, platdir, + core_name); + char *prefix = xasprintf ("%s%s", prefix_drive ? : "", + relative_grubdir); + grub_install_make_image_wrap (/* source dir */ grub_install_source_directory, + /*prefix */ prefix, + /* output */ imgfile, + /* memdisk */ NULL, + have_load_cfg ? load_cfg : NULL, + /* image target */ mkimage_target, 0); + /* Backward-compatibility kludges. */ + switch (platform) + { + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + { + char *dst = grub_util_path_concat (2, bootdir, "grub.elf"); + grub_install_copy_file (imgfile, dst, 1); + free (dst); + } + break; + + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + { + char *dst = grub_util_path_concat (2, grubdir, "grub"); + grub_install_copy_file (imgfile, dst, 1); + free (dst); + } + break; + + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + { + char *dst = grub_util_path_concat (2, platdir, "grub.efi"); + grub_install_make_image_wrap (/* source dir */ grub_install_source_directory, + /* prefix */ "", + /* output */ dst, + /* memdisk */ NULL, + have_load_cfg ? load_cfg : NULL, + /* image target */ mkimage_target, 0); + } + break; + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_I386_PC: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_QEMU: + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + break; + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + + /* Perform the platform-dependent install */ + + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_PC: + { + char *boot_img_src = grub_util_path_concat (2, + grub_install_source_directory, + "boot.img"); + char *boot_img = grub_util_path_concat (2, platdir, + "boot.img"); + grub_install_copy_file (boot_img_src, boot_img, 1); + + grub_util_info ("%sgrub-bios-setup %s %s %s %s %s --directory='%s' --device-map='%s' '%s'", + /* TRANSLATORS: This is a prefix in the log to indicate that usually + a command would be executed but due to an option was skipped. */ + install_bootsector ? "" : _("NOT RUNNING: "), + allow_floppy ? "--allow-floppy " : "", + verbosity ? "--verbose " : "", + force ? "--force " : "", + !fs_probe ? "--skip-fs-probe" : "", + !add_rs_codes ? "--no-rs-codes" : "", + platdir, + device_map, + install_device); + + /* Now perform the installation. */ + if (install_bootsector) + { + grub_util_bios_setup (platdir, "boot.img", "core.img", + install_drive, force, + fs_probe, allow_floppy, add_rs_codes, + !grub_install_is_short_mbrgap_supported ()); + + grub_set_install_backup_ponr (); + } + break; + } + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + { + char *boot_img_src = grub_util_path_concat (2, + grub_install_source_directory, + "boot.img"); + char *boot_img = grub_util_path_concat (2, platdir, + "boot.img"); + grub_install_copy_file (boot_img_src, boot_img, 1); + + grub_util_info ("%sgrub-sparc64-setup %s %s %s %s --directory='%s' --device-map='%s' '%s'", + install_bootsector ? "" : "NOT RUNNING: ", + allow_floppy ? "--allow-floppy " : "", + verbosity ? "--verbose " : "", + force ? "--force " : "", + !fs_probe ? "--skip-fs-probe" : "", + platdir, + device_map, + install_drive); + + /* Now perform the installation. */ + if (install_bootsector) + { + grub_util_sparc_setup (platdir, "boot.img", "core.img", + install_drive, force, + fs_probe, allow_floppy, + 0 /* unused */, 0 /* unused */ ); + + grub_set_install_backup_ponr (); + } + break; + } + + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + if (macppcdir) + { + char *core_services = grub_util_path_concat (4, macppcdir, + "System", "Library", + "CoreServices"); + char *mach_kernel = grub_util_path_concat (2, macppcdir, + "mach_kernel"); + char *grub_elf, *bootx; + FILE *f; + grub_device_t ins_dev; + char *grub_chrp = grub_util_path_concat (2, + grub_install_source_directory, + "grub.chrp"); + + grub_install_mkdir_p (core_services); + + bootx = grub_util_path_concat (2, core_services, "BootX"); + grub_install_copy_file (grub_chrp, bootx, 1); + + grub_elf = grub_util_path_concat (2, core_services, "grub.elf"); + grub_install_copy_file (imgfile, grub_elf, 1); + + grub_set_install_backup_ponr (); + + f = grub_util_fopen (mach_kernel, "a+"); + if (!f) + grub_util_error (_("Can't create file: %s"), strerror (errno)); + fclose (f); + + fill_core_services (core_services); + + ins_dev = grub_device_open (install_drive); + if (ins_dev == NULL) + grub_util_error ("%s", grub_errmsg); + + bless (ins_dev, core_services, 0); + + if (update_nvram) + { + const char *dev; + int partno; + + partno = ins_dev->disk->partition + ? ins_dev->disk->partition->number + 1 : 0; + dev = grub_util_get_os_disk (install_device); + grub_install_register_ieee1275 (0, dev, partno, + "\\\\BootX"); + } + grub_device_close (ins_dev); + free (grub_elf); + free (bootx); + free (mach_kernel); + free (grub_chrp); + break; + } + /* If a install device is defined, copy the core.elf to PReP partition. */ + if (is_prep && install_device && install_device[0]) + { + grub_device_t ins_dev; + ins_dev = grub_device_open (install_drive); + if (!ins_dev || !is_prep_partition (ins_dev)) + { + grub_util_error ("%s", _("the chosen partition is not a PReP partition")); + } + if (is_prep_empty (ins_dev)) + { + if (write_to_disk (ins_dev, imgfile)) + grub_util_error ("%s", _("failed to copy Grub to the PReP partition")); + } + else + { + char *s = xasprintf ("dd if=/dev/zero of=%s", install_device); + grub_util_error (_("the PReP partition is not empty. If you are sure you want to use it, run dd to clear it: `%s'"), + s); + } + grub_device_close (ins_dev); + if (update_nvram) + grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_device), + 0, NULL); + break; + } + /* fallthrough. */ + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + if (update_nvram) + { + const char *dev; + char *relpath; + int partno; + relpath = grub_make_system_path_relative_to_its_root (imgfile); + partno = grub_dev->disk->partition + ? grub_dev->disk->partition->number + 1 : 0; + dev = grub_util_get_os_disk (grub_devices[0]); + grub_install_register_ieee1275 (0, dev, + partno, relpath); + } + break; + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + grub_install_sgi_setup (install_device, imgfile, "grub"); + break; + + case GRUB_INSTALL_PLATFORM_I386_EFI: + if (!efidir_is_mac) + { + char *dst = grub_util_path_concat (2, efidir, "grub.efi"); + /* For old macs. Suggested by Peter Jones. */ + grub_install_copy_file (imgfile, dst, 1); + free (dst); + } + /* Fallthrough. */ + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + if (efidir_is_mac) + { + char *boot_efi; + char *core_services = grub_util_path_concat (4, efidir, + "System", "Library", + "CoreServices"); + char *mach_kernel = grub_util_path_concat (2, efidir, + "mach_kernel"); + FILE *f; + grub_device_t ins_dev; + + grub_install_mkdir_p (core_services); + + boot_efi = grub_util_path_concat (2, core_services, "boot.efi"); + grub_install_copy_file (imgfile, boot_efi, 1); + + grub_set_install_backup_ponr (); + + f = grub_util_fopen (mach_kernel, "r+"); + if (!f) + grub_util_error (_("Can't create file: %s"), strerror (errno)); + fclose (f); + + fill_core_services(core_services); + + ins_dev = grub_device_open (install_drive); + if (ins_dev == NULL) + grub_util_error ("%s", grub_errmsg); + + bless (ins_dev, boot_efi, 1); + if (!removable && update_nvram) + { + /* Try to make this image bootable using the EFI Boot Manager, if available. */ + int ret; + ret = grub_install_register_efi (efidir_grub_dev, + "\\System\\Library\\CoreServices", + efi_distributor); + if (ret) + grub_util_error (_("efibootmgr failed to register the boot entry: %s"), + strerror (ret)); + } + + grub_device_close (ins_dev); + free (boot_efi); + free (mach_kernel); + break; + } + /* FALLTHROUGH */ + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + { + char *dst = grub_util_path_concat (2, efidir, efi_file); + grub_install_copy_file (imgfile, dst, 1); + + grub_set_install_backup_ponr (); + + free (dst); + } + if (!removable && update_nvram) + { + char * efifile_path; + char * part; + int ret; + + /* Try to make this image bootable using the EFI Boot Manager, if available. */ + if (!efi_distributor || efi_distributor[0] == '\0') + grub_util_error ("%s", _("EFI bootloader id isn't specified.")); + efifile_path = xasprintf ("\\EFI\\%s\\%s", + efi_distributor, + efi_file); + part = (efidir_grub_dev->disk->partition + ? grub_partition_get_name (efidir_grub_dev->disk->partition) + : 0); + grub_util_info ("Registering with EFI: distributor = `%s'," + " path = `%s', ESP at %s%s%s", + efi_distributor, efifile_path, + efidir_grub_dev->disk->name, + (part ? ",": ""), (part ? : "")); + grub_free (part); + ret = grub_install_register_efi (efidir_grub_dev, + efifile_path, efi_distributor); + if (ret) + grub_util_error (_("efibootmgr failed to register the boot entry: %s"), + strerror (ret)); + } + break; + + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_QEMU: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + grub_util_warn ("%s", + _("WARNING: no platform-specific install was performed")); + break; + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + + /* + * Either there are no platform specific code, or it didn't raise + * ponr. Raise it here, because usually this is already past point + * of no return. If we leave this flag false, at exit all the modules + * will be removed from the prefix which would be very confusing. + */ + grub_set_install_backup_ponr (); + + fprintf (stderr, "%s\n", _("Installation finished. No error reported.")); + + /* Free resources. */ + grub_gcry_fini_all (); + grub_fini_all (); + + return 0; +} diff --git a/util/grub-kbdcomp.in b/util/grub-kbdcomp.in new file mode 100644 index 0000000..a15ec24 --- /dev/null +++ b/util/grub-kbdcomp.in @@ -0,0 +1,77 @@ +#!/bin/sh + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +bindir="@bindir@" +datarootdir="@datarootdir@" +datadir="@datadir@" +if [ "x$pkgdatadir" = x ]; then + pkgdatadir="${datadir}/@PACKAGE@" +fi + +grub_mklayout="${bindir}/@grub_mklayout@" + +ckbcomp_options="" + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR="@localedir@" + +. "${pkgdatadir}/grub-mkconfig_lib" + +self=`basename $0` + +usage () { + gettext_printf "Usage: %s -o OUTPUT CKBMAP_ARGUMENTS...\n" "$self" + gettext "Make GRUB keyboard layout file."; echo + echo + print_option_help "-h, --help" "$(gettext "print this message and exit")" + print_option_help "-V, --version" "$(gettext "print the version information and exit")" + print_option_help "-o, --output=$(gettext FILE)" "$(gettext "save output in FILE [required]")" + echo + gettext_printf "%s generates a keyboard layout for GRUB using ckbcomp\n" "$self" + echo + gettext "Report bugs to <bug-grub@gnu.org>."; echo +} + +argument () { + opt=$1 + shift + + if test $# -eq 0; then + gettext_printf "%s: option requires an argument -- \`%s'\n" "$0" "$opt" 1>&2 + exit 1 + fi + echo $1 +} + +output= + +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) + output=`argument $option "$@"`; shift ;; + --output=*) + output=`echo "$option" | sed 's/--output=//'` ;; + *) + ckbcomp_options="$ckbcomp_options $option";; + esac +done + +if [ "x${output}" = x ] ; then + gettext "output file must be specified" >&2 + echo >&2 + usage + exit 1 +fi + +ckbcomp $ckbcomp_options | "$grub_mklayout" -o "${output}" + diff --git a/util/grub-macbless.c b/util/grub-macbless.c new file mode 100644 index 0000000..e9b15a0 --- /dev/null +++ b/util/grub-macbless.c @@ -0,0 +1,205 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/device.h> +#include <grub/disk.h> +#include <grub/file.h> +#include <grub/fs.h> +#include <grub/partition.h> +#include <grub/msdos_partition.h> +#include <grub/emu/hostdisk.h> +#include <grub/emu/getroot.h> +#include <grub/term.h> +#include <grub/env.h> +#include <grub/diskfilter.h> +#include <grub/i18n.h> +#include <grub/crypto.h> +#include <grub/cryptodisk.h> +#include <grub/hfsplus.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/stat.h> + +#define _GNU_SOURCE 1 +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include "progname.h" + +static void +bless (const char *path, int x86) +{ + char *drive_name = NULL; + char **devices; + char *grub_path = NULL; + char *filebuf_via_grub = NULL, *filebuf_via_sys = NULL; + grub_device_t dev = NULL; + grub_err_t err; + struct stat st; + + grub_path = grub_canonicalize_file_name (path); + + if (stat (grub_path, &st) < 0) + grub_util_error (N_("cannot stat `%s': %s"), + grub_path, strerror (errno)); + + devices = grub_guess_root_devices (grub_path); + + if (! devices || !devices[0]) + grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path); + + drive_name = grub_util_get_grub_dev (devices[0]); + if (! drive_name) + grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), + devices[0]); + + grub_util_info ("opening %s", drive_name); + dev = grub_device_open (drive_name); + if (! dev) + grub_util_error ("%s", grub_errmsg); + + err = grub_mac_bless_inode (dev, st.st_ino, S_ISDIR (st.st_mode), x86); + if (err) + grub_util_error ("%s", grub_errmsg); + free (grub_path); + free (filebuf_via_grub); + free (filebuf_via_sys); + free (drive_name); + free (devices); + grub_device_close (dev); +} + +static struct argp_option options[] = { + {"x86", 'x', 0, 0, + N_("bless for x86-based macs"), 0}, + {"ppc", 'p', 0, 0, + N_("bless for ppc-based macs"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + { 0, 0, 0, 0, 0, 0 } +}; + +struct arguments +{ + char *arg; + int ppc; +}; + +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; + + switch (key) + { + case 'v': + verbosity++; + break; + + case 'x': + arguments->ppc = 0; + break; + + case 'p': + arguments->ppc = 1; + break; + + case ARGP_KEY_NO_ARGS: + fprintf (stderr, "%s", _("No path or device is specified.\n")); + argp_usage (state); + break; + + case ARGP_KEY_ARG: + if (arguments->arg) + { + fprintf (stderr, _("Unknown extra argument `%s'."), arg); + fprintf (stderr, "\n"); + return ARGP_ERR_UNKNOWN; + } + arguments->arg = xstrdup (arg); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { + options, argp_parser, N_("--ppc PATH|--x86 FILE"), + N_("Mac-style bless on HFS or HFS+"), + NULL, NULL, NULL +}; + +int +main (int argc, char *argv[]) +{ + struct arguments arguments; + + grub_util_host_init (&argc, &argv); + + /* Check for options. */ + memset (&arguments, 0, sizeof (struct arguments)); + if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + if (verbosity > 1) + grub_env_set ("debug", "all"); + + /* Initialize the emulated biosdisk driver. */ + grub_util_biosdisk_init (NULL); + + /* Initialize all modules. */ + grub_init_all (); + grub_gcry_init_all (); + + grub_lvm_fini (); + grub_mdraid09_fini (); + grub_mdraid1x_fini (); + grub_diskfilter_fini (); + grub_diskfilter_init (); + grub_mdraid09_init (); + grub_mdraid1x_init (); + grub_lvm_init (); + + /* Do it. */ + bless (arguments.arg, !arguments.ppc); + + /* Free resources. */ + grub_gcry_fini_all (); + grub_fini_all (); + grub_util_biosdisk_fini (); + + return 0; +} diff --git a/util/grub-macho2img.c b/util/grub-macho2img.c new file mode 100644 index 0000000..6dfb5fc --- /dev/null +++ b/util/grub-macho2img.c @@ -0,0 +1,120 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <grub/types.h> +#include <grub/macho.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +/* Please don't internationalise this file. It's pointless. */ + +/* 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..a39f869 --- /dev/null +++ b/util/grub-menulst2cfg.c @@ -0,0 +1,135 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <grub/legacy_parse.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <grub/util/misc.h> +#include <grub/misc.h> +#include <grub/i18n.h> + +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; + const char *out_fname = 0; + + grub_util_host_init (&argc, &argv); + + if (argc >= 2 && argv[1][0] == '-') + { + fprintf (stdout, _("Usage: %s [INFILE [OUTFILE]]\n"), argv[0]); + return 0; + } + + if (argc >= 2) + { + in = grub_util_fopen (argv[1], "r"); + if (!in) + { + fprintf (stderr, _("cannot open `%s': %s"), + argv[1], strerror (errno)); + return 1; + } + } + else + in = stdin; + + if (argc >= 3) + { + out = grub_util_fopen (argv[2], "w"); + if (!out) + { + if (in != stdin) + fclose (in); + fprintf (stderr, _("cannot open `%s': %s"), + argv[2], strerror (errno)); + return 1; + } + out_fname = argv[2]; + } + else + out = stdout; + + while (1) + { + char *parsed; + + if (getline (&buf, &bufsize, in) < 0) + break; + + { + char *oldname = NULL; + char *newsuffix; + + oldname = entryname; + parsed = grub_legacy_parse (buf, &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"); + + if (fwrite (suffix, 1, suffixlen, out) != suffixlen) + { + if (out_fname) + grub_util_error ("cannot write to `%s': %s", + out_fname, strerror (errno)); + else + grub_util_error ("cannot write to the stdout: %s", strerror (errno)); + } + + 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..f8cbb8d --- /dev/null +++ b/util/grub-mkconfig.in @@ -0,0 +1,309 @@ +#! /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 <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +sbindir="@sbindir@" +bindir="@bindir@" +sysconfdir="@sysconfdir@" +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +host_os=@host_os@ +datadir="@datadir@" +if [ "x$pkgdatadir" = x ]; then + pkgdatadir="${datadir}/@PACKAGE@" +fi +# export it for scripts +export pkgdatadir + +grub_cfg="" +grub_mkconfig_dir="${sysconfdir}"/grub.d + +self=`basename $0` + +grub_probe="${sbindir}/@grub_probe@" +grub_file="${bindir}/@grub_file@" +grub_editenv="${bindir}/@grub_editenv@" +grub_script_check="${bindir}/@grub_script_check@" + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR="@localedir@" + +. "${pkgdatadir}/grub-mkconfig_lib" + +# Usage: usage +# Print the usage. +usage () { + gettext_printf "Usage: %s [OPTION]\n" "$self" + gettext "Generate a grub config file"; echo + echo + print_option_help "-o, --output=$(gettext FILE)" "$(gettext "output generated config to FILE [default=stdout]")" + print_option_help "-h, --help" "$(gettext "print this message and exit")" + print_option_help "-V, --version" "$(gettext "print the version information and exit")" + echo + gettext "Report bugs to <bug-grub@gnu.org>."; echo +} + +argument () { + opt=$1 + shift + + if test $# -eq 0; then + gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$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=//'` + ;; + -*) + gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 + usage + exit 1 + ;; + # Explicitly ignore non-option arguments, for compatibility. + esac +done + +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 + gettext_printf "%s: You must run this as root\n" "$self" >&2 + exit 1 + fi +fi + +set $grub_probe dummy +if test -f "$1"; then + : +else + gettext_printf "%s: Not found.\n" "$1" 1>&2 + exit 1 +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 +GRUB_DEVICE_PARTUUID="`${grub_probe} --device ${GRUB_DEVICE} --target=partuuid 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 + +# Disable os-prober by default due to security reasons. +GRUB_DISABLE_OS_PROBER="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 [ x"$GRUB_FS" = xunknown ]; then + GRUB_FS="$(stat -f -c %T / || echo unknown)" +fi + +# Provide a default set of stock linux early initrd images. +# Define here so the list can be modified in the sourced config file. +if [ "x${GRUB_EARLY_INITRD_LINUX_STOCK}" = "x" ]; then + GRUB_EARLY_INITRD_LINUX_STOCK="intel-uc.img intel-ucode.img amd-uc.img amd-ucode.img early_ucode.cpio microcode.cpio" +fi + +if test -f ${sysconfdir}/default/grub ; then + . ${sysconfdir}/default/grub +fi + +if [ "x${GRUB_DISABLE_UUID}" = "xtrue" ]; then + if [ -z "${GRUB_DISABLE_LINUX_UUID}" ]; then + GRUB_DISABLE_LINUX_UUID="true" + fi + if [ -z "${GRUB_DISABLE_LINUX_PARTUUID}" ]; then + GRUB_DISABLE_LINUX_PARTUUID="true" + fi +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 + case "x${x}" in + xgfxterm) ;; + xconsole | xserial | xofconsole | xvga_text) + # 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 + +GRUB_ACTUAL_DEFAULT="$GRUB_DEFAULT" + +if [ "x${GRUB_ACTUAL_DEFAULT}" = "xsaved" ] ; then GRUB_ACTUAL_DEFAULT="`"${grub_editenv}" - list | sed -n '/^saved_entry=/ s,^saved_entry=,,p'`" ; fi + + +# These are defined in this script, export them here so that user can +# override them. +export GRUB_DEVICE \ + GRUB_DEVICE_UUID \ + GRUB_DEVICE_PARTUUID \ + GRUB_DEVICE_BOOT \ + GRUB_DEVICE_BOOT_UUID \ + GRUB_DISABLE_OS_PROBER \ + GRUB_FS \ + GRUB_FONT \ + GRUB_PRELOAD_MODULES \ + GRUB_ACTUAL_DEFAULT + +# These are optional, user-defined variables. +export GRUB_DEFAULT \ + GRUB_HIDDEN_TIMEOUT \ + GRUB_HIDDEN_TIMEOUT_QUIET \ + GRUB_TIMEOUT \ + GRUB_TIMEOUT_STYLE \ + GRUB_DEFAULT_BUTTON \ + GRUB_HIDDEN_TIMEOUT_BUTTON \ + GRUB_TIMEOUT_BUTTON \ + GRUB_TIMEOUT_STYLE_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_LINUX_XEN_REPLACE \ + GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT \ + GRUB_CMDLINE_NETBSD \ + GRUB_CMDLINE_NETBSD_DEFAULT \ + GRUB_CMDLINE_GNUMACH \ + GRUB_EARLY_INITRD_LINUX_CUSTOM \ + GRUB_EARLY_INITRD_LINUX_STOCK \ + GRUB_TERMINAL_INPUT \ + GRUB_TERMINAL_OUTPUT \ + GRUB_SERIAL_COMMAND \ + GRUB_DISABLE_UUID \ + GRUB_DISABLE_LINUX_UUID \ + GRUB_DISABLE_LINUX_PARTUUID \ + GRUB_DISABLE_RECOVERY \ + GRUB_VIDEO_BACKEND \ + GRUB_GFXMODE \ + GRUB_BACKGROUND \ + GRUB_THEME \ + GRUB_GFXPAYLOAD_LINUX \ + GRUB_INIT_TUNE \ + GRUB_SAVEDEFAULT \ + GRUB_ENABLE_CRYPTODISK \ + GRUB_BADRAM \ + GRUB_OS_PROBER_SKIP_LIST \ + GRUB_DISABLE_SUBMENU + +if test "x${grub_cfg}" != "x"; then + rm -f "${grub_cfg}.new" + oldumask=$(umask); umask 077 + exec > "${grub_cfg}.new" + umask $oldumask +fi +gettext "Generating grub configuration file ..." >&2 +echo >&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 + # TRANSLATORS: %s is replaced by filename + gettext_printf "Syntax errors are detected in generated GRUB config file. +Ensure that there are no errors in /etc/default/grub +and /etc/grub.d/* files or please file a bug report with +%s file attached." "${grub_cfg}.new" >&2 + echo >&2 + exit 1 + else + # none of the children aborted with error, install the new grub.cfg + cat ${grub_cfg}.new > ${grub_cfg} + rm -f ${grub_cfg}.new + fi +fi + +gettext "done" >&2 +echo >&2 diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in new file mode 100644 index 0000000..301d1ac --- /dev/null +++ b/util/grub-mkconfig_lib.in @@ -0,0 +1,375 @@ +# 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 <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +datadir="@datadir@" +bindir="@bindir@" +sbindir="@sbindir@" +if [ "x$pkgdatadir" = x ]; then + pkgdatadir="${datadir}/@PACKAGE@" +fi + +if test "x$grub_probe" = x; then + grub_probe="${sbindir}/@grub_probe@" +fi +if test "x$grub_file" = x; then + grub_file="${bindir}/@grub_file@" +fi +if test "x$grub_mkrelpath" = x; then + grub_mkrelpath="${bindir}/@grub_mkrelpath@" +fi + +if command -v gettext >/dev/null; then + : +else + gettext () { + printf "%s" "$@" + } +fi + +grub_warn () +{ + echo "$(gettext "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 abstractions="`"${grub_probe}" -t abstraction "$path"`" 2> /dev/null ; then + : + else + return 1 + fi + + if [ x$GRUB_ENABLE_CRYPTODISK = xy ]; then + return 0 + fi + + for abstraction in $abstractions; do + if [ "x$abstraction" = xcryptodisk ]; then + return 1 + fi + done + + 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 () +{ + old_ifs="$IFS" + IFS=' +' + partmap="`"${grub_probe}" --device $@ --target=partmap`" + for module in ${partmap} ; do + case "${module}" in + netbsd | openbsd) + echo "insmod part_bsd";; + *) + echo "insmod part_${module}";; + esac + done + + # Abstraction modules aren't auto-loaded. + abstraction="`"${grub_probe}" --device $@ --target=abstraction`" + for module in ${abstraction} ; do + echo "insmod ${module}" + done + + fs="`"${grub_probe}" --device $@ --target=fs`" + for module in ${fs} ; do + echo "insmod ${module}" + done + + if [ x$GRUB_ENABLE_CRYPTODISK = xy ]; then + for uuid in `"${grub_probe}" --device $@ --target=cryptodisk_uuid`; do + echo "cryptomount -u $uuid" + done + fi + + # If there's a filesystem UUID that GRUB is capable of identifying, use it; + # otherwise set root as per value in device.map. + fs_hint="`"${grub_probe}" --device $@ --target=compatibility_hint`" + if [ "x$fs_hint" != x ]; then + echo "set root='$fs_hint'" + fi + if [ "x${GRUB_DISABLE_UUID}" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then + hints="`"${grub_probe}" --device $@ --target=hints_string 2> /dev/null`" || hints= + if [ "x$hints" != x ]; then + echo "if [ x\$feature_platform_search_hint = xy ]; then" + echo " search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}" + echo "else" + echo " search --no-floppy --fs-uuid --set=root ${fs_uuid}" + echo "fi" + else + echo "search --no-floppy --fs-uuid --set=root ${fs_uuid}" + fi + fi + IFS="$old_ifs" +} + +grub_get_device_id () +{ + old_ifs="$IFS" + IFS=' +' + device="$1" + if [ "x${GRUB_DISABLE_UUID}" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device ${device} --target=fs_uuid 2> /dev/null`" ; then + echo "$fs_uuid"; + else + echo $device |sed 's, ,_,g' + fi + IFS="$old_ifs" +} + +grub_file_is_not_garbage () +{ + if test -f "$1" ; then + case "$1" in + *.dpkg-*) return 1 ;; # debian dpkg + *.rpmsave|*.rpmnew) return 1 ;; + README*|*/README*) return 1 ;; # documentation + *.sig) return 1 ;; # signatures + esac + else + return 1 + fi + return 0 +} + +version_sort () +{ + case $version_sort_sort_has_v in + yes) + LC_ALL=C sort -V;; + no) + LC_ALL=C sort -n;; + *) + if sort -V </dev/null > /dev/null 2>&1; then + version_sort_sort_has_v=yes + LC_ALL=C sort -V + else + version_sort_sort_has_v=no + LC_ALL=C sort -n + fi;; + esac +} + +version_test_numeric () +{ + version_test_numeric_a="$1" + version_test_numeric_cmp="$2" + version_test_numeric_b="$3" + if [ "$version_test_numeric_a" = "$version_test_numeric_b" ] ; then + case "$version_test_numeric_cmp" in + ge|eq|le) return 0 ;; + gt|lt) return 1 ;; + esac + fi + if [ "$version_test_numeric_cmp" = "lt" ] ; then + version_test_numeric_c="$version_test_numeric_a" + version_test_numeric_a="$version_test_numeric_b" + version_test_numeric_b="$version_test_numeric_c" + fi + if (echo "$version_test_numeric_a" ; echo "$version_test_numeric_b") | version_sort | head -n 1 | grep -qx "$version_test_numeric_b" ; then + return 0 + else + return 1 + fi +} + +version_test_gt () +{ + version_test_gt_a="`echo "$1" | sed -e "s/[^-]*-//"`" + version_test_gt_b="`echo "$2" | sed -e "s/[^-]*-//"`" + version_test_gt_cmp=gt + if [ "x$version_test_gt_b" = "x" ] ; then + return 0 + fi + case "$version_test_gt_a:$version_test_gt_b" in + *.old:*.old) ;; + *.old:*) version_test_gt_a="`echo "$version_test_gt_a" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=gt ;; + *:*.old) version_test_gt_b="`echo "$version_test_gt_b" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=ge ;; + esac + version_test_numeric "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b" + return "$?" +} + +version_find_latest () +{ + version_find_latest_a="" + for i in "$@" ; do + if version_test_gt "$i" "$version_find_latest_a" ; then + version_find_latest_a="$i" + fi + done + echo "$version_find_latest_a" +} + +# One layer of quotation is eaten by "" and the second by sed; so this turns +# ' into \'. +grub_quote () { + sed "s/'/'\\\\''/g" +} + +gettext_quoted () { + gettext "$@" | grub_quote +} + +# Run the first argument through gettext, and then pass that and all +# remaining arguments to printf. This is a useful abbreviation and tends to +# be easier to type. +gettext_printf () { + gettext_printf_format="$1" + shift + printf "$(gettext "$gettext_printf_format")" "$@" +} + +uses_abstraction () { + device="$1" + old_ifs="$IFS" + IFS=' +' + + abstraction="`"${grub_probe}" --device ${device} --target=abstraction`" + for module in ${abstraction}; do + if test "x${module}" = "x$2"; then + IFS="$old_ifs" + return 0 + fi + done + IFS="$old_ifs" + return 1 +} + +print_option_help () { + if test x$print_option_help_wc = x; then + if wc -L </dev/null > /dev/null 2>&1; then + print_option_help_wc=-L + elif wc -m </dev/null > /dev/null 2>&1; then + print_option_help_wc=-m + else + print_option_help_wc=-b + fi + fi + if test x$grub_have_fmt = x; then + if fmt -w 40 </dev/null > /dev/null 2>&1; then + grub_have_fmt=y; + else + grub_have_fmt=n; + fi + fi + print_option_help_lead=" $1" + print_option_help_lspace="$(echo "$print_option_help_lead" | wc $print_option_help_wc)" + print_option_help_fill="$((26 - print_option_help_lspace))" + printf "%s" "$print_option_help_lead" + if test $print_option_help_fill -le 0; then + print_option_help_nl=y + echo + else + print_option_help_i=0; + while test $print_option_help_i -lt $print_option_help_fill; do + printf " " + print_option_help_i=$((print_option_help_i+1)) + done + print_option_help_nl=n + fi + if test x$grub_have_fmt = xy; then + print_option_help_split="$(echo "$2" | fmt -w 50)" + else + print_option_help_split="$2" + fi + if test x$print_option_help_nl = xy; then + echo "$print_option_help_split" | awk \ + '{ print " " $0; }' + else + echo "$print_option_help_split" | awk 'BEGIN { n = 0 } + { if (n == 1) print " " $0; else print $0; n = 1 ; }' + fi +} + +grub_fmt () { + if test x$grub_have_fmt = x; then + if fmt -w 40 < /dev/null > /dev/null; then + grub_have_fmt=y; + else + grub_have_fmt=n; + fi + fi + + if test x$grub_have_fmt = xy; then + fmt + else + cat + fi +} + +grub_tab=" " + +grub_add_tab () { + sed -e "s/^/$grub_tab/" +} + diff --git a/util/grub-mkfont.c b/util/grub-mkfont.c new file mode 100644 index 0000000..0fe45a6 --- /dev/null +++ b/util/grub-mkfont.c @@ -0,0 +1,1287 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/misc.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/misc.h> +#include <grub/i18n.h> +#include <grub/fontformat.h> +#include <grub/font.h> +#include <grub/unicode.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifndef GRUB_BUILD +#define _GNU_SOURCE 1 +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" +#endif +#include <assert.h> + +#include <errno.h> + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TRUETYPE_TAGS_H +#include FT_TRUETYPE_TABLES_H +#include FT_SYNTHESIS_H + +#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 + +#ifndef GRUB_BUILD +#include "progname.h" +#endif + +#ifdef GRUB_BUILD +#define grub_util_fopen fopen +#endif + +#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 +}; + +enum + { + GRUB_FONT_FLAG_BOLD = 1, + GRUB_FONT_FLAG_NOBITMAP = 2, + GRUB_FONT_FLAG_NOHINTING = 4, + GRUB_FONT_FLAG_FORCEHINT = 8 + }; + +struct grub_font_info +{ + const 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 int font_verbosity; + +static 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 + /* TRANSLATORS: These qualifiers are used for cursive typography, + mainly Arabic. Note that the terms refer to the visual position + and not logical order and if used in left-to-right script then + leftmost is initial but with right-to-left script like Arabic + rightmost is the initial. */ + ? ((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 (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; +} GRUB_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; + } GRUB_PACKED features[0]; +} GRUB_PACKED; + +struct gsub_feature +{ + grub_uint16_t params; + grub_uint16_t lookupcount; + grub_uint16_t lookupindices[0]; +} GRUB_PACKED; + +struct gsub_lookup_list +{ + grub_uint16_t count; + grub_uint16_t offsets[0]; +} GRUB_PACKED; + +struct gsub_lookup +{ + grub_uint16_t type; + grub_uint16_t flag; + grub_uint16_t subtablecount; + grub_uint16_t subtables[0]; +} GRUB_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]; + }; + }; +} GRUB_PACKED; + +struct gsub_coverage_list +{ + grub_uint16_t type; + grub_uint16_t count; + grub_uint16_t glyphs[0]; +} GRUB_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; + } GRUB_PACKED ranges[0]; +} GRUB_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 +subst (const struct gsub_substitution *sub, grub_uint32_t glyph, + struct glyph_replace **target, int *i) +{ + 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); +} + +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 = NULL; + struct gsub_substitution *sub; + + 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)) + { + /* TRANSLATORS: "lookup" is taken directly from font specifications + which are formulated as "Under condition X replace LOOKUP with + SUBSTITUITION". "*/ + 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) + { + grub_util_info ("unsupported substitution flag: 0x%x", + 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_get_unaligned16 (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 (sub, grub_be_to_cpu16 (cover->glyphs[l]), target, &i); + } + 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 (sub, m, target, &i); + } + else + /* TRANSLATORS: most font transformations apply only to + some glyphs. Those glyphs are described as "coverage". + There are 2 coverage specifications: list and range. + This warning is thrown when another coverage specification + is detected. */ + fprintf (stderr, + _("Unsupported coverage specification: %d\n"), covertype); + } + } +} + +static 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) + fprintf (stderr, + _("WARNING: unsupported font 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] = '?'; + /* TRANSLATORS: It's gsub feature, not gsub font. */ + grub_util_info ("Unknown gsub font feature 0x%x (%s)", + 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); + } +} + +static void +write_string_section (const char *name, const char *str, + int *offset, FILE *file, + const char *filename) +{ + grub_uint32_t leng, leng_be32; + + leng = strlen (str) + 1; + leng_be32 = grub_cpu_to_be32 (leng); + + grub_util_write_image (name, 4, file, filename); + grub_util_write_image ((char *) &leng_be32, 4, file, filename); + grub_util_write_image (str, leng, file, filename); + + *offset += 8 + leng; +} + +static void +write_be16_section (const char *name, grub_uint16_t data, int* offset, + FILE *file, const char *filename) +{ + grub_uint32_t leng; + + leng = grub_cpu_to_be32_compile_time (2); + data = grub_cpu_to_be16 (data); + grub_util_write_image (name, 4, file, filename); + grub_util_write_image ((char *) &leng, 4, file, filename); + grub_util_write_image ((char *) &data, 2, file, filename); + + *offset += 10; +} + +static 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 - 1; 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); + } + } +} + +static 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, *ptr; + int offset; + struct grub_glyph_info *cur; + + file = grub_util_fopen (output_file, "wb"); + if (! file) + grub_util_error (_("cannot write to `%s': %s"), output_file, + strerror (errno)); + + offset = 0; + + leng = grub_cpu_to_be32_compile_time (4); + grub_util_write_image (FONT_FORMAT_SECTION_NAMES_FILE, + sizeof(FONT_FORMAT_SECTION_NAMES_FILE) - 1, file, + output_file); + grub_util_write_image ((char *) &leng, 4, file, output_file); + grub_util_write_image (FONT_FORMAT_PFF2_MAGIC, 4, file, output_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 = xmalloc (strlen (font_info->name) + strlen (&style_name[1]) + + 3 + 20); + ptr = grub_stpcpy (font_name, font_info->name); + *ptr++ = ' '; + ptr = grub_stpcpy (ptr, &style_name[1]); + *ptr++ = ' '; + snprintf (ptr, 20, "%d", font_info->size); + + write_string_section (FONT_FORMAT_SECTION_NAMES_FONT_NAME, + font_name, &offset, file, output_file); + write_string_section (FONT_FORMAT_SECTION_NAMES_FAMILY, + font_info->name, &offset, file, output_file); + write_string_section (FONT_FORMAT_SECTION_NAMES_WEIGHT, + (font_info->style & FT_STYLE_FLAG_BOLD) ? + "bold" : "normal", + &offset, file, output_file); + write_string_section (FONT_FORMAT_SECTION_NAMES_SLAN, + (font_info->style & FT_STYLE_FLAG_ITALIC) ? + "italic" : "normal", + &offset, file, output_file); + + write_be16_section (FONT_FORMAT_SECTION_NAMES_POINT_SIZE, + font_info->size, &offset, file, output_file); + write_be16_section (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH, + font_info->max_width, &offset, file, output_file); + write_be16_section (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT, + font_info->max_height, &offset, file, output_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, output_file); + write_be16_section (FONT_FORMAT_SECTION_NAMES_DESCENT, + font_info->desc, &offset, file, output_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, output_file); + grub_util_write_image ((char *) &leng, 4, file, output_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, output_file); + data8 = 0; + grub_util_write_image ((char *) &data8, 1, file, output_file); + data32 = grub_cpu_to_be32 (offset); + grub_util_write_image ((char *) &data32, 4, file, output_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, output_file); + grub_util_write_image ((char *) &leng, 4, file, output_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, output_file); + data = grub_cpu_to_be16 (cur->height); + grub_util_write_image ((char *) &data, 2, file, output_file); + data = grub_cpu_to_be16 (cur->x_ofs); + grub_util_write_image ((char *) &data, 2, file, output_file); + data = grub_cpu_to_be16 (cur->y_ofs); + grub_util_write_image ((char *) &data, 2, file, output_file); + data = grub_cpu_to_be16 (cur->device_width); + grub_util_write_image ((char *) &data, 2, file, output_file); + grub_util_write_image ((char *) &cur->bitmap[0], cur->bitmap_size, + file, output_file); + } + + fclose (file); +} + +#ifndef GRUB_BUILD +static struct argp_option options[] = { + {"output", 'o', N_("FILE"), 0, N_("save output in FILE [required]"), 0}, + /* TRANSLATORS: bitmaps are images like e.g. in JPEG. */ + {"index", 'i', N_("NUM"), 0, + /* TRANSLATORS: some font files may have multiple faces (fonts). + This option is used to chose among them, the first face being '0'. + Rarely used. */ + N_("select face index"), 0}, + {"range", 'r', N_("FROM-TO[,FROM-TO]"), 0, + /* TRANSLATORS: It refers to the range of characters in font. */ + N_("set font range"), 0}, + {"name", 'n', N_("NAME"), 0, + /* TRANSLATORS: "family name" for font is just a generic name without suffix + like "Bold". */ + N_("set font family name"), 0}, + {"size", 's', N_("SIZE"), 0, N_("set font size"), 0}, + {"desc", 'd', N_("NUM"), 0, N_("set font descent"), 0}, + {"asce", 'c', N_("NUM"), 0, N_("set font ascent"), 0}, + {"bold", 'b', 0, 0, N_("convert to bold font"), 0}, + {"force-autohint", 'a', 0, 0, N_("force autohint"), 0}, + {"no-hinting", 0x101, 0, 0, N_("disable hinting"), 0}, + {"no-bitmap", 0x100, 0, 0, + /* TRANSLATORS: some fonts contain bitmap rendering for + some sizes. This option forces rerendering even if + pre-rendered bitmap is available. + */ + N_("ignore bitmap strikes when loading"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + { 0, 0, 0, 0, 0, 0 } +}; +#define my_argp_parse argp_parse +#define MY_ARGP_KEY_ARG ARGP_KEY_ARG +#define my_error_t error_t +#define MY_ARGP_ERR_UNKNOWN ARGP_ERR_UNKNOWN +#define my_argp_state argp_state + +#else + +#define my_error_t int +#define MY_ARGP_ERR_UNKNOWN -1 +#define MY_ARGP_KEY_ARG -1 +#define my_argp_parse(a, argc, argv, b, c, st) my_argp_parse_real(argc, argv, st) +struct my_argp_state +{ + void *input; +}; + +#endif + +struct arguments +{ + struct grub_font_info font_info; + size_t nfiles; + size_t files_max; + char **files; + char *output_file; + int font_index; + int font_size; + enum file_formats file_format; +}; + +#ifdef GRUB_BUILD + +static int +has_argument (int v) +{ + return v =='o' || v == 'i' || v == 'r' || v == 'n' || v == 's' + || v == 'd' || v == 'c'; +} + +#endif + +static my_error_t +argp_parser (int key, char *arg, struct my_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; + + switch (key) + { + case 'b': + arguments->font_info.flags |= GRUB_FONT_FLAG_BOLD; + break; + + case 0x100: + arguments->font_info.flags |= GRUB_FONT_FLAG_NOBITMAP; + break; + + case 0x101: + arguments->font_info.flags |= GRUB_FONT_FLAG_NOHINTING; + break; + + case 'a': + arguments->font_info.flags |= GRUB_FONT_FLAG_FORCEHINT; + break; + + case 'o': + arguments->output_file = xstrdup (arg); + break; + + case 'n': + arguments->font_info.name = xstrdup (arg); + break; + + case 'i': + arguments->font_index = strtoul (arg, NULL, 0); + break; + + case 's': + arguments->font_size = strtoul (arg, NULL, 0); + break; + + case 'r': + { + char *p = arg; + + while (1) + { + grub_uint32_t a, b; + + a = strtoul (p, &p, 0); + if (*p != '-') + /* TRANSLATORS: It refers to the range of characters in font. */ + grub_util_error ("%s", _("invalid font range")); + b = strtoul (p + 1, &p, 0); + if ((arguments->font_info.num_range + & (GRUB_FONT_RANGE_BLOCK - 1)) == 0) + arguments->font_info.ranges = xrealloc (arguments->font_info.ranges, + (arguments->font_info.num_range + + GRUB_FONT_RANGE_BLOCK) * + sizeof (grub_uint32_t) * 2); + + arguments->font_info.ranges[arguments->font_info.num_range * 2] = a; + arguments->font_info.ranges[arguments->font_info.num_range * 2 + 1] = b; + arguments->font_info.num_range++; + + if (*p) + { + if (*p != ',') + grub_util_error ("%s", _("invalid font range")); + p++; + } + else + break; + } + break; + } + + case 'd': + arguments->font_info.desc = strtoul (arg, NULL, 0); + break; + + case 'c': + arguments->font_info.asce = strtoul (arg, NULL, 0); + break; + + case 'v': + font_verbosity++; + break; + + case MY_ARGP_KEY_ARG: + assert (arguments->nfiles < arguments->files_max); + arguments->files[arguments->nfiles++] = xstrdup(arg); + break; + + default: + return MY_ARGP_ERR_UNKNOWN; + } + return 0; +} + +#ifdef GRUB_BUILD + +/* We don't require host platform to have argp. In the same time configuring + gnulib for build would result in even worse mess. So we have our + minimalistic argp replacement just enough for build system. Most + argp features are omitted. */ + +static int +my_argp_parse_real (int argc, char **argv, void *st) +{ + int curar; + struct my_argp_state p; + + p.input = st; + + for (curar = 1; curar < argc; ) + { + if (argv[curar][0] == '-') + { + if (has_argument (argv[curar][1]) + && curar + 1 >= argc) + return 1; + if (has_argument (argv[curar][1])) + { + if (argp_parser (argv[curar][1], argv[curar + 1], &p)) + return 1; + curar += 2; + continue; + } + if (argp_parser (argv[curar][1], NULL, &p)) + return 1; + curar++; + continue; + } + if (argp_parser (MY_ARGP_KEY_ARG, argv[curar], &p)) + return 1; + curar++; + } + return 0; +} +#endif + +#ifndef GRUB_BUILD +static struct argp argp = { + options, argp_parser, N_("[OPTIONS] FONT_FILES"), + N_("Convert common font file formats into PF2"), + NULL, NULL, NULL +}; +#endif + +int +main (int argc, char *argv[]) +{ + FT_Library ft_lib; + struct arguments arguments; + +#ifndef GRUB_BUILD + grub_util_host_init (&argc, &argv); +#endif + + memset (&arguments, 0, sizeof (struct arguments)); + arguments.file_format = PF2; + arguments.files_max = argc + 1; + arguments.files = xmalloc ((arguments.files_max + 1) + * sizeof (arguments.files[0])); + memset (arguments.files, 0, (arguments.files_max + 1) + * sizeof (arguments.files[0])); + + if (my_argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + if (! arguments.output_file) + grub_util_error ("%s", _("output file must be specified")); + + if (FT_Init_FreeType (&ft_lib)) + grub_util_error ("%s", _("FT_Init_FreeType fails")); + + { + size_t i; + for (i = 0; i < arguments.nfiles; i++) + { + FT_Face ft_face; + int size; + FT_Error err; + + err = FT_New_Face (ft_lib, arguments.files[i], + arguments.font_index, &ft_face); + if (err) + { + printf (_("can't open file %s, index %d: error %d"), + arguments.files[i], + arguments.font_index, err); + if (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs)) + printf (": %s\n", ft_errmsgs[err]); + else + printf ("\n"); + + continue; + } + + if ((! arguments.font_info.name) && (ft_face->family_name)) + arguments.font_info.name = xstrdup (ft_face->family_name); + + size = arguments.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; + } + + arguments.font_info.style = ft_face->style_flags; + arguments.font_info.size = size; + + err = FT_Set_Pixel_Sizes (ft_face, size, size); + + if (err) + grub_util_error (_("can't set %dx%d font size: Freetype error %d: %s"), + size, size, err, + (err > 0 && err < (signed) ARRAY_SIZE (ft_errmsgs)) + ? ft_errmsgs[err] : ""); + add_font (&arguments.font_info, ft_face, arguments.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 = arguments.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 (arguments.font_info.num_glyphs + * sizeof (tmp[0])); + for (cur = arguments.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 + arguments.font_info.num_glyphs; cur++) + counter[((cur->char_code & 0xffff0000) >> 16) + 1]++; + for (i = 0; i < 0x10000; i++) + counter[i+1] += counter[i]; + arguments.font_info.glyphs_sorted = xmalloc (arguments.font_info.num_glyphs + * sizeof (arguments.font_info.glyphs_sorted[0])); + for (cur = tmp; cur < tmp + arguments.font_info.num_glyphs; cur++) + arguments.font_info.glyphs_sorted[counter[(cur->char_code & 0xffff0000) + >> 16]++] = *cur; + free (tmp); + } + + switch (arguments.file_format) + { + case PF2: + write_font_pf2 (&arguments.font_info, arguments.output_file); + break; + } + + if (font_verbosity > 1) + print_glyphs (&arguments.font_info); + + { + size_t i; + for (i = 0; i < arguments.nfiles; i++) + free (arguments.files[i]); + } + + return 0; +} diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c new file mode 100644 index 0000000..c0d5599 --- /dev/null +++ b/util/grub-mkimage.c @@ -0,0 +1,351 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/elf.h> +#include <grub/aout.h> +#include <grub/i18n.h> +#include <grub/kernel.h> +#include <grub/disk.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/util/resolve.h> +#include <grub/misc.h> +#include <grub/offsets.h> +#include <grub/crypto.h> +#include <grub/dl.h> +#include <time.h> +#include <multiboot.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include <grub/efi/pe32.h> +#include <grub/uboot/image.h> +#include <grub/arm/reloc.h> +#include <grub/ia64/reloc.h> +#include <grub/osdep/hostfile.h> +#include <grub/util/install.h> +#include <grub/emu/config.h> + +#define _GNU_SOURCE 1 + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + + +#include "progname.h" + + + +static struct argp_option options[] = { + {"directory", 'd', N_("DIR"), 0, + /* TRANSLATORS: platform here isn't identifier. It can be translated. */ + N_("use images and modules under DIR [default=%s/<platform>]"), 0}, + {"prefix", 'p', N_("DIR"), 0, N_("set prefix directory"), 0}, + {"memdisk", 'm', N_("FILE"), 0, + /* TRANSLATORS: "memdisk" here isn't an identifier, it can be translated. + "embed" is a verb (command description). "*/ + N_("embed FILE as a memdisk image\n" + "Implies `-p (memdisk)/boot/grub' and overrides any prefix supplied previously," + " but the prefix itself can be overridden by later options"), 0}, + {"dtb", 'D', N_("FILE"), 0, N_("embed FILE as a device tree (DTB)\n"), 0}, + /* TRANSLATORS: "embed" is a verb (command description). "*/ + {"config", 'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0}, + /* TRANSLATORS: "embed" is a verb (command description). "*/ + {"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for signature checking"), 0}, + /* TRANSLATORS: NOTE is a name of segment. */ + {"note", 'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0}, + {"output", 'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0}, + {"format", 'O', N_("FORMAT"), 0, 0, 0}, + {"compression", 'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 0}, + {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0}, + {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + { 0, 0, 0, 0, 0, 0 } +}; + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +static char * +help_filter (int key, const char *text, void *input __attribute__ ((unused))) +{ + switch (key) + { + case 'd': + return xasprintf (text, grub_util_get_pkglibdir ()); + case 'O': + { + char *formats = grub_install_get_image_targets_string (), *ret; + ret = xasprintf ("%s\n%s %s", _("generate an image in FORMAT"), + _("available formats:"), formats); + free (formats); + return ret; + } + default: + return (char *) text; + } +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +struct arguments +{ + size_t nmodules; + size_t modules_max; + char **modules; + char *output; + char *dir; + char *prefix; + char *memdisk; + char *dtb; + char **pubkeys; + size_t npubkeys; + char *font; + char *config; + char *sbat; + int note; + int disable_shim_lock; + const struct grub_install_image_target_desc *image_target; + grub_compression_t comp; +}; + +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; + + switch (key) + { + case 'o': + if (arguments->output) + free (arguments->output); + + arguments->output = xstrdup (arg); + break; + + case 'O': + { + arguments->image_target = grub_install_get_image_target (arg); + if (!arguments->image_target) + { + printf (_("unknown target format %s\n"), arg); + argp_usage (state); + exit (1); + } + break; + } + case 'd': + if (arguments->dir) + free (arguments->dir); + + arguments->dir = xstrdup (arg); + break; + + case 'n': + arguments->note = 1; + break; + + case 'm': + if (arguments->memdisk) + free (arguments->memdisk); + + arguments->memdisk = xstrdup (arg); + + if (arguments->prefix) + free (arguments->prefix); + + arguments->prefix = xstrdup ("(memdisk)/boot/grub"); + break; + + case 'D': + if (arguments->dtb) + free (arguments->dtb); + + arguments->dtb = xstrdup (arg); + break; + + case 'k': + arguments->pubkeys = xrealloc (arguments->pubkeys, + sizeof (arguments->pubkeys[0]) + * (arguments->npubkeys + 1)); + arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg); + break; + + case 'c': + if (arguments->config) + free (arguments->config); + + arguments->config = xstrdup (arg); + break; + + case 'C': + if (grub_strcmp (arg, "xz") == 0) + { +#ifdef HAVE_LIBLZMA + arguments->comp = GRUB_COMPRESSION_XZ; +#else + grub_util_error ("%s", + _("grub-mkimage is compiled without XZ support")); +#endif + } + else if (grub_strcmp (arg, "none") == 0) + arguments->comp = GRUB_COMPRESSION_NONE; + else if (grub_strcmp (arg, "auto") == 0) + arguments->comp = GRUB_COMPRESSION_AUTO; + else + grub_util_error (_("Unknown compression format %s"), arg); + break; + + case 'p': + if (arguments->prefix) + free (arguments->prefix); + + arguments->prefix = xstrdup (arg); + break; + + case 's': + if (arguments->sbat) + free (arguments->sbat); + + arguments->sbat = xstrdup (arg); + break; + + case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: + arguments->disable_shim_lock = 1; + break; + + case 'v': + verbosity++; + break; + case ARGP_KEY_ARG: + assert (arguments->nmodules < arguments->modules_max); + arguments->modules[arguments->nmodules++] = xstrdup(arg); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { + options, argp_parser, N_("[OPTION]... [MODULES]"), + N_("Make a bootable image of GRUB."), + NULL, help_filter, NULL +}; + +int +main (int argc, char *argv[]) +{ + FILE *fp = stdout; + struct arguments arguments; + unsigned i; + + grub_util_host_init (&argc, &argv); + + memset (&arguments, 0, sizeof (struct arguments)); + arguments.comp = GRUB_COMPRESSION_AUTO; + arguments.modules_max = argc + 1; + arguments.modules = xmalloc ((arguments.modules_max + 1) + * sizeof (arguments.modules[0])); + memset (arguments.modules, 0, (arguments.modules_max + 1) + * sizeof (arguments.modules[0])); + + if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + if (!arguments.image_target) + { + char *program = xstrdup(program_name); + printf ("%s\n", _("Target format not specified (use the -O option).")); + argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program); + free (program); + exit(1); + } + + if (!arguments.prefix) + { + char *program = xstrdup(program_name); + printf ("%s\n", _("Prefix not specified (use the -p option).")); + argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program); + free (program); + exit(1); + } + + if (arguments.output) + { + fp = grub_util_fopen (arguments.output, "wb"); + if (! fp) + grub_util_error (_("cannot open `%s': %s"), arguments.output, + strerror (errno)); + } + + if (!arguments.dir) + { + const char *dn = grub_util_get_target_dirname (arguments.image_target); + const char *pkglibdir = grub_util_get_pkglibdir (); + char *ptr; + arguments.dir = xmalloc (grub_strlen (pkglibdir) + grub_strlen (dn) + 2); + ptr = grub_stpcpy (arguments.dir, pkglibdir); + *ptr++ = '/'; + strcpy (ptr, dn); + } + + grub_install_generate_image (arguments.dir, arguments.prefix, fp, + arguments.output, arguments.modules, + arguments.memdisk, arguments.pubkeys, + arguments.npubkeys, arguments.config, + arguments.image_target, arguments.note, + arguments.comp, arguments.dtb, + arguments.sbat, arguments.disable_shim_lock); + + if (grub_util_file_sync (fp) < 0) + grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout", + strerror (errno)); + if (fclose (fp) == EOF) + grub_util_error (_("cannot close `%s': %s"), arguments.output ? : "stdout", + strerror (errno)); + + for (i = 0; i < arguments.nmodules; i++) + free (arguments.modules[i]); + + free (arguments.dir); + free (arguments.prefix); + free (arguments.modules); + + if (arguments.output) + free (arguments.output); + + if (arguments.sbat) + free (arguments.sbat); + + return 0; +} diff --git a/util/grub-mkimage32.c b/util/grub-mkimage32.c new file mode 100644 index 0000000..026a2dd --- /dev/null +++ b/util/grub-mkimage32.c @@ -0,0 +1,26 @@ +#define MKIMAGE_ELF32 1 + +# define SUFFIX(x) x ## 32 +# define ELFCLASSXX ELFCLASS32 +# define Elf_Ehdr Elf32_Ehdr +# define Elf_Phdr Elf32_Phdr +# define Elf_Nhdr Elf32_Nhdr +# 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_Word Elf32_Word +# define Elf_Half Elf32_Half +# define Elf_Section Elf32_Section +# define ELF_R_SYM(val) ELF32_R_SYM(val) +# define ELF_R_TYPE(val) ELF32_R_TYPE(val) +# define ELF_ST_TYPE(val) ELF32_ST_TYPE(val) + +#define XEN_NOTE_SIZE 132 +#define XEN_PVH_NOTE_SIZE 20 + +#ifndef GRUB_MKIMAGEXX +#include "grub-mkimagexx.c" +#endif diff --git a/util/grub-mkimage64.c b/util/grub-mkimage64.c new file mode 100644 index 0000000..170defb --- /dev/null +++ b/util/grub-mkimage64.c @@ -0,0 +1,26 @@ +#define MKIMAGE_ELF64 1 + +# define SUFFIX(x) x ## 64 +# define ELFCLASSXX ELFCLASS64 +# define Elf_Ehdr Elf64_Ehdr +# define Elf_Phdr Elf64_Phdr +# define Elf_Nhdr Elf64_Nhdr +# 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_Word Elf64_Word +# define Elf_Half Elf64_Half +# define Elf_Section Elf64_Section +# define ELF_R_SYM(val) ELF64_R_SYM(val) +# define ELF_R_TYPE(val) ELF64_R_TYPE(val) +# define ELF_ST_TYPE(val) ELF64_ST_TYPE(val) + +#define XEN_NOTE_SIZE 120 +#define XEN_PVH_NOTE_SIZE 24 + +#ifndef GRUB_MKIMAGEXX +#include "grub-mkimagexx.c" +#endif diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c new file mode 100644 index 0000000..d78fa3e --- /dev/null +++ b/util/grub-mkimagexx.c @@ -0,0 +1,2452 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/elf.h> +#include <grub/aout.h> +#include <grub/i18n.h> +#include <grub/kernel.h> +#include <grub/disk.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/util/resolve.h> +#include <grub/misc.h> +#include <grub/offsets.h> +#include <grub/crypto.h> +#include <grub/dl.h> +#include <time.h> +#include <multiboot.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include <grub/efi/pe32.h> +#include <grub/uboot/image.h> +#include <grub/arm/reloc.h> +#include <grub/arm64/reloc.h> +#include <grub/ia64/reloc.h> +#include <grub/osdep/hostfile.h> +#include <grub/util/install.h> +#include <grub/util/mkimage.h> + +#include <xen/elfnote.h> + +#pragma GCC diagnostic ignored "-Wcast-align" + +#define GRUB_MKIMAGEXX +#if !defined(MKIMAGE_ELF32) && !defined(MKIMAGE_ELF64) +#if __SIZEOF_POINTER__ == 8 +#include "grub-mkimage64.c" +#else +#include "grub-mkimage32.c" +#endif +#endif + +/* These structures are defined according to the CHRP binding to IEEE1275, + "Client Program Format" section. */ + +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; +}; + +#define GRUB_IEEE1275_NOTE_NAME "PowerPC" +#define GRUB_IEEE1275_NOTE_TYPE 0x1275 + +struct grub_ieee1275_note +{ + Elf32_Nhdr header; + char name[ALIGN_UP(sizeof (GRUB_IEEE1275_NOTE_NAME), 4)]; + struct grub_ieee1275_note_desc descriptor; +}; + +#define GRUB_XEN_NOTE_NAME "Xen" + +struct fixup_block_list +{ + struct fixup_block_list *next; + int state; + struct grub_pe32_fixup_block b; +}; + +#define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof)) + +struct section_metadata +{ + Elf_Half num_sections; + Elf_Shdr *sections; + Elf_Addr *addrs; + Elf_Addr *vaddrs; + Elf_Half section_entsize; + Elf_Shdr *symtab; + const char *strtab; +}; + +static int +is_relocatable (const struct grub_install_image_target_desc *image_target) +{ + return image_target->id == IMAGE_EFI || image_target->id == IMAGE_UBOOT + || (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM); +} + +#ifdef MKIMAGE_ELF32 + +/* + * R_ARM_THM_CALL/THM_JUMP24 + * + * Relocate Thumb (T32) instruction set relative branches: + * B.W, BL and BLX + */ +static grub_err_t +grub_arm_reloc_thm_call (grub_uint16_t *target, Elf32_Addr sym_addr) +{ + grub_int32_t offset; + + offset = grub_arm_thm_call_get_offset (target); + + grub_dprintf ("dl", " sym_addr = 0x%08x", sym_addr); + + offset += sym_addr; + + grub_dprintf("dl", " BL*: target=%p, sym_addr=0x%08x, offset=%d\n", + target, sym_addr, offset); + + /* Keep traditional (pre-Thumb2) limits on blx. In any case if the kernel + is bigger than 2M (currently under 150K) then we probably have a problem + somewhere else. */ + if (offset < -0x200000 || offset >= 0x200000) + return grub_error (GRUB_ERR_BAD_MODULE, + "THM_CALL Relocation out of range."); + + grub_dprintf ("dl", " relative destination = %p", + (char *) target + offset); + + return grub_arm_thm_call_set_offset (target, offset); +} + +/* + * R_ARM_THM_JUMP19 + * + * Relocate conditional Thumb (T32) B<c>.W + */ +static grub_err_t +grub_arm_reloc_thm_jump19 (grub_uint16_t *target, Elf32_Addr sym_addr) +{ + grub_int32_t offset; + + if (!(sym_addr & 1)) + return grub_error (GRUB_ERR_BAD_MODULE, + "Relocation targeting wrong execution state"); + + offset = grub_arm_thm_jump19_get_offset (target); + + /* Adjust and re-truncate offset */ + offset += sym_addr; + + if (!grub_arm_thm_jump19_check_offset (offset)) + return grub_error (GRUB_ERR_BAD_MODULE, + "THM_JUMP19 Relocation out of range."); + + grub_arm_thm_jump19_set_offset (target, offset); + + return GRUB_ERR_NONE; +} + +/* + * R_ARM_JUMP24 + * + * Relocate ARM (A32) B + */ +static grub_err_t +grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) +{ + grub_int32_t offset; + + if (sym_addr & 1) + return grub_error (GRUB_ERR_BAD_MODULE, + "Relocation targeting wrong execution state"); + + offset = grub_arm_jump24_get_offset (target); + offset += sym_addr; + + if (!grub_arm_jump24_check_offset (offset)) + return grub_error (GRUB_ERR_BAD_MODULE, + "JUMP24 Relocation out of range."); + + + grub_arm_jump24_set_offset (target, offset); + + return GRUB_ERR_NONE; +} + +#endif + +void +SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target, + int note, char **core_img, size_t *core_size, + Elf_Addr target_addr, + struct grub_mkimage_layout *layout) +{ + char *elf_img; + size_t program_size; + Elf_Ehdr *ehdr; + Elf_Phdr *phdr; + Elf_Shdr *shdr; + int header_size, footer_size = 0; + int phnum = 1; + int shnum = 4; + int string_size = sizeof (".text") + sizeof ("mods") + 1; + + if (image_target->id != IMAGE_LOONGSON_ELF) + phnum += 2; + + if (note) + { + phnum++; + footer_size += sizeof (struct grub_ieee1275_note); + } + if (image_target->id == IMAGE_XEN || image_target->id == IMAGE_XEN_PVH) + { + phnum++; + shnum++; + string_size += sizeof (".xen"); + footer_size += (image_target->id == IMAGE_XEN) ? XEN_NOTE_SIZE : XEN_PVH_NOTE_SIZE; + } + header_size = ALIGN_UP (sizeof (*ehdr) + phnum * sizeof (*phdr) + + shnum * sizeof (*shdr) + string_size, layout->align); + + program_size = ALIGN_ADDR (*core_size); + + elf_img = xmalloc (program_size + header_size + footer_size); + memset (elf_img, 0, program_size + header_size + footer_size); + memcpy (elf_img + header_size, *core_img, *core_size); + ehdr = (void *) elf_img; + phdr = (void *) (elf_img + sizeof (*ehdr)); + shdr = (void *) (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)); + memcpy (ehdr->e_ident, ELFMAG, SELFMAG); + ehdr->e_ident[EI_CLASS] = ELFCLASSXX; + 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); + + ehdr->e_shoff = grub_host_to_target32 ((grub_uint8_t *) shdr + - (grub_uint8_t *) ehdr); + if (image_target->id == IMAGE_LOONGSON_ELF) + ehdr->e_shentsize = grub_host_to_target16 (0); + else + ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf_Shdr)); + ehdr->e_shnum = grub_host_to_target16 (shnum); + ehdr->e_shstrndx = grub_host_to_target16 (1); + + 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); + + 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 (layout->align > image_target->link_align ? + layout->align : image_target->link_align); + if (image_target->id == IMAGE_LOONGSON_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_LOONGSON_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 (layout->kernel_size); + if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM) + phdr->p_memsz = grub_host_to_target32 (layout->kernel_size); + else + phdr->p_memsz = grub_host_to_target32 (layout->kernel_size + layout->bss_size); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_GNU_STACK); + phdr->p_offset = grub_host_to_target32 (header_size + layout->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 + layout->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 - layout->kernel_size); + + if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_386) + target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR; + else if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM) + target_addr_mods = ALIGN_UP (target_addr + layout->end + + image_target->mod_gap, + image_target->mod_align); + else + target_addr_mods = ALIGN_UP (target_addr + layout->kernel_size + layout->bss_size + + image_target->mod_gap, + image_target->mod_align); + phdr->p_vaddr = grub_host_to_target_addr (target_addr_mods); + phdr->p_paddr = grub_host_to_target_addr (target_addr_mods); + phdr->p_align = grub_host_to_target32 (image_target->link_align); + } + + if (image_target->id == IMAGE_XEN) + { + char *note_start = (elf_img + program_size + header_size); + Elf_Nhdr *note_ptr; + char *ptr = (char *) note_start; + + grub_util_info ("adding XEN NOTE segment"); + + /* Guest OS. */ + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (sizeof (PACKAGE_NAME)); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_GUEST_OS); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memcpy (ptr, PACKAGE_NAME, sizeof (PACKAGE_NAME)); + ptr += ALIGN_UP (sizeof (PACKAGE_NAME), 4); + + /* Loader. */ + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (sizeof ("generic")); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_LOADER); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memcpy (ptr, "generic", sizeof ("generic")); + ptr += ALIGN_UP (sizeof ("generic"), 4); + + /* Version. */ + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (sizeof ("xen-3.0")); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_XEN_VERSION); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memcpy (ptr, "xen-3.0", sizeof ("xen-3.0")); + ptr += ALIGN_UP (sizeof ("xen-3.0"), 4); + + /* Entry. */ + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_ENTRY); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memset (ptr, 0, image_target->voidp_sizeof); + ptr += image_target->voidp_sizeof; + + /* Virt base. */ + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_VIRT_BASE); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memset (ptr, 0, image_target->voidp_sizeof); + ptr += image_target->voidp_sizeof; + + /* PAE. */ + if (image_target->elf_target == EM_386) + { + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (sizeof ("yes,bimodal")); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_PAE_MODE); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memcpy (ptr, "yes", sizeof ("yes")); + ptr += ALIGN_UP (sizeof ("yes"), 4); + } + + assert (XEN_NOTE_SIZE == (ptr - note_start)); + + 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 (XEN_NOTE_SIZE); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); + } + + if (image_target->id == IMAGE_XEN_PVH) + { + char *note_start = (elf_img + program_size + header_size); + Elf_Nhdr *note_ptr; + char *ptr = (char *) note_start; + + grub_util_info ("adding XEN NOTE segment"); + + /* Phys32 Entry. */ + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_PHYS32_ENTRY); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memset (ptr, 0, image_target->voidp_sizeof); + *(grub_uint32_t *) ptr = GRUB_KERNEL_I386_XEN_PVH_LINK_ADDR; + ptr += image_target->voidp_sizeof; + + assert (XEN_PVH_NOTE_SIZE == (ptr - note_start)); + + 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 (XEN_PVH_NOTE_SIZE); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); + } + + if (note) + { + int note_size = sizeof (struct grub_ieee1275_note); + struct grub_ieee1275_note *note_ptr = (struct grub_ieee1275_note *) + (elf_img + program_size + header_size); + + grub_util_info ("adding CHRP NOTE segment"); + + note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME)); + note_ptr->header.n_descsz = grub_host_to_target32 (sizeof (struct grub_ieee1275_note_desc)); + note_ptr->header.n_type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE); + strcpy (note_ptr->name, GRUB_IEEE1275_NOTE_NAME); + note_ptr->descriptor.real_mode = grub_host_to_target32 (0xffffffff); + note_ptr->descriptor.real_base = grub_host_to_target32 (0x00c00000); + note_ptr->descriptor.real_size = grub_host_to_target32 (0xffffffff); + note_ptr->descriptor.virt_base = grub_host_to_target32 (0xffffffff); + note_ptr->descriptor.virt_size = grub_host_to_target32 (0xffffffff); + note_ptr->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); + } + + { + char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr) + + shnum * sizeof (*shdr)); + char *ptr = str_start + 1; + + shdr++; + + shdr->sh_name = grub_host_to_target32 (0); + shdr->sh_type = grub_host_to_target32 (SHT_STRTAB); + shdr->sh_addr = grub_host_to_target_addr (0); + shdr->sh_offset = grub_host_to_target_addr (str_start - elf_img); + shdr->sh_size = grub_host_to_target32 (string_size); + shdr->sh_link = grub_host_to_target32 (0); + shdr->sh_info = grub_host_to_target32 (0); + shdr->sh_addralign = grub_host_to_target32 (layout->align); + shdr->sh_entsize = grub_host_to_target32 (0); + shdr++; + + memcpy (ptr, ".text", sizeof (".text")); + + shdr->sh_name = grub_host_to_target32 (ptr - str_start); + ptr += sizeof (".text"); + shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS); + shdr->sh_addr = grub_host_to_target_addr (target_addr); + shdr->sh_offset = grub_host_to_target_addr (header_size); + shdr->sh_size = grub_host_to_target32 (layout->kernel_size); + shdr->sh_link = grub_host_to_target32 (0); + shdr->sh_info = grub_host_to_target32 (0); + shdr->sh_addralign = grub_host_to_target32 (layout->align); + shdr->sh_entsize = grub_host_to_target32 (0); + shdr++; + + memcpy (ptr, "mods", sizeof ("mods")); + shdr->sh_name = grub_host_to_target32 (ptr - str_start); + ptr += sizeof ("mods"); + shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS); + shdr->sh_addr = grub_host_to_target_addr (target_addr + layout->kernel_size); + shdr->sh_offset = grub_host_to_target_addr (header_size + layout->kernel_size); + shdr->sh_size = grub_host_to_target32 (*core_size - layout->kernel_size); + shdr->sh_link = grub_host_to_target32 (0); + shdr->sh_info = grub_host_to_target32 (0); + shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof); + shdr->sh_entsize = grub_host_to_target32 (0); + shdr++; + + if (image_target->id == IMAGE_XEN || image_target->id == IMAGE_XEN_PVH) + { + memcpy (ptr, ".xen", sizeof (".xen")); + shdr->sh_name = grub_host_to_target32 (ptr - str_start); + ptr += sizeof (".xen"); + shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS); + shdr->sh_addr = grub_host_to_target_addr (target_addr + layout->kernel_size); + shdr->sh_offset = grub_host_to_target_addr (program_size + header_size); + if (image_target->id == IMAGE_XEN) + shdr->sh_size = grub_host_to_target32 (XEN_NOTE_SIZE); + else + shdr->sh_size = grub_host_to_target32 (XEN_PVH_NOTE_SIZE); + shdr->sh_link = grub_host_to_target32 (0); + shdr->sh_info = grub_host_to_target32 (0); + shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof); + shdr->sh_entsize = grub_host_to_target32 (0); + shdr++; + } + } + + free (*core_img); + *core_img = elf_img; + *core_size = program_size + header_size + footer_size; +} + +/* 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, struct section_metadata *smd, + void *jumpers, Elf_Addr jumpers_addr, + Elf_Addr bss_start, Elf_Addr end, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Word symtab_size, sym_size, num_syms; + Elf_Off symtab_offset; + Elf_Addr start_address = (Elf_Addr) -1; + Elf_Sym *sym; + Elf_Word i; + Elf_Shdr *symtab_section; + const char *symtab; + grub_uint64_t *jptr = jumpers; + + symtab_section = (Elf_Shdr *) ((char *) smd->sections + + grub_target_to_host32 (smd->symtab->sh_link) + * smd->section_entsize); + symtab = (char *) e + grub_target_to_host (symtab_section->sh_offset); + + symtab_size = grub_target_to_host (smd->symtab->sh_size); + sym_size = grub_target_to_host (smd->symtab->sh_entsize); + symtab_offset = grub_target_to_host (smd->symtab->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 cur_index; + const char *name; + + name = symtab + grub_target_to_host32 (sym->st_name); + + cur_index = grub_target_to_host16 (sym->st_shndx); + if (cur_index == STN_ABS) + { + continue; + } + else if (cur_index == STN_UNDEF) + { + if (sym->st_name && grub_strcmp (name, "__bss_start") == 0) + sym->st_value = bss_start; + else if (sym->st_name && grub_strcmp (name, "_end") == 0) + sym->st_value = end; + else if (sym->st_name) + grub_util_error ("undefined symbol %s", name); + else + continue; + } + else if (cur_index >= smd->num_sections) + grub_util_error ("section %d does not exist", cur_index); + else + { + sym->st_value = (grub_target_to_host (sym->st_value) + + smd->vaddrs[cur_index]); + } + + if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info) + == STT_FUNC) + { + *jptr = grub_host_to_target64 (sym->st_value); + sym->st_value = (char *) jptr - (char *) jumpers + jumpers_addr; + jptr++; + *jptr = 0; + jptr++; + } + grub_util_info ("locating %s at 0x%" GRUB_HOST_PRIxLONG_LONG + " (0x%" GRUB_HOST_PRIxLONG_LONG ")", name, + (unsigned long long) sym->st_value, + (unsigned long long) smd->vaddrs[cur_index]); + + if (start_address == (Elf_Addr)-1) + 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, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Sym *sym; + + sym = (Elf_Sym *) ((char *) e + + grub_target_to_host (s->sh_offset) + + i * grub_target_to_host (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, + const struct grub_install_image_target_desc *image_target) +{ + return (Elf_Addr *) ((char *) e + grub_target_to_host (s->sh_offset) + offset); +} + +#ifdef MKIMAGE_ELF64 +static Elf_Addr +SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Word symtab_size, sym_size, num_syms; + Elf_Off symtab_offset; + Elf_Sym *sym; + Elf_Word i; + int ret = 0; + + 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)) + if (ELF_ST_TYPE (sym->st_info) == STT_FUNC) + ret++; + + return ret; +} +#endif + +#ifdef MKIMAGE_ELF32 +/* 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 grub_size_t +arm_get_trampoline_size (Elf_Ehdr *e, + Elf_Shdr *sections, + Elf_Half section_entsize, + Elf_Half num_sections, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Half i; + Elf_Shdr *s; + grub_size_t ret = 0; + + 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 j; + + symtab_section = (Elf_Shdr *) ((char *) sections + + (grub_target_to_host32 (s->sh_link) + * section_entsize)); + + rtab_size = grub_target_to_host (s->sh_size); + r_size = grub_target_to_host (s->sh_entsize); + rtab_offset = grub_target_to_host (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 sym_addr; + + info = grub_target_to_host (r->r_info); + sym_addr = SUFFIX (get_symbol_address) (e, symtab_section, + ELF_R_SYM (info), image_target); + + sym_addr += (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? + grub_target_to_host (r->r_addend) : 0; + + switch (ELF_R_TYPE (info)) + { + case R_ARM_ABS32: + case R_ARM_V4BX: + break; + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: + case R_ARM_THM_JUMP19: + if (!(sym_addr & 1)) + ret += 8; + break; + + case R_ARM_CALL: + case R_ARM_JUMP24: + if (sym_addr & 1) + ret += 16; + break; + + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + } + } + return ret; +} +#endif + +static int +SUFFIX (is_kept_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target); +static int +SUFFIX (is_kept_reloc_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target, + struct section_metadata *smd); + +/* 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_addrs) (Elf_Ehdr *e, struct section_metadata *smd, + char *pe_target, Elf_Addr tramp_off, Elf_Addr got_off, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Half i; + Elf_Shdr *s; +#ifdef MKIMAGE_ELF64 + struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off); + grub_uint64_t *gpptr = (void *) (pe_target + got_off); + unsigned unmatched_adr_got_page = 0; +#define MASK19 ((1 << 19) - 1) +#else + grub_uint32_t *tr = (void *) (pe_target + tramp_off); +#endif + + for (i = 0, s = smd->sections; + i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->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_Word target_section_index; + Elf_Addr target_section_addr; + Elf_Shdr *target_section; + Elf_Word j; + + if (!SUFFIX (is_kept_section) (s, image_target) && + !SUFFIX (is_kept_reloc_section) (s, image_target, smd)) + { + grub_util_info ("not translating relocations for omitted section %s", + smd->strtab + grub_le_to_cpu32 (s->sh_name)); + continue; + } + + target_section_index = grub_target_to_host32 (s->sh_info); + target_section_addr = smd->addrs[target_section_index]; + target_section = (Elf_Shdr *) ((char *) smd->sections + + (target_section_index + * smd->section_entsize)); + + grub_util_info ("dealing with the relocation section %s for %s", + smd->strtab + grub_target_to_host32 (s->sh_name), + smd->strtab + grub_target_to_host32 (target_section->sh_name)); + + rtab_size = grub_target_to_host (s->sh_size); + r_size = grub_target_to_host (s->sh_entsize); + rtab_offset = grub_target_to_host (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, smd->symtab, + ELF_R_SYM (info), image_target); + + addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? + grub_target_to_host (r->r_addend) : 0; + + switch (image_target->elf_target) + { + case EM_386: + 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%" + GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) *target, + (unsigned long long) 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%" + GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) *target, + (unsigned long long) offset); + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; +#ifdef MKIMAGE_ELF64 + case EM_X86_64: + 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%" + GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) *target, + (unsigned long long) offset); + break; + + case R_X86_64_PC32: + case R_X86_64_PLT32: + { + 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%" + GRUB_HOST_PRIxLONG_LONG, + *t32, (unsigned long long) offset); + break; + } + + case R_X86_64_PC64: + { + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + grub_util_info ("relocating an R_X86_64_PC64 entry to 0x%" + GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) *target, + (unsigned long long) 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%" + GRUB_HOST_PRIxLONG_LONG, + *t32, (unsigned long long) offset); + break; + } + + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + case EM_IA_64: + switch (ELF_R_TYPE (info)) + { + case R_IA64_PCREL21B: + { + grub_uint64_t noff; + grub_ia64_make_trampoline (tr, addend + sym_addr); + noff = ((char *) tr - (char *) pe_target + - target_section_addr - (offset & ~3)) >> 4; + tr++; + if (noff & ~MASK19) + grub_util_error ("trampoline offset too big (%" + GRUB_HOST_PRIxLONG_LONG ")", + (unsigned long long) noff); + grub_ia64_add_value_to_slot_20b ((grub_addr_t) target, noff); + } + break; + + case R_IA64_LTOFF22X: + case R_IA64_LTOFF22: + { + Elf_Sym *sym; + + sym = (Elf_Sym *) ((char *) e + + grub_target_to_host (smd->symtab->sh_offset) + + ELF_R_SYM (info) * grub_target_to_host (smd->symtab->sh_entsize)); + if (ELF_ST_TYPE (sym->st_info) == STT_FUNC) + sym_addr = grub_target_to_host64 (*(grub_uint64_t *) (pe_target + + sym->st_value + - image_target->vaddr_offset)); + } + /* FALLTHROUGH */ + case R_IA64_LTOFF_FPTR22: + *gpptr = grub_host_to_target64 (addend + sym_addr); + grub_ia64_add_value_to_slot_21 ((grub_addr_t) target, + (char *) gpptr - (char *) pe_target + + image_target->vaddr_offset); + gpptr++; + break; + + case R_IA64_GPREL22: + grub_ia64_add_value_to_slot_21 ((grub_addr_t) target, + addend + sym_addr); + break; + case R_IA64_GPREL64I: + grub_ia64_set_immu64 ((grub_addr_t) target, + addend + sym_addr); + break; + case R_IA64_PCREL64LSB: + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + break; + + case R_IA64_SEGREL64LSB: + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr - target_section_addr); + break; + case R_IA64_DIR64LSB: + case R_IA64_FPTR64LSB: + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr); + grub_util_info ("relocating a direct entry to 0x%" + GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) + grub_target_to_host64 (*target), + (unsigned long long) offset); + break; + + /* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */ + case R_IA64_LDXMOV: + break; + + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + case EM_AARCH64: + { + sym_addr += addend; + switch (ELF_R_TYPE (info)) + { + case R_AARCH64_ABS64: + { + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr); + } + break; + case R_AARCH64_PREL32: + { + grub_uint32_t *t32 = (grub_uint32_t *) target; + *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32) + + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + grub_util_info ("relocating an R_AARCH64_PREL32 entry to 0x%x at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + *t32, (unsigned long long) offset); + break; + } + case R_AARCH64_ADD_ABS_LO12_NC: + grub_arm64_set_abs_lo12 ((grub_uint32_t *) target, + sym_addr); + break; + case R_AARCH64_LDST64_ABS_LO12_NC: + grub_arm64_set_abs_lo12_ldst64 ((grub_uint32_t *) target, + sym_addr); + break; + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: + { + sym_addr -= offset; + sym_addr -= target_section_addr + image_target->vaddr_offset; + if (!grub_arm_64_check_xxxx26_offset (sym_addr)) + grub_util_error ("%s", "CALL26 Relocation out of range"); + + grub_arm64_set_xxxx26_offset((grub_uint32_t *)target, + sym_addr); + } + break; + case R_AARCH64_ADR_GOT_PAGE: + { + Elf64_Rela *rel2; + grub_int64_t gpoffset = (((char *) gpptr - (char *) pe_target + image_target->vaddr_offset) & ~0xfffULL) + - ((offset + target_section_addr + image_target->vaddr_offset) & ~0xfffULL); + unsigned k; + *gpptr = grub_host_to_target64 (sym_addr); + unmatched_adr_got_page++; + if (!grub_arm64_check_hi21_signed (gpoffset)) + grub_util_error ("HI21 out of range"); + grub_arm64_set_hi21((grub_uint32_t *)target, + gpoffset); + for (k = 0, rel2 = (Elf_Rela *) ((char *) r + r_size); + k < num_rs; + k++, rel2 = (Elf_Rela *) ((char *) rel2 + r_size)) + if (ELF_R_SYM (rel2->r_info) + == ELF_R_SYM (r->r_info) + && r->r_addend == rel2->r_addend + && ELF_R_TYPE (rel2->r_info) == R_AARCH64_LD64_GOT_LO12_NC) + { + grub_arm64_set_abs_lo12_ldst64 ((grub_uint32_t *) SUFFIX (get_target_address) (e, target_section, + grub_target_to_host (rel2->r_offset), image_target), + ((char *) gpptr - (char *) pe_target + image_target->vaddr_offset)); + break; + } + if (k >= num_rs) + grub_util_error ("ADR_GOT_PAGE without matching LD64_GOT_LO12_NC"); + gpptr++; + } + break; + case R_AARCH64_LD64_GOT_LO12_NC: + if (unmatched_adr_got_page == 0) + grub_util_error ("LD64_GOT_LO12_NC without matching ADR_GOT_PAGE"); + unmatched_adr_got_page--; + break; + case R_AARCH64_ADR_PREL_PG_HI21: + { + sym_addr &= ~0xfffULL; + sym_addr -= (offset + target_section_addr + image_target->vaddr_offset) & ~0xfffULL; + if (!grub_arm64_check_hi21_signed (sym_addr)) + grub_util_error ("%s", "CALL26 Relocation out of range"); + + grub_arm64_set_hi21((grub_uint32_t *)target, + sym_addr); + } + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + } +#endif +#if defined(MKIMAGE_ELF32) + case EM_ARM: + { + sym_addr += addend; + sym_addr -= image_target->vaddr_offset; + switch (ELF_R_TYPE (info)) + { + case R_ARM_ABS32: + { + grub_util_info (" ABS32:\toffset=%d\t(0x%08x)", + (int) sym_addr, (int) sym_addr); + /* Data will be naturally aligned */ + if (image_target->id == IMAGE_EFI) + sym_addr += GRUB_PE32_SECTION_ALIGNMENT; + *target = grub_host_to_target32 (grub_target_to_host32 (*target) + sym_addr); + } + break; + /* Happens when compiled with -march=armv4. + Since currently we need at least armv5, keep bx as-is. + */ + case R_ARM_V4BX: + break; + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: + case R_ARM_THM_JUMP19: + { + grub_err_t err; + Elf_Sym *sym; + grub_util_info (" THM_JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)", + (unsigned long) ((char *) target + - (char *) e), + sym_addr); + sym = (Elf_Sym *) ((char *) e + + grub_target_to_host (smd->symtab->sh_offset) + + ELF_R_SYM (info) * grub_target_to_host (smd->symtab->sh_entsize)); + if (ELF_ST_TYPE (sym->st_info) != STT_FUNC) + sym_addr |= 1; + if (!(sym_addr & 1)) + { + grub_uint32_t tr_addr; + grub_int32_t new_offset; + tr_addr = (char *) tr - (char *) pe_target + - target_section_addr; + new_offset = sym_addr - tr_addr - 12; + + if (!grub_arm_jump24_check_offset (new_offset)) + return grub_util_error ("jump24 relocation out of range"); + + tr[0] = grub_host_to_target32 (0x46c04778); /* bx pc; nop */ + tr[1] = grub_host_to_target32 (((new_offset >> 2) & 0xffffff) | 0xea000000); /* b new_offset */ + tr += 2; + sym_addr = tr_addr | 1; + } + sym_addr -= offset; + /* Thumb instructions can be 16-bit aligned */ + if (ELF_R_TYPE (info) == R_ARM_THM_JUMP19) + err = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr); + else + err = grub_arm_reloc_thm_call ((grub_uint16_t *) target, + sym_addr); + if (err) + grub_util_error ("%s", grub_errmsg); + } + break; + + case R_ARM_CALL: + case R_ARM_JUMP24: + { + grub_err_t err; + grub_util_info (" JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)", (unsigned long) ((char *) target - (char *) e), sym_addr); + if (sym_addr & 1) + { + grub_uint32_t tr_addr; + grub_int32_t new_offset; + tr_addr = (char *) tr - (char *) pe_target + - target_section_addr; + new_offset = sym_addr - tr_addr - 12; + + /* There is no immediate version of bx, only register one... */ + tr[0] = grub_host_to_target32 (0xe59fc004); /* ldr ip, [pc, #4] */ + tr[1] = grub_host_to_target32 (0xe08cc00f); /* add ip, ip, pc */ + tr[2] = grub_host_to_target32 (0xe12fff1c); /* bx ip */ + tr[3] = grub_host_to_target32 (new_offset | 1); + tr += 4; + sym_addr = tr_addr; + } + sym_addr -= offset; + err = grub_arm_reloc_jump24 (target, + sym_addr); + if (err) + grub_util_error ("%s", grub_errmsg); + } + break; + + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + } +#endif /* MKIMAGE_ELF32 */ + case EM_RISCV: + { + grub_uint64_t *t64 = (grub_uint64_t *) target; + grub_uint32_t *t32 = (grub_uint32_t *) target; + grub_uint16_t *t16 = (grub_uint16_t *) target; + grub_uint8_t *t8 = (grub_uint8_t *) target; + grub_int64_t off; + + /* + * Instructions and instruction encoding are documented in the RISC-V + * specification. This file is based on version 2.2: + * + * https://github.com/riscv/riscv-isa-manual/blob/master/release/riscv-spec-v2.2.pdf + */ + + sym_addr += addend; + off = sym_addr - target_section_addr - offset - image_target->vaddr_offset; + + switch (ELF_R_TYPE (info)) + { + case R_RISCV_ADD8: + *t8 = *t8 + sym_addr; + break; + case R_RISCV_ADD16: + *t16 = grub_host_to_target16 (grub_target_to_host16 (*t16) + sym_addr); + break; + case R_RISCV_32: + case R_RISCV_ADD32: + *t32 = grub_host_to_target32 (grub_target_to_host32 (*t32) + sym_addr); + break; + case R_RISCV_64: + case R_RISCV_ADD64: + *t64 = grub_host_to_target64 (grub_target_to_host64 (*t64) + sym_addr); + break; + + case R_RISCV_SUB8: + *t8 = sym_addr - *t8; + break; + case R_RISCV_SUB16: + *t16 = grub_host_to_target16 (grub_target_to_host16 (*t16) - sym_addr); + break; + case R_RISCV_SUB32: + *t32 = grub_host_to_target32 (grub_target_to_host32 (*t32) - sym_addr); + break; + case R_RISCV_SUB64: + *t64 = grub_host_to_target64 (grub_target_to_host64 (*t64) - sym_addr); + break; + case R_RISCV_BRANCH: + { + grub_uint32_t imm12 = (off & 0x1000) << (31 - 12); + grub_uint32_t imm11 = (off & 0x800) >> (11 - 7); + grub_uint32_t imm10_5 = (off & 0x7e0) << (30 - 10); + grub_uint32_t imm4_1 = (off & 0x1e) << (11 - 4); + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0x1fff07f) + | imm12 | imm11 | imm10_5 | imm4_1); + } + break; + case R_RISCV_JAL: + { + grub_uint32_t imm20 = (off & 0x100000) << (31 - 20); + grub_uint32_t imm19_12 = (off & 0xff000); + grub_uint32_t imm11 = (off & 0x800) << (20 - 11); + grub_uint32_t imm10_1 = (off & 0x7fe) << (30 - 10); + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfff) + | imm20 | imm19_12 | imm11 | imm10_1); + } + break; + case R_RISCV_CALL: + { + grub_uint32_t hi20, lo12; + + if (off != (grub_int32_t)off) + grub_util_error ("target %lx not reachable from pc=%lx", (long)sym_addr, (long)((char *)target - (char *)e)); + + hi20 = (off + 0x800) & 0xfffff000; + lo12 = (off - hi20) & 0xfff; + t32[0] = grub_host_to_target32 ((grub_target_to_host32 (t32[0]) & 0xfff) | hi20); + t32[1] = grub_host_to_target32 ((grub_target_to_host32 (t32[1]) & 0xfffff) | (lo12 << 20)); + } + break; + case R_RISCV_RVC_BRANCH: + { + grub_uint16_t imm8 = (off & 0x100) << (12 - 8); + grub_uint16_t imm7_6 = (off & 0xc0) >> (6 - 5); + grub_uint16_t imm5 = (off & 0x20) >> (5 - 2); + grub_uint16_t imm4_3 = (off & 0x18) << (12 - 5); + grub_uint16_t imm2_1 = (off & 0x6) << (12 - 10); + *t16 = grub_host_to_target16 ((grub_target_to_host16 (*t16) & 0xe383) + | imm8 | imm7_6 | imm5 | imm4_3 | imm2_1); + } + break; + case R_RISCV_RVC_JUMP: + { + grub_uint16_t imm11 = (off & 0x800) << (12 - 11); + grub_uint16_t imm10 = (off & 0x400) >> (10 - 8); + grub_uint16_t imm9_8 = (off & 0x300) << (12 - 11); + grub_uint16_t imm7 = (off & 0x80) >> (7 - 6); + grub_uint16_t imm6 = (off & 0x40) << (12 - 11); + grub_uint16_t imm5 = (off & 0x20) >> (5 - 2); + grub_uint16_t imm4 = (off & 0x10) << (12 - 5); + grub_uint16_t imm3_1 = (off & 0xe) << (12 - 10); + *t16 = grub_host_to_target16 ((grub_target_to_host16 (*t16) & 0xe003) + | imm11 | imm10 | imm9_8 | imm7 | imm6 + | imm5 | imm4 | imm3_1); + } + break; + case R_RISCV_PCREL_HI20: + { + grub_int32_t hi20; + + if (off != (grub_int32_t)off) + grub_util_error ("target %lx not reachable from pc=%lx", (long)sym_addr, (long)((char *)target - (char *)e)); + + hi20 = (off + 0x800) & 0xfffff000; + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfff) | hi20); + } + break; + case R_RISCV_PCREL_LO12_I: + case R_RISCV_PCREL_LO12_S: + { + Elf_Rela *rel2; + Elf_Word k; + /* Search backwards for matching HI20 reloc. */ + for (k = j, rel2 = (Elf_Rela *) ((char *) r - r_size); + k > 0; + k--, rel2 = (Elf_Rela *) ((char *) rel2 - r_size)) + { + Elf_Addr rel2_info; + Elf_Addr rel2_offset; + Elf_Addr rel2_sym_addr; + Elf_Addr rel2_addend; + Elf_Addr rel2_loc; + grub_int64_t rel2_off; + + rel2_offset = grub_target_to_host (rel2->r_offset); + rel2_info = grub_target_to_host (rel2->r_info); + rel2_loc = target_section_addr + rel2_offset + image_target->vaddr_offset; + + if (ELF_R_TYPE (rel2_info) == R_RISCV_PCREL_HI20 + && rel2_loc == sym_addr) + { + rel2_sym_addr = SUFFIX (get_symbol_address) + (e, smd->symtab, ELF_R_SYM (rel2_info), + image_target); + rel2_addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? + grub_target_to_host (rel2->r_addend) : 0; + rel2_off = rel2_sym_addr + rel2_addend - rel2_loc; + off = rel2_off - ((rel2_off + 0x800) & 0xfffff000); + + if (ELF_R_TYPE (info) == R_RISCV_PCREL_LO12_I) + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfffff) | (off & 0xfff) << 20); + else + { + grub_uint32_t imm11_5 = (off & 0xfe0) << (31 - 11); + grub_uint32_t imm4_0 = (off & 0x1f) << (11 - 4); + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0x1fff07f) | imm11_5 | imm4_0); + } + break; + } + } + if (k == 0) + grub_util_error ("cannot find matching HI20 relocation"); + } + break; + case R_RISCV_HI20: + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfff) | (((grub_int32_t) sym_addr + 0x800) & 0xfffff000)); + break; + case R_RISCV_LO12_I: + { + grub_int32_t lo12 = (grub_int32_t) sym_addr - (((grub_int32_t) sym_addr + 0x800) & 0xfffff000); + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfffff) | ((lo12 & 0xfff) << 20)); + } + break; + case R_RISCV_LO12_S: + { + grub_int32_t lo12 = (grub_int32_t) sym_addr - (((grub_int32_t) sym_addr + 0x800) & 0xfffff000); + grub_uint32_t imm11_5 = (lo12 & 0xfe0) << (31 - 11); + grub_uint32_t imm4_0 = (lo12 & 0x1f) << (11 - 4); + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0x1fff07f) | imm11_5 | imm4_0); + } + break; + case R_RISCV_RELAX: + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + } + default: + grub_util_error ("unknown architecture type %d", + image_target->elf_target); + } + } + } +} + +/* Add a PE32's fixup entry for a relocation. Return the resulting address + after having written to the file OUT. */ +static Elf_Addr +add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type, + Elf_Addr addr, int flush, Elf_Addr current_address, + const struct grub_install_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 cur_index; + + next_address = current_address + b->block_size; + padding_size = ((ALIGN_UP (next_address, image_target->section_align) + - next_address) + >> 1); + cur_index = ((b->block_size - sizeof (*b)) >> 1); + grub_util_info ("adding %d padding fixup entries", padding_size); + while (padding_size--) + { + b->entries[cur_index++] = 0; + b->block_size += 2; + } + } + else while (b->block_size & (8 - 1)) + { + /* If not aligned with a 32-bit boundary, add + a padding entry. */ + size_t cur_index; + + grub_util_info ("adding a padding fixup entry"); + cur_index = ((b->block_size - sizeof (*b)) >> 1); + b->entries[cur_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 cur_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. */ + cur_index = ((b->block_size - sizeof (*b)) >> 1); + entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva); + b->entries[cur_index] = grub_host_to_target16 (entry); + b->block_size += 2; + } + + return current_address; +} + +struct raw_reloc +{ + struct raw_reloc *next; + grub_uint32_t offset; + enum raw_reloc_type { + RAW_RELOC_NONE = -1, + RAW_RELOC_32 = 0, + RAW_RELOC_MAX = 1, + } type; +}; + +struct translate_context +{ + /* PE */ + struct fixup_block_list *lst, *lst0; + Elf_Addr current_address; + + /* Raw */ + struct raw_reloc *raw_relocs; +}; + +static void +translate_reloc_start (struct translate_context *ctx, + const struct grub_install_image_target_desc *image_target) +{ + grub_memset (ctx, 0, sizeof (*ctx)); + if (image_target->id == IMAGE_EFI) + { + ctx->lst = ctx->lst0 = xmalloc (sizeof (*ctx->lst) + 2 * 0x1000); + memset (ctx->lst, 0, sizeof (*ctx->lst) + 2 * 0x1000); + ctx->current_address = 0; + } +} + +static void +translate_relocation_pe (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, + const struct grub_install_image_target_desc *image_target) +{ + /* Necessary to relocate only absolute addresses. */ + switch (image_target->elf_target) + { + case EM_386: + if (ELF_R_TYPE (info) == R_386_32) + { + grub_util_info ("adding a relocation entry for 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) addr); + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, ctx->current_address, + image_target); + } + break; + case EM_X86_64: + 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) + { + grub_util_info ("adding a relocation entry for 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) addr); + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, + 0, ctx->current_address, + image_target); + } + break; + case EM_IA_64: + switch (ELF_R_TYPE (info)) + { + case R_IA64_PCREL64LSB: + case R_IA64_LDXMOV: + case R_IA64_PCREL21B: + case R_IA64_LTOFF_FPTR22: + case R_IA64_LTOFF22X: + case R_IA64_LTOFF22: + case R_IA64_GPREL22: + case R_IA64_GPREL64I: + case R_IA64_SEGREL64LSB: + break; + + case R_IA64_FPTR64LSB: + case R_IA64_DIR64LSB: +#if 1 + { + grub_util_info ("adding a relocation entry for 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) addr); + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, + 0, ctx->current_address, + image_target); + } +#endif + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + case EM_AARCH64: + switch (ELF_R_TYPE (info)) + { + case R_AARCH64_ABS64: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, 0, ctx->current_address, + image_target); + } + break; + /* Relative relocations do not require fixup entries. */ + case R_AARCH64_CALL26: + case R_AARCH64_JUMP26: + case R_AARCH64_PREL32: + break; + /* Page-relative relocations do not require fixup entries. */ + case R_AARCH64_ADR_PREL_PG_HI21: + /* We page-align the whole kernel, so no need + for fixup entries. + */ + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_LDST64_ABS_LO12_NC: + break; + + /* GOT is relocated separately. */ + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_LD64_GOT_LO12_NC: + break; + + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + break; +#if defined(MKIMAGE_ELF32) + case EM_ARM: + switch (ELF_R_TYPE (info)) + { + case R_ARM_V4BX: + /* Relative relocations do not require fixup entries. */ + case R_ARM_JUMP24: + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + case R_ARM_CALL: + { + grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) ctx->current_address); + } + break; + /* Create fixup entry for PE/COFF loader */ + case R_ARM_ABS32: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, ctx->current_address, + image_target); + } + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; +#endif /* defined(MKIMAGE_ELF32) */ + case EM_RISCV: + switch (ELF_R_TYPE (info)) + { + case R_RISCV_32: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, ctx->current_address, + image_target); + } + break; + case R_RISCV_64: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, 0, ctx->current_address, + image_target); + } + break; + /* Relative relocations do not require fixup entries. */ + case R_RISCV_BRANCH: + case R_RISCV_JAL: + case R_RISCV_CALL: + case R_RISCV_PCREL_HI20: + case R_RISCV_PCREL_LO12_I: + case R_RISCV_PCREL_LO12_S: + case R_RISCV_RVC_BRANCH: + case R_RISCV_RVC_JUMP: + case R_RISCV_ADD32: + case R_RISCV_SUB32: + grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) ctx->current_address); + break; + case R_RISCV_HI20: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_RISCV_HI20, + addr, 0, ctx->current_address, + image_target); + } + break; + case R_RISCV_LO12_I: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_RISCV_LOW12I, + addr, 0, ctx->current_address, + image_target); + } + break; + case R_RISCV_LO12_S: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_RISCV_LOW12S, + addr, 0, ctx->current_address, + image_target); + } + break; + case R_RISCV_RELAX: + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + default: + grub_util_error ("unknown machine type 0x%x", image_target->elf_target); + } +} + +static enum raw_reloc_type +classify_raw_reloc (Elf_Addr info, + const struct grub_install_image_target_desc *image_target) +{ + /* Necessary to relocate only absolute addresses. */ + switch (image_target->elf_target) + { + case EM_ARM: + switch (ELF_R_TYPE (info)) + { + case R_ARM_V4BX: + case R_ARM_JUMP24: + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + case R_ARM_CALL: + return RAW_RELOC_NONE; + case R_ARM_ABS32: + return RAW_RELOC_32; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + default: + grub_util_error ("unknown machine type 0x%x", image_target->elf_target); + } +} + +static void +translate_relocation_raw (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, + const struct grub_install_image_target_desc *image_target) +{ + enum raw_reloc_type class = classify_raw_reloc (info, image_target); + struct raw_reloc *rel; + if (class == RAW_RELOC_NONE) + return; + rel = xmalloc (sizeof (*rel)); + rel->next = ctx->raw_relocs; + rel->type = class; + rel->offset = addr; + ctx->raw_relocs = rel; +} + +static void +translate_relocation (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, + const struct grub_install_image_target_desc *image_target) +{ + if (image_target->id == IMAGE_EFI) + translate_relocation_pe (ctx, addr, info, image_target); + else + translate_relocation_raw (ctx, addr, info, image_target); +} + +static void +finish_reloc_translation_pe (struct translate_context *ctx, struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ + ctx->current_address = add_fixup_entry (&ctx->lst, 0, 0, 1, ctx->current_address, image_target); + + { + grub_uint8_t *ptr; + layout->reloc_section = ptr = xmalloc (ctx->current_address); + for (ctx->lst = ctx->lst0; ctx->lst; ctx->lst = ctx->lst->next) + if (ctx->lst->state) + { + memcpy (ptr, &ctx->lst->b, grub_target_to_host32 (ctx->lst->b.block_size)); + ptr += grub_target_to_host32 (ctx->lst->b.block_size); + } + assert ((ctx->current_address + (grub_uint8_t *) layout->reloc_section) == ptr); + } + + for (ctx->lst = ctx->lst0; ctx->lst; ) + { + struct fixup_block_list *next; + next = ctx->lst->next; + free (ctx->lst); + ctx->lst = next; + } + + layout->reloc_size = ctx->current_address; + if (image_target->elf_target == EM_ARM && layout->reloc_size > GRUB_KERNEL_ARM_STACK_SIZE) + grub_util_error ("Reloc section (%d) is bigger than stack size (%d). " + "This breaks assembly assumptions. Please increase stack size", + (int) layout->reloc_size, + (int) GRUB_KERNEL_ARM_STACK_SIZE); +} + +/* + Layout: + <type 0 relocations> + <fffffffe> + <type 1 relocations> + <fffffffe> + ... + <type n relocations> + <ffffffff> + each relocation starts with 32-bit offset. Rest depends on relocation. + mkimage stops when it sees first unknown type or end marker. + This allows images to be created with mismatched mkimage and + kernel as long as no relocations are present in kernel that mkimage + isn't aware of (in which case mkimage aborts). + This also allows simple assembly to do the relocs. +*/ + +#define RAW_SEPARATOR 0xfffffffe +#define RAW_END_MARKER 0xffffffff + +static void +finish_reloc_translation_raw (struct translate_context *ctx, struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ + size_t count = 0, sz; + enum raw_reloc_type highest = RAW_RELOC_NONE; + enum raw_reloc_type curtype; + struct raw_reloc *cur; + grub_uint32_t *p; + if (!ctx->raw_relocs) + { + layout->reloc_section = p = xmalloc (sizeof (grub_uint32_t)); + p[0] = RAW_END_MARKER; + layout->reloc_size = sizeof (grub_uint32_t); + return; + } + for (cur = ctx->raw_relocs; cur; cur = cur->next) + { + count++; + if (cur->type > highest) + highest = cur->type; + } + /* highest separators, count relocations and one end marker. */ + sz = (highest + count + 1) * sizeof (grub_uint32_t); + layout->reloc_section = p = xmalloc (sz); + for (curtype = 0; curtype <= highest; curtype++) + { + /* Support for special cases would go here. */ + for (cur = ctx->raw_relocs; cur; cur = cur->next) + if (cur->type == curtype) + { + *p++ = cur->offset; + } + *p++ = RAW_SEPARATOR; + } + *--p = RAW_END_MARKER; + layout->reloc_size = sz; +} + +static void +finish_reloc_translation (struct translate_context *ctx, struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ + if (image_target->id == IMAGE_EFI) + finish_reloc_translation_pe (ctx, layout, image_target); + else + finish_reloc_translation_raw (ctx, layout, image_target); +} + + +static void +create_u64_fixups (struct translate_context *ctx, + Elf_Addr jumpers, grub_size_t njumpers, + const struct grub_install_image_target_desc *image_target) +{ + unsigned i; + assert (image_target->id == IMAGE_EFI); + for (i = 0; i < njumpers; i++) + ctx->current_address = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + jumpers + 8 * i, + 0, ctx->current_address, + image_target); +} + +/* Make a .reloc section. */ +static void +make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, + struct section_metadata *smd, + const struct grub_install_image_target_desc *image_target) +{ + unsigned i; + Elf_Shdr *s; + struct translate_context ctx; + + translate_reloc_start (&ctx, image_target); + + for (i = 0, s = smd->sections; i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + if ((grub_target_to_host32 (s->sh_type) == SHT_REL) || + (grub_target_to_host32 (s->sh_type) == SHT_RELA)) + { + Elf_Rel *r; + Elf_Word rtab_size, r_size, num_rs; + Elf_Off rtab_offset; + Elf_Addr section_address; + Elf_Word j; + + if (!SUFFIX (is_kept_reloc_section) (s, image_target, smd)) + { + grub_util_info ("not translating the skipped relocation section %s", + smd->strtab + grub_le_to_cpu32 (s->sh_name)); + continue; + } + + grub_util_info ("translating the relocation section %s", + smd->strtab + grub_le_to_cpu32 (s->sh_name)); + + rtab_size = grub_target_to_host (s->sh_size); + r_size = grub_target_to_host (s->sh_entsize); + rtab_offset = grub_target_to_host (s->sh_offset); + num_rs = rtab_size / r_size; + + section_address = smd->vaddrs[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; + Elf_Addr addr; + + offset = grub_target_to_host (r->r_offset); + info = grub_target_to_host (r->r_info); + + addr = section_address + offset; + + translate_relocation (&ctx, addr, info, image_target); + } + } + + if (image_target->elf_target == EM_IA_64) + create_u64_fixups (&ctx, + layout->ia64jmp_off + + image_target->vaddr_offset, + 2 * layout->ia64jmpnum, + image_target); + if (image_target->elf_target == EM_IA_64 || image_target->elf_target == EM_AARCH64) + create_u64_fixups (&ctx, + layout->got_off + + image_target->vaddr_offset, + (layout->got_size / 8), + image_target); + + finish_reloc_translation (&ctx, layout, image_target); +} + +/* 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, const struct grub_install_image_target_desc *image_target) +{ + if (!is_relocatable (image_target) + && 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. */ +static int +SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) +{ + if (!is_relocatable (image_target) + && 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) && !(grub_target_to_host32 (s->sh_type) == SHT_NOBITS); +} + +static int +SUFFIX (is_bss_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) +{ + if (!is_relocatable (image_target)) + return 0; + return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) + == SHF_ALLOC) && (grub_target_to_host32 (s->sh_type) == SHT_NOBITS); +} + +/* Determine if a section is going to be in the final output */ +static int +SUFFIX (is_kept_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) +{ + /* We keep .text and .data */ + if (SUFFIX (is_text_section) (s, image_target) + || SUFFIX (is_data_section) (s, image_target)) + return 1; + + /* + * And we keep .bss if we're producing PE binaries or the target doesn't + * have a relocating loader. Platforms other than EFI and U-boot shouldn't + * have .bss in their binaries as we build with -Wl,-Ttext. + */ + if (SUFFIX (is_bss_section) (s, image_target) + && (image_target->id == IMAGE_EFI || !is_relocatable (image_target))) + return 1; + + /* Otherwise this is not a section we're keeping in the final output. */ + return 0; +} + +static int +SUFFIX (is_kept_reloc_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target, + struct section_metadata *smd) +{ + int i; + int r = 0; + const char *name = smd->strtab + grub_host_to_target32 (s->sh_name); + + if (!strncmp (name, ".rela.", 6)) + name += 5; + else if (!strncmp (name, ".rel.", 5)) + name += 4; + else + return 1; + + for (i = 0, s = smd->sections; i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + { + const char *sname = smd->strtab + grub_host_to_target32 (s->sh_name); + if (strcmp (sname, name)) + continue; + + return SUFFIX (is_kept_section) (s, image_target); + } + + return r; +} + +/* Return if the ELF header is valid. */ +static int +SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_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; +} + +static Elf_Addr +SUFFIX (put_section) (Elf_Shdr *s, int i, + Elf_Addr current_address, + struct section_metadata *smd, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Word align = grub_host_to_target_addr (s->sh_addralign); + const char *name = smd->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%" + GRUB_HOST_PRIxLONG_LONG, + name, (unsigned long long) current_address); + if (!is_relocatable (image_target)) + current_address = grub_host_to_target_addr (s->sh_addr) + - image_target->link_addr; + smd->addrs[i] = current_address; + current_address += grub_host_to_target_addr (s->sh_size); + return current_address; +} + +/* + * Locate section addresses by merging code sections and data sections + * into .text and .data, respectively. + */ +static void +SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path, + struct section_metadata *smd, + struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ + int i; + Elf_Shdr *s; + + layout->align = 1; + /* Page-aligning simplifies relocation handling. */ + if (image_target->elf_target == EM_AARCH64) + layout->align = 4096; + + layout->kernel_size = 0; + + for (i = 0, s = smd->sections; + i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC) + && grub_host_to_target32 (s->sh_addralign) > layout->align) + layout->align = grub_host_to_target32 (s->sh_addralign); + + /* .text */ + for (i = 0, s = smd->sections; + i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + if (SUFFIX (is_text_section) (s, image_target)) + { + layout->kernel_size = SUFFIX (put_section) (s, i, layout->kernel_size, + smd, image_target); + if (!is_relocatable (image_target) && + grub_host_to_target_addr (s->sh_addr) != image_target->link_addr) + { + char *msg + = grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx" + " instead of 0x%llx: ld.gold bug?"), + kernel_path, + (unsigned long long) grub_host_to_target_addr (s->sh_addr), + (unsigned long long) image_target->link_addr); + grub_util_error ("%s", msg); + } + } + +#ifdef MKIMAGE_ELF32 + if (image_target->elf_target == EM_ARM) + { + grub_size_t tramp; + + layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); + + tramp = arm_get_trampoline_size (e, smd->sections, smd->section_entsize, + smd->num_sections, image_target); + + layout->tramp_off = layout->kernel_size; + layout->kernel_size += ALIGN_UP (tramp, 16); + } +#endif + + layout->kernel_size = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset, + image_target->section_align) + - image_target->vaddr_offset; + layout->exec_size = layout->kernel_size; + + /* .data */ + for (i = 0, s = smd->sections; + i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + if (SUFFIX (is_data_section) (s, image_target)) + layout->kernel_size = SUFFIX (put_section) (s, i, layout->kernel_size, smd, + image_target); + + layout->bss_start = layout->kernel_size; + layout->end = layout->kernel_size; + + /* .bss */ + for (i = 0, s = smd->sections; + i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + { + if (SUFFIX (is_bss_section) (s, image_target)) + layout->end = SUFFIX (put_section) (s, i, layout->end, smd, image_target); + + /* + * This must to be in the last time this function passes through the loop. + */ + smd->vaddrs[i] = smd->addrs[i] + image_target->vaddr_offset; + } + + layout->end = ALIGN_UP (layout->end + image_target->vaddr_offset, + image_target->section_align) - image_target->vaddr_offset; + /* Explicitly initialize BSS + when producing PE32 to avoid a bug in EFI implementations. + Platforms other than EFI and U-boot shouldn't have .bss in + their binaries as we build with -Wl,-Ttext. + */ + if (image_target->id == IMAGE_EFI || !is_relocatable (image_target)) + layout->kernel_size = layout->end; +} + +char * +SUFFIX (grub_mkimage_load_image) (const char *kernel_path, + size_t total_module_size, + struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ + char *kernel_img, *out_img; + struct section_metadata smd = { 0, 0, 0, 0, 0, 0, 0 }; + Elf_Ehdr *e; + int i; + Elf_Shdr *s; + Elf_Off section_offset; + grub_size_t kernel_size; + + grub_memset (layout, 0, sizeof (*layout)); + + layout->start_address = 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); + smd.section_entsize = grub_target_to_host16 (e->e_shentsize); + smd.num_sections = grub_target_to_host16 (e->e_shnum); + + if (kernel_size < section_offset + + (grub_uint32_t) smd.section_entsize * smd.num_sections) + grub_util_error (_("premature end of file %s"), kernel_path); + + smd.sections = (Elf_Shdr *) (kernel_img + section_offset); + + /* Relocate sections then symbols in the virtual address space. */ + s = (Elf_Shdr *) ((char *) smd.sections + + grub_host_to_target16 (e->e_shstrndx) * smd.section_entsize); + smd.strtab = (char *) e + grub_host_to_target_addr (s->sh_offset); + + smd.addrs = xcalloc (smd.num_sections, sizeof (*smd.addrs)); + smd.vaddrs = xcalloc (smd.num_sections, sizeof (*smd.vaddrs)); + + SUFFIX (locate_sections) (e, kernel_path, &smd, layout, image_target); + + if (!is_relocatable (image_target)) + { + Elf_Addr current_address = layout->kernel_size; + + for (i = 0, s = smd.sections; + i < smd.num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize)) + if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) + { + Elf_Word sec_align = grub_host_to_target_addr (s->sh_addralign); + const char *name = smd.strtab + grub_host_to_target32 (s->sh_name); + + if (sec_align) + current_address = ALIGN_UP (current_address + + image_target->vaddr_offset, + sec_align) + - image_target->vaddr_offset; + + grub_util_info ("locating the section %s at 0x%" + GRUB_HOST_PRIxLONG_LONG, + name, (unsigned long long) current_address); + if (!is_relocatable (image_target)) + current_address = grub_host_to_target_addr (s->sh_addr) + - image_target->link_addr; + + smd.vaddrs[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; + layout->bss_size = current_address - layout->kernel_size; + } + else + layout->bss_size = 0; + + if (image_target->id == IMAGE_SPARC64_AOUT + || image_target->id == IMAGE_SPARC64_RAW + || image_target->id == IMAGE_UBOOT + || image_target->id == IMAGE_COREBOOT + || image_target->id == IMAGE_SPARC64_CDCORE) + layout->kernel_size = ALIGN_UP (layout->kernel_size, image_target->mod_align); + + if (is_relocatable (image_target)) + { + smd.symtab = NULL; + for (i = 0, s = smd.sections; + i < smd.num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize)) + if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB)) + { + smd.symtab = s; + break; + } + if (! smd.symtab) + grub_util_error ("%s", _("no symbol table")); +#ifdef MKIMAGE_ELF64 + if (image_target->elf_target == EM_IA_64) + { + grub_size_t tramp; + + layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); + + grub_ia64_dl_get_tramp_got_size (e, &tramp, &layout->got_size); + + layout->tramp_off = layout->kernel_size; + layout->kernel_size += ALIGN_UP (tramp, 16); + + layout->ia64jmp_off = layout->kernel_size; + layout->ia64jmpnum = SUFFIX (count_funcs) (e, smd.symtab, + image_target); + layout->kernel_size += 16 * layout->ia64jmpnum; + + layout->got_off = layout->kernel_size; + layout->kernel_size += ALIGN_UP (layout->got_size, 16); + } + if (image_target->elf_target == EM_AARCH64) + { + grub_size_t tramp; + + layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); + + grub_arm64_dl_get_tramp_got_size (e, &tramp, &layout->got_size); + + layout->got_off = layout->kernel_size; + layout->kernel_size += ALIGN_UP (layout->got_size, 16); + } +#endif + + if (image_target->id == IMAGE_EFI) + layout->kernel_size = ALIGN_UP (layout->kernel_size, + GRUB_PE32_FILE_ALIGNMENT); + } + else + { + layout->reloc_size = 0; + layout->reloc_section = NULL; + } + + out_img = xmalloc (layout->kernel_size + total_module_size); + memset (out_img, 0, layout->kernel_size + total_module_size); + + if (is_relocatable (image_target)) + { + layout->start_address = SUFFIX (relocate_symbols) (e, &smd, + (char *) out_img + layout->ia64jmp_off, + layout->ia64jmp_off + image_target->vaddr_offset, + layout->bss_start, layout->end, image_target); + + if (layout->start_address == (Elf_Addr) -1) + grub_util_error ("start symbol is not defined"); + + /* Resolve addrs in the virtual address space. */ + SUFFIX (relocate_addrs) (e, &smd, out_img, layout->tramp_off, + layout->got_off, image_target); + + make_reloc_section (e, layout, &smd, image_target); + if (image_target->id != IMAGE_EFI) + { + out_img = xrealloc (out_img, layout->kernel_size + total_module_size + + ALIGN_UP (layout->reloc_size, image_target->mod_align)); + memcpy (out_img + layout->kernel_size, layout->reloc_section, layout->reloc_size); + memset (out_img + layout->kernel_size + layout->reloc_size, 0, + total_module_size + ALIGN_UP (layout->reloc_size, image_target->mod_align) - layout->reloc_size); + layout->kernel_size += ALIGN_UP (layout->reloc_size, image_target->mod_align); + } + } + + for (i = 0, s = smd.sections; + i < smd.num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize)) + if (SUFFIX (is_kept_section) (s, image_target)) + { + if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) + memset (out_img + smd.addrs[i], 0, + grub_host_to_target_addr (s->sh_size)); + else + memcpy (out_img + smd.addrs[i], + kernel_img + grub_host_to_target_addr (s->sh_offset), + grub_host_to_target_addr (s->sh_size)); + } + free (kernel_img); + + free (smd.vaddrs); + smd.vaddrs = NULL; + free (smd.addrs); + smd.addrs = NULL; + + return out_img; +} diff --git a/util/grub-mklayout.c b/util/grub-mklayout.c new file mode 100644 index 0000000..d171c27 --- /dev/null +++ b/util/grub-mklayout.c @@ -0,0 +1,529 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <grub/util/misc.h> +#include <grub/i18n.h> +#include <grub/term.h> +#include <grub/keyboard_layouts.h> + +#define _GNU_SOURCE 1 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <unistd.h> +#include <errno.h> + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" + +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include "progname.h" + +struct arguments +{ + char *input; + char *output; + int verbosity; +}; + +static struct argp_option options[] = { + {"input", 'i', N_("FILE"), 0, + N_("set input filename. Default is STDIN"), 0}, + {"output", 'o', N_("FILE"), 0, + N_("set output filename. Default is STDOUT"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + { 0, 0, 0, 0, 0, 0 } +}; + +struct console_grub_equivalence +{ + const 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, GRUB_KEYBOARD_KEY_JP_RO, + /* 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, + /* 0x70 */ 0, 0, + /* 0x72 */ 0, GRUB_KEYBOARD_KEY_JP_RO, + /* 0x74 */ 0, 0, + /* 0x76 */ 0, 0, + /* 0x78 */ 0, GRUB_KEYBOARD_KEY_KPCOMMA, + /* 0x7a */ 0, 0, + /* 0x7c */ GRUB_KEYBOARD_KEY_JP_YEN, +}; + +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; + + /* TRANSLATORS: scan identifier is keyboard key symbolic name. */ + fprintf (stderr, _("Unknown keyboard scan identifier %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, const char *fname, struct grub_keyboard_layout *layout) +{ + grub_uint32_t version; + unsigned i; + + version = grub_cpu_to_le32_compile_time (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]); + + if (fwrite (GRUB_KEYBOARD_LAYOUTS_FILEMAGIC, 1, + GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE, out) + != GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE + || fwrite (&version, sizeof (version), 1, out) != 1 + || fwrite (layout, 1, sizeof (*layout), out) != sizeof (*layout)) + { + if (fname) + grub_util_error ("cannot write to `%s': %s", fname, strerror (errno)); + else + grub_util_error ("cannot write to the stdout: %s", strerror (errno)); + } +} + +static void +write_keymaps (FILE *in, FILE *out, const char *out_filename) +{ + 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); + + if (keycode_linux >= ARRAY_SIZE (linux_to_usb_map)) + { + /* TRANSLATORS: scan code is keyboard key numeric identifier. */ + fprintf (stderr, _("Unknown keyboard scan code 0x%02x\n"), keycode_linux); + continue; + } + + /* 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) + { + /* TRANSLATORS: scan code is keyboard key numeric identifier. */ + fprintf (stderr, _("Unknown keyboard scan code 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) + { + /* TRANSLATORS: this error is triggered when input doesn't contain any + key descriptions. */ + fprintf (stderr, "%s", _("ERROR: no valid keyboard layout found. Check the input.\n")); + exit (1); + } + + add_special_keys (&layout); + + write_file (out, out_filename, &layout); +} + +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; + + switch (key) + { + case 'i': + arguments->input = xstrdup (arg); + break; + + case 'o': + arguments->output = xstrdup (arg); + break; + + case 'v': + arguments->verbosity++; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +static struct argp argp = { + options, argp_parser, N_("[OPTIONS]"), + /* TRANSLATORS: "one" is a shortcut for "keyboard layout". */ + N_("Generate GRUB keyboard layout from Linux console one."), + NULL, NULL, NULL +}; + +int +main (int argc, char *argv[]) +{ + FILE *in, *out; + struct arguments arguments; + + grub_util_host_init (&argc, &argv); + + /* Check for options. */ + memset (&arguments, 0, sizeof (struct arguments)); + if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + if (arguments.input) + in = grub_util_fopen (arguments.input, "r"); + else + in = stdin; + + if (!in) + grub_util_error (_("cannot open `%s': %s"), arguments.input ? : "stdin", + strerror (errno)); + + if (arguments.output) + out = grub_util_fopen (arguments.output, "wb"); + else + out = stdout; + + if (!out) + { + if (in != stdin) + fclose (in); + grub_util_error (_("cannot open `%s': %s"), arguments.output ? : "stdout", + strerror (errno)); + } + + write_keymaps (in, out, arguments.output); + + if (in != stdin) + fclose (in); + + if (out != stdout) + fclose (out); + + return 0; +} diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c new file mode 100644 index 0000000..a2461cd --- /dev/null +++ b/util/grub-mknetdir.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <config.h> + +#include <grub/util/install.h> +#include <grub/emu/config.h> +#include <grub/util/misc.h> + +#include <string.h> +#include <errno.h> + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +static char *rootdir = NULL, *subdir = NULL; +static char *debug_image = NULL; + +enum + { + OPTION_NET_DIRECTORY = 0x301, + OPTION_SUBDIR, + OPTION_DEBUG, + OPTION_DEBUG_IMAGE + }; + +static struct argp_option options[] = { + GRUB_INSTALL_OPTIONS, + {"net-directory", OPTION_NET_DIRECTORY, N_("DIR"), + 0, N_("root directory of TFTP server"), 2}, + {"subdir", OPTION_SUBDIR, N_("DIR"), + 0, N_("relative subdirectory on network server"), 2}, + {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2}, + {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2}, + {0, 0, 0, 0, 0, 0} +}; + +static error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + if (grub_install_parse (key, arg)) + return 0; + switch (key) + { + case OPTION_NET_DIRECTORY: + free (rootdir); + rootdir = xstrdup (arg); + return 0; + case OPTION_SUBDIR: + free (subdir); + subdir = xstrdup (arg); + return 0; + /* This is an undocumented feature... */ + case OPTION_DEBUG: + verbosity++; + return 0; + case OPTION_DEBUG_IMAGE: + free (debug_image); + debug_image = xstrdup (arg); + return 0; + + case ARGP_KEY_ARG: + default: + return ARGP_ERR_UNKNOWN; + } +} + + +struct argp argp = { + options, argp_parser, NULL, + "\v"N_("Prepares GRUB network boot images at net_directory/subdir " + "assuming net_directory being TFTP root."), + NULL, grub_install_help_filter, NULL +}; + +static char *base; + +static const struct +{ + const char *mkimage_target; + const char *netmodule; + const char *ext; +} targets[GRUB_INSTALL_PLATFORM_MAX] = + { + [GRUB_INSTALL_PLATFORM_I386_PC] = { "i386-pc-pxe", "pxe", ".0" }, + [GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275] = { "sparc64-ieee1275-aout", "ofnet", ".img" }, + [GRUB_INSTALL_PLATFORM_I386_IEEE1275] = { "i386-ieee1275", "ofnet", ".elf" }, + [GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275] = { "powerpc-ieee1275", "ofnet", ".elf" }, + [GRUB_INSTALL_PLATFORM_I386_EFI] = { "i386-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_X86_64_EFI] = { "x86_64-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_IA64_EFI] = { "ia64-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_ARM_EFI] = { "arm-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_RISCV32_EFI] = { "riscv32-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_RISCV64_EFI] = { "riscv64-efi", "efinet", ".efi" }, + }; + +static void +process_input_dir (const char *input_dir, enum grub_install_plat platform) +{ + char *platsub = grub_install_get_platform_name (platform); + char *grubdir = grub_util_path_concat (3, rootdir, subdir, platsub); + char *load_cfg = grub_util_path_concat (2, grubdir, "load.cfg"); + char *prefix; + char *output; + char *grub_cfg; + FILE *cfg; + + grub_install_copy_files (input_dir, base, platform); + grub_util_unlink (load_cfg); + + if (debug_image) + { + FILE *f = grub_util_fopen (load_cfg, "wb"); + if (!f) + grub_util_error (_("cannot open `%s': %s"), load_cfg, + strerror (errno)); + fprintf (f, "set debug='%s'\n", debug_image); + fclose (f); + } + else + { + free (load_cfg); + load_cfg = 0; + } + + prefix = xasprintf ("/%s", subdir); + if (!targets[platform].mkimage_target) + grub_util_error (_("unsupported platform %s"), platsub); + + grub_cfg = grub_util_path_concat (2, grubdir, "grub.cfg"); + cfg = grub_util_fopen (grub_cfg, "wb"); + if (!cfg) + grub_util_error (_("cannot open `%s': %s"), grub_cfg, + strerror (errno)); + fprintf (cfg, "source %s/grub.cfg", subdir); + fclose (cfg); + + grub_install_push_module (targets[platform].netmodule); + + output = grub_util_path_concat_ext (2, grubdir, "core", targets[platform].ext); + grub_install_make_image_wrap (input_dir, prefix, output, + 0, load_cfg, + targets[platform].mkimage_target, 0); + + grub_set_install_backup_ponr (); + + grub_install_pop_module (); + + /* TRANSLATORS: First %s is replaced by platform name. Second one by filename. */ + printf (_("Netboot directory for %s created. Configure your DHCP server to point to %s\n"), + platsub, output); + + free (platsub); + free (output); + free (prefix); + free (grub_cfg); + free (grubdir); +} + + +int +main (int argc, char *argv[]) +{ + const char *pkglibdir; + + grub_util_host_init (&argc, &argv); + grub_util_disable_fd_syncs (); + rootdir = xstrdup ("/srv/tftp"); + pkglibdir = grub_util_get_pkglibdir (); + + subdir = grub_util_path_concat (2, GRUB_BOOT_DIR_NAME, GRUB_DIR_NAME); + + argp_parse (&argp, argc, argv, 0, 0, 0); + + base = grub_util_path_concat (2, rootdir, subdir); + /* Create the GRUB directory if it is not present. */ + + grub_install_mkdir_p (base); + + grub_install_push_module ("tftp"); + + if (!grub_install_source_directory) + { + enum grub_install_plat plat; + + for (plat = 0; plat < GRUB_INSTALL_PLATFORM_MAX; plat++) + if (targets[plat].mkimage_target) + { + char *platdir = grub_util_path_concat (2, pkglibdir, + grub_install_get_platform_name (plat)); + + grub_util_info ("Looking for `%s'", platdir); + + if (!grub_util_is_directory (platdir)) + { + free (platdir); + continue; + } + process_input_dir (platdir, plat); + } + } + else + { + enum grub_install_plat plat; + plat = grub_install_get_target (grub_install_source_directory); + process_input_dir (grub_install_source_directory, plat); + } + return 0; +} diff --git a/util/grub-mkpasswd-pbkdf2.c b/util/grub-mkpasswd-pbkdf2.c new file mode 100644 index 0000000..5805f3c --- /dev/null +++ b/util/grub-mkpasswd-pbkdf2.c @@ -0,0 +1,210 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <grub/types.h> +#include <grub/crypto.h> +#include <grub/auth.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/i18n.h> +#include <grub/misc.h> + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define _GNU_SOURCE 1 + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + + +#include "progname.h" + +static struct argp_option options[] = { + {"iteration-count", 'c', N_("NUM"), 0, N_("Number of PBKDF2 iterations"), 0}, + {"buflen", 'l', N_("NUM"), 0, N_("Length of generated hash"), 0}, + {"salt", 's', N_("NUM"), 0, N_("Length of salt"), 0}, + { 0, 0, 0, 0, 0, 0 } +}; + +struct arguments +{ + unsigned int count; + unsigned int buflen; + unsigned int saltlen; +}; + +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; + + switch (key) + { + case 'c': + arguments->count = strtoul (arg, NULL, 0); + break; + + case 'l': + arguments->buflen = strtoul (arg, NULL, 0); + break; + + case 's': + arguments->saltlen = strtoul (arg, NULL, 0); + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { + options, argp_parser, N_("[OPTIONS]"), + N_("Generate PBKDF2 password hash."), + NULL, NULL, NULL +}; + + +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[]) +{ + struct arguments arguments = { + .count = 10000, + .buflen = 64, + .saltlen = 64 + }; + char *result, *ptr; + gcry_err_code_t gcry_err; + grub_uint8_t *buf, *salt; + char pass1[GRUB_AUTH_MAX_PASSLEN]; + char pass2[GRUB_AUTH_MAX_PASSLEN]; + + grub_util_host_init (&argc, &argv); + + /* Check for options. */ + if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + buf = xmalloc (arguments.buflen); + salt = xmalloc (arguments.saltlen); + + printf ("%s", _("Enter password: ")); + if (!grub_password_get (pass1, GRUB_AUTH_MAX_PASSLEN)) + { + free (buf); + free (salt); + grub_util_error ("%s", _("failure to read password")); + } + printf ("%s", _("Reenter password: ")); + if (!grub_password_get (pass2, GRUB_AUTH_MAX_PASSLEN)) + { + free (buf); + free (salt); + grub_util_error ("%s", _("failure to read password")); + } + + if (strcmp (pass1, pass2) != 0) + { + memset (pass1, 0, sizeof (pass1)); + memset (pass2, 0, sizeof (pass2)); + free (buf); + free (salt); + grub_util_error ("%s", _("passwords don't match")); + } + memset (pass2, 0, sizeof (pass2)); + + if (grub_get_random (salt, arguments.saltlen)) + { + memset (pass1, 0, sizeof (pass1)); + free (buf); + free (salt); + grub_util_error ("%s", _("couldn't retrieve random data for salt")); + } + + gcry_err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, + (grub_uint8_t *) pass1, strlen (pass1), + salt, arguments.saltlen, + arguments.count, buf, arguments.buflen); + memset (pass1, 0, sizeof (pass1)); + + if (gcry_err) + { + memset (buf, 0, arguments.buflen); + free (buf); + memset (salt, 0, arguments.saltlen); + free (salt); + grub_util_error (_("cryptographic error number %d"), gcry_err); + } + + result = xmalloc (sizeof ("grub.pbkdf2.sha512.XXXXXXXXXXXXXXXXXXX.S.S") + + arguments.buflen * 2 + arguments.saltlen * 2); + ptr = result; + memcpy (ptr, "grub.pbkdf2.sha512.", sizeof ("grub.pbkdf2.sha512.") - 1); + ptr += sizeof ("grub.pbkdf2.sha512.") - 1; + + grub_snprintf (ptr, sizeof ("XXXXXXXXXXXXXXXXXXX"), "%d", arguments.count); + ptr += strlen (ptr); + *ptr++ = '.'; + hexify (ptr, salt, arguments.saltlen); + ptr += arguments.saltlen * 2; + *ptr++ = '.'; + hexify (ptr, buf, arguments.buflen); + ptr += arguments.buflen * 2; + *ptr = '\0'; + + printf (_("PBKDF2 hash of your password is %s\n"), result); + memset (buf, 0, arguments.buflen); + free (buf); + memset (salt, 0, arguments.saltlen); + free (salt); + + return 0; +} diff --git a/util/grub-mkrelpath.c b/util/grub-mkrelpath.c new file mode 100644 index 0000000..47a241a --- /dev/null +++ b/util/grub-mkrelpath.c @@ -0,0 +1,105 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <stdio.h> +#include <string.h> +#include <grub/util/misc.h> +#include <grub/emu/misc.h> +#include <grub/i18n.h> + +#define _GNU_SOURCE 1 +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include "progname.h" + +struct arguments +{ + char *pathname; +}; + +static struct argp_option options[] = { + { 0, 0, 0, 0, 0, 0 } +}; + +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; + + switch (key) + { + case ARGP_KEY_ARG: + if (state->arg_num == 0) + arguments->pathname = xstrdup (arg); + else + { + /* Too many arguments. */ + fprintf (stderr, _("Unknown extra argument `%s'."), arg); + fprintf (stderr, "\n"); + argp_usage (state); + } + break; + case ARGP_KEY_NO_ARGS: + fprintf (stderr, "%s", _("No path is specified.\n")); + argp_usage (state); + exit (1); + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { + options, argp_parser, N_("PATH"), + N_("Transform a system filename into GRUB one."), + NULL, NULL, NULL +}; + +int +main (int argc, char *argv[]) +{ + char *relpath; + struct arguments arguments; + + grub_util_host_init (&argc, &argv); + + memset (&arguments, 0, sizeof (struct arguments)); + + /* Check for options. */ + if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + relpath = grub_make_system_path_relative_to_its_root (arguments.pathname); + printf ("%s\n", relpath); + free (relpath); + + return 0; +} diff --git a/util/grub-mkrescue.c b/util/grub-mkrescue.c new file mode 100644 index 0000000..fb4dcc6 --- /dev/null +++ b/util/grub-mkrescue.c @@ -0,0 +1,999 @@ +/* + * Make GRUB rescue image + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <grub/util/install.h> +#include <grub/util/misc.h> +#include <grub/emu/exec.h> +#include <grub/emu/config.h> +#include <grub/emu/hostdisk.h> +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include <sys/types.h> +#include <sys/wait.h> + +#include <string.h> +#include <time.h> + +static char *source_dirs[GRUB_INSTALL_PLATFORM_MAX]; +static char *rom_directory; +static char *label_font; +static char *label_color; +static char *label_bgcolor; +static char *product_name; +static char *product_version; +static char *output_image; +static char *xorriso; +static char *boot_grub; +static int xorriso_argc; +static int xorriso_arg_alloc; +static char **xorriso_argv; +static char *iso_uuid; +static char *iso9660_dir; + +static void +xorriso_push (const char *val) +{ + if (xorriso_arg_alloc <= xorriso_argc + 1) + { + xorriso_arg_alloc = 2 * (4 + xorriso_argc); + xorriso_argv = xrealloc (xorriso_argv, + sizeof (xorriso_argv[0]) + * xorriso_arg_alloc); + } + xorriso_argv[xorriso_argc++] = xstrdup (val); +} + +static void +xorriso_link (const char *from, const char *to) +{ + char *tof = grub_util_path_concat (2, iso9660_dir, to); + char *val = xasprintf ("%s=%s", from, tof); + xorriso_push (val); + free (val); + free (tof); +} + +enum + { + OPTION_OUTPUT = 'o', + OPTION_ROM_DIRECTORY = 0x301, + OPTION_XORRISO, + OPTION_GLUE_EFI, + OPTION_RENDER_LABEL, + OPTION_LABEL_FONT, + OPTION_LABEL_COLOR, + OPTION_LABEL_BGCOLOR, + OPTION_PRODUCT_NAME, + OPTION_PRODUCT_VERSION, + OPTION_SPARC_BOOT, + OPTION_ARCS_BOOT + }; + +static struct argp_option options[] = { + GRUB_INSTALL_OPTIONS, + {"output", 'o', N_("FILE"), + 0, N_("save output in FILE [required]"), 2}, + {"rom-directory", OPTION_ROM_DIRECTORY, N_("DIR"), + 0, N_("save ROM images in DIR [optional]"), 2}, + {"xorriso", OPTION_XORRISO, N_("FILE"), + /* TRANSLATORS: xorriso is a program for creating ISOs and burning CDs. */ + 0, N_("use FILE as xorriso [optional]"), 2}, + {"grub-glue-efi", OPTION_GLUE_EFI, N_("FILE"), OPTION_HIDDEN, 0, 2}, + {"grub-render-label", OPTION_RENDER_LABEL, N_("FILE"), OPTION_HIDDEN, 0, 2}, + {"label-font", OPTION_LABEL_FONT, N_("FILE"), 0, N_("use FILE as font for label"), 2}, + {"label-color", OPTION_LABEL_COLOR, N_("COLOR"), 0, N_("use COLOR for label"), 2}, + {"label-bgcolor", OPTION_LABEL_BGCOLOR, N_("COLOR"), 0, N_("use COLOR for label background"), 2}, + {"product-name", OPTION_PRODUCT_NAME, N_("STRING"), 0, N_("use STRING as product name"), 2}, + {"product-version", OPTION_PRODUCT_VERSION, N_("STRING"), 0, N_("use STRING as product version"), 2}, + {"sparc-boot", OPTION_SPARC_BOOT, 0, 0, N_("enable sparc boot. Disables HFS+, APM, ARCS and boot as disk image for i386-pc"), 2}, + {"arcs-boot", OPTION_ARCS_BOOT, 0, 0, N_("enable ARCS (big-endian mips machines, mostly SGI) boot. Disables HFS+, APM, sparc64 and boot as disk image for i386-pc"), 2}, + {0, 0, 0, 0, 0, 0} +}; + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +static char * +help_filter (int key, const char *text, void *input __attribute__ ((unused))) +{ + switch (key) + { + case ARGP_KEY_HELP_PRE_DOC: + /* TRANSLATORS: it generates one single image which is bootable through any method. */ + return strdup (_("Make GRUB CD-ROM, disk, pendrive and floppy bootable image.")); + case ARGP_KEY_HELP_POST_DOC: + { + char *p1, *out; + + p1 = xasprintf (_("Generates a bootable CD/USB/floppy image. Arguments other than options to this program" + " are passed to xorriso, and indicate source files, source directories, or any of the " + "mkisofs options listed by the output of `%s'."), "xorriso -as mkisofs -help"); + out = xasprintf ("%s\n\n%s\n\n%s", p1, + _("Option -- switches to native xorriso command mode."), + _("Mail xorriso support requests to <bug-xorriso@gnu.org>.")); + free (p1); + return out; + } + default: + return grub_install_help_filter (key, text, input); + } +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +enum { + SYS_AREA_AUTO, + SYS_AREA_COMMON, + SYS_AREA_SPARC, + SYS_AREA_ARCS +} system_area = SYS_AREA_AUTO; + +static error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + if (grub_install_parse (key, arg)) + return 0; + switch (key) + { + case OPTION_OUTPUT: + free (output_image); + output_image = xstrdup (arg); + return 0; + case OPTION_ROM_DIRECTORY: + free (rom_directory); + rom_directory = xstrdup (arg); + return 0; + + /* + FIXME: + # Intentionally undocumented + --grub-mkimage-extra) + mkimage_extra_arg="$mkimage_extra_arg `argument $option "$@"`"; shift ;; + --grub-mkimage-extra=*) + mkimage_extra_arg="$mkimage_extra_arg `echo "$option" | sed 's/--grub-mkimage-extra=//'`" ;; + */ + case OPTION_SPARC_BOOT: + system_area = SYS_AREA_SPARC; + return 0; + case OPTION_ARCS_BOOT: + system_area = SYS_AREA_ARCS; + return 0; + case OPTION_PRODUCT_NAME: + free (product_name); + product_name = xstrdup (arg); + return 0; + case OPTION_PRODUCT_VERSION: + free (product_version); + product_version = xstrdup (arg); + return 0; + /* Accept and ignore for compatibility. */ + case OPTION_GLUE_EFI: + case OPTION_RENDER_LABEL: + return 0; + case OPTION_LABEL_FONT: + free (label_font); + label_font = xstrdup (arg); + return 0; + + case OPTION_LABEL_COLOR: + free (label_color); + label_color = xstrdup (arg); + return 0; + + case OPTION_LABEL_BGCOLOR: + free (label_bgcolor); + label_bgcolor = xstrdup (arg); + return 0; + + case OPTION_XORRISO: + free (xorriso); + xorriso = xstrdup (arg); + return 0; + + default: + return ARGP_ERR_UNKNOWN; + } +} + +struct argp argp = { + options, argp_parser, N_("[OPTION] SOURCE..."), + NULL, NULL, help_filter, NULL +}; + +static void +write_part (FILE *f, const char *srcdir) +{ + FILE *in; + char *inname = grub_util_path_concat (2, srcdir, "partmap.lst"); + char buf[260]; + in = grub_util_fopen (inname, "rb"); + if (!in) + return; + while (fgets (buf, 256, in)) + { + char *ptr; + for (ptr = buf + strlen (buf) - 1; + ptr >= buf && (*ptr == '\n' || *ptr == '\r'); + ptr--); + ptr[1] = '\0'; + fprintf (f, "insmod %s\n", buf); + } + fclose (in); +} + +static void +make_image_abs (enum grub_install_plat plat, + const char *mkimage_target, + const char *output) +{ + char *load_cfg; + FILE *load_cfg_f; + + if (!source_dirs[plat]) + return; + + grub_util_info (N_("enabling %s support ..."), + mkimage_target); + + load_cfg = grub_util_make_temporary_file (); + + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + fprintf (load_cfg_f, "search --fs-uuid --set=root %s\n", iso_uuid); + fprintf (load_cfg_f, "set prefix=(${root})/boot/grub\n"); + + write_part (load_cfg_f, source_dirs[plat]); + fclose (load_cfg_f); + + grub_install_push_module ("search"); + grub_install_push_module ("iso9660"); + grub_install_make_image_wrap (source_dirs[plat], "/boot/grub", output, + 0, load_cfg, + mkimage_target, 0); + grub_install_pop_module (); + grub_install_pop_module (); + grub_util_unlink (load_cfg); +} + +static void +make_image (enum grub_install_plat plat, + const char *mkimage_target, + const char *output_sub) +{ + char *out = grub_util_path_concat (2, boot_grub, output_sub); + make_image_abs (plat, mkimage_target, out); + free (out); +} + +static void +make_image_fwdisk_abs (enum grub_install_plat plat, + const char *mkimage_target, + const char *output) +{ + char *load_cfg; + FILE *load_cfg_f; + + if (!source_dirs[plat]) + return; + + grub_util_info (N_("enabling %s support ..."), + mkimage_target); + + load_cfg = grub_util_make_temporary_file (); + + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + write_part (load_cfg_f, source_dirs[plat]); + fclose (load_cfg_f); + + grub_install_push_module ("iso9660"); + grub_install_make_image_wrap (source_dirs[plat], "()/boot/grub", output, + 0, load_cfg, mkimage_target, 0); + grub_install_pop_module (); + grub_util_unlink (load_cfg); +} + +static int +check_xorriso (const char *val) +{ + const char *argv[5]; + int fd; + pid_t pid; + FILE *mdadm; + char *buf = NULL; + size_t len = 0; + int ret = 0; + int wstatus = 0; + + argv[0] = xorriso; + argv[1] = "-as"; + argv[2] = "mkisofs"; + argv[3] = "-help"; + argv[4] = NULL; + + pid = grub_util_exec_pipe_stderr (argv, &fd); + + if (!pid) + return 0; + + /* Parent. Read mdadm's output. */ + mdadm = fdopen (fd, "r"); + if (! mdadm) + return 0; + + while (getline (&buf, &len, mdadm) > 0) + { + if (grub_strstr (buf, val)) + ret = 1; + } + + close (fd); + waitpid (pid, &wstatus, 0); + free (buf); + if (!WIFEXITED (wstatus) || WEXITSTATUS(wstatus) != 0) + return 0; + return ret; +} + +static void +make_image_fwdisk (enum grub_install_plat plat, + const char *mkimage_target, + const char *output_sub) +{ + char *out = grub_util_path_concat (2, boot_grub, output_sub); + make_image_fwdisk_abs (plat, mkimage_target, out); + free (out); +} + +static int +option_is_end (const struct argp_option *opt) +{ + return !opt->key && !opt->name && !opt->doc && !opt->group; +} + + +static int +args_to_eat (const char *arg) +{ + int j; + + if (arg[0] != '-') + return 0; + + if (arg[1] == '-') + { + for (j = 0; !option_is_end(&options[j]); j++) + { + size_t len = strlen (options[j].name); + if (strncmp (arg + 2, options[j].name, len) == 0) + { + if (arg[2 + len] == '=') + return 1; + if (arg[2 + len] == '\0' && options[j].arg) + return 2; + if (arg[2 + len] == '\0') + return 1; + } + } + if (strcmp (arg, "--help") == 0) + return 1; + if (strcmp (arg, "--usage") == 0) + return 1; + if (strcmp (arg, "--version") == 0) + return 1; + return 0; + } + if (arg[2] && arg[3]) + return 0; + for (j = 0; !option_is_end(&options[j]); j++) + { + if (options[j].key > 0 && options[j].key < 128 && arg[1] == options[j].key) + { + if (options[j].arg) + return 2; + return 1; + } + if (arg[1] == '?') + return 1; + } + return 0; +} + +int +main (int argc, char *argv[]) +{ + char *romdir; + char *sysarea_img = NULL; + const char *pkgdatadir; + int argp_argc; + char **argp_argv; + int xorriso_tail_argc; + char **xorriso_tail_argv; + int rv; + + grub_util_host_init (&argc, &argv); + grub_util_disable_fd_syncs (); + + pkgdatadir = grub_util_get_pkgdatadir (); + + product_name = xstrdup (PACKAGE_NAME); + product_version = xstrdup (PACKAGE_VERSION); + xorriso = xstrdup ("xorriso"); + label_font = grub_util_path_concat (2, pkgdatadir, "unicode.pf2"); + + argp_argv = xcalloc (argc, sizeof (argp_argv[0])); + xorriso_tail_argv = xcalloc (argc, sizeof (argp_argv[0])); + + xorriso_tail_argc = 0; + /* Program name */ + argp_argv[0] = argv[0]; + argp_argc = 1; + + /* argp doesn't allow us to catch unknwon arguments, + so catch them before passing to argp + */ + { + int i; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-output") == 0) { + argp_argv[argp_argc++] = (char *) "--output"; + i++; + argp_argv[argp_argc++] = argv[i]; + continue; + } + switch (args_to_eat (argv[i])) + { + case 2: + argp_argv[argp_argc++] = argv[i++]; + /* Fallthrough */ + case 1: + argp_argv[argp_argc++] = argv[i]; + break; + case 0: + xorriso_tail_argv[xorriso_tail_argc++] = argv[i]; + break; + } + } + } + + argp_parse (&argp, argp_argc, argp_argv, 0, 0, 0); + + if (!output_image) + grub_util_error ("%s", _("output file must be specified")); + + if (!check_xorriso ("graft-points")) { + grub_util_error ("%s", _("xorriso not found")); + } + + grub_init_all (); + grub_hostfs_init (); + grub_host_init (); + + xorriso_push (xorriso); + xorriso_push ("-as"); + xorriso_push ("mkisofs"); + xorriso_push ("-graft-points"); + + iso9660_dir = grub_util_make_temporary_dir (); + grub_util_info ("temporary iso9660 dir is `%s'", iso9660_dir); + boot_grub = grub_util_path_concat (3, iso9660_dir, "boot", "grub"); + grub_install_mkdir_p (boot_grub); + romdir = grub_util_path_concat (2, boot_grub, "roms"); + grub_util_mkdir (romdir); + + if (!grub_install_source_directory) + { + const char *pkglibdir = grub_util_get_pkglibdir (); + enum grub_install_plat plat; + + for (plat = 0; plat < GRUB_INSTALL_PLATFORM_MAX; plat++) + { + char *platdir = grub_util_path_concat (2, pkglibdir, + grub_install_get_platform_name (plat)); + + if (!grub_util_is_directory (platdir)) + { + free (platdir); + continue; + } + source_dirs[plat] = platdir; + grub_install_copy_files (platdir, + boot_grub, plat); + } + } + else + { + enum grub_install_plat plat; + plat = grub_install_get_target (grub_install_source_directory); + grub_install_copy_files (grub_install_source_directory, + boot_grub, plat); + source_dirs[plat] = xstrdup (grub_install_source_directory); + } + + grub_set_install_backup_ponr (); + + if (system_area == SYS_AREA_AUTO || grub_install_source_directory) + { + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC] + || source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275] + || source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_IA64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_ARM_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_ARM64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_RISCV32_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_RISCV64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]) + system_area = SYS_AREA_COMMON; + else if (source_dirs[GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275]) + system_area = SYS_AREA_SPARC; + else if (source_dirs[GRUB_INSTALL_PLATFORM_MIPS_ARC]) + system_area = SYS_AREA_ARCS; + } + + /* obtain date-based UUID. */ + { + time_t tim; + struct tm *tmm; + tim = time (NULL); + tmm = gmtime (&tim); + iso_uuid = xmalloc (55); + grub_snprintf (iso_uuid, 50, + "%04d-%02d-%02d-%02d-%02d-%02d-00", + tmm->tm_year + 1900, + tmm->tm_mon + 1, + tmm->tm_mday, + tmm->tm_hour, + tmm->tm_min, + tmm->tm_sec); + } + { + char *uuid_out = xmalloc (strlen (iso_uuid) + 1 + 40); + char *optr; + const char *iptr; + optr = grub_stpcpy (uuid_out, "--modification-date="); + for (iptr = iso_uuid; *iptr; iptr++) + if (*iptr != '-') + *optr++ = *iptr; + *optr = '\0'; + xorriso_push (uuid_out); + free (uuid_out); + } + + /* build BIOS core.img. */ + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC]) + { + char *load_cfg; + FILE *load_cfg_f; + char *output = grub_util_path_concat (3, boot_grub, "i386-pc", "eltorito.img"); + load_cfg = grub_util_make_temporary_file (); + + grub_util_info (N_("enabling %s support ..."), "BIOS"); + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + write_part (load_cfg_f, source_dirs[GRUB_INSTALL_PLATFORM_I386_PC]); + fclose (load_cfg_f); + + grub_install_push_module ("biosdisk"); + grub_install_push_module ("iso9660"); + grub_install_make_image_wrap (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC], + "/boot/grub", output, + 0, load_cfg, + "i386-pc-eltorito", 0); + + xorriso_push ("-b"); + xorriso_push ("boot/grub/i386-pc/eltorito.img"); + xorriso_push ("-no-emul-boot"); + xorriso_push ("-boot-load-size"); + xorriso_push ("4"); + xorriso_push ("-boot-info-table"); + if (system_area == SYS_AREA_COMMON) + { + if (check_xorriso ("grub2-boot-info")) + { + char *boot_hybrid = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_I386_PC], + "boot_hybrid.img"); + xorriso_push ("--grub2-boot-info"); + xorriso_push ("--grub2-mbr"); + xorriso_push (boot_hybrid); + } + else + { + FILE *sa, *bi; + size_t sz; + char buf[512]; + char *bin = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_I386_PC], + "boot.img"); + grub_util_warn ("%s", _("Your xorriso doesn't support `--grub2-boot-info'. Some features are disabled. Please use xorriso 1.2.9 or later.")); + sysarea_img = grub_util_make_temporary_file (); + sa = grub_util_fopen (sysarea_img, "wb"); + if (!sa) + grub_util_error (_("cannot open `%s': %s"), sysarea_img, + strerror (errno)); + bi = grub_util_fopen (bin, "rb"); + if (!bi) + grub_util_error (_("cannot open `%s': %s"), bin, + strerror (errno)); + if (fread (buf, 1, 512, bi) != 512) + grub_util_error (_("cannot read `%s': %s"), bin, + strerror (errno)); + fclose (bi); + fwrite (buf, 1, 512, sa); + + grub_install_make_image_wrap_file (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC], + "/boot/grub", sa, sysarea_img, + 0, load_cfg, + "i386-pc", 0); + sz = ftello (sa); + fflush (sa); + grub_util_fd_sync (fileno (sa)); + fclose (sa); + + if (sz > 32768) + { + grub_util_warn ("%s", _("Your xorriso doesn't support `--grub2-boot-info'. Your core image is too big. Boot as disk is disabled. Please use xorriso 1.2.9 or later.")); + } + else + { + xorriso_push ("-G"); + xorriso_push (sysarea_img); + } + } + } + grub_install_pop_module (); + grub_install_pop_module (); + grub_util_unlink (load_cfg); + } + + /** build multiboot core.img */ + grub_install_push_module ("pata"); + grub_install_push_module ("ahci"); + grub_install_push_module ("at_keyboard"); + make_image (GRUB_INSTALL_PLATFORM_I386_MULTIBOOT, "i386-multiboot", "i386-multiboot/core.elf"); + grub_install_pop_module (); + grub_install_pop_module (); + grub_install_pop_module (); + + make_image_fwdisk (GRUB_INSTALL_PLATFORM_I386_IEEE1275, "i386-ieee1275", "ofwx86.elf"); + + char *core_services = NULL; + + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275]) + { + char *mach_ker, *sv, *label, *label_text; + FILE *f; + core_services = grub_util_path_concat (4, iso9660_dir, "System", "Library", "CoreServices"); + grub_install_mkdir_p (core_services); + + mach_ker = grub_util_path_concat (2, iso9660_dir, "mach_kernel"); + f = grub_util_fopen (mach_ker, "wb"); + fclose (f); + free (mach_ker); + + sv = grub_util_path_concat (2, core_services, "SystemVersion.plist"); + f = grub_util_fopen (sv, "wb"); + fprintf (f, "<plist version=\"1.0\">\n" + "<dict>\n" + " <key>ProductBuildVersion</key>\n" + " <string></string>\n" + " <key>ProductName</key>\n" + " <string>%s</string>\n" + " <key>ProductVersion</key>\n" + " <string>%s</string>\n" + "</dict>\n" + "</plist>\n", product_name, product_version); + fclose (f); + free (sv); + label = grub_util_path_concat (2, core_services, ".disk_label"); + char *label_string = xasprintf ("%s %s", product_name, product_version); + grub_util_render_label (label_font, label_bgcolor ? : "white", + label_color ? : "black", label_string, label); + free (label); + label_text = grub_util_path_concat (2, core_services, ".disk_label.contentDetails"); + f = grub_util_fopen (label_text, "wb"); + fprintf (f, "%s\n", label_string); + fclose (f); + free (label_string); + free (label_text); + if (system_area == SYS_AREA_COMMON) + { + xorriso_push ("-hfsplus"); + xorriso_push ("-apm-block-size"); + xorriso_push ("2048"); + xorriso_push ("-hfsplus-file-creator-type"); + xorriso_push ("chrp"); + xorriso_push ("tbxj"); + xorriso_push ("/System/Library/CoreServices/.disk_label"); + + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]) + { + xorriso_push ("-hfs-bless-by"); + xorriso_push ("i"); + xorriso_push ("/System/Library/CoreServices/boot.efi"); + } + } + } + + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_IA64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_ARM_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_ARM64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_RISCV32_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_RISCV64_EFI]) + { + char *efidir = grub_util_make_temporary_dir (); + char *efidir_efi = grub_util_path_concat (2, efidir, "efi"); + char *efidir_efi_boot = grub_util_path_concat (3, efidir, "efi", "boot"); + char *imgname, *img32, *img64, *img_mac = NULL; + char *efiimgfat; + grub_install_mkdir_p (efidir_efi_boot); + + grub_install_push_module ("part_gpt"); + grub_install_push_module ("part_msdos"); + + imgname = grub_util_path_concat (2, efidir_efi_boot, "bootia64.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_IA64_EFI, "ia64-efi", imgname); + free (imgname); + + grub_install_push_module ("part_apple"); + img64 = grub_util_path_concat (2, efidir_efi_boot, "bootx64.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_X86_64_EFI, "x86_64-efi", img64); + grub_install_pop_module (); + + grub_install_push_module ("part_apple"); + img32 = grub_util_path_concat (2, efidir_efi_boot, "bootia32.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_I386_EFI, "i386-efi", img32); + grub_install_pop_module (); + + imgname = grub_util_path_concat (2, efidir_efi_boot, "bootarm.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_ARM_EFI, "arm-efi", imgname); + free (imgname); + + imgname = grub_util_path_concat (2, efidir_efi_boot, "bootaa64.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_ARM64_EFI, "arm64-efi", + imgname); + free (imgname); + + imgname = grub_util_path_concat (2, efidir_efi_boot, "bootriscv32.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_RISCV32_EFI, "riscv32-efi", + imgname); + free (imgname); + + imgname = grub_util_path_concat (2, efidir_efi_boot, "bootriscv64.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_RISCV64_EFI, "riscv64-efi", + imgname); + free (imgname); + + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI]) + { + imgname = grub_util_path_concat (2, efidir_efi_boot, "boot.efi"); + /* For old macs. Suggested by Peter Jones. */ + grub_install_copy_file (img32, imgname, 1); + } + + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]) + img_mac = grub_util_path_concat (2, core_services, "boot.efi"); + + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI] + && source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]) + grub_util_glue_efi (img32, img64, img_mac); + else if (source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]) + grub_install_copy_file (img64, img_mac, 1); + else if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI]) + grub_install_copy_file (img32, img_mac, 1); + + free (img_mac); + free (img32); + free (img64); + free (efidir_efi_boot); + + efiimgfat = grub_util_path_concat (2, iso9660_dir, "efi.img"); + rv = grub_util_exec ((const char * []) { "mformat", "-C", "-f", "2880", "-L", "16", "-i", + efiimgfat, "::", NULL }); + if (rv != 0) + grub_util_error ("`%s` invocation failed\n", "mformat"); + rv = grub_util_exec ((const char * []) { "mcopy", "-s", "-i", efiimgfat, efidir_efi, "::/", NULL }); + if (rv != 0) + grub_util_error ("`%s` invocation failed\n", "mcopy"); + xorriso_push ("--efi-boot"); + xorriso_push ("efi.img"); + xorriso_push ("-efi-boot-part"); + xorriso_push ("--efi-boot-image"); + + grub_util_unlink_recursive (efidir); + free (efiimgfat); + free (efidir_efi); + free (efidir); + grub_install_pop_module (); + grub_install_pop_module (); + } + + grub_install_push_module ("part_apple"); + make_image_fwdisk (GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275, "powerpc-ieee1275", "powerpc-ieee1275/core.elf"); + grub_install_pop_module (); + + if (source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275]) + { + char *grub_chrp = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275], + "grub.chrp"); + char *bisrc = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275], + "bootinfo.txt"); + char *bootx = grub_util_path_concat (2, core_services, "BootX"); + char *ppc_chrp = grub_util_path_concat (3, iso9660_dir, "ppc", "chrp"); + char *bitgt = grub_util_path_concat (3, iso9660_dir, "ppc", "bootinfo.txt"); + grub_install_copy_file (grub_chrp, bootx, 1); + grub_install_mkdir_p (ppc_chrp); + grub_install_copy_file (bisrc, bitgt, 1); + xorriso_link ("/System/Library/CoreServices/grub.elf", "/boot/grub/powerpc-ieee1275/core.elf"); + xorriso_link ("/boot/grub/powerpc.elf", "/boot/grub/powerpc-ieee1275/core.elf"); + /* FIXME: add PreP */ + if (system_area == SYS_AREA_COMMON) + { + xorriso_push ("-hfsplus-file-creator-type"); + xorriso_push ("chrp"); + xorriso_push ("tbxi"); + xorriso_push ("/System/Library/CoreServices/BootX"); + xorriso_push ("-hfs-bless-by"); + xorriso_push ("p"); + xorriso_push ("/System/Library/CoreServices"); + } + xorriso_push ("-sysid"); + xorriso_push ("PPC"); + } + + make_image_fwdisk (GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275, + "sparc64-ieee1275-cdcore", "sparc64-ieee1275/core.img"); + + if (source_dirs[GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275] + && system_area == SYS_AREA_SPARC) + { + char *cdboot; + FILE *in, *out; + char buf[512]; + sysarea_img = grub_util_make_temporary_file (); + cdboot = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275], + "cdboot.img"); + in = grub_util_fopen (cdboot, "rb"); + if (!in) + grub_util_error (_("cannot open `%s': %s"), cdboot, + strerror (errno)); + out = grub_util_fopen (sysarea_img, "wb"); + if (!out) + grub_util_error (_("cannot open `%s': %s"), sysarea_img, + strerror (errno)); + memset (buf, 0, 512); + fwrite (buf, 1, 512, out); + if (fread (buf, 1, 512, in) != 512) + grub_util_error (_("cannot read `%s': %s"), cdboot, + strerror (errno)); + fwrite (buf, 1, 512, out); + fclose (in); + fclose (out); + xorriso_push ("-G"); + xorriso_push (sysarea_img); + xorriso_push ("-B"); + xorriso_push (","); + xorriso_push ("--grub2-sparc-core"); + xorriso_push ("/boot/grub/sparc64-ieee1275/core.img"); + } + + make_image_fwdisk (GRUB_INSTALL_PLATFORM_MIPS_ARC, "mips-arc", "mips-arc/core.img"); + + if (source_dirs[GRUB_INSTALL_PLATFORM_MIPS_ARC]) + { + xorriso_link ("/boot/grub/mips-arc/grub", "/boot/grub/mips-arc/core.img"); + xorriso_link ("/boot/grub/mips-arc/sashARCS", "/boot/grub/mips-arc/core.img"); + xorriso_link ("/boot/grub/mips-arc/sash", "/boot/grub/mips-arc/core.img"); + } + if (source_dirs[GRUB_INSTALL_PLATFORM_MIPS_ARC] && system_area == SYS_AREA_ARCS) + { + xorriso_push ("-mips-boot"); + xorriso_push ("/boot/grub/mips-arc/sashARCS"); + xorriso_push ("-mips-boot"); + xorriso_push ("/boot/grub/mips-arc/sash"); + xorriso_push ("-mips-boot"); + xorriso_push ("/boot/grub/mips-arc/grub"); + } + + make_image_fwdisk (GRUB_INSTALL_PLATFORM_MIPSEL_ARC, "mipsel-arc", "arc.exe"); + + grub_install_push_module ("pata"); + make_image (GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS, "mipsel-qemu_mips-elf", "roms/mipsel-qemu_mips.elf"); + + make_image (GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "mipsel-loongson-elf", "loongson.elf"); + + make_image (GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "mipsel-yeeloong-flash", "mipsel-yeeloong.bin"); + make_image (GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "mipsel-fuloong2f-flash", "mipsel-fuloong2f.bin"); + + make_image (GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS, "mips-qemu_mips-elf", "roms/mips-qemu_mips.elf"); + + grub_install_push_module ("at_keyboard"); + + make_image (GRUB_INSTALL_PLATFORM_I386_QEMU, "i386-qemu", "roms/qemu.img"); + + grub_install_push_module ("ahci"); + + make_image (GRUB_INSTALL_PLATFORM_I386_COREBOOT, "i386-coreboot", "roms/coreboot.elf"); + grub_install_pop_module (); + grub_install_pop_module (); + grub_install_pop_module (); + + if (rom_directory) + { + const struct + { + enum grub_install_plat plat; + const char *from, *to; + } roms[] = + { + {GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS, "roms/mipsel-qemu_mips.elf", "mipsel-qemu_mips.elf"}, + {GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "loongson.elf", "mipsel-loongson.elf"}, + {GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "roms/mipsel-yeeloong.bin", "mipsel-yeeloong.bin"}, + {GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "roms/mipsel-fulong.bin", "mipsel-fulong.bin"}, + {GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS, "roms/mips-qemu_mips.elf", "mips-qemu_mips.elf"}, + {GRUB_INSTALL_PLATFORM_I386_QEMU, "roms/qemu.img", "qemu.img"}, + {GRUB_INSTALL_PLATFORM_I386_COREBOOT, "roms/coreboot.elf", "coreboot.elf"}, + }; + grub_size_t i; + for (i = 0; i < ARRAY_SIZE (roms); i++) + { + char *from = grub_util_path_concat (2, boot_grub, roms[i].from); + char *to = grub_util_path_concat (2, rom_directory, roms[i].to); + grub_install_copy_file (from, to, 0); + } + } + + xorriso_push ("--protective-msdos-label"); + xorriso_push ("-o"); + xorriso_push (output_image); + xorriso_push ("-r"); + xorriso_push (iso9660_dir); + xorriso_push ("--sort-weight"); + xorriso_push ("0"); + xorriso_push ("/"); + xorriso_push ("--sort-weight"); + xorriso_push ("1"); + xorriso_push ("/boot"); + int i; + for (i = 0; i < xorriso_tail_argc; i++) + xorriso_push (xorriso_tail_argv[i]); + + xorriso_argv[xorriso_argc] = NULL; + + rv = grub_util_exec ((const char *const *)xorriso_argv); + if (rv != 0) + grub_util_error ("`%s` invocation failed\n", "xorriso"); + + grub_util_unlink_recursive (iso9660_dir); + + if (sysarea_img) + grub_util_unlink (sysarea_img); + + free (core_services); + free (romdir); + return 0; +} diff --git a/util/grub-mkstandalone.c b/util/grub-mkstandalone.c new file mode 100644 index 0000000..5f50a3b --- /dev/null +++ b/util/grub-mkstandalone.c @@ -0,0 +1,363 @@ + +/* + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <config.h> + +#include <grub/util/install.h> +#include <grub/util/misc.h> +#include <grub/emu/config.h> + +#include <string.h> + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +static char *output_image; +static char **files; +static int nfiles; +const struct grub_install_image_target_desc *format; +static FILE *memdisk; + +enum + { + OPTION_OUTPUT = 'o', + OPTION_FORMAT = 'O' + }; + +static struct argp_option options[] = { + GRUB_INSTALL_OPTIONS, + {"output", 'o', N_("FILE"), + 0, N_("save output in FILE [required]"), 2}, + {"format", 'O', N_("FILE"), 0, 0, 2}, + {"compression", 'C', "xz|none|auto", OPTION_HIDDEN, 0, 2}, + {0, 0, 0, 0, 0, 0} +}; + +static char * +help_filter (int key, const char *text, void *input __attribute__ ((unused))) +{ + switch (key) + { + case 'O': + { + char *formats = grub_install_get_image_targets_string (), *ret; + ret = xasprintf ("%s\n%s %s", _("generate an image in FORMAT"), + _("available formats:"), formats); + free (formats); + return ret; + } + default: + return grub_install_help_filter (key, text, input); + } +} + +static error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + if (key == 'C') + key = GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS; + + if (grub_install_parse (key, arg)) + return 0; + + switch (key) + { + + case 'o': + if (output_image) + free (output_image); + + output_image = xstrdup (arg); + break; + + case 'O': + { + format = grub_install_get_image_target (arg); + if (!format) + { + printf (_("unknown target format %s\n"), arg); + argp_usage (state); + exit (1); + } + break; + } + + case ARGP_KEY_ARG: + files[nfiles++] = xstrdup (arg); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +struct argp argp = { + options, argp_parser, N_("[OPTION] SOURCE..."), + N_("Generate a standalone image (containing all modules) in the selected format")"\v"N_("Graft point syntax (E.g. /boot/grub/grub.cfg=./grub.cfg) is accepted"), + NULL, help_filter, NULL +}; + +/* tar support */ +#define MAGIC "ustar" +struct head +{ + char name[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char typeflag; + char linkname[100]; + char magic[6]; + char version[2]; + char uname[32]; + char gname[32]; + char devmajor[8]; + char devminor[8]; + char prefix[155]; + char pad[12]; +} GRUB_PACKED; + +static void +write_zeros (unsigned rsz) +{ + char buf[512]; + + memset (buf, 0, 512); + fwrite (buf, 1, rsz, memdisk); +} + +static void +write_pad (unsigned sz) +{ + write_zeros ((~sz + 1) & 511); +} + +static void +set_tar_value (char *field, grub_uint32_t val, + unsigned len) +{ + unsigned i; + for (i = 0; i < len - 1; i++) + field[len - 2 - i] = '0' + ((val >> (3 * i)) & 7); +} + +static void +compute_checksum (struct head *hd) +{ + unsigned int chk = 0; + unsigned char *ptr; + memset (hd->chksum, ' ', 8); + for (ptr = (unsigned char *) hd; ptr < (unsigned char *) (hd + 1); ptr++) + chk += *ptr; + set_tar_value (hd->chksum, chk, 8); +} + +static void +add_tar_file (const char *from, + const char *to) +{ + char *tcn; + const char *iptr; + char *optr; + struct head hd; + grub_util_fd_t in; + ssize_t r; + grub_uint32_t mtime = 0; + grub_uint32_t size; + + COMPILE_TIME_ASSERT (sizeof (hd) == 512); + + if (grub_util_is_special_file (from)) + return; + + mtime = grub_util_get_mtime (from); + + optr = tcn = xmalloc (strlen (to) + 1); + for (iptr = to; *iptr == '/'; iptr++); + for (; *iptr; iptr++) + if (!(iptr[0] == '/' && iptr[1] == '/')) + *optr++ = *iptr; + *optr = '\0'; + + if (grub_util_is_directory (from)) + { + grub_util_fd_dir_t d; + grub_util_fd_dirent_t de; + + d = grub_util_fd_opendir (from); + + while ((de = grub_util_fd_readdir (d))) + { + char *fp, *tfp; + if (strcmp (de->d_name, ".") == 0) + continue; + if (strcmp (de->d_name, "..") == 0) + continue; + fp = grub_util_path_concat (2, from, de->d_name); + tfp = xasprintf ("%s/%s", to, de->d_name); + add_tar_file (fp, tfp); + free (fp); + } + grub_util_fd_closedir (d); + free (tcn); + return; + } + + if (optr - tcn > 99) + { + memset (&hd, 0, sizeof (hd)); + memcpy (hd.name, tcn, 99); + memcpy (hd.mode, "0000600", 7); + memcpy (hd.uid, "0001750", 7); + memcpy (hd.gid, "0001750", 7); + + set_tar_value (hd.size, optr - tcn, 12); + set_tar_value (hd.mtime, mtime, 12); + hd.typeflag = 'L'; + memcpy (hd.magic, MAGIC, sizeof (hd.magic)); + memcpy (hd.uname, "grub", 4); + memcpy (hd.gname, "grub", 4); + + compute_checksum (&hd); + + fwrite (&hd, 1, sizeof (hd), memdisk); + fwrite (tcn, 1, optr - tcn, memdisk); + + write_pad (optr - tcn); + } + + in = grub_util_fd_open (from, GRUB_UTIL_FD_O_RDONLY); + if (!GRUB_UTIL_FD_IS_VALID (in)) + grub_util_error (_("cannot open `%s': %s"), from, grub_util_fd_strerror ()); + + if (!grub_install_copy_buffer) + grub_install_copy_buffer = xmalloc (GRUB_INSTALL_COPY_BUFFER_SIZE); + + size = grub_util_get_fd_size (in, from, NULL); + + memset (&hd, 0, sizeof (hd)); + memcpy (hd.name, tcn, optr - tcn < 99 ? optr - tcn : 99); + memcpy (hd.mode, "0000600", 7); + memcpy (hd.uid, "0001750", 7); + memcpy (hd.gid, "0001750", 7); + + set_tar_value (hd.size, size, 12); + set_tar_value (hd.mtime, mtime, 12); + hd.typeflag = '0'; + memcpy (hd.magic, MAGIC, sizeof (hd.magic)); + memcpy (hd.uname, "grub", 4); + memcpy (hd.gname, "grub", 4); + + compute_checksum (&hd); + + fwrite (&hd, 1, sizeof (hd), memdisk); + + while (1) + { + r = grub_util_fd_read (in, grub_install_copy_buffer, GRUB_INSTALL_COPY_BUFFER_SIZE); + if (r <= 0) + break; + fwrite (grub_install_copy_buffer, 1, r, memdisk); + } + grub_util_fd_close (in); + + write_pad (size); + free (tcn); +} + +int +main (int argc, char *argv[]) +{ + const char *pkglibdir; + int i; + + grub_util_host_init (&argc, &argv); + grub_util_disable_fd_syncs (); + + files = xcalloc (argc + 1, sizeof (files[0])); + + argp_parse (&argp, argc, argv, 0, 0, 0); + + pkglibdir = grub_util_get_pkglibdir (); + + if (!output_image) + grub_util_error ("%s", _("output file must be specified")); + + if (!format) + grub_util_error ("%s", _("Target format not specified (use the -O option).")); + + if (!grub_install_source_directory) + grub_install_source_directory = grub_util_path_concat (2, pkglibdir, grub_util_get_target_dirname (format)); + + enum grub_install_plat plat = grub_install_get_target (grub_install_source_directory); + + char *memdisk_dir = grub_util_make_temporary_dir (); + char *boot_grub = grub_util_path_concat (3, memdisk_dir, "boot", "grub"); + grub_install_copy_files (grub_install_source_directory, + boot_grub, plat); + + grub_set_install_backup_ponr (); + + char *memdisk_img = grub_util_make_temporary_file (); + + memdisk = grub_util_fopen (memdisk_img, "wb"); + + add_tar_file (memdisk_dir, ""); + for (i = 0; i < nfiles; i++) + { + char *eq = grub_strchr (files[i], '='); + char *from, *to; + if (!eq) + { + from = files[i]; + to = files[i]; + } + else + { + *eq = '\0'; + to = files[i]; + from = eq + 1; + } + while (*to == '/') + to++; + add_tar_file (from, to); + } + write_zeros (512); + + fclose (memdisk); + + grub_util_unlink_recursive (memdisk_dir); + + grub_install_push_module ("memdisk"); + grub_install_push_module ("tar"); + + grub_install_make_image_wrap (grub_install_source_directory, + "(memdisk)/boot/grub", output_image, + memdisk_img, NULL, + grub_util_get_target_name (format), 0); + + grub_util_unlink (memdisk_img); + return 0; +} diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c new file mode 100644 index 0000000..163529c --- /dev/null +++ b/util/grub-module-verifier.c @@ -0,0 +1,234 @@ +#include <stdio.h> +#include <string.h> + +#include <grub/elf.h> +#include <grub/module_verifier.h> +#include <grub/misc.h> +#include <grub/util/misc.h> + +struct grub_module_verifier_arch archs[] = { + { "i386", 4, 0, EM_386, GRUB_MODULE_VERIFY_SUPPORTS_REL, (int[]){ + R_386_32, + R_386_PC32, + -1 + } }, + { "x86_64", 8, 0, EM_X86_64, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_X86_64_64, + R_X86_64_PC64, + /* R_X86_64_32, R_X86_64_32S are supported but shouldn't be used because of their limited range. */ + -1 + }, (int[]){ + R_X86_64_PC32, + R_X86_64_PLT32, + -1 + } + }, + { "powerpc", 4, 1, EM_PPC, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + GRUB_ELF_R_PPC_ADDR16_LO, + GRUB_ELF_R_PPC_REL24, /* It has limited range but GRUB adds trampolines when necessarry. */ + GRUB_ELF_R_PPC_ADDR16_HA, + GRUB_ELF_R_PPC_ADDR32, + GRUB_ELF_R_PPC_REL32, + GRUB_ELF_R_PPC_PLTREL24, + -1 + } }, + { "sparc64", 8, 1, EM_SPARCV9, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_SPARC_WDISP30, /* It has limited range but GRUB adds trampolines when necessarry. */ + R_SPARC_HH22, + R_SPARC_HM10, + R_SPARC_LM22, + R_SPARC_LO10, + R_SPARC_64, + R_SPARC_OLO10, + /* Following 2 relocations have limited range but unfortunately + clang generates them, as it doesn't implement mcmodel=large properly. + At least our heap and core are under 4G, so it's not a problem + usually. */ + R_SPARC_HI22, + R_SPARC_32, + -1 + } }, + { "ia64", 8, 0, EM_IA_64, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_IA64_PCREL21B, /* We should verify that it's pointing either + to a function or to a section in the same module. + Checking that external symbol is a function is + non-trivial and I have never seen this relocation used + for anything else, so assume that it always points to a + function. + */ + R_IA64_SEGREL64LSB, + R_IA64_FPTR64LSB, + R_IA64_DIR64LSB, + R_IA64_PCREL64LSB, + R_IA64_LTOFF22X, + R_IA64_LTOFF22, + R_IA64_GPREL64I, + R_IA64_LTOFF_FPTR22, + R_IA64_LDXMOV, + -1 + }, (int[]){ + R_IA64_GPREL22, + -1 + } }, + { "mipsel", 4, 0, EM_MIPS, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_MIPS_HI16, + R_MIPS_LO16, + R_MIPS_32, + R_MIPS_GPREL32, + R_MIPS_26, + R_MIPS_GOT16, + R_MIPS_CALL16, + R_MIPS_JALR, + -1 + } }, + { "mips", 4, 1, EM_MIPS, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_MIPS_HI16, + R_MIPS_LO16, + R_MIPS_32, + R_MIPS_GPREL32, + R_MIPS_26, + R_MIPS_GOT16, + R_MIPS_CALL16, + R_MIPS_JALR, + -1 + } }, + { "arm", 4, 0, EM_ARM, GRUB_MODULE_VERIFY_SUPPORTS_REL, (int[]){ + /* Some relocations are range-limited but trampolines are added when necessarry. */ + R_ARM_ABS32, + R_ARM_CALL, + R_ARM_JUMP24, + R_ARM_THM_CALL, + R_ARM_THM_JUMP24, + R_ARM_V4BX, + R_ARM_THM_MOVW_ABS_NC, + R_ARM_THM_MOVT_ABS, + R_ARM_THM_JUMP19, + -1 + } }, + { "arm64", 8, 0, EM_AARCH64, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_AARCH64_ABS64, + R_AARCH64_CALL26, + R_AARCH64_JUMP26, + R_AARCH64_ADR_GOT_PAGE, + R_AARCH64_LD64_GOT_LO12_NC, + -1 + }, (int[]){ + R_AARCH64_ADR_PREL_PG_HI21, + R_AARCH64_ADD_ABS_LO12_NC, + R_AARCH64_LDST64_ABS_LO12_NC, + R_AARCH64_PREL32, + -1 + } }, + { "riscv32", 4, 0, EM_RISCV, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_RISCV_32, + R_RISCV_64, + R_RISCV_ADD8, + R_RISCV_ADD16, + R_RISCV_ADD32, + R_RISCV_ADD64, + R_RISCV_SUB8, + R_RISCV_SUB16, + R_RISCV_SUB32, + R_RISCV_SUB64, + R_RISCV_ALIGN, + R_RISCV_BRANCH, + R_RISCV_CALL, + R_RISCV_CALL_PLT, + R_RISCV_GOT_HI20, + R_RISCV_HI20, + R_RISCV_JAL, + R_RISCV_LO12_I, + R_RISCV_LO12_S, + R_RISCV_PCREL_HI20, + R_RISCV_PCREL_LO12_I, + R_RISCV_PCREL_LO12_S, + R_RISCV_RELAX, + R_RISCV_RVC_BRANCH, + R_RISCV_RVC_JUMP, + -1 + } }, + { "riscv64", 8, 0, EM_RISCV, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_RISCV_32, + R_RISCV_64, + R_RISCV_ADD8, + R_RISCV_ADD16, + R_RISCV_ADD32, + R_RISCV_ADD64, + R_RISCV_SUB8, + R_RISCV_SUB16, + R_RISCV_SUB32, + R_RISCV_SUB64, + R_RISCV_ALIGN, + R_RISCV_BRANCH, + R_RISCV_CALL, + R_RISCV_CALL_PLT, + R_RISCV_GOT_HI20, + R_RISCV_HI20, + R_RISCV_JAL, + R_RISCV_LO12_I, + R_RISCV_LO12_S, + R_RISCV_PCREL_HI20, + R_RISCV_PCREL_LO12_I, + R_RISCV_PCREL_LO12_S, + R_RISCV_RELAX, + R_RISCV_RVC_BRANCH, + R_RISCV_RVC_JUMP, + -1 + } + }, +}; + +struct platform_whitelist { + const char *arch; + const char *platform; + const char **whitelist_empty; +}; + +static struct platform_whitelist whitelists[] = { + {"i386", "xen", (const char *[]) {"all_video", 0}}, + {"i386", "xen_pvh", (const char *[]) {"all_video", 0}}, + {"x86_64", "xen", (const char *[]) {"all_video", 0}}, + {"sparc64", "ieee1275", (const char *[]) {"all_video", 0}}, + + /* video is compiled-in on MIPS. */ + {"mipsel", "loongson", (const char *[]) {"all_video", 0}}, + {"mipsel", "qemu_mips", (const char *[]) {"all_video", 0}}, + {"mipsel", "arc", (const char *[]) {"all_video", 0}}, + {"mips", "qemu_mips", (const char *[]) {"all_video", 0}}, + {"mips", "arc", (const char *[]) {"all_video", 0}}, +}; + + +int +main (int argc, char **argv) +{ + size_t module_size; + unsigned arch, whitelist; + const char **whitelist_empty = 0; + char *module_img; + if (argc != 4) { + fprintf (stderr, "usage: %s FILE ARCH PLATFORM\n", argv[0]); + return 1; + } + + for (arch = 0; arch < ARRAY_SIZE(archs); arch++) + if (strcmp(archs[arch].name, argv[2]) == 0) + break; + if (arch == ARRAY_SIZE(archs)) + grub_util_error("%s: unknown arch: %s", argv[1], argv[2]); + + for (whitelist = 0; whitelist < ARRAY_SIZE(whitelists); whitelist++) + if (strcmp(whitelists[whitelist].arch, argv[2]) == 0 + && strcmp(whitelists[whitelist].platform, argv[3]) == 0) + break; + if (whitelist != ARRAY_SIZE(whitelists)) + whitelist_empty = whitelists[whitelist].whitelist_empty; + + module_size = grub_util_get_image_size (argv[1]); + module_img = grub_util_read_image (argv[1]); + if (archs[arch].voidp_sizeof == 8) + grub_module_verify64(argv[1], module_img, module_size, &archs[arch], whitelist_empty); + else + grub_module_verify32(argv[1], module_img, module_size, &archs[arch], whitelist_empty); + return 0; +} diff --git a/util/grub-module-verifier32.c b/util/grub-module-verifier32.c new file mode 100644 index 0000000..257229f --- /dev/null +++ b/util/grub-module-verifier32.c @@ -0,0 +1,2 @@ +#define MODULEVERIFIER_ELF32 1 +#include "grub-module-verifierXX.c" diff --git a/util/grub-module-verifier64.c b/util/grub-module-verifier64.c new file mode 100644 index 0000000..4db6b4b --- /dev/null +++ b/util/grub-module-verifier64.c @@ -0,0 +1,2 @@ +#define MODULEVERIFIER_ELF64 1 +#include "grub-module-verifierXX.c" diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c new file mode 100644 index 0000000..ceb2430 --- /dev/null +++ b/util/grub-module-verifierXX.c @@ -0,0 +1,439 @@ +#include <string.h> + +#include <grub/elf.h> +#include <grub/module_verifier.h> +#include <grub/util/misc.h> + +#if defined(MODULEVERIFIER_ELF32) +# define SUFFIX(x) x ## 32 +# define ELFCLASSXX ELFCLASS32 +# define Elf_Ehdr Elf32_Ehdr +# define Elf_Phdr Elf32_Phdr +# define Elf_Nhdr Elf32_Nhdr +# 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_Word Elf32_Word +# define Elf_Half Elf32_Half +# define Elf_Section Elf32_Section +# define ELF_R_SYM(val) ELF32_R_SYM(val) +# define ELF_R_TYPE(val) ELF32_R_TYPE(val) +# define ELF_ST_TYPE(val) ELF32_ST_TYPE(val) +#elif defined(MODULEVERIFIER_ELF64) +# define SUFFIX(x) x ## 64 +# define ELFCLASSXX ELFCLASS64 +# define Elf_Ehdr Elf64_Ehdr +# define Elf_Phdr Elf64_Phdr +# define Elf_Nhdr Elf64_Nhdr +# 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_Word Elf64_Word +# define Elf_Half Elf64_Half +# define Elf_Section Elf64_Section +# define ELF_R_SYM(val) ELF64_R_SYM(val) +# define ELF_R_TYPE(val) ELF64_R_TYPE(val) +# define ELF_ST_TYPE(val) ELF64_ST_TYPE(val) +#else +#error "I'm confused" +#endif + +#define grub_target_to_host32(x) (grub_target_to_host32_real (arch, (x))) +#define grub_host_to_target32(x) (grub_host_to_target32_real (arch, (x))) +#define grub_target_to_host64(x) (grub_target_to_host64_real (arch, (x))) +#define grub_host_to_target64(x) (grub_host_to_target64_real (arch, (x))) +#define grub_host_to_target_addr(x) (grub_host_to_target_addr_real (arch, (x))) +#define grub_target_to_host16(x) (grub_target_to_host16_real (arch, (x))) +#define grub_host_to_target16(x) (grub_host_to_target16_real (arch, (x))) +#define grub_target_to_host(val) grub_target_to_host_real(arch, (val)) + +static inline grub_uint32_t +grub_target_to_host32_real (const struct grub_module_verifier_arch *arch, + grub_uint32_t in) +{ + if (arch->bigendian) + return grub_be_to_cpu32 (in); + else + return grub_le_to_cpu32 (in); +} + +static inline grub_uint64_t +grub_target_to_host64_real (const struct grub_module_verifier_arch *arch, + grub_uint64_t in) +{ + if (arch->bigendian) + return grub_be_to_cpu64 (in); + else + return grub_le_to_cpu64 (in); +} + +static inline grub_uint64_t +grub_host_to_target64_real (const struct grub_module_verifier_arch *arch, + grub_uint64_t in) +{ + if (arch->bigendian) + return grub_cpu_to_be64 (in); + else + return grub_cpu_to_le64 (in); +} + +static inline grub_uint32_t +grub_host_to_target32_real (const struct grub_module_verifier_arch *arch, + grub_uint32_t in) +{ + if (arch->bigendian) + return grub_cpu_to_be32 (in); + else + return grub_cpu_to_le32 (in); +} + +static inline grub_uint16_t +grub_target_to_host16_real (const struct grub_module_verifier_arch *arch, + grub_uint16_t in) +{ + if (arch->bigendian) + return grub_be_to_cpu16 (in); + else + return grub_le_to_cpu16 (in); +} + +static inline grub_uint16_t +grub_host_to_target16_real (const struct grub_module_verifier_arch *arch, + grub_uint16_t in) +{ + if (arch->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 (const struct grub_module_verifier_arch *arch, grub_uint64_t in) +{ + if (arch->voidp_sizeof == 8) + return grub_host_to_target64_real (arch, in); + else + return grub_host_to_target32_real (arch, in); +} + +static inline grub_uint64_t +grub_target_to_host_real (const struct grub_module_verifier_arch *arch, grub_uint64_t in) +{ + if (arch->voidp_sizeof == 8) + return grub_target_to_host64_real (arch, in); + else + return grub_target_to_host32_real (arch, in); +} + + +static Elf_Shdr * +find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const char *name) +{ + Elf_Shdr *s; + const char *str; + unsigned i; + + s = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + grub_target_to_host16 (e->e_shstrndx) * grub_target_to_host16 (e->e_shentsize)); + str = (char *) e + grub_target_to_host (s->sh_offset); + + for (i = 0, s = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff)); + i < grub_target_to_host16 (e->e_shnum); + i++, s = (Elf_Shdr *) ((char *) s + grub_target_to_host16 (e->e_shentsize))) + if (strcmp (str + grub_target_to_host32 (s->sh_name), name) == 0) + return s; + return NULL; +} + +static void +check_license (const char * const filename, + const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) +{ + Elf_Shdr *s = find_section (arch, e, ".module_license"); + if (s && (strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv3") == 0 + || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv3+") == 0 + || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv2+") == 0)) + return; + grub_util_error ("%s: incompatible license", filename); +} + +static Elf_Sym * +get_symtab (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word *size, Elf_Word *entsize) +{ + unsigned i; + Elf_Shdr *s, *sections; + Elf_Sym *sym; + + sections = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff)); + for (i = 0, s = sections; + i < grub_target_to_host16 (e->e_shnum); + i++, s = (Elf_Shdr *) ((char *) s + grub_target_to_host16 (e->e_shentsize))) + if (grub_target_to_host32 (s->sh_type) == SHT_SYMTAB) + break; + + if (i == grub_target_to_host16 (e->e_shnum)) + return NULL; + + sym = (Elf_Sym *) ((char *) e + grub_target_to_host (s->sh_offset)); + *size = grub_target_to_host (s->sh_size); + *entsize = grub_target_to_host (s->sh_entsize); + return sym; +} + +static int +is_whitelisted (const char *modname, const char **whitelist) +{ + const char **ptr; + if (!whitelist) + return 0; + if (!modname) + return 0; + for (ptr = whitelist; *ptr; ptr++) + if (strcmp (modname, *ptr) == 0) + return 1; + return 0; +} + +static void +check_symbols (const struct grub_module_verifier_arch *arch, + Elf_Ehdr *e, const char *modname, + const char **whitelist_empty) +{ + Elf_Sym *sym; + Elf_Word size, entsize; + unsigned i; + + /* Module without symbol table and without .moddeps section is useless + at boot time, so catch it early to prevent build errors */ + sym = get_symtab (arch, e, &size, &entsize); + if (!sym) + { + Elf_Shdr *s; + + /* However some modules are dependencies-only, + e.g. insmod all_video pulls in all video drivers. + Some platforms e.g. xen have no video drivers, so + the module does nothing. */ + if (is_whitelisted (modname, whitelist_empty)) + return; + + s = find_section (arch, e, ".moddeps"); + + if (!s) + grub_util_error ("%s: no symbol table and no .moddeps section", modname); + + if (!s->sh_size) + grub_util_error ("%s: no symbol table and empty .moddeps section", modname); + + return; + } + + for (i = 0; + i < size / entsize; + i++, sym = (Elf_Sym *) ((char *) sym + entsize)) + { + unsigned char type = ELF_ST_TYPE (sym->st_info); + + switch (type) + { + case STT_NOTYPE: + case STT_OBJECT: + case STT_FUNC: + case STT_SECTION: + case STT_FILE: + break; + + default: + return grub_util_error ("%s: unknown symbol type `%d'", modname, (int) type); + } + } +} + +static int +is_symbol_local(Elf_Sym *sym) +{ + switch (ELF_ST_TYPE (sym->st_info)) + { + case STT_NOTYPE: + case STT_OBJECT: + if (sym->st_name != 0 && sym->st_shndx == 0) + return 0; + return 1; + + case STT_FUNC: + case STT_SECTION: + return 1; + + default: + return 0; + } +} + +static void +section_check_relocations (const char * const modname, + const struct grub_module_verifier_arch *arch, void *ehdr, + Elf_Shdr *s, size_t target_seg_size) +{ + Elf_Rel *rel, *max; + Elf_Sym *symtab; + Elf_Word symtabsize, symtabentsize; + + symtab = get_symtab (arch, ehdr, &symtabsize, &symtabentsize); + if (!symtab) + grub_util_error ("%s: relocation without symbol table", modname); + + for (rel = (Elf_Rel *) ((char *) ehdr + grub_target_to_host (s->sh_offset)), + max = (Elf_Rel *) ((char *) rel + grub_target_to_host (s->sh_size)); + rel < max; + rel = (Elf_Rel *) ((char *) rel + grub_target_to_host (s->sh_entsize))) + { + Elf_Sym *sym; + unsigned i; + + if (target_seg_size < grub_target_to_host (rel->r_offset)) + grub_util_error ("%s: reloc offset is out of the segment", modname); + + grub_uint32_t type = ELF_R_TYPE (grub_target_to_host (rel->r_info)); + + if (arch->machine == EM_SPARCV9) + type &= 0xff; + + for (i = 0; arch->supported_relocations[i] != -1; i++) + if (type == arch->supported_relocations[i]) + break; + if (arch->supported_relocations[i] != -1) + continue; + if (!arch->short_relocations) + grub_util_error ("%s: unsupported relocation 0x%x", modname, type); + for (i = 0; arch->short_relocations[i] != -1; i++) + if (type == arch->short_relocations[i]) + break; + if (arch->short_relocations[i] == -1) + grub_util_error ("%s: unsupported relocation 0x%x", modname, type); + sym = (Elf_Sym *) ((char *) symtab + symtabentsize * ELF_R_SYM (grub_target_to_host (rel->r_info))); + + if (is_symbol_local (sym)) + continue; + grub_util_error ("%s: relocation 0x%x is not module-local", modname, type); + } +#if defined(MODULEVERIFIER_ELF64) + if (arch->machine == EM_AARCH64) + { + unsigned unmatched_adr_got_page = 0; + Elf_Rela *rel2; + for (rel = (Elf_Rel *) ((char *) ehdr + grub_target_to_host (s->sh_offset)), + max = (Elf_Rel *) ((char *) rel + grub_target_to_host (s->sh_size)); + rel < max; + rel = (Elf_Rel *) ((char *) rel + grub_target_to_host (s->sh_entsize))) + { + switch (ELF_R_TYPE (grub_target_to_host (rel->r_info))) + { + case R_AARCH64_ADR_GOT_PAGE: + unmatched_adr_got_page++; + for (rel2 = (Elf_Rela *) ((char *) rel + grub_target_to_host (s->sh_entsize)); + rel2 < (Elf_Rela *) max; + rel2 = (Elf_Rela *) ((char *) rel2 + grub_target_to_host (s->sh_entsize))) + if (ELF_R_SYM (rel2->r_info) + == ELF_R_SYM (rel->r_info) + && ((Elf_Rela *) rel)->r_addend == rel2->r_addend + && ELF_R_TYPE (rel2->r_info) == R_AARCH64_LD64_GOT_LO12_NC) + break; + if (rel2 >= (Elf_Rela *) max) + grub_util_error ("%s: ADR_GOT_PAGE without matching LD64_GOT_LO12_NC", modname); + break; + case R_AARCH64_LD64_GOT_LO12_NC: + if (unmatched_adr_got_page == 0) + grub_util_error ("%s: LD64_GOT_LO12_NC without matching ADR_GOT_PAGE", modname); + unmatched_adr_got_page--; + break; + } + } + } +#endif +} + +static void +check_relocations (const char * const modname, + const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) +{ + Elf_Shdr *s; + unsigned i; + + for (i = 0, s = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff)); + i < grub_target_to_host16 (e->e_shnum); + i++, s = (Elf_Shdr *) ((char *) s + grub_target_to_host16 (e->e_shentsize))) + if (grub_target_to_host32 (s->sh_type) == SHT_REL || grub_target_to_host32 (s->sh_type) == SHT_RELA) + { + Elf_Shdr *ts; + + if (grub_target_to_host32 (s->sh_type) == SHT_REL && !(arch->flags & GRUB_MODULE_VERIFY_SUPPORTS_REL)) + grub_util_error ("%s: unsupported SHT_REL", modname); + if (grub_target_to_host32 (s->sh_type) == SHT_RELA && !(arch->flags & GRUB_MODULE_VERIFY_SUPPORTS_RELA)) + grub_util_error ("%s: unsupported SHT_RELA", modname); + + /* Find the target segment. */ + if (grub_target_to_host32 (s->sh_info) >= grub_target_to_host16 (e->e_shnum)) + grub_util_error ("%s: orphaned reloc section", modname); + ts = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + grub_target_to_host32 (s->sh_info) * grub_target_to_host16 (e->e_shentsize)); + + section_check_relocations (modname, arch, e, s, grub_target_to_host (ts->sh_size)); + } +} + +void +SUFFIX(grub_module_verify) (const char * const filename, + void *module_img, size_t size, + const struct grub_module_verifier_arch *arch, + const char **whitelist_empty) +{ + Elf_Ehdr *e = module_img; + + /* Check the header size. */ + if (size < sizeof (Elf_Ehdr)) + grub_util_error ("%s: ELF header smaller than expected", filename); + + /* Check the magic numbers. */ + if (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 + || grub_target_to_host32 (e->e_version) != EV_CURRENT) + grub_util_error ("%s: invalid arch-independent ELF magic", filename); + + if (e->e_ident[EI_CLASS] != ELFCLASSXX + || e->e_ident[EI_DATA] != (arch->bigendian ? ELFDATA2MSB : ELFDATA2LSB) + || grub_target_to_host16 (e->e_machine) != arch->machine) + grub_util_error ("%s: invalid arch-dependent ELF magic", filename); + + if (grub_target_to_host16 (e->e_type) != ET_REL) + { + grub_util_error ("%s: this ELF file is not of the right type", filename); + } + + /* Make sure that every section is within the core. */ + if (size < grub_target_to_host (e->e_shoff) + + (grub_uint32_t) grub_target_to_host16 (e->e_shentsize) * grub_target_to_host16(e->e_shnum)) + { + grub_util_error ("%s: ELF sections outside core", filename); + } + + check_license (filename, arch, e); + + Elf_Shdr *s; + const char *modname; + + s = find_section (arch, e, ".modname"); + if (!s) + grub_util_error ("%s: no module name found", filename); + + modname = (const char *) e + grub_target_to_host (s->sh_offset); + + check_symbols(arch, e, modname, whitelist_empty); + check_relocations(modname, arch, e); +} diff --git a/util/grub-mount.c b/util/grub-mount.c new file mode 100644 index 0000000..d7be2a4 --- /dev/null +++ b/util/grub-mount.c @@ -0,0 +1,620 @@ +/* grub-mount.c - FUSE driver for filesystems that GRUB understands */ +/* + * 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 <http://www.gnu.org/licenses/>. + */ +#define FUSE_USE_VERSION 26 +#include <config.h> +#include <grub/types.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/misc.h> +#include <grub/device.h> +#include <grub/disk.h> +#include <grub/file.h> +#include <grub/fs.h> +#include <grub/env.h> +#include <grub/term.h> +#include <grub/mm.h> +#include <grub/lib/hexdump.h> +#include <grub/crypto.h> +#include <grub/command.h> +#include <grub/zfs/zfs.h> +#include <grub/i18n.h> +#include <fuse/fuse.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include "progname.h" + +static const char *root = NULL; +grub_device_t dev = NULL; +grub_fs_t fs = NULL; +static char **images = NULL; +static char *debug_str = NULL; +static char **fuse_args = NULL; +static int fuse_argc = 0; +static int num_disks = 0; +static int mount_crypt = 0; + +static grub_err_t +execute_command (const 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); +} + +/* Translate GRUB error numbers into OS error numbers. Print any unexpected + errors. */ +static int +translate_error (void) +{ + int ret; + + switch (grub_errno) + { + case GRUB_ERR_NONE: + ret = 0; + break; + + case GRUB_ERR_OUT_OF_MEMORY: + grub_print_error (); + ret = -ENOMEM; + break; + + case GRUB_ERR_BAD_FILE_TYPE: + /* This could also be EISDIR. Take a guess. */ + ret = -ENOTDIR; + break; + + case GRUB_ERR_FILE_NOT_FOUND: + ret = -ENOENT; + break; + + case GRUB_ERR_FILE_READ_ERROR: + case GRUB_ERR_READ_ERROR: + case GRUB_ERR_IO: + grub_print_error (); + ret = -EIO; + break; + + case GRUB_ERR_SYMLINK_LOOP: + ret = -ELOOP; + break; + + default: + grub_print_error (); + ret = -EINVAL; + break; + } + + /* Any previous errors were handled. */ + grub_errno = GRUB_ERR_NONE; + + return ret; +} + +/* Context for fuse_getattr. */ +struct fuse_getattr_ctx +{ + char *filename; + struct grub_dirhook_info file_info; + int file_exists; +}; + +/* A hook for iterating directories. */ +static int +fuse_getattr_find_file (const char *cur_filename, + const struct grub_dirhook_info *info, void *data) +{ + struct fuse_getattr_ctx *ctx = data; + + if ((info->case_insensitive ? grub_strcasecmp (cur_filename, ctx->filename) + : grub_strcmp (cur_filename, ctx->filename)) == 0) + { + ctx->file_info = *info; + ctx->file_exists = 1; + return 1; + } + return 0; +} + +static int +fuse_getattr (const char *path, struct stat *st) +{ + struct fuse_getattr_ctx ctx; + char *pathname, *path2; + + if (path[0] == '/' && path[1] == 0) + { + st->st_dev = 0; + st->st_ino = 0; + st->st_mode = 0555 | S_IFDIR; + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + st->st_size = 0; + st->st_blksize = 512; + st->st_blocks = (st->st_blksize + 511) >> 9; + st->st_atime = st->st_mtime = st->st_ctime = 0; + return 0; + } + + ctx.file_exists = 0; + + pathname = xstrdup (path); + + /* Remove trailing '/'. */ + while (*pathname && pathname[grub_strlen (pathname) - 1] == '/') + pathname[grub_strlen (pathname) - 1] = 0; + + /* Split into path and filename. */ + ctx.filename = grub_strrchr (pathname, '/'); + if (! ctx.filename) + { + path2 = grub_strdup ("/"); + ctx.filename = pathname; + } + else + { + ctx.filename++; + path2 = grub_strdup (pathname); + path2[ctx.filename - pathname] = 0; + } + + /* It's the whole device. */ + (fs->fs_dir) (dev, path2, fuse_getattr_find_file, &ctx); + + grub_free (path2); + if (!ctx.file_exists) + { + grub_errno = GRUB_ERR_NONE; + return -ENOENT; + } + st->st_dev = 0; + st->st_ino = 0; + st->st_mode = ctx.file_info.dir ? (0555 | S_IFDIR) : (0444 | S_IFREG); + st->st_uid = 0; + st->st_gid = 0; + st->st_rdev = 0; + st->st_size = 0; + if (!ctx.file_info.dir) + { + grub_file_t file; + file = grub_file_open (path, GRUB_FILE_TYPE_GET_SIZE); + if (! file && grub_errno == GRUB_ERR_BAD_FILE_TYPE) + { + grub_errno = GRUB_ERR_NONE; + st->st_mode = (0555 | S_IFDIR); + } + else if (! file) + return translate_error (); + else + { + st->st_size = file->size; + grub_file_close (file); + } + } + st->st_blksize = 512; + st->st_blocks = (st->st_size + 511) >> 9; + st->st_atime = st->st_mtime = st->st_ctime = ctx.file_info.mtimeset + ? ctx.file_info.mtime : 0; + grub_errno = GRUB_ERR_NONE; + return 0; +} + +static int +fuse_opendir (const char *path, struct fuse_file_info *fi) +{ + return 0; +} + +/* FIXME */ +static grub_file_t files[65536]; +static int first_fd = 1; + +static int +fuse_open (const char *path, struct fuse_file_info *fi __attribute__ ((unused))) +{ + grub_file_t file; + file = grub_file_open (path, GRUB_FILE_TYPE_MOUNT); + if (! file) + return translate_error (); + files[first_fd++] = file; + fi->fh = first_fd; + files[first_fd++] = file; + grub_errno = GRUB_ERR_NONE; + return 0; +} + +static int +fuse_read (const char *path, char *buf, size_t sz, off_t off, + struct fuse_file_info *fi) +{ + grub_file_t file = files[fi->fh]; + grub_ssize_t size; + + if (off > file->size) + return -EINVAL; + + file->offset = off; + + size = grub_file_read (file, buf, sz); + if (size < 0) + return translate_error (); + else + { + grub_errno = GRUB_ERR_NONE; + return size; + } +} + +static int +fuse_release (const char *path, struct fuse_file_info *fi) +{ + grub_file_close (files[fi->fh]); + files[fi->fh] = NULL; + grub_errno = GRUB_ERR_NONE; + return 0; +} + +/* Context for fuse_readdir. */ +struct fuse_readdir_ctx +{ + const char *path; + void *buf; + fuse_fill_dir_t fill; +}; + +/* Helper for fuse_readdir. */ +static int +fuse_readdir_call_fill (const char *filename, + const struct grub_dirhook_info *info, void *data) +{ + struct fuse_readdir_ctx *ctx = data; + struct stat st; + + grub_memset (&st, 0, sizeof (st)); + st.st_mode = info->dir ? (0555 | S_IFDIR) : (0444 | S_IFREG); + if (!info->dir) + { + grub_file_t file; + char *tmp; + tmp = xasprintf ("%s/%s", ctx->path, filename); + file = grub_file_open (tmp, GRUB_FILE_TYPE_GET_SIZE); + free (tmp); + /* Symlink to directory. */ + if (! file && grub_errno == GRUB_ERR_BAD_FILE_TYPE) + { + grub_errno = GRUB_ERR_NONE; + st.st_mode = (0555 | S_IFDIR); + } + else if (!file) + { + grub_errno = GRUB_ERR_NONE; + } + else + { + st.st_size = file->size; + grub_file_close (file); + } + } + st.st_blksize = 512; + st.st_blocks = (st.st_size + 511) >> 9; + st.st_atime = st.st_mtime = st.st_ctime + = info->mtimeset ? info->mtime : 0; + ctx->fill (ctx->buf, filename, &st, 0); + return 0; +} + +static int +fuse_readdir (const char *path, void *buf, + fuse_fill_dir_t fill, off_t off, struct fuse_file_info *fi) +{ + struct fuse_readdir_ctx ctx = { + .path = path, + .buf = buf, + .fill = fill + }; + char *pathname; + + pathname = xstrdup (path); + + /* Remove trailing '/'. */ + while (pathname [0] && pathname[1] + && pathname[grub_strlen (pathname) - 1] == '/') + pathname[grub_strlen (pathname) - 1] = 0; + + (fs->fs_dir) (dev, pathname, fuse_readdir_call_fill, &ctx); + free (pathname); + grub_errno = GRUB_ERR_NONE; + return 0; +} + +struct fuse_operations grub_opers = { + .getattr = fuse_getattr, + .open = fuse_open, + .release = fuse_release, + .opendir = fuse_opendir, + .readdir = fuse_readdir, + .read = fuse_read +}; + +static grub_err_t +fuse_init (void) +{ + int i; + + for (i = 0; i < num_disks; i++) + { + char *argv[2]; + char *host_file; + char *loop_name; + loop_name = grub_xasprintf ("loop%d", i); + if (!loop_name) + grub_util_error ("%s", grub_errmsg); + + host_file = grub_xasprintf ("(host)%s", images[i]); + if (!host_file) + grub_util_error ("%s", grub_errmsg); + + argv[0] = loop_name; + argv[1] = host_file; + + if (execute_command ("loopback", 2, argv)) + grub_util_error (_("`loopback' command fails: %s"), grub_errmsg); + + grub_free (loop_name); + grub_free (host_file); + } + + if (mount_crypt) + { + char *argv[2] = { xstrdup ("-a"), NULL}; + if (execute_command ("cryptomount", 1, argv)) + grub_util_error (_("`cryptomount' command fails: %s"), + grub_errmsg); + free (argv[0]); + } + + grub_lvm_fini (); + grub_mdraid09_fini (); + grub_mdraid1x_fini (); + grub_diskfilter_fini (); + grub_diskfilter_init (); + grub_mdraid09_init (); + grub_mdraid1x_init (); + grub_lvm_init (); + + dev = grub_device_open (0); + if (! dev) + return grub_errno; + + fs = grub_fs_probe (dev); + if (! fs) + { + grub_device_close (dev); + return grub_errno; + } + + if (fuse_main (fuse_argc, fuse_args, &grub_opers, NULL)) + grub_error (GRUB_ERR_IO, "fuse_main failed"); + + for (i = 0; i < num_disks; i++) + { + char *argv[2]; + char *loop_name; + + loop_name = grub_xasprintf ("loop%d", i); + if (!loop_name) + grub_util_error ("%s", grub_errmsg); + + argv[0] = xstrdup ("-d"); + argv[1] = loop_name; + + execute_command ("loopback", 2, argv); + + grub_free (argv[0]); + grub_free (loop_name); + } + + return grub_errno; +} + +static struct argp_option options[] = { + {"root", 'r', N_("DEVICE_NAME"), 0, N_("Set root device."), 2}, + {"debug", 'd', N_("STRING"), 0, N_("Set debug environment variable."), 2}, + {"crypto", 'C', NULL, 0, N_("Mount crypto devices."), 2}, + {"zfs-key", 'K', + /* TRANSLATORS: "prompt" is a keyword. */ + N_("FILE|prompt"), 0, N_("Load zfs crypto key."), 2}, + {"verbose", 'v', NULL, 0, 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; + +static error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'r': + root = arg; + return 0; + + case 'K': + if (strcmp (arg, "prompt") == 0) + { + char buf[1024]; + grub_printf ("%s", _("Enter ZFS password: ")); + if (grub_password_get (buf, 1023)) + { + grub_zfs_add_key ((grub_uint8_t *) buf, grub_strlen (buf), 1); + } + } + else + { + FILE *f; + ssize_t real_size; + grub_uint8_t buf[1024]; + f = grub_util_fopen (arg, "rb"); + if (!f) + { + printf (_("%s: error:"), program_name); + printf (_("cannot open `%s': %s"), arg, strerror (errno)); + printf ("\n"); + return 0; + } + real_size = fread (buf, 1, 1024, f); + if (real_size < 0) + { + printf (_("%s: error:"), program_name); + printf (_("cannot read `%s': %s"), arg, + strerror (errno)); + printf ("\n"); + fclose (f); + return 0; + } + grub_zfs_add_key (buf, real_size, 0); + fclose (f); + } + return 0; + + case 'C': + mount_crypt = 1; + return 0; + + case 'd': + debug_str = arg; + return 0; + + case 'v': + verbosity++; + return 0; + + case ARGP_KEY_ARG: + if (arg[0] != '-') + break; + + /* FALLTHROUGH */ + default: + if (!arg) + return 0; + + fuse_args = xrealloc (fuse_args, (fuse_argc + 1) * sizeof (fuse_args[0])); + fuse_args[fuse_argc] = xstrdup (arg); + fuse_argc++; + return 0; + } + + images = xrealloc (images, (num_disks + 1) * sizeof (images[0])); + images[num_disks] = grub_canonicalize_file_name (arg); + num_disks++; + + return 0; +} + +struct argp argp = { + options, argp_parser, N_("IMAGE1 [IMAGE2 ...] MOUNTPOINT"), + N_("Debug tool for filesystem driver."), + NULL, NULL, NULL +}; + +int +main (int argc, char *argv[]) +{ + const char *default_root; + char *alloc_root; + + grub_util_host_init (&argc, &argv); + + fuse_args = xrealloc (fuse_args, (fuse_argc + 2) * sizeof (fuse_args[0])); + fuse_args[fuse_argc] = xstrdup (argv[0]); + fuse_argc++; + /* Run single-threaded. */ + fuse_args[fuse_argc] = xstrdup ("-s"); + fuse_argc++; + + argp_parse (&argp, argc, argv, 0, 0, 0); + + if (num_disks < 2) + grub_util_error ("%s", _("need an image and mountpoint")); + fuse_args = xrealloc (fuse_args, (fuse_argc + 2) * sizeof (fuse_args[0])); + fuse_args[fuse_argc] = images[num_disks - 1]; + fuse_argc++; + num_disks--; + fuse_args[fuse_argc] = NULL; + + /* 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. */ + fuse_init (); + if (grub_errno) + { + grub_print_error (); + return 1; + } + + /* Free resources. */ + grub_fini_all (); + + return 0; +} diff --git a/util/grub-pe2elf.c b/util/grub-pe2elf.c new file mode 100644 index 0000000..1133129 --- /dev/null +++ b/util/grub-pe2elf.c @@ -0,0 +1,573 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/util/misc.h> +#include <grub/elf.h> +#include <grub/efi/pe32.h> +#include <grub/misc.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> + + +/* Please don't internationalise this file. It's pointless. */ + +/* + * Section layout + * + * null + * .text + * .rdata + * .data + * .bss + * .modname + * .moddeps + * .symtab + * .strtab + * relocation sections + */ + +#if GRUB_TARGET_WORDSIZE == 64 +typedef Elf64_Rela elf_reloc_t; +#define GRUB_PE32_MACHINE GRUB_PE32_MACHINE_X86_64 +#else +typedef Elf32_Rel elf_reloc_t; +#define GRUB_PE32_MACHINE GRUB_PE32_MACHINE_I386 +#endif + +#define STRTAB_BLOCK 256 + +static char *strtab; +static int strtab_max, strtab_len; + +static Elf_Ehdr ehdr; +static Elf_Shdr *shdr; +static int num_sections, first_reloc_section, reloc_sections_end, symtab_section, strtab_section; +static grub_uint32_t offset, image_base; + +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, const char *name, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr) +{ + int *section_map; + int i; + grub_uint32_t last_category = 0; + grub_uint32_t idx, idx_reloc; + char *pe_strtab = (image + pe_chdr->symtab_offset + + pe_chdr->num_symbols * sizeof (struct grub_pe32_symbol)); + + section_map = xcalloc (2 * pe_chdr->num_sections + 5, sizeof (int)); + section_map[0] = 0; + shdr = xcalloc (2 * pe_chdr->num_sections + 5, sizeof (shdr[0])); + idx = 1; + idx_reloc = pe_chdr->num_sections + 1; + + for (i = 0; i < pe_chdr->num_sections; i++, pe_shdr++) + { + grub_uint32_t category; + const char *shname = pe_shdr->name; + grub_size_t secsize; + + if (shname[0] == '/' && grub_isdigit (shname[1])) + { + char t[sizeof (pe_shdr->name) + 1]; + memcpy (t, shname, sizeof (pe_shdr->name)); + t[sizeof (pe_shdr->name)] = 0; + shname = pe_strtab + atoi (t + 1); + } + + secsize = pe_shdr->raw_data_size; + + shdr[idx].sh_type = SHT_PROGBITS; + + if (! strcmp (shname, ".text")) + { + category = 0; + shdr[idx].sh_flags = SHF_ALLOC | SHF_EXECINSTR; + } + else if (! strncmp (shname, ".rdata", 6)) + { + category = 1; + shdr[idx].sh_flags = SHF_ALLOC; + } + else if (! strcmp (shname, ".data")) + { + category = 2; + shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; + } + else if (! strcmp (shname, ".bss")) + { + category = 3; + shdr[idx].sh_type = SHT_NOBITS; + shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; + if (secsize < pe_shdr->virtual_size) + secsize = pe_shdr->virtual_size; + } + else if (strcmp (shname, ".modname") == 0 || strcmp (shname, ".moddeps") == 0 + || strcmp (shname, ".module_license") == 0) + category = 4; + else + { + section_map[i + 1] = -1; + continue; + } + + if (category < last_category) + grub_util_error ("out of order sections"); + + section_map[i + 1] = idx; + + if (pe_shdr->virtual_size + && pe_shdr->virtual_size < secsize) + secsize = pe_shdr->virtual_size; + + shdr[idx].sh_size = secsize; + shdr[idx].sh_addralign = 1 << (((pe_shdr->characteristics >> + GRUB_PE32_SCN_ALIGN_SHIFT) & + GRUB_PE32_SCN_ALIGN_MASK) - 1); + shdr[idx].sh_addr = pe_shdr->virtual_address + image_base; + + if (shdr[idx].sh_type != SHT_NOBITS) + { + shdr[idx].sh_offset = offset; + grub_util_write_image_at (image + pe_shdr->raw_data_offset, + pe_shdr->raw_data_size, offset, fp, + shname); + + offset += secsize; + } + + if (pe_shdr->relocations_offset) + { + char relname[5 + strlen (shname)]; + + sprintf (relname, ".rel%s", shname); + + shdr[idx_reloc].sh_name = insert_string (relname); + shdr[idx_reloc].sh_link = i; + shdr[idx_reloc].sh_info = idx; + + shdr[idx].sh_name = shdr[idx_reloc].sh_name + 4; + + idx_reloc++; + } + else + shdr[idx].sh_name = insert_string (shname); + idx++; + } + + idx_reloc -= pe_chdr->num_sections + 1; + num_sections = idx + idx_reloc + 2; + first_reloc_section = idx; + reloc_sections_end = idx + idx_reloc; + memmove (shdr + idx, shdr + pe_chdr->num_sections + 1, + idx_reloc * sizeof (shdr[0])); + memset (shdr + idx + idx_reloc, 0, 3 * sizeof (shdr[0])); + memset (shdr, 0, sizeof (shdr[0])); + + symtab_section = idx + idx_reloc; + strtab_section = idx + idx_reloc + 1; + + return section_map; +} + +static void +write_reloc_section (FILE* fp, const char *name, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr, + Elf_Sym *symtab, + int *symtab_map) +{ + int i; + + for (i = first_reloc_section; i < reloc_sections_end; i++) + { + struct grub_pe32_section_table *pe_sec; + struct grub_pe32_reloc *pe_rel; + elf_reloc_t *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 = (elf_reloc_t *) xcalloc (pe_sec->num_relocations, sizeof (elf_reloc_t)); + 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"); + + ofs = pe_rel->offset - pe_sec->virtual_address; + addr = (grub_uint32_t *)(image + pe_sec->raw_data_offset + ofs); + + switch (pe_rel->type) + { +#if GRUB_TARGET_WORDSIZE == 64 + case 1: + type = R_X86_64_64; + rel[num_rels].r_addend = *(grub_int64_t *)addr; + *(grub_int64_t *)addr = 0; + modified = 1; + break; + case 4: + type = R_X86_64_PC32; + rel[num_rels].r_addend = *(grub_int32_t *)addr; + *addr = 0; + modified = 1; + break; + case 14: + type = R_X86_64_PC64; + rel[num_rels].r_addend = *(grub_uint64_t *)addr - 8; + *(grub_uint64_t *)addr = 0; + modified = 1; + break; +#else + case GRUB_PE32_REL_I386_DIR32: + type = R_386_32; + break; + case GRUB_PE32_REL_I386_REL32: + type = R_386_PC32; + break; +#endif + default: + grub_util_error ("unknown pe relocation type %d", pe_rel->type); + } + + if (type == +#if GRUB_TARGET_WORDSIZE == 64 + R_386_PC32 +#else + R_X86_64_PC32 +#endif + + ) + { + unsigned char code; + + code = image[pe_sec->raw_data_offset + ofs - 1]; + +#if GRUB_TARGET_WORDSIZE == 32 + if (((code != 0xe8) && (code != 0xe9)) || (*addr)) + grub_util_error ("invalid relocation (%x %x)", code, *addr); +#endif + + if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx + && symtab[symtab_map[pe_rel->symtab_index]].st_shndx + == shdr[i].sh_info) + { + modified = 1; + *addr += (symtab[symtab_map[pe_rel->symtab_index]].st_value + - ofs - 4); + + continue; + } + else + { +#if GRUB_TARGET_WORDSIZE == 64 + rel[num_rels].r_addend -= 4; +#else + modified = 1; + *addr = -4; +#endif + } + } + + rel[num_rels].r_offset = ofs; + rel[num_rels].r_info = ELF_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, name); + +#if GRUB_TARGET_WORDSIZE == 64 + shdr[i].sh_type = SHT_RELA; +#else + shdr[i].sh_type = SHT_REL; +#endif + shdr[i].sh_offset = offset; + shdr[i].sh_link = symtab_section; + shdr[i].sh_addralign = 4; + shdr[i].sh_entsize = sizeof (elf_reloc_t); + shdr[i].sh_size = num_rels * sizeof (elf_reloc_t); + + grub_util_write_image_at (rel, shdr[i].sh_size, offset, fp, name); + offset += shdr[i].sh_size; + free (rel); + } +} + +static void +write_symbol_table (FILE* fp, const char *name, 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; + Elf_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 = (Elf_Sym *) xcalloc (pe_chdr->num_symbols + 1, sizeof (Elf_Sym)); + num_syms = 1; + + symtab_map = (int *) xcalloc (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 *symname; + + if (pe_symtab->long_name[0]) + { + strncpy (short_name, pe_symtab->short_name, 8); + short_name[8] = 0; + symname = short_name; + } + else + symname = pe_strtab + pe_symtab->long_name[1]; + + if ((strcmp (symname, "_grub_mod_init")) && + (strcmp (symname, "_grub_mod_fini")) && + (strcmp (symname, "grub_mod_init")) && + (strcmp (symname, "grub_mod_fini")) && + (bind == STB_LOCAL)) + continue; + + symtab[num_syms].st_name = insert_string (symname); + } + + symtab[num_syms].st_shndx = section_map[pe_symtab->section]; + symtab[num_syms].st_value = pe_symtab->value; + symtab[num_syms].st_info = ELF_ST_INFO (bind, type); + + symtab_map[i] = num_syms; + num_syms++; + } + + write_reloc_section (fp, name, 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 (Elf_Sym); + shdr[symtab_section].sh_entsize = sizeof (Elf_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, name); + offset += shdr[symtab_section].sh_size; + + free (symtab); + free (symtab_map); +} + +static void +write_string_table (FILE *fp, const char *name) +{ + 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, + name); + offset += strtab_len; + + free (strtab); +} + +static void +write_section_header (FILE *fp, const char *name) +{ + 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; + +#if GRUB_TARGET_WORDSIZE == 64 + ehdr.e_ident[EI_CLASS] = ELFCLASS64; + ehdr.e_ident[EI_DATA] = ELFDATA2LSB; + ehdr.e_machine = EM_X86_64; +#else + ehdr.e_ident[EI_CLASS] = ELFCLASS32; + ehdr.e_ident[EI_DATA] = ELFDATA2LSB; + ehdr.e_machine = EM_386; +#endif + ehdr.e_ehsize = sizeof (ehdr); + ehdr.e_shentsize = sizeof (Elf_Shdr); + ehdr.e_shstrndx = strtab_section; + + ehdr.e_shoff = offset; + ehdr.e_shnum = num_sections; + grub_util_write_image_at (shdr, sizeof (Elf_Shdr) * num_sections, + offset, fp, name); + + grub_util_write_image_at (&ehdr, sizeof (Elf_Ehdr), 0, fp, name); +} + +static void +convert_pe (FILE* fp, const char *name, char *image) +{ + struct grub_pe32_coff_header *pe_chdr; + struct grub_pe32_section_table *pe_shdr; + int *section_map; + + if (image[0] == 'M' && image[1] == 'Z') + pe_chdr = (struct grub_pe32_coff_header *) (image + (grub_le_to_cpu32 (((grub_uint32_t *)image)[0xf]) + 4)); + else + pe_chdr = (struct grub_pe32_coff_header *) image; + if (grub_le_to_cpu16 (pe_chdr->machine) != GRUB_PE32_MACHINE) + grub_util_error ("invalid coff image (%x != %x)", + grub_le_to_cpu16 (pe_chdr->machine), GRUB_PE32_MACHINE); + + strtab = xmalloc (STRTAB_BLOCK); + strtab_max = STRTAB_BLOCK; + strtab[0] = 0; + strtab_len = 1; + + offset = sizeof (ehdr); + if (pe_chdr->optional_header_size) + { +#if GRUB_TARGET_WORDSIZE == 64 + struct grub_pe64_optional_header *o; +#else + struct grub_pe32_optional_header *o; +#endif + o = (void *) (pe_chdr + 1); + image_base = o->image_base; + } + pe_shdr = (struct grub_pe32_section_table *) ((char *) (pe_chdr + 1) + pe_chdr->optional_header_size); + + section_map = write_section_data (fp, name, image, pe_chdr, pe_shdr); + + write_symbol_table (fp, name, image, pe_chdr, pe_shdr, section_map); + free (section_map); + + write_string_table (fp, name); + + write_section_header (fp, name); +} + +int +main (int argc, char *argv[]) +{ + char *image; + FILE* fp; + char *in, *out; + + /* Obtain PATH. */ + if (1 >= argc) + { + fprintf (stderr, "Filename not specified.\n"); + return 1; + } + + in = argv[1]; + if (argc > 2) + out = argv[2]; + else + out = in; + image = grub_util_read_image (in); + + fp = grub_util_fopen (out, "wb"); + if (! fp) + grub_util_error ("cannot open %s", out); + + convert_pe (fp, out, image); + + fclose (fp); + + return 0; +} diff --git a/util/grub-probe.c b/util/grub-probe.c new file mode 100644 index 0000000..c08e46b --- /dev/null +++ b/util/grub-probe.c @@ -0,0 +1,931 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/device.h> +#include <grub/disk.h> +#include <grub/file.h> +#include <grub/fs.h> +#include <grub/partition.h> +#include <grub/msdos_partition.h> +#include <grub/gpt_partition.h> +#include <grub/i386/pc/boot.h> +#include <grub/emu/hostdisk.h> +#include <grub/emu/getroot.h> +#include <grub/term.h> +#include <grub/env.h> +#include <grub/diskfilter.h> +#include <grub/i18n.h> +#include <grub/emu/misc.h> +#include <grub/util/ofpath.h> +#include <grub/crypto.h> +#include <grub/cryptodisk.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +#define _GNU_SOURCE 1 + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include "progname.h" + +enum { + PRINT_FS, + PRINT_FS_UUID, + PRINT_FS_LABEL, + PRINT_DRIVE, + PRINT_DEVICE, + PRINT_PARTMAP, + PRINT_PARTUUID, + PRINT_ABSTRACTION, + PRINT_CRYPTODISK_UUID, + PRINT_HINT_STR, + PRINT_BIOS_HINT, + PRINT_IEEE1275_HINT, + PRINT_BAREMETAL_HINT, + PRINT_EFI_HINT, + PRINT_ARC_HINT, + PRINT_COMPATIBILITY_HINT, + PRINT_MSDOS_PARTTYPE, + PRINT_GPT_PARTTYPE, + PRINT_ZERO_CHECK, + PRINT_DISK +}; + +static const char *targets[] = + { + [PRINT_FS] = "fs", + [PRINT_FS_UUID] = "fs_uuid", + [PRINT_FS_LABEL] = "fs_label", + [PRINT_DRIVE] = "drive", + [PRINT_DEVICE] = "device", + [PRINT_PARTMAP] = "partmap", + [PRINT_PARTUUID] = "partuuid", + [PRINT_ABSTRACTION] = "abstraction", + [PRINT_CRYPTODISK_UUID] = "cryptodisk_uuid", + [PRINT_HINT_STR] = "hints_string", + [PRINT_BIOS_HINT] = "bios_hints", + [PRINT_IEEE1275_HINT] = "ieee1275_hints", + [PRINT_BAREMETAL_HINT] = "baremetal_hints", + [PRINT_EFI_HINT] = "efi_hints", + [PRINT_ARC_HINT] = "arc_hints", + [PRINT_COMPATIBILITY_HINT] = "compatibility_hint", + [PRINT_MSDOS_PARTTYPE] = "msdos_parttype", + [PRINT_GPT_PARTTYPE] = "gpt_parttype", + [PRINT_ZERO_CHECK] = "zero_check", + [PRINT_DISK] = "disk", + }; + +static int print = PRINT_FS; +static unsigned int argument_is_device = 0; + +static char * +get_targets_string (void) +{ + char **arr = xmalloc (sizeof (targets)); + int len = 0; + char *str; + char *ptr; + unsigned i; + + memcpy (arr, targets, sizeof (targets)); + qsort (arr, ARRAY_SIZE (targets), sizeof (char *), grub_qsort_strcmp); + for (i = 0; i < ARRAY_SIZE (targets); i++) + len += grub_strlen (targets[i]) + 2; + ptr = str = xmalloc (len); + for (i = 0; i < ARRAY_SIZE (targets); i++) + { + ptr = grub_stpcpy (ptr, arr[i]); + *ptr++ = ','; + *ptr++ = ' '; + } + ptr[-2] = '\0'; + free (arr); + + return str; +} + +static int +print_gpt_guid (grub_gpt_part_guid_t guid) +{ + guid.data1 = grub_le_to_cpu32 (guid.data1); + guid.data2 = grub_le_to_cpu16 (guid.data2); + guid.data3 = grub_le_to_cpu16 (guid.data3); + + return grub_printf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid.data1, guid.data2, guid.data3, guid.data4[0], + guid.data4[1], guid.data4[2], guid.data4[3], + guid.data4[4], guid.data4[5], guid.data4[6], + guid.data4[7]); +} + +static void +do_print (const char *x, void *data) +{ + char delim = *(const char *) data; + grub_printf ("%s%c", x, delim); +} + +static void +probe_partmap (grub_disk_t disk, char delim) +{ + grub_partition_t part; + grub_disk_memberlist_t list = NULL, tmp; + + if (disk->partition == NULL) + { + grub_util_info ("no partition map found for %s", disk->name); + } + + for (part = disk->partition; part; part = part->parent) + printf ("%s%c", part->partmap->name, delim); + + if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID) + grub_diskfilter_get_partmap (disk, do_print, &delim); + + /* In case of LVM/RAID, check the member devices as well. */ + if (disk->dev->disk_memberlist) + { + list = disk->dev->disk_memberlist (disk); + } + while (list) + { + probe_partmap (list->disk, delim); + tmp = list->next; + free (list); + list = tmp; + } +} + +static void +probe_partuuid (grub_disk_t disk, char delim) +{ + grub_partition_t p = disk->partition; + + /* + * Nested partitions not supported for now. + * Non-nested partitions must have disk->partition->parent == NULL + */ + if (p && p->parent == NULL) + { + disk->partition = p->parent; + + if (strcmp(p->partmap->name, "msdos") == 0) + { + /* + * The partition GUID for MSDOS is the partition number (starting + * with 1) prepended with the NT disk signature. + */ + grub_uint32_t nt_disk_sig; + + if (grub_disk_read (disk, 0, GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, + sizeof(nt_disk_sig), &nt_disk_sig) == 0) + grub_printf ("%08x-%02x", + grub_le_to_cpu32(nt_disk_sig), 1 + p->number); + } + else if (strcmp(p->partmap->name, "gpt") == 0) + { + struct grub_gpt_partentry gptdata; + + if (grub_disk_read (disk, p->offset, p->index, + sizeof(gptdata), &gptdata) == 0) + print_gpt_guid(gptdata.guid); + } + + disk->partition = p; + } +} + +static void +probe_cryptodisk_uuid (grub_disk_t disk, char delim) +{ + grub_disk_memberlist_t list = NULL, tmp; + + /* In case of LVM/RAID, check the member devices as well. */ + if (disk->dev->disk_memberlist) + { + list = disk->dev->disk_memberlist (disk); + } + while (list) + { + probe_cryptodisk_uuid (list->disk, delim); + tmp = list->next; + free (list); + list = tmp; + } + if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) + { + const char *uu = grub_util_cryptodisk_get_uuid (disk); + grub_printf ("%s%c", uu, delim); + } +} + +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_DISKFILTER_ID) + return -1; + + if (disk->name[0] != 'm' || disk->name[1] != 'd') + return -1; + + if (!((struct grub_diskfilter_lv *) disk->data)->segments) + return -1; + return ((struct grub_diskfilter_lv *) disk->data)->segments->type; +} + +static void +probe_abstraction (grub_disk_t disk, char delim) +{ + grub_disk_memberlist_t list = NULL, tmp; + int raid_level; + + if (disk->dev->disk_memberlist) + list = disk->dev->disk_memberlist (disk); + while (list) + { + probe_abstraction (list->disk, delim); + + tmp = list->next; + free (list); + list = tmp; + } + + if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID + && (grub_memcmp (disk->name, "lvm/", sizeof ("lvm/") - 1) == 0 || + grub_memcmp (disk->name, "lvmid/", sizeof ("lvmid/") - 1) == 0)) + printf ("lvm%c", delim); + + if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID + && grub_memcmp (disk->name, "ldm/", sizeof ("ldm/") - 1) == 0) + printf ("ldm%c", delim); + + if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) + grub_util_cryptodisk_get_abstraction (disk, do_print, &delim); + + raid_level = probe_raid_level (disk); + if (raid_level >= 0) + { + printf ("diskfilter%c", delim); + if (disk->dev->disk_raidname) + printf ("%s%c", disk->dev->disk_raidname (disk), delim); + } + if (raid_level == 5) + printf ("raid5rec%c", delim); + if (raid_level == 6) + printf ("raid6rec%c", delim); +} + +static void +probe (const char *path, char **device_names, char delim) +{ + char **drives_names = NULL; + char **curdev, **curdrive; + char *grub_path = NULL; + int ndev = 0; + + if (path != NULL) + { + grub_path = grub_canonicalize_file_name (path); + if (! grub_path) + grub_util_error (_("failed to get canonical path of `%s'"), path); + device_names = grub_guess_root_devices (grub_path); + free (grub_path); + } + + if (! device_names) + grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path); + + if (print == PRINT_DEVICE) + { + for (curdev = device_names; *curdev; curdev++) + { + printf ("%s", *curdev); + putchar (delim); + } + goto free_device_names; + } + + if (print == PRINT_DISK) + { + for (curdev = device_names; *curdev; curdev++) + { + char *disk; + disk = grub_util_get_os_disk (*curdev); + if (!disk) + { + grub_print_error (); + continue; + } + printf ("%s", disk); + putchar (delim); + free (disk); + } + goto free_device_names; + } + + for (curdev = device_names; *curdev; curdev++) + { + grub_util_pull_device (*curdev); + ndev++; + } + + drives_names = xcalloc (ndev + 1, sizeof (drives_names[0])); + + for (curdev = device_names, curdrive = drives_names; *curdev; curdev++, + curdrive++) + { + *curdrive = grub_util_get_grub_dev (*curdev); + if (! *curdrive) + grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), + *curdev); + } + *curdrive = 0; + + if (print == PRINT_DRIVE) + { + for (curdrive = drives_names; *curdrive; curdrive++) + { + printf ("(%s)", *curdrive); + putchar (delim); + } + goto end; + } + + if (print == PRINT_ZERO_CHECK) + { + for (curdev = drives_names; *curdev; curdev++) + { + grub_device_t dev = NULL; + grub_uint32_t buffer[32768]; + grub_disk_addr_t addr; + grub_disk_addr_t dsize; + + grub_util_info ("opening %s", *curdev); + dev = grub_device_open (*curdev); + if (! dev || !dev->disk) + grub_util_error ("%s", grub_errmsg); + + dsize = grub_disk_native_sectors (dev->disk); + for (addr = 0; addr < dsize; + addr += sizeof (buffer) / GRUB_DISK_SECTOR_SIZE) + { + grub_size_t sz = sizeof (buffer); + grub_uint32_t *ptr; + + if (sizeof (buffer) / GRUB_DISK_SECTOR_SIZE > dsize - addr) + sz = (dsize - addr) * GRUB_DISK_SECTOR_SIZE; + grub_disk_read (dev->disk, addr, 0, sz, buffer); + + for (ptr = buffer; ptr < buffer + sz / sizeof (*buffer); ptr++) + if (*ptr) + { + grub_printf ("false\n"); + grub_device_close (dev); + goto end; + } + } + + grub_device_close (dev); + } + grub_printf ("true\n"); + } + + if (print == PRINT_FS || print == PRINT_FS_UUID + || print == PRINT_FS_LABEL) + { + grub_device_t dev = NULL; + grub_fs_t fs; + + grub_util_info ("opening %s", drives_names[0]); + dev = grub_device_open (drives_names[0]); + if (! dev) + grub_util_error ("%s", grub_errmsg); + + fs = grub_fs_probe (dev); + if (! fs) + grub_util_error ("%s", grub_errmsg); + + if (print == PRINT_FS) + { + printf ("%s", fs->name); + putchar (delim); + } + else if (print == PRINT_FS_UUID) + { + char *uuid; + if (! fs->fs_uuid) + grub_util_error (_("%s does not support UUIDs"), fs->name); + + if (fs->fs_uuid (dev, &uuid) != GRUB_ERR_NONE) + grub_util_error ("%s", grub_errmsg); + + printf ("%s", uuid); + putchar (delim); + } + else if (print == PRINT_FS_LABEL) + { + char *label; + if (! fs->fs_label) + grub_util_error (_("filesystem `%s' does not support labels"), + fs->name); + + if (fs->fs_label (dev, &label) != GRUB_ERR_NONE) + grub_util_error ("%s", grub_errmsg); + + printf ("%s", label); + putchar (delim); + } + grub_device_close (dev); + goto end; + } + + for (curdrive = drives_names, curdev = device_names; *curdrive; + curdrive++, curdev++) + { + grub_device_t dev = NULL; + + grub_util_info ("opening %s", *curdrive); + dev = grub_device_open (*curdrive); + if (! dev) + grub_util_error ("%s", grub_errmsg); + + if (print == PRINT_HINT_STR) + { + const char *osdev = grub_util_biosdisk_get_osdev (dev->disk); + char *ofpath = osdev ? grub_util_devname_to_ofpath (osdev) : 0; + char *biosname, *bare, *efi; + const char *map; + + if (ofpath) + { + char *tmp = xmalloc (strlen (ofpath) + sizeof ("ieee1275/")); + char *p; + p = grub_stpcpy (tmp, "ieee1275/"); + strcpy (p, ofpath); + printf ("--hint-ieee1275='"); + grub_util_fprint_full_disk_name (stdout, tmp, dev); + printf ("' "); + free (tmp); + free (ofpath); + } + + biosname = grub_util_guess_bios_drive (*curdev); + if (biosname) + { + printf ("--hint-bios="); + grub_util_fprint_full_disk_name (stdout, biosname, dev); + printf (" "); + } + free (biosname); + + efi = grub_util_guess_efi_drive (*curdev); + if (efi) + { + printf ("--hint-efi="); + grub_util_fprint_full_disk_name (stdout, efi, dev); + printf (" "); + } + free (efi); + + bare = grub_util_guess_baremetal_drive (*curdev); + if (bare) + { + printf ("--hint-baremetal="); + grub_util_fprint_full_disk_name (stdout, bare, dev); + printf (" "); + } + free (bare); + + /* FIXME: Add ARC hint. */ + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + printf ("--hint='"); + grub_util_fprint_full_disk_name (stdout, map, dev); + printf ("' "); + } + if (curdrive[1]) + printf (" "); + else + printf ("\n"); + } + + else if ((print == PRINT_COMPATIBILITY_HINT || print == PRINT_BIOS_HINT + || print == PRINT_IEEE1275_HINT || print == PRINT_BAREMETAL_HINT + || print == PRINT_EFI_HINT || print == PRINT_ARC_HINT) + && dev->disk->dev->id != GRUB_DISK_DEVICE_HOSTDISK_ID) + { + grub_util_fprint_full_disk_name (stdout, dev->disk->name, dev); + putchar (delim); + } + + else if (print == PRINT_COMPATIBILITY_HINT) + { + const char *map; + char *biosname; + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + grub_util_fprint_full_disk_name (stdout, map, dev); + putchar (delim); + grub_device_close (dev); + /* Compatibility hint is one device only. */ + break; + } + biosname = grub_util_guess_bios_drive (*curdev); + if (biosname) + { + grub_util_fprint_full_disk_name (stdout, biosname, dev); + putchar (delim); + free (biosname); + /* Compatibility hint is one device only. */ + grub_device_close (dev); + break; + } + } + + else if (print == PRINT_BIOS_HINT) + { + char *biosname; + biosname = grub_util_guess_bios_drive (*curdev); + if (biosname) + { + grub_util_fprint_full_disk_name (stdout, biosname, dev); + putchar (delim); + free (biosname); + } + } + else if (print == PRINT_IEEE1275_HINT) + { + const char *osdev = grub_util_biosdisk_get_osdev (dev->disk); + char *ofpath = grub_util_devname_to_ofpath (osdev); + const char *map; + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + grub_util_fprint_full_disk_name (stdout, map, dev); + putchar (delim); + } + + if (ofpath) + { + char *tmp = xmalloc (strlen (ofpath) + sizeof ("ieee1275/")); + char *p; + p = grub_stpcpy (tmp, "ieee1275/"); + strcpy (p, ofpath); + grub_util_fprint_full_disk_name (stdout, tmp, dev); + free (tmp); + free (ofpath); + putchar (delim); + } + } + else if (print == PRINT_EFI_HINT) + { + char *biosname; + const char *map; + biosname = grub_util_guess_efi_drive (*curdev); + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + grub_util_fprint_full_disk_name (stdout, map, dev); + putchar (delim); + } + if (biosname) + { + grub_util_fprint_full_disk_name (stdout, biosname, dev); + putchar (delim); + free (biosname); + } + } + + else if (print == PRINT_BAREMETAL_HINT) + { + char *biosname; + const char *map; + + biosname = grub_util_guess_baremetal_drive (*curdev); + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + grub_util_fprint_full_disk_name (stdout, map, dev); + putchar (delim); + } + if (biosname) + { + grub_util_fprint_full_disk_name (stdout, biosname, dev); + putchar (delim); + free (biosname); + } + } + + else if (print == PRINT_ARC_HINT) + { + const char *map; + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + if (map) + { + grub_util_fprint_full_disk_name (stdout, map, dev); + putchar (delim); + } + } + + else if (print == PRINT_ABSTRACTION) + probe_abstraction (dev->disk, delim); + + else if (print == PRINT_CRYPTODISK_UUID) + probe_cryptodisk_uuid (dev->disk, delim); + + else if (print == PRINT_PARTMAP) + /* Check if dev->disk itself is contained in a partmap. */ + probe_partmap (dev->disk, delim); + + else if (print == PRINT_PARTUUID) + { + probe_partuuid (dev->disk, delim); + putchar (delim); + } + + else if (print == PRINT_MSDOS_PARTTYPE) + { + if (dev->disk->partition + && strcmp(dev->disk->partition->partmap->name, "msdos") == 0) + printf ("%02x", dev->disk->partition->msdostype); + + putchar (delim); + } + + else if (print == PRINT_GPT_PARTTYPE) + { + if (dev->disk->partition + && strcmp (dev->disk->partition->partmap->name, "gpt") == 0) + { + struct grub_gpt_partentry gptdata; + grub_partition_t p = dev->disk->partition; + dev->disk->partition = dev->disk->partition->parent; + + if (grub_disk_read (dev->disk, p->offset, p->index, + sizeof (gptdata), &gptdata) == 0) + print_gpt_guid(gptdata.type); + dev->disk->partition = p; + } + putchar (delim); + } + + grub_device_close (dev); + } + + end: + for (curdrive = drives_names; *curdrive; curdrive++) + free (*curdrive); + free (drives_names); + +free_device_names: + if (path != NULL) + { + for (curdev = device_names; *curdev; curdev++) + free (*curdev); + free (device_names); + } +} + +static struct argp_option options[] = { + {"device", 'd', 0, 0, + N_("given argument is a system device, not a path"), 0}, + {"device-map", 'm', N_("FILE"), 0, + N_("use FILE as the device map [default=%s]"), 0}, + {"target", 't', N_("TARGET"), 0, 0, 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + {0, '0', 0, 0, N_("separate items in output using ASCII NUL characters"), 0}, + { 0, 0, 0, 0, 0, 0 } +}; + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +static char * +help_filter (int key, const char *text, void *input __attribute__ ((unused))) +{ + switch (key) + { + case 'm': + return xasprintf (text, DEFAULT_DEVICE_MAP); + + case 't': + { + char *ret, *t = get_targets_string (), *def; + + def = xasprintf (_("[default=%s]"), targets[print]); + + ret = xasprintf ("%s\n%s %s %s", _("print TARGET"), + _("available targets:"), t, def); + free (t); + free (def); + return ret; + } + + default: + return (char *) text; + } +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +struct arguments +{ + char **devices; + size_t device_max; + size_t ndevices; + char *dev_map; + int zero_delim; +}; + +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; + + switch (key) + { + case 'd': + argument_is_device = 1; + break; + + case 'm': + if (arguments->dev_map) + free (arguments->dev_map); + + arguments->dev_map = xstrdup (arg); + break; + + case 't': + { + int i; + + for (i = PRINT_FS; i < ARRAY_SIZE (targets); i++) + if (strcmp (arg, targets[i]) == 0) + { + print = i; + break; + } + if (i == ARRAY_SIZE (targets)) + argp_usage (state); + } + break; + + case '0': + arguments->zero_delim = 1; + break; + + case 'v': + verbosity++; + break; + + case ARGP_KEY_NO_ARGS: + fprintf (stderr, "%s", _("No path or device is specified.\n")); + argp_usage (state); + break; + + case ARGP_KEY_ARG: + assert (arguments->ndevices < arguments->device_max); + arguments->devices[arguments->ndevices++] = xstrdup(arg); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { + options, argp_parser, N_("[OPTION]... [PATH|DEVICE]"), + N_("\ +Probe device information for a given path (or device, if the -d option is given)."), + NULL, help_filter, NULL +}; + +int +main (int argc, char *argv[]) +{ + char delim; + struct arguments arguments; + + grub_util_host_init (&argc, &argv); + + memset (&arguments, 0, sizeof (struct arguments)); + arguments.device_max = argc + 1; + arguments.devices = xmalloc ((arguments.device_max + 1) + * sizeof (arguments.devices[0])); + memset (arguments.devices, 0, (arguments.device_max + 1) + * sizeof (arguments.devices[0])); + + /* 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); + } + + if (verbosity > 1) + grub_env_set ("debug", "all"); + + /* Obtain ARGUMENT. */ + if (arguments.ndevices != 1 && !argument_is_device) + { + char *program = xstrdup(program_name); + fprintf (stderr, _("Unknown extra argument `%s'."), arguments.devices[1]); + fprintf (stderr, "\n"); + argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program); + free (program); + exit(1); + } + + /* Initialize the emulated biosdisk driver. */ + grub_util_biosdisk_init (arguments.dev_map ? : DEFAULT_DEVICE_MAP); + + /* Initialize all modules. */ + grub_init_all (); + grub_gcry_init_all (); + + grub_lvm_fini (); + grub_mdraid09_fini (); + grub_mdraid1x_fini (); + grub_diskfilter_fini (); + grub_diskfilter_init (); + grub_mdraid09_init (); + grub_mdraid1x_init (); + grub_lvm_init (); + + if (print == PRINT_BIOS_HINT + || print == PRINT_IEEE1275_HINT || print == PRINT_BAREMETAL_HINT + || print == PRINT_EFI_HINT || print == PRINT_ARC_HINT) + delim = ' '; + else + delim = '\n'; + + if (arguments.zero_delim) + delim = '\0'; + + /* Do it. */ + if (argument_is_device) + probe (NULL, arguments.devices, delim); + else + probe (arguments.devices[0], NULL, delim); + + if (delim == ' ') + putchar ('\n'); + + /* Free resources. */ + grub_gcry_fini_all (); + grub_fini_all (); + grub_util_biosdisk_fini (); + + { + size_t i; + for (i = 0; i < arguments.ndevices; i++) + free (arguments.devices[i]); + } + free (arguments.devices); + + free (arguments.dev_map); + + return 0; +} diff --git a/util/grub-reboot.in b/util/grub-reboot.in new file mode 100644 index 0000000..ef3b5c0 --- /dev/null +++ b/util/grub-reboot.in @@ -0,0 +1,160 @@ +#! /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 <http://www.gnu.org/licenses/>. + +# Initialize some variables. +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +sbindir=@sbindir@ +sysconfdir="@sysconfdir@" +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +datarootdir="@datarootdir@" +datadir="@datadir@" +if [ "x$pkgdatadir" = x ]; then + pkgdatadir="${datadir}/@PACKAGE@" +fi + +self=`basename $0` + +grub_editenv=${bindir}/@grub_editenv@ +grub_probe=${sbindir}/@grub_probe@ +rootdir= +bootdir= +grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR="@localedir@" + +. "${pkgdatadir}/grub-mkconfig_lib" + +# Usage: usage +# Print the usage. +usage () { + gettext_printf "Usage: %s [OPTION] MENU_ENTRY\n" "$self" + gettext "Set the default boot menu entry for GRUB, for the next boot only."; echo + print_option_help "-h, --help" "$(gettext "print this message and exit")" + print_option_help "-V, --version" "$(gettext "print the version information and exit")" + dirmsg="$(gettext_printf "expect GRUB images under the directory DIR/%s instead of the %s directory" "@grubdirname@" "$grubdir")" + print_option_help "--boot-directory=$(gettext "DIR")" "$dirmsg" + echo + gettext "MENU_ENTRY is a number, a menu item title or a menu item identifier. Please note that menu items in +submenus or sub-submenus require specifying the submenu components and then the +menu item component. The titles should be separated using the greater-than +character (>) with no extra spaces. Depending on your shell some characters including > may need escaping. More information about this is available +in the GRUB Manual in the section about the 'default' command. "; echo + echo + gettext "NOTE: In cases where GRUB cannot write to the environment block, such as when it is stored on an MDRAID or LVM device, the chosen boot menu entry will remain the default even after reboot. "; echo + echo + gettext "Report bugs to <bug-grub@gnu.org>."; echo +} + +argument () { + opt=$1 + shift + + if test $# -eq 0; then + gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$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=//'` ;; + + -*) + gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 + usage + exit 1 + ;; + *) + if test "x$entry" != x; then + gettext "More than one menu entry?" 1>&2 + echo >&2 + usage + exit 1 + fi + entry="${option}" ;; + esac +done + +if test "x$entry" = x; then + gettext "Menu entry not specified." 1>&2 + echo >&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'` + +abstractions=`$grub_probe --target=abstraction ${grubdir}/grubenv` +for abstraction in $abstractions; do + case "$abstraction" in + diskfilter | lvm) + gettext_printf "\nWARNING: Detected GRUB environment block on $abstraction device\n" + gettext_printf "%s will remain the default boot entry until manually cleared with:\n" "${entry}" + gettext_printf " grub-editenv ${grubdir}/grubenv unset next_entry\n\n" + break + ;; + esac +done + +# Restore saved_entry if it was set by previous version +prev_saved_entry=`$grub_editenv ${grubdir}/grubenv list | sed -n 's/^prev_saved_entry=//p'` +if [ "$prev_saved_entry" ]; then + $grub_editenv ${grubdir}/grubenv set saved_entry="$prev_saved_entry" + $grub_editenv ${grubdir}/grubenv unset prev_saved_entry +fi + +$grub_editenv ${grubdir}/grubenv set next_entry="$entry" + +# Bye. +exit 0 diff --git a/util/grub-render-label.c b/util/grub-render-label.c new file mode 100644 index 0000000..ec0923b --- /dev/null +++ b/util/grub-render-label.c @@ -0,0 +1,193 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2012,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include <config.h> + +#include <grub/util/misc.h> +#include <grub/i18n.h> +#include <grub/term.h> +#include <grub/font.h> +#include <grub/gfxmenu_view.h> +#include <grub/color.h> +#include <grub/util/install.h> +#include <grub/emu/hostdisk.h> + +#define _GNU_SOURCE 1 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include "progname.h" + +struct arguments +{ + char *input; + char *text; + char *output; + char *font; + char *fgcolor; + char *bgcolor; + int verbosity; +}; + +static struct argp_option options[] = { + {"input", 'i', N_("FILE"), 0, + N_("read text from FILE."), 0}, + {"color", 'c', N_("COLOR"), 0, + N_("use COLOR for text"), 0}, + {"bgcolor", 'b', N_("COLOR"), 0, + N_("use COLOR for background"), 0}, + {"text", 't', N_("STRING"), 0, + /* TRANSLATORS: The result is always stored to file and + never shown directly, so don't use "show" as synonym for render. Use "create" if + "render" doesn't translate directly. */ + N_("set the label to render"), 0}, + {"output", 'o', N_("FILE"), 0, + N_("set output filename. Default is STDOUT"), 0}, + {"font", 'f', N_("FILE"), 0, + N_("use FILE as font (PF2)."), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + { 0, 0, 0, 0, 0, 0 } +}; + +#include <grub/err.h> +#include <grub/types.h> +#include <grub/dl.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/video.h> +#include <grub/video_fb.h> + +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; + + switch (key) + { + case 'i': + arguments->input = xstrdup (arg); + break; + + case 'b': + arguments->bgcolor = xstrdup (arg); + break; + + case 'c': + arguments->fgcolor = xstrdup (arg); + break; + + case 'f': + arguments->font = xstrdup (arg); + break; + + case 't': + arguments->text = xstrdup (arg); + break; + + case 'o': + arguments->output = xstrdup (arg); + break; + + case 'v': + arguments->verbosity++; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +static struct argp argp = { + options, argp_parser, N_("[OPTIONS]"), + /* TRANSLATORS: This file takes a text and creates a graphical representation of it, + putting the result into .disk_label file. The result is always stored to file and + never shown directly, so don't use "show" as synonym for render. Use "create" if + "render" doesn't translate directly. */ + N_("Render Apple .disk_label."), + NULL, NULL, NULL +}; + +int +main (int argc, char *argv[]) +{ + char *text; + struct arguments arguments; + + grub_util_host_init (&argc, &argv); + + /* Check for options. */ + memset (&arguments, 0, sizeof (struct arguments)); + if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + if ((!arguments.input && !arguments.text) || !arguments.font) + { + fprintf (stderr, "%s", _("Missing arguments\n")); + exit(1); + } + + if (arguments.text) + text = arguments.text; + else + { + FILE *in = grub_util_fopen (arguments.input, "r"); + size_t s; + if (!in) + grub_util_error (_("cannot open `%s': %s"), arguments.input, + strerror (errno)); + fseek (in, 0, SEEK_END); + s = ftell (in); + fseek (in, 0, SEEK_SET); + text = xmalloc (s + 1); + if (fread (text, 1, s, in) != s) + grub_util_error (_("cannot read `%s': %s"), arguments.input, + strerror (errno)); + text[s] = 0; + fclose (in); + } + + grub_init_all (); + grub_hostfs_init (); + grub_host_init (); + + grub_util_render_label (arguments.font, + arguments.bgcolor, + arguments.fgcolor, + text, + arguments.output); + + return 0; +} diff --git a/util/grub-script-check.c b/util/grub-script-check.c new file mode 100644 index 0000000..801b3df --- /dev/null +++ b/util/grub-script-check.c @@ -0,0 +1,218 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/i18n.h> +#include <grub/parser.h> +#include <grub/script_sh.h> + +#define _GNU_SOURCE 1 + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include "progname.h" + +struct arguments +{ + int verbose; + char *filename; +}; + +static struct argp_option options[] = { + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + { 0, 0, 0, 0, 0, 0 } +}; + +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; + + switch (key) + { + case 'v': + arguments->verbose = 1; + break; + + case ARGP_KEY_ARG: + if (state->arg_num == 0) + arguments->filename = xstrdup (arg); + else + { + /* Too many arguments. */ + fprintf (stderr, _("Unknown extra argument `%s'."), arg); + fprintf (stderr, "\n"); + argp_usage (state); + } + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { + options, argp_parser, N_("[PATH]"), + N_("Checks GRUB script configuration file for syntax errors."), + NULL, NULL, NULL +}; + +/* Context for main. */ +struct main_ctx +{ + int lineno; + FILE *file; + struct arguments arguments; +}; + +/* Helper for main. */ +static grub_err_t +get_config_line (char **line, int cont __attribute__ ((unused)), void *data) +{ + struct main_ctx *ctx = data; + int i; + char *cmdline = 0; + size_t len = 0; + ssize_t curread; + + curread = getline (&cmdline, &len, (ctx->file ?: stdin)); + if (curread == -1) + { + *line = 0; + grub_errno = GRUB_ERR_READ_ERROR; + + if (cmdline) + free (cmdline); + return grub_errno; + } + + if (ctx->arguments.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'; + } + + ctx->lineno++; + *line = grub_strdup (cmdline); + + free (cmdline); + return 0; +} + +int +main (int argc, char *argv[]) +{ + struct main_ctx ctx = { + .lineno = 0, + .file = 0 + }; + char *input; + int found_input = 0, found_cmd = 0; + struct grub_script *script = NULL; + + grub_util_host_init (&argc, &argv); + + memset (&ctx.arguments, 0, sizeof (struct arguments)); + + /* Check for options. */ + if (argp_parse (&argp, argc, argv, 0, 0, &ctx.arguments) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + /* Obtain ARGUMENT. */ + if (!ctx.arguments.filename) + { + ctx.file = 0; /* read from stdin */ + } + else + { + ctx.file = grub_util_fopen (ctx.arguments.filename, "r"); + if (! ctx.file) + { + char *program = xstrdup(program_name); + fprintf (stderr, _("cannot open `%s': %s"), + ctx.arguments.filename, strerror (errno)); + argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program); + free(program); + exit(1); + } + } + + do + { + input = 0; + get_config_line (&input, 0, &ctx); + if (! input) + break; + found_input = 1; + + script = grub_script_parse (input, get_config_line, &ctx); + if (script) + { + if (script->cmd) + found_cmd = 1; + grub_script_execute (script); + grub_script_free (script); + } + + grub_free (input); + } while (script != 0); + + if (ctx.file) fclose (ctx.file); + + if (found_input && script == 0) + { + fprintf (stderr, _("Syntax error at line %u\n"), ctx.lineno); + return 1; + } + if (! found_cmd) + { + fprintf (stderr, _("Script `%s' contains no commands and will do nothing\n"), + ctx.arguments.filename); + return 1; + } + + return 0; +} diff --git a/util/grub-set-default.in b/util/grub-set-default.in new file mode 100644 index 0000000..6036f81 --- /dev/null +++ b/util/grub-set-default.in @@ -0,0 +1,137 @@ +#! /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 <http://www.gnu.org/licenses/>. + +# Initialize some variables. +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +sysconfdir="@sysconfdir@" +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +datarootdir="@datarootdir@" +datadir="@datadir@" +if [ "x$pkgdatadir" = x ]; then + pkgdatadir="${datadir}/@PACKAGE@" +fi + +self=`basename $0` + +grub_editenv=${bindir}/@grub_editenv@ +rootdir= +bootdir= +grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR="@localedir@" + +. "${pkgdatadir}/grub-mkconfig_lib" + +# Usage: usage +# Print the usage. +usage () { + gettext_printf "Usage: %s [OPTION] MENU_ENTRY\n" "$self" + gettext "Set the default boot menu entry for GRUB."; echo + gettext_printf "This requires setting GRUB_DEFAULT=saved in %s/default/grub.\n" "$sysconfdir" + echo + print_option_help "-h, --help" "$(gettext "print this message and exit")" + print_option_help "-V, --version" "$(gettext "print the version information and exit")" + dirmsg="$(gettext_printf "expect GRUB images under the directory DIR/%s instead of the %s directory" "@grubdirname@" "$grubdir")" + print_option_help "--boot-directory=$(gettext "DIR")" "$dirmsg" + echo + gettext "MENU_ENTRY is a number, a menu item title or a menu item identifier."; echo + echo + gettext "Report bugs to <bug-grub@gnu.org>."; echo +} + +argument () { + opt=$1 + shift + + if test $# -eq 0; then + gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$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=//'` ;; + + -*) + gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 + usage + exit 1 + ;; + *) + if test "x$entry" != x; then + gettext "More than one menu entry?" 1>&2 + echo >&2 + usage + exit 1 + fi + entry="${option}" ;; + esac +done + +if test "x$entry" = x; then + gettext "Menu entry not specified." 1>&2 + echo >&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 unset next_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..1783224 --- /dev/null +++ b/util/grub-setup.c @@ -0,0 +1,333 @@ +/* grub-setup.c - make GRUB usable */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#define _GNU_SOURCE 1 + +#include <string.h> + +#include <grub/types.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/device.h> +#include <grub/disk.h> +#include <grub/file.h> +#include <grub/fs.h> +#include <grub/partition.h> +#include <grub/env.h> +#include <grub/emu/hostdisk.h> +#include <grub/term.h> +#include <grub/i18n.h> +#include <grub/crypto.h> +#include <grub/emu/getroot.h> +#include <grub/util/install.h> + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +/* 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" + +/* Non-printable "keys" for arguments with no short form. + * See grub-core/lib/gnulib/argp.h for details. */ +enum { + NO_RS_CODES_KEY = 0x100, +}; + +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}, + {"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, + /* TRANSLATORS: The potential breakage isn't limited to floppies but it's + likely to make the install unbootable from HDD. */ + N_("make the drive also bootable as floppy (default for fdX devices). May break on some BIOSes."), 0}, + {"no-rs-codes", NO_RS_CODES_KEY, 0, 0, + N_("Do not apply any reed-solomon codes when embedding core.img. " + "This option is only available on x86 BIOS targets."), 0}, + { 0, 0, 0, 0, 0, 0 } +}; + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +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; + } +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +struct arguments +{ + char *boot_file; + char *core_file; + char *dir; + char *dev_map; + int force; + int fs_probe; + int allow_floppy; + char *device; + int add_rs_codes; +}; + +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; + + 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 'f': + arguments->force = 1; + break; + + case 's': + arguments->fs_probe = 0; + break; + + case 'v': + verbosity++; + break; + + case NO_RS_CODES_KEY: + arguments->add_rs_codes = 0; + break; + + case ARGP_KEY_ARG: + if (state->arg_num == 0) + arguments->device = xstrdup(arg); + else + { + /* Too many arguments. */ + fprintf (stderr, _("Unknown extra argument `%s'."), arg); + fprintf (stderr, "\n"); + argp_usage (state); + } + break; + + case ARGP_KEY_NO_ARGS: + fprintf (stderr, "%s", _("No device is specified.\n")); + argp_usage (state); + exit (1); + 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; + struct arguments arguments; + + grub_util_host_init (&argc, &argv); + + /* Default option values. */ + memset (&arguments, 0, sizeof (struct arguments)); + arguments.fs_probe = 1; + arguments.add_rs_codes = 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_SETUP_SPARC64 + 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_gcry_init_all (); + + grub_lvm_fini (); + grub_mdraid09_fini (); + grub_mdraid1x_fini (); + grub_diskfilter_fini (); + grub_diskfilter_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); + } + + /* Do the real work. */ + GRUB_SETUP_FUNC (arguments.dir ? : DEFAULT_DIRECTORY, + arguments.boot_file ? : DEFAULT_BOOT_FILE, + arguments.core_file ? : DEFAULT_CORE_FILE, + dest_dev, arguments.force, + arguments.fs_probe, arguments.allow_floppy, + arguments.add_rs_codes, 0); + + /* Free resources. */ + grub_fini_all (); + grub_util_biosdisk_fini (); + + free (arguments.boot_file); + free (arguments.core_file); + free (arguments.dir); + free (arguments.dev_map); + free (arguments.device); + free (root_dev); + free (dest_dev); + + return 0; +} diff --git a/util/grub-syslinux2cfg.c b/util/grub-syslinux2cfg.c new file mode 100644 index 0000000..85fa0da --- /dev/null +++ b/util/grub-syslinux2cfg.c @@ -0,0 +1,246 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2012,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include <config.h> + +#include <grub/util/misc.h> +#include <grub/i18n.h> +#include <grub/term.h> +#include <grub/font.h> +#include <grub/emu/hostdisk.h> + +#define _GNU_SOURCE 1 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <grub/err.h> +#include <grub/types.h> +#include <grub/dl.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/syslinux_parse.h> + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include <argp.h> +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include "progname.h" + +struct arguments +{ + char *input; + char *root; + char *target_root; + char *cwd; + char *target_cwd; + char *output; + int verbosity; + grub_syslinux_flavour_t flav; +}; + +static struct argp_option options[] = { + {"target-root", 't', N_("DIR"), 0, + N_("root directory as it will be seen on runtime [default=/]."), 0}, + {"root", 'r', N_("DIR"), 0, + N_("root directory of the syslinux disk [default=/]."), 0}, + {"target-cwd", 'T', N_("DIR"), 0, + N_( + "current directory of syslinux as it will be seen on runtime [default is parent directory of input file]." +), 0}, + {"cwd", 'c', N_("DIR"), 0, + N_("current directory of syslinux [default is parent directory of input file]."), 0}, + + {"output", 'o', N_("FILE"), 0, N_("write output to FILE [default=stdout]."), 0}, + {"isolinux", 'i', 0, 0, N_("assume input is an isolinux configuration file."), 0}, + {"pxelinux", 'p', 0, 0, N_("assume input is a pxelinux configuration file."), 0}, + {"syslinux", 's', 0, 0, N_("assume input is a syslinux configuration file."), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + { 0, 0, 0, 0, 0, 0 } +}; + +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; + + switch (key) + { + case 't': + free (arguments->target_root); + arguments->target_root = xstrdup (arg); + break; + + case 'T': + free (arguments->target_cwd); + arguments->target_cwd = xstrdup (arg); + break; + + case 'c': + free (arguments->cwd); + arguments->cwd = xstrdup (arg); + break; + + case 'o': + free (arguments->output); + arguments->output = xstrdup (arg); + break; + + case ARGP_KEY_ARG: + if (!arguments->input) + { + arguments->input = xstrdup (arg); + return 0; + } + return ARGP_ERR_UNKNOWN; + + case 'r': + free (arguments->root); + arguments->root = xstrdup (arg); + return 0; + + case 'i': + arguments->flav = GRUB_SYSLINUX_ISOLINUX; + break; + + case 's': + arguments->flav = GRUB_SYSLINUX_SYSLINUX; + break; + case 'p': + arguments->flav = GRUB_SYSLINUX_PXELINUX; + break; + + case 'v': + arguments->verbosity++; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +static struct argp argp = { + options, argp_parser, N_("FILE"), + N_("Transform syslinux config into GRUB one."), + NULL, NULL, NULL +}; + +int +main (int argc, char *argv[]) +{ + struct arguments arguments; + + grub_util_host_init (&argc, &argv); + + /* Check for options. */ + memset (&arguments, 0, sizeof (struct arguments)); + if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) + { + fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); + exit(1); + } + + if (!arguments.input) + { + fprintf (stderr, "%s", _("Missing arguments\n")); + exit(1); + } + + grub_init_all (); + grub_hostfs_init (); + grub_host_init (); + + char *t, *inpfull, *rootfull, *res; + t = grub_canonicalize_file_name (arguments.input); + if (!t) + { + grub_util_error (_("cannot open `%s': %s"), arguments.input, + strerror (errno)); + } + + inpfull = xasprintf ("(host)/%s", t); + free (t); + + t = grub_canonicalize_file_name (arguments.root ? : "/"); + if (!t) + { + grub_util_error (_("cannot open `%s': %s"), arguments.root, + strerror (errno)); + } + + rootfull = xasprintf ("(host)/%s", t); + free (t); + + char *cwd = xstrdup (arguments.input); + char *p = strrchr (cwd, '/'); + char *cwdfull; + if (p) + *p = '\0'; + else + { + free (cwd); + cwd = xstrdup ("."); + } + + t = grub_canonicalize_file_name (arguments.cwd ? : cwd); + if (!t) + { + grub_util_error (_("cannot open `%s': %s"), arguments.root, + strerror (errno)); + } + + cwdfull = xasprintf ("(host)/%s", t); + free (t); + + res = grub_syslinux_config_file (rootfull, arguments.target_root ? : "/", + cwdfull, arguments.target_cwd ? : cwd, + inpfull, arguments.flav); + if (!res) + grub_util_error ("%s", grub_errmsg); + if (arguments.output) + { + FILE *f = grub_util_fopen (arguments.output, "wb"); + if (!f) + grub_util_error (_("cannot open `%s': %s"), arguments.output, + strerror (errno)); + fwrite (res, 1, strlen (res), f); + fclose (f); + } + else + printf ("%s\n", res); + free (res); + free (rootfull); + free (inpfull); + free (arguments.root); + free (arguments.output); + free (arguments.target_root); + free (arguments.input); + free (cwdfull); + free (cwd); + + return 0; +} diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in new file mode 100644 index 0000000..93a9023 --- /dev/null +++ b/util/grub.d/00_header.in @@ -0,0 +1,356 @@ +#! /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 <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +grub_lang=`echo $LANG | cut -d . -f 1` + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR="@localedir@" + +. "$pkgdatadir/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=auto ; 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 <<EOF +if cmostest $GRUB_BUTTON_CMOS_ADDRESS ; then + set default="${GRUB_DEFAULT_BUTTON}" +elif [ "\${next_entry}" ] ; then + set default="\${next_entry}" + set next_entry= + save_env next_entry + set boot_once=true +else + set default="${GRUB_DEFAULT}" +fi +EOF +else + cat <<EOF +if [ "\${next_entry}" ] ; then + set default="\${next_entry}" + set next_entry= + save_env next_entry + set boot_once=true +else + set default="${GRUB_DEFAULT}" +fi +EOF +fi +cat <<EOF + +if [ x"\${feature_menuentry_id}" = xy ]; then + menuentry_id_option="--id" +else + menuentry_id_option="" +fi + +export menuentry_id_option + +if [ "\${prev_saved_entry}" ]; then + set saved_entry="\${prev_saved_entry}" + save_env saved_entry + set prev_saved_entry= + save_env prev_saved_entry + set boot_once=true +fi + +function savedefault { + if [ -z "\${boot_once}" ]; then + saved_entry="\${chosen}" + save_env saved_entry + fi +} + +function load_video { +EOF +if [ -n "${GRUB_VIDEO_BACKEND}" ]; then + cat <<EOF + insmod ${GRUB_VIDEO_BACKEND} +EOF +else +# If all_video.mod isn't available load all modules available +# with versions prior to introduction of all_video.mod +cat <<EOF + if [ x\$feature_all_video_module = xy ]; then + insmod all_video + else + insmod efi_gop + insmod efi_uga + insmod ieee1275_fb + insmod vbe + insmod vga + insmod video_bochs + insmod video_cirrus + fi +EOF +fi +cat <<EOF +} + +EOF + +serial=0; +gfxterm=0; +for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do + if [ xserial = "x$x" ]; then + serial=1; + fi + if [ xgfxterm = "x$x" ]; then + gfxterm=1; + fi +done + +if [ "x$serial" = x1 ]; then + if [ "x${GRUB_SERIAL_COMMAND}" = "x" ] ; then + grub_warn "$(gettext "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 + if [ -n "$GRUB_FONT" ] ; then + # Make the font accessible + prepare_grub_to_access_device `${grub_probe} --target=device "${GRUB_FONT}"` + cat << EOF +if loadfont `make_system_path_relative_to_its_root "${GRUB_FONT}"` ; then +EOF + else + for dir in "${pkgdatadir}" "`echo '/@bootdirname@/@grubdirname@' | sed "s,//*,/,g"`" /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 + font_path="${path}" + else + continue + fi + break 2 + done + done + if [ -n "${font_path}" ] ; then + cat << EOF +if [ x\$feature_default_font_path = xy ] ; then + font=unicode +else +EOF + # Make the font accessible + prepare_grub_to_access_device `${grub_probe} --target=device "${font_path}"` + cat << EOF + font="`make_system_path_relative_to_its_root "${font_path}"`" +fi + +if loadfont \$font ; then +EOF + else + cat << EOF +if loadfont unicode ; then +EOF + fi + fi + + cat << EOF + set gfxmode=${GRUB_GFXMODE} + load_video + insmod gfxterm +EOF + +# Gettext variables and module +if [ "x${LANG}" != "xC" ] && [ "x${LANG}" != "x" ]; then + cat << EOF + set locale_dir=\$prefix/locale + set lang=${grub_lang} + insmod gettext +EOF +fi + +cat <<EOF +fi +EOF +fi + +case x${GRUB_TERMINAL_INPUT} in + x) + # Just use the native terminal + ;; + x*) + cat << EOF +terminal_input ${GRUB_TERMINAL_INPUT} +EOF + ;; +esac + +case x${GRUB_TERMINAL_OUTPUT} in + x) + # Just use the native terminal + ;; + x*) + cat << EOF +terminal_output ${GRUB_TERMINAL_OUTPUT} +EOF + ;; +esac + +if [ "x$gfxterm" = x1 ]; then + if [ "x$GRUB_THEME" != x ] && [ -f "$GRUB_THEME" ] \ + && is_path_readable_by_grub "$GRUB_THEME"; then + gettext_printf "Found theme: %s\n" "$GRUB_THEME" >&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` +export theme +EOF + elif [ "x$GRUB_BACKGROUND" != x ] && [ -f "$GRUB_BACKGROUND" ] \ + && is_path_readable_by_grub "$GRUB_BACKGROUND"; then + gettext_printf "Found background: %s\n" "$GRUB_BACKGROUND" >&2 + case "$GRUB_BACKGROUND" in + *.png) reader=png ;; + *.tga) reader=tga ;; + *.jpg|*.jpeg) reader=jpeg ;; + *) gettext "Unsupported image format" >&2; echo >&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${3}" != "x" ] ; then + timeout="${2}" + style="${3}" + elif [ "x${1}" != "x" ] && [ "x${1}" != "x0" ] ; then + # Handle the deprecated GRUB_HIDDEN_TIMEOUT scheme. + timeout="${1}" + if [ "x${2}" != "x0" ] ; then + grub_warn "$(gettext "Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.")" + fi + if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then + style="hidden" + verbose= + else + style="countdown" + verbose=" --verbose" + fi + else + # No hidden timeout, so treat as GRUB_TIMEOUT_STYLE=menu + timeout="${2}" + style="menu" + fi + cat << EOF +if [ x\$feature_timeout_style = xy ] ; then + set timeout_style=${style} + set timeout=${timeout} +EOF + if [ "x${style}" = "xmenu" ] ; then + cat << EOF +# Fallback normal timeout code in case the timeout_style feature is +# unavailable. +else + set timeout=${timeout} +EOF + else + cat << EOF +# Fallback hidden-timeout code in case the timeout_style feature is +# unavailable. +elif sleep${verbose} --interruptible ${timeout} ; then + set timeout=0 +EOF + fi + cat << EOF +fi +EOF +} + +if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then + cat <<EOF +if cmostest $GRUB_BUTTON_CMOS_ADDRESS ; then +EOF +make_timeout "${GRUB_HIDDEN_TIMEOUT_BUTTON}" "${GRUB_TIMEOUT_BUTTON}" "${GRUB_TIMEOUT_STYLE_BUTTON}" +echo else +make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}" "${GRUB_TIMEOUT_STYLE}" +echo fi +else +make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}" "${GRUB_TIMEOUT_STYLE}" +fi + +if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ] && [ "x$GRUB_BUTTON_CMOS_CLEAN" = "xyes" ]; then + cat <<EOF +cmosclean $GRUB_BUTTON_CMOS_ADDRESS +EOF +fi + +# Play an initial tune +if [ "x${GRUB_INIT_TUNE}" != "x" ] ; then + echo "play ${GRUB_INIT_TUNE}" +fi + +if [ "x${GRUB_BADRAM}" != "x" ] ; then + echo "badram ${GRUB_BADRAM}" +fi diff --git a/util/grub.d/10_hurd.in b/util/grub.d/10_hurd.in new file mode 100644 index 0000000..3663d36 --- /dev/null +++ b/util/grub.d/10_hurd.in @@ -0,0 +1,188 @@ +#! /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 <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR="@localedir@" + +. "$pkgdatadir/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|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${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` + gettext_printf "Found GNU Mach: %s" "$i" >&2 + echo >&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 + gettext_printf "Found Hurd module: %s" "$i" >&2 + echo >&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 + gettext "Some Hurd stuff found, but not enough to boot." >&2 + echo >&2 + exit 1 +fi + +title_correction_code= + +hurd_entry () { + kernel="$1" + type="$2" + kernel_base="`basename "${kernel}"`" + + if [ x$type != xsimple ] ; then + if [ x$type = xrecovery ] ; then + title="$(gettext_printf "%s, with Hurd %s (recovery mode)" "${OS}" "${kernel_base}")" + oldtitle="$OS using $kernel_base (recovery mode)" + else + title="$(gettext_printf "%s, with Hurd %s" "${OS}" "${kernel_base}")" + oldtitle="$OS using $kernel_base" + fi + if [ x"$oldtitle" = x"$GRUB_ACTUAL_DEFAULT" ]; then + quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" + title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" + grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnuhurd-advanced-$boot_device_id>'gnuhurd-$kernel-$type-$(grub_get_device_id "${GRUB_DEVICE_BOOT}")'")" + fi + sed "s/^/$submenu_indentation/" << EOF +menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnuhurd-$kernel-$type-$(grub_get_device_id "${GRUB_DEVICE_BOOT}")' { +EOF + else + sed "s/^/$submenu_indentation/" << EOF +menuentry '$(echo "$OS" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnuhurd-simple-$(grub_get_device_id "${GRUB_DEVICE_BOOT}")' { +EOF + fi + + prepare_grub_to_access_device "${GRUB_DEVICE_BOOT}" | grub_add_tab|sed "s/^/$submenu_indentation/" + message="$(gettext_printf "Loading GNU Mach ...")" + + if [ x$type = xrecovery ] ; then + opts="-s" + else + opts= + fi + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' + multiboot ${kernel} root=device:${GRUB_DEVICE#/dev/} $opts ${GRUB_CMDLINE_GNUMACH} +EOF + + if [ x$type != xrecovery ] ; then + save_default_entry | grub_add_tab| sed "s/^/$submenu_indentation/" + fi + prepare_grub_to_access_device "${GRUB_DEVICE}" | grub_add_tab| sed "s/^/$submenu_indentation/" + message="$(gettext_printf "Loading the Hurd ...")" + if [ x$type = xrecovery ] ; then + opts= + else + opts="--readonly" + fi + + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' + module /hurd/${hurd_fs}.static ${hurd_fs} $opts \\ + --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 + +} + +title_correction_code= + +# Extra indentation to add to menu entries in a submenu. We're not in a submenu +# yet, so it's empty. In a submenu it will be equal to '\t' (one tab). +submenu_indentation="" +is_top_level=true + +while [ "x$kernels" != "x" ] ; do + kernel=`version_find_latest $kernels` + + # The GRUB_DISABLE_SUBMENU option used to be different than others since it was + # mentioned in the documentation that has to be set to 'y' instead of 'true' to + # enable it. This caused a lot of confusion to users that set the option to 'y', + # 'yes' or 'true'. This was fixed but all of these values must be supported now. + if [ "x${GRUB_DISABLE_SUBMENU}" = xyes ] || [ "x${GRUB_DISABLE_SUBMENU}" = xy ]; then + GRUB_DISABLE_SUBMENU="true" + fi + + if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then + hurd_entry "$kernel" simple + submenu_indentation="$grub_tab" + + # TRANSLATORS: %s is replaced with an OS name + echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnuhurd-advanced-$(grub_get_device_id "${GRUB_DEVICE_BOOT}")' {" + is_top_level=false + fi + + hurd_entry "$kernel" advanced + hurd_entry "$kernel" recovery + + kernels=`echo $kernels | tr ' ' '\n' | fgrep -vx "$kernel" | tr '\n' ' '` +done + +# If at least one kernel was found, then we need to +# add a closing '}' for the submenu command. +if [ x"$is_top_level" != xtrue ]; then + echo '}' +fi + +echo "$title_correction_code" diff --git a/util/grub.d/10_illumos.in b/util/grub.d/10_illumos.in new file mode 100644 index 0000000..a133e1b --- /dev/null +++ b/util/grub.d/10_illumos.in @@ -0,0 +1,53 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +. "$pkgdatadir/grub-mkconfig_lib" + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR="@localedir@" + +CLASS="--class os" + +case "${GRUB_DISTRIBUTOR}" in + *) + OS="Illumos" + CLASS="--class illumos ${CLASS}" + ;; +esac + +echo "menuentry '$(echo "$OS" | grub_quote)' ${CLASS} \$menuentry_id_option 'illumos-$(grub_get_device_id "${GRUB_DEVICE_BOOT}")' {" +save_default_entry | grub_add_tab +prepare_grub_to_access_device "${GRUB_DEVICE_BOOT}" | grub_add_tab +message="$(gettext_printf "Loading kernel of Illumos ...")" + cat << EOF + insmod gzio + if cpuid -l ; then + ISADIR=amd64 + else + ISADIR= + fi + zfs-bootfs $($grub_mkrelpath /) ZFS_BOOTFS + echo '$(echo "$message" | grub_quote)' + multiboot $($grub_mkrelpath /platform/i86pc/kernel)/\$ISADIR/unix /platform/i86pc/kernel/\$ISADIR/unix -B \$ZFS_BOOTFS,console=text + module $($grub_mkrelpath /platform/i86pc)/\$ISADIR/boot_archive /platform/i86pc/\$ISADIR/boot_archive +} +EOF diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in new file mode 100644 index 0000000..199b20e --- /dev/null +++ b/util/grub.d/10_kfreebsd.in @@ -0,0 +1,252 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +. "$pkgdatadir/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|LC_ALL=C sed 's,[^[:alnum:]_],_,g') --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}") | grub_add_tab)" + fi + + printf '%s\n' "${prepare_module_dir_cache}" + cat << EOF + kfreebsd_module_elf ${module_dir_rel}/${mod}.ko +EOF +} + +title_correction_code= + +kfreebsd_entry () +{ + os="$1" + version="$2" + type="$3" + args="$4" + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi + if [ x$type != xsimple ] ; then + if [ x$type = xrecovery ] ; then + title="$(gettext_printf "%s, with kFreeBSD %s (recovery mode)" "${os}" "${version}")" + else + title="$(gettext_printf "%s, with kFreeBSD %s" "${os}" "${version}")" + fi + replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')" + if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then + quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" + title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" + grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "kfreebsd-advanced-$boot_device_id>kfreebsd-$version-$type-$boot_device_id")" + fi + echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'kfreebsd-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + else + echo "menuentry '$(echo "$OS" | grub_quote)' ${CLASS} \$menuentry_id_option 'kfreebsd-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + fi + if [ x$type != xrecovery ] ; then + save_default_entry | grub_add_tab | sed "s/^/$submenu_indentation/" + fi + if [ -z "${prepare_boot_cache}" ]; then + prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | grub_add_tab)" + fi + + printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/" + message="$(gettext_printf "Loading kernel of FreeBSD %s ..." ${version})" + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' + kfreebsd ${rel_dirname}/${basename} ${args} +EOF + + if test -n "${devices}" ; then + sed "s/^/$submenu_indentation/" << EOF + kfreebsd_loadenv ${devices_rel_dirname}/${devices_basename} +EOF + fi + + load_kfreebsd_module acpi true + + for abstraction in dummy $(${grub_probe} -t abstraction --device ${GRUB_DEVICE}) ; do + case $abstraction in + lvm) load_kfreebsd_module geom_linux_lvm false ;; + esac + done + + case "${kfreebsd_fs}" in + zfs) + load_kfreebsd_module opensolaris false + + ls "/boot/zfs/zpool.cache" > /dev/null + printf '%s\n' "${prepare_boot_cache}" + sed "s/^/$submenu_indentation/" << EOF + kfreebsd_module $(make_system_path_relative_to_its_root /boot)/zfs/zpool.cache type=/boot/zfs/zpool.cache +EOF + ;; + esac + + if [ x${kfreebsd_fs} = xufs ]; then + load_kfreebsd_module ${kfreebsd_fs} true | sed "s/^/$submenu_indentation/" + else + load_kfreebsd_module ${kfreebsd_fs} false | sed "s/^/$submenu_indentation/" + fi + + sed "s/^/$submenu_indentation/" << 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 + list="$list $i" + fi +done +prepare_boot_cache= +boot_device_id= +title_correction_code= + +# Extra indentation to add to menu entries in a submenu. We're not in a submenu +# yet, so it's empty. In a submenu it will be equal to '\t' (one tab). +submenu_indentation="" + +is_top_level=true + +while [ "x$list" != "x" ] ; do + kfreebsd=`version_find_latest $list` + gettext_printf "Found kernel of FreeBSD: %s\n" "$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 + gettext_printf "Found kernel module directory: %s\n" "${module_dir}" >&2 + module_dir_rel=$(make_system_path_relative_to_its_root $module_dir) + fi + + # The GRUB_DISABLE_SUBMENU option used to be different than others since it was + # mentioned in the documentation that has to be set to 'y' instead of 'true' to + # enable it. This caused a lot of confusion to users that set the option to 'y', + # 'yes' or 'true'. This was fixed but all of these values must be supported now. + if [ "x${GRUB_DISABLE_SUBMENU}" = xyes ] || [ "x${GRUB_DISABLE_SUBMENU}" = xy ]; then + GRUB_DISABLE_SUBMENU="true" + fi + + if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then + kfreebsd_entry "${OS}" "${version}" simple + submenu_indentation="$grub_tab" + + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi + # TRANSLATORS: %s is replaced with an OS name + echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'kfreebsd-advanced-$boot_device_id' {" + is_top_level=false + fi + + kfreebsd_entry "${OS}" "${version}" advanced + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then + kfreebsd_entry "${OS}" "${version}" recovery "-s" + fi + + list=`echo $list | tr ' ' '\n' | fgrep -vx "$kfreebsd" | tr '\n' ' '` +done + +# If at least one kernel was found, then we need to +# add a closing '}' for the submenu command. +if [ x"$is_top_level" != xtrue ]; then + echo '}' +fi + +echo "$title_correction_code" + diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in new file mode 100644 index 0000000..e8b01c0 --- /dev/null +++ b/util/grub.d/10_linux.in @@ -0,0 +1,302 @@ +#! /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 <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" + +. "$pkgdatadir/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|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${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 + +# Default to disabling partition uuid support to maintian compatibility with +# older kernels. +GRUB_DISABLE_LINUX_PARTUUID=${GRUB_DISABLE_LINUX_PARTUUID-true} + +# btrfs may reside on multiple devices. We cannot pass them as value of root= parameter +# and mounting btrfs requires user space scanning, so force UUID in this case. +if ( [ "x${GRUB_DEVICE_UUID}" = "x" ] && [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] ) \ + || ( [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ + && [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ] ) \ + || ( ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \ + && ! test -e "/dev/disk/by-partuuid/${GRUB_DEVICE_PARTUUID}" ) \ + || ( test -e "${GRUB_DEVICE}" && uses_abstraction "${GRUB_DEVICE}" lvm ); then + LINUX_ROOT_DEVICE=${GRUB_DEVICE} +elif [ "x${GRUB_DEVICE_UUID}" = "x" ] \ + || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ]; then + LINUX_ROOT_DEVICE=PARTUUID=${GRUB_DEVICE_PARTUUID} +else + LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} +fi + +case x"$GRUB_FS" in + xbtrfs) + 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;; + xzfs) + rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true` + bootfs="`make_system_path_relative_to_its_root / | sed -e "s,@$,,"`" + LINUX_ROOT_DEVICE="ZFS=${rpool}${bootfs%/}" + ;; +esac + +title_correction_code= + +linux_entry () +{ + os="$1" + version="$2" + type="$3" + args="$4" + + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi + if [ x$type != xsimple ] ; then + case $type in + recovery) + title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;; + *) + title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;; + esac + if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then + replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')" + quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" + title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" + grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")" + fi + echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + else + echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + fi + if [ x$type != xrecovery ] ; then + save_default_entry | grub_add_tab + 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 + echo " load_video" | sed "s/^/$submenu_indentation/" + if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \ + && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then + echo " set gfxpayload=keep" | sed "s/^/$submenu_indentation/" + fi + else + if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then + echo " load_video" | sed "s/^/$submenu_indentation/" + fi + echo " set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/" + fi + + echo " insmod gzio" | sed "s/^/$submenu_indentation/" + + if [ x$dirname = x/ ]; then + if [ -z "${prepare_root_cache}" ]; then + prepare_root_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | grub_add_tab)" + fi + printf '%s\n' "${prepare_root_cache}" | sed "s/^/$submenu_indentation/" + else + if [ -z "${prepare_boot_cache}" ]; then + prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | grub_add_tab)" + fi + printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/" + fi + message="$(gettext_printf "Loading Linux %s ..." ${version})" + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' + linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args} +EOF + if test -n "${initrd}" ; then + # TRANSLATORS: ramdisk isn't identifier. Should be translated. + message="$(gettext_printf "Loading initial ramdisk ...")" + initrd_path= + for i in ${initrd}; do + initrd_path="${initrd_path} ${rel_dirname}/${i}" + done + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' + initrd $(echo $initrd_path) +EOF + fi + sed "s/^/$submenu_indentation/" << EOF +} +EOF +} + +machine=`uname -m` +case "x$machine" in + xi?86 | xx86_64) + list= + for i in /boot/vmlinuz-* /vmlinuz-* /boot/kernel-* ; do + if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi + done ;; + *) + list= + for i in /boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* /boot/kernel-* ; do + if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi + done ;; +esac + +case "$machine" in + i?86) GENKERNEL_ARCH="x86" ;; + mips|mips64) GENKERNEL_ARCH="mips" ;; + mipsel|mips64el) GENKERNEL_ARCH="mipsel" ;; + arm*) GENKERNEL_ARCH="arm" ;; + *) GENKERNEL_ARCH="$machine" ;; +esac + +prepare_boot_cache= +prepare_root_cache= +boot_device_id= +title_correction_code= + +# Extra indentation to add to menu entries in a submenu. We're not in a submenu +# yet, so it's empty. In a submenu it will be equal to '\t' (one tab). +submenu_indentation="" + +is_top_level=true +while [ "x$list" != "x" ] ; do + linux=`version_find_latest $list` + gettext_printf "Found linux image: %s\n" "$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_early= + for i in ${GRUB_EARLY_INITRD_LINUX_STOCK} \ + ${GRUB_EARLY_INITRD_LINUX_CUSTOM}; do + if test -e "${dirname}/${i}" ; then + initrd_early="${initrd_early} ${i}" + fi + done + + initrd_real= + for i in "initrd.img-${version}" "initrd-${version}.img" "initrd-${version}.gz" \ + "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}" \ + "initramfs-genkernel-${GENKERNEL_ARCH}-${version}" \ + "initramfs-genkernel-${GENKERNEL_ARCH}-${alt_version}"; do + if test -e "${dirname}/${i}" ; then + initrd_real="${i}" + break + fi + done + + initrd= + if test -n "${initrd_early}" || test -n "${initrd_real}"; then + initrd="${initrd_early} ${initrd_real}" + + initrd_display= + for i in ${initrd}; do + initrd_display="${initrd_display} ${dirname}/${i}" + done + gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 + fi + + 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 -z "${initramfs}" && test -z "${initrd_real}" ; then + # "UUID=" and "ZFS=" magic is parsed by initrd or initramfs. Since there's + # no initrd or builtin initramfs, it can't work here. + if [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] \ + || [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ]; then + + linux_root_device_thisversion=${GRUB_DEVICE} + else + linux_root_device_thisversion=PARTUUID=${GRUB_DEVICE_PARTUUID} + fi + fi + + # The GRUB_DISABLE_SUBMENU option used to be different than others since it was + # mentioned in the documentation that has to be set to 'y' instead of 'true' to + # enable it. This caused a lot of confusion to users that set the option to 'y', + # 'yes' or 'true'. This was fixed but all of these values must be supported now. + if [ "x${GRUB_DISABLE_SUBMENU}" = xyes ] || [ "x${GRUB_DISABLE_SUBMENU}" = xy ]; then + GRUB_DISABLE_SUBMENU="true" + fi + + if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then + linux_entry "${OS}" "${version}" simple \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + + submenu_indentation="$grub_tab" + + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi + # TRANSLATORS: %s is replaced with an OS name + echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {" + is_top_level=false + fi + + linux_entry "${OS}" "${version}" advanced \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then + linux_entry "${OS}" "${version}" recovery \ + "single ${GRUB_CMDLINE_LINUX}" + fi + + list=`echo $list | tr ' ' '\n' | fgrep -vx "$linux" | tr '\n' ' '` +done + +# If at least one kernel was found, then we need to +# add a closing '}' for the submenu command. +if [ x"$is_top_level" != xtrue ]; then + echo '}' +fi + +echo "$title_correction_code" diff --git a/util/grub.d/10_netbsd.in b/util/grub.d/10_netbsd.in new file mode 100644 index 0000000..dc0cd1b --- /dev/null +++ b/util/grub.d/10_netbsd.in @@ -0,0 +1,194 @@ +#! /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 <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +. "$pkgdatadir/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" || test -z "$kversion" || test ! -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,^, ,' | sed "s/^/$submenu_indentation/" + case "${loader}" in + knetbsd) + printf "${grub_tab}knetbsd_module_elf %s\n" "${kmodule_rel}" | sed "s/^/$submenu_indentation/" + ;; + multiboot) + printf "${grub_tab}module %s\n" "${kmodule_rel}" | sed "s/^/$submenu_indentation/" + ;; + esac +} + +title_correction_code= + +netbsd_entry () +{ + loader="$1" # "knetbsd" or "multiboot" + kernel="$2" # absolute path to the kernel file + type="$3" + args="$4" # extra arguments appended to loader command + + kroot_device="$(echo ${GRUB_DEVICE} | sed -e 's,^/dev/r,,')" + + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi + + if [ x$type != xsimple ] ; then + if [ x$type = xrecovery ] ; then + title="$(gettext_printf "%s, with kernel %s (via %s, recovery mode)" "${OS}" "$(echo ${kernel} | sed -e 's,^.*/,,')" "${loader}")" + else + title="$(gettext_printf "%s, with kernel %s (via %s)" "${OS}" "$(echo ${kernel} | sed -e 's,^.*/,,')" "${loader}")" + fi + replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')" + if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then + quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" + title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" + grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "netbsd-advanced-$boot_device_id>netbsd-${loader}-$kernel-$type-$boot_device_id")" + fi + + echo "menuentry '$(echo "$title" | grub_quote)' \$menuentry_id_option 'netbsd-${loader}-$kernel-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + else + echo "menuentry '$(echo "$OS" | grub_quote)' \$menuentry_id_option 'netbsd-${loader}-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + fi + + printf "%s\n" "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/" + case "${loader}" in + knetbsd) + printf "${grub_tab}knetbsd %s -r %s %s\n" \ + "${kernel}" "${kroot_device}" "${GRUB_CMDLINE_NETBSD} ${args}" | sed "s/^/$submenu_indentation/" + ;; + multiboot) + printf "${grub_tab}multiboot %s %s root=%s %s\n" \ + "${kernel}" "${kernel}" "${kroot_device}" "${GRUB_CMDLINE_NETBSD} ${args}" | sed "s/^/$submenu_indentation/" + ;; + esac + + netbsd_load_fs_module "${loader}" "${kernel}" + + printf "}\n" | sed "s/^/$submenu_indentation/" +} + +prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e 's,^, ,')" +boot_device_id= + +# 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" +# Extra indentation to add to menu entries in a submenu. We're not in a submenu +# yet, so it's empty. In a submenu it will be equal to '\t' (one tab). +submenu_indentation="" + +is_top_level=true +for k in /netbsd $(ls -t /netbsd?* 2>/dev/null) ; 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 + + gettext_printf "Found NetBSD kernel: %s\n" "$k" >&2 + + # The GRUB_DISABLE_SUBMENU option used to be different than others since it was + # mentioned in the documentation that has to be set to 'y' instead of 'true' to + # enable it. This caused a lot of confusion to users that set the option to 'y', + # 'yes' or 'true'. This was fixed but all of these values must be supported now. + if [ "x${GRUB_DISABLE_SUBMENU}" = xyes ] || [ "x${GRUB_DISABLE_SUBMENU}" = xy ]; then + GRUB_DISABLE_SUBMENU="true" + fi + + if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then + netbsd_entry "knetbsd" "$k" simple "${GRUB_CMDLINE_NETBSD_DEFAULT}" + submenu_indentation="$grub_tab" + + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi + # TRANSLATORS: %s is replaced with an OS name + echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'netbsd-advanced-$boot_device_id' {" + is_top_level=false + fi + + netbsd_entry "knetbsd" "$k" advanced "${GRUB_CMDLINE_NETBSD_DEFAULT}" + netbsd_entry "multiboot" "$k" advanced "${GRUB_CMDLINE_NETBSD_DEFAULT}" + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then + netbsd_entry "knetbsd" "$k" recovery "-s" + netbsd_entry "multiboot" "$k" recovery "-s" + fi +done + +# If at least one kernel was found, then we need to +# add a closing '}' for the submenu command. +if [ x"$is_top_level" != xtrue ]; then + echo '}' +fi + +echo "$title_correction_code" diff --git a/util/grub.d/10_windows.in b/util/grub.d/10_windows.in new file mode 100644 index 0000000..554c561 --- /dev/null +++ b/util/grub.d/10_windows.in @@ -0,0 +1,100 @@ +#! /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 <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR="@localedir@" + +. "$pkgdatadir/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' + get_os_name_from_boot_ini_part=`sed -n 's,^default=,,p' "$1" | sed 's,\\\\,/,g;s,[ $grub_tab\r]*$,,;1q'` + test -n "$get_os_name_from_boot_ini_part" || return 1 + + # Search 'PARTITION="NAME" ...' + get_os_name_from_boot_ini_name=`sed -n 's,\\\\,/,g;s,^'"$get_os_name_from_boot_ini_part"'="\([^"]*\)".*$,\1,p' "$1" | sed 1q` + test -n "$get_os_name_from_boot_ini_name" || return 1 + + echo "$get_os_name_from_boot_ini_name" +} + + +for drv in $drives ; do + + # Convert to Cygwin path. + dir=`cygpath "$drv"` + test -n "$dir" || continue + + needmap= + osid= + + # Check for Vista bootmgr. + if [ -f "$dir"/bootmgr ] && [ -f "$dir"/boot/bcd ] ; then + OS="$(gettext "Windows Vista/7 (loader)")" + osid=bootmgr + # Check for NTLDR. + elif [ -f "$dir"/ntldr ] && [ -f "$dir"/ntdetect.com ] && [ -f "$dir"/boot.ini ] ; then + OS=`get_os_name_from_boot_ini "$dir"/boot.ini` || OS="$(gettext "Windows NT/2000/XP (loader)")" + osid=ntldr + needmap=t + + else + continue + fi + + # Get boot device. + dev=`${grub_probe} -t device "$dir" 2>/dev/null` || continue + + gettext_printf "Found %s on %s (%s)\n" "$OS" "$drv" "$dev" >&2 + cat << EOF +menuentry '$(echo "$OS" | grub_quote)' \$menuentry_id_option '$osid-$(grub_get_device_id "${dev}")' { +EOF + + save_default_entry | sed -e 's,^,$grub_tab,' + prepare_grub_to_access_device "$dev" | sed 's,^,$grub_tab,' + test -z "$needmap" || cat <<EOF + drivemap -s (hd0) \$root +EOF + cat << EOF + chainloader +1 +} +EOF +done + diff --git a/util/grub.d/10_xnu.in b/util/grub.d/10_xnu.in new file mode 100644 index 0000000..9c40b45 --- /dev/null +++ b/util/grub.d/10_xnu.in @@ -0,0 +1,98 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2006,2007,2008,2009,2012 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR="@localedir@" + +. "$pkgdatadir/grub-mkconfig_lib" + +osx_entry() { + if [ x$2 = x32 ]; then + # TRANSLATORS: it refers to kernel architecture (32-bit) + bitstr="$(gettext "(32-bit)")" + else + # TRANSLATORS: it refers to kernel architecture (64-bit) + bitstr="$(gettext "(64-bit)")" + fi + # TRANSLATORS: it refers on the OS residing on device %s + onstr="$(gettext_printf "(on %s)" "${GRUB_DEVICE}")" + cat << EOF +menuentry '$(echo "Darwin/Mac OS X $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${GRUB_DEVICE}")' { +EOF + save_default_entry | grub_add_tab + prepare_grub_to_access_device ${GRUB_DEVICE} | grub_add_tab + 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 + if [ /kernelcache -nt /System/Library/Extensions ]; then + $1 /kernelcache boot-uuid=\${uuid} rd=*uuid + elif [ -f /System/Library/Kernels/kernel ]; then + $1 /System/Library/Kernels/kernel boot-uuid=\${uuid} rd=*uuid + xnu_kextdir /System/Library/Extensions + else + $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 + 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 +} + +OSXUUID="`${grub_probe} --target=fs_uuid --device ${GRUB_DEVICE} 2> /dev/null`" +osx_entry xnu_kernel 32 +osx_entry xnu_kernel64 64 diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in new file mode 100644 index 0000000..3b1f470 --- /dev/null +++ b/util/grub.d/20_linux_xen.in @@ -0,0 +1,363 @@ +#! /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 <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" + +. "$pkgdatadir/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|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${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 + +# Default to disabling partition uuid support to maintian compatibility with +# older kernels. +GRUB_DISABLE_LINUX_PARTUUID=${GRUB_DISABLE_LINUX_PARTUUID-true} + +# btrfs may reside on multiple devices. We cannot pass them as value of root= parameter +# and mounting btrfs requires user space scanning, so force UUID in this case. +if ( [ "x${GRUB_DEVICE_UUID}" = "x" ] && [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] ) \ + || ( [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ + && [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ] ) \ + || ( ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \ + && ! test -e "/dev/disk/by-partuuid/${GRUB_DEVICE_PARTUUID}" ) \ + || ( test -e "${GRUB_DEVICE}" && uses_abstraction "${GRUB_DEVICE}" lvm ); then + LINUX_ROOT_DEVICE=${GRUB_DEVICE} +elif [ "x${GRUB_DEVICE_UUID}" = "x" ] \ + || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ]; then + LINUX_ROOT_DEVICE=PARTUUID=${GRUB_DEVICE_PARTUUID} +else + LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} +fi + +# Allow overriding GRUB_CMDLINE_LINUX and GRUB_CMDLINE_LINUX_DEFAULT. +if [ "${GRUB_CMDLINE_LINUX_XEN_REPLACE}" ]; then + GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX_XEN_REPLACE}" +fi +if [ "${GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT}" ]; then + GRUB_CMDLINE_LINUX_DEFAULT="${GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT}" +fi + +case x"$GRUB_FS" in + xbtrfs) + 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;; + xzfs) + rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true` + bootfs="`make_system_path_relative_to_its_root / | sed -e "s,@$,,"`" + LINUX_ROOT_DEVICE="ZFS=${rpool}${bootfs%/}" + ;; +esac + +title_correction_code= + +linux_entry () +{ + linux_entry_xsm "$@" false + linux_entry_xsm "$@" true +} +linux_entry_xsm () +{ + os="$1" + version="$2" + xen_version="$3" + type="$4" + args="$5" + xen_args="$6" + xsm="$7" + # If user wants to enable XSM support, make sure there's + # corresponding policy file. + if ${xsm} ; then + xenpolicy="xenpolicy-$xen_version" + if test ! -e "${xen_dirname}/${xenpolicy}" ; then + return + fi + xen_args="$xen_args flask=enforcing" + xen_version="$(gettext_printf "%s (XSM enabled)" "$xen_version")" + # xen_version is used for messages only; actual file is xen_basename + fi + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi + if [ x$type != xsimple ] ; then + if [ x$type = xrecovery ] ; then + title="$(gettext_printf "%s, with Xen %s and Linux %s (recovery mode)" "${os}" "${xen_version}" "${version}")" + else + title="$(gettext_printf "%s, with Xen %s and Linux %s" "${os}" "${xen_version}" "${version}")" + fi + replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')" + if [ x"Xen ${xen_version}>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then + quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" + title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" + grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")" + fi + echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'xen-gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + else + title="$(gettext_printf "%s, with Xen hypervisor" "${os}")" + echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'xen-gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + fi + if [ x$type != xrecovery ] ; then + save_default_entry | grub_add_tab | sed "s/^/$submenu_indentation/" + fi + + if [ -z "${prepare_boot_cache}" ]; then + prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | grub_add_tab)" + fi + printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/" + xmessage="$(gettext_printf "Loading Xen %s ..." ${xen_version})" + lmessage="$(gettext_printf "Loading Linux %s ..." ${version})" + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$xmessage" | grub_quote)' + if [ "\$grub_platform" = "pc" -o "\$grub_platform" = "" ]; then + xen_rm_opts= + else + xen_rm_opts="no-real-mode edd=off" + fi + ${xen_loader} ${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} \${xen_rm_opts} + echo '$(echo "$lmessage" | grub_quote)' + ${module_loader} ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args} +EOF + if test -n "${initrd}" ; then + # TRANSLATORS: ramdisk isn't identifier. Should be translated. + message="$(gettext_printf "Loading initial ramdisk ...")" + initrd_path= + for i in ${initrd}; do + initrd_path="${initrd_path} ${rel_dirname}/${i}" + done + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' + ${module_loader} --nounzip $(echo $initrd_path) +EOF + fi + if test -n "${xenpolicy}" ; then + message="$(gettext_printf "Loading XSM policy ...")" + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' + ${module_loader} ${rel_dirname}/${xenpolicy} +EOF + fi + sed "s/^/$submenu_indentation/" << 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 linux_list="$linux_list $i" ; fi + fi +done +if [ "x${linux_list}" = "x" ] ; then + exit 0 +fi + +file_is_not_xen_garbage () { + case "$1" in + */xen-syms-*) + return 1;; + */xenpolicy-*) + return 1;; + */*.config) + return 1;; + *) + return 0;; + esac +} + +xen_list= +for i in /boot/xen*; do + if grub_file_is_not_garbage "$i" && file_is_not_xen_garbage "$i" ; then xen_list="$xen_list $i" ; fi +done +prepare_boot_cache= +boot_device_id= + +title_correction_code= + +machine=`uname -m` + +case "$machine" in + i?86) GENKERNEL_ARCH="x86" ;; + mips|mips64) GENKERNEL_ARCH="mips" ;; + mipsel|mips64el) GENKERNEL_ARCH="mipsel" ;; + arm*) GENKERNEL_ARCH="arm" ;; + *) GENKERNEL_ARCH="$machine" ;; +esac + +# Extra indentation to add to menu entries in a submenu. We're not in a submenu +# yet, so it's empty. In a submenu it will be equal to '\t' (one tab). +submenu_indentation="" + +is_top_level=true + +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"` + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi + if [ "x$is_top_level" != xtrue ]; then + echo " submenu '$(gettext_printf "Xen hypervisor, version %s" "${xen_version}" | grub_quote)' \$menuentry_id_option 'xen-hypervisor-$xen_version-$boot_device_id' {" + fi + if ($grub_file --is-arm64-efi $current_xen); then + xen_loader="xen_hypervisor" + module_loader="xen_module" + else + if ($grub_file --is-x86-multiboot2 $current_xen); then + xen_loader="multiboot2" + module_loader="module2" + else + xen_loader="multiboot" + module_loader="module" + fi + fi + + initrd_early= + for i in ${GRUB_EARLY_INITRD_LINUX_STOCK} \ + ${GRUB_EARLY_INITRD_LINUX_CUSTOM}; do + if test -e "${xen_dirname}/${i}" ; then + initrd_early="${initrd_early} ${i}" + fi + done + + while [ "x$list" != "x" ] ; do + linux=`version_find_latest $list` + gettext_printf "Found linux image: %s\n" "$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_real= + for i in "initrd.img-${version}" "initrd-${version}.img" "initrd-${version}.gz" \ + "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}" \ + "initramfs-genkernel-${GENKERNEL_ARCH}-${version}" \ + "initramfs-genkernel-${GENKERNEL_ARCH}-${alt_version}" ; do + if test -e "${dirname}/${i}" ; then + initrd_real="$i" + break + fi + done + + initrd= + if test -n "${initrd_early}" || test -n "${initrd_real}"; then + initrd="${initrd_early} ${initrd_real}" + + initrd_display= + for i in ${initrd}; do + initrd_display="${initrd_display} ${dirname}/${i}" + done + gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 + fi + + if test -z "${initrd_real}"; then + # "UUID=" magic is parsed by initrds. Since there's no initrd, it can't work here. + if [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] \ + || [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ]; then + + linux_root_device_thisversion=${GRUB_DEVICE} + else + linux_root_device_thisversion=PARTUUID=${GRUB_DEVICE_PARTUUID} + fi + fi + + # The GRUB_DISABLE_SUBMENU option used to be different than others since it was + # mentioned in the documentation that has to be set to 'y' instead of 'true' to + # enable it. This caused a lot of confusion to users that set the option to 'y', + # 'yes' or 'true'. This was fixed but all of these values must be supported now. + if [ "x${GRUB_DISABLE_SUBMENU}" = xyes ] || [ "x${GRUB_DISABLE_SUBMENU}" = xy ]; then + GRUB_DISABLE_SUBMENU="true" + fi + + if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then + linux_entry "${OS}" "${version}" "${xen_version}" simple \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" "${GRUB_CMDLINE_XEN} ${GRUB_CMDLINE_XEN_DEFAULT}" + + submenu_indentation="$grub_tab$grub_tab" + + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi + # TRANSLATORS: %s is replaced with an OS name + echo "submenu '$(gettext_printf "Advanced options for %s (with Xen hypervisor)" "${OS}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {" + echo " submenu '$(gettext_printf "Xen hypervisor, version %s" "${xen_version}" | grub_quote)' \$menuentry_id_option 'xen-hypervisor-$xen_version-$boot_device_id' {" + is_top_level=false + fi + + linux_entry "${OS}" "${version}" "${xen_version}" advanced \ + "${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}" recovery \ + "single ${GRUB_CMDLINE_LINUX}" "${GRUB_CMDLINE_XEN}" + fi + + list=`echo $list | tr ' ' '\n' | fgrep -vx "$linux" | tr '\n' ' '` + done + if [ x"$is_top_level" != xtrue ]; then + echo ' }' + fi + xen_list=`echo $xen_list | tr ' ' '\n' | fgrep -vx "$current_xen" | tr '\n' ' '` +done + +# If at least one kernel was found, then we need to +# add a closing '}' for the submenu command. +if [ x"$is_top_level" != xtrue ]; then + echo '}' +fi + +echo "$title_correction_code" diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in new file mode 100644 index 0000000..5984e92 --- /dev/null +++ b/util/grub.d/30_os-prober.in @@ -0,0 +1,346 @@ +#! /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 <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR="@localedir@" + +. "$pkgdatadir/grub-mkconfig_lib" + +if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then + grub_warn "$(gettext_printf "os-prober will not be executed to detect other bootable partitions.\nSystems on them will not be added to the GRUB boot configuration.\nCheck GRUB_DISABLE_OS_PROBER documentation entry.")" + exit 0 +fi + +if ! command -v os-prober > /dev/null || ! command -v linux-boot-prober > /dev/null ; then + # missing os-prober and/or linux-boot-prober + exit 0 +fi + +grub_warn "$(gettext_printf "os-prober will be executed to detect other bootable partitions.\nIts output will be used to detect bootable binaries on them and create new boot entries.")" + +OSPROBED="`os-prober | tr ' ' '^' | paste -s -d ' '`" +if [ -z "${OSPROBED}" ] ; then + # empty os-prober output, nothing doing + exit 0 +fi + +osx_entry() { + if [ x$2 = x32 ]; then + # TRANSLATORS: it refers to kernel architecture (32-bit) + bitstr="$(gettext "(32-bit)")" + else + # TRANSLATORS: it refers to kernel architecture (64-bit) + bitstr="$(gettext "(64-bit)")" + fi + # TRANSLATORS: it refers on the OS residing on device %s + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF +menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' { +EOF + save_default_entry | grub_add_tab + prepare_grub_to_access_device ${DEVICE} | grub_add_tab + 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 + if [ /kernelcache -nt /System/Library/Extensions ]; then + $1 /kernelcache boot-uuid=\${uuid} rd=*uuid + elif [ -f /System/Library/Kernels/kernel ]; then + $1 /System/Library/Kernels/kernel boot-uuid=\${uuid} rd=*uuid + xnu_kextdir /System/Library/Extensions + else + $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 + 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 +} + +used_osprober_linux_ids= + +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 UUID="`${grub_probe} --target=fs_uuid --device ${DEVICE%@*}`"; then + EXPUUID="$UUID" + + if [ x"${DEVICE#*@}" != x ] ; then + EXPUUID="${EXPUUID}@${DEVICE#*@}" + fi + + if [ "x${GRUB_OS_PROBER_SKIP_LIST}" != "x" ] && [ "x`echo ${GRUB_OS_PROBER_SKIP_LIST} | grep -i -e '\b'${EXPUUID}'\b'`" != "x" ] ; then + echo "Skipped ${LONGNAME} on ${DEVICE} by user request." >&2 + continue + fi + fi + + BTRFS="`echo ${OS} | cut -d ':' -f 5`" + if [ "x$BTRFS" = "xbtrfs" ]; then + BTRFSuuid="`echo ${OS} | cut -d ':' -f 6`" + BTRFSsubvol="`echo ${OS} | cut -d ':' -f 7`" + fi + + if [ -z "${LONGNAME}" ] ; then + LONGNAME="${LABEL}" + fi + + # os-prober returns text string followed by optional counter + CLASS="--class $(echo "${LABEL}" | LC_ALL=C sed 's,[[:digit:]]*$,,' | cut -d' ' -f1 | tr 'A-Z' 'a-z' | LC_ALL=C sed 's,[^[:alnum:]_],_,g')" + + gettext_printf "Found %s on %s\n" "${LONGNAME}" "${DEVICE}" >&2 + + case ${BOOT} in + chain) + + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF +menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' $CLASS --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' { +EOF + save_default_entry | grub_add_tab + prepare_grub_to_access_device ${DEVICE} | grub_add_tab + + if [ x"`${grub_probe} --device ${DEVICE} --target=partmap`" = xmsdos ]; then + cat << EOF + parttool \${root} hidden- +EOF + fi + + case ${LONGNAME} in + Windows\ Vista*|Windows\ 7*|Windows\ Server\ 2008*) + ;; + *) + cat << EOF + drivemap -s (hd0) \${root} +EOF + ;; + esac + + cat <<EOF + chainloader +1 +} +EOF + ;; + efi) + + EFIPATH=${DEVICE#*@} + DEVICE=${DEVICE%@*} + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF +menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' $CLASS --class os \$menuentry_id_option 'osprober-efi-$(grub_get_device_id "${DEVICE}")' { +EOF + save_default_entry | sed -e "s/^/\t/" + prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/" + + cat <<EOF + chainloader ${EFIPATH} +} +EOF + ;; + linux) + if [ "x$BTRFS" = "xbtrfs" ]; then + LINUXPROBED="`linux-boot-prober btrfs ${BTRFSuuid} ${BTRFSsubvol} 2> /dev/null | tr ' ' '^' | paste -s -d ' '`" + else + LINUXPROBED="`linux-boot-prober ${DEVICE} 2> /dev/null | tr ' ' '^' | paste -s -d ' '`" + fi + prepare_boot_cache= + boot_device_id= + is_top_level=true + title_correction_code= + OS="${LONGNAME}" + + for LINUX in ${LINUXPROBED} ; do + LROOT="`echo ${LINUX} | cut -d ':' -f 1`" + LBOOT="`echo ${LINUX} | cut -d ':' -f 2`" + LLABEL="`echo ${LINUX} | cut -d ':' -f 3 | tr '^' ' '`" + LKERNEL="`echo ${LINUX} | cut -d ':' -f 4`" + LINITRD="`echo ${LINUX} | cut -d ':' -f 5`" + LPARAMS="`echo ${LINUX} | cut -d ':' -f 6- | tr '^' ' '`" + + if [ -z "${LLABEL}" ] ; then + LLABEL="${LONGNAME}" + fi + + if [ "${LROOT}" != "${LBOOT}" ]; then + LKERNEL="${LKERNEL#/boot}" + LINITRD="${LINITRD#/boot}" + fi + + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + recovery_params="$(echo "${LPARAMS}" | grep single)" || true + counter=1 + while echo "$used_osprober_linux_ids" | grep 'osprober-gnulinux-$LKERNEL-${recovery_params}-$counter-$boot_device_id' > /dev/null; do + counter=$((counter+1)); + done + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${DEVICE}")" + fi + used_osprober_linux_ids="$used_osprober_linux_ids 'osprober-gnulinux-$LKERNEL-${recovery_params}-$counter-$boot_device_id'" + + if [ -z "${prepare_boot_cache}" ]; then + prepare_boot_cache="$(prepare_grub_to_access_device ${LBOOT} | grub_add_tab)" + fi + + # The GRUB_DISABLE_SUBMENU option used to be different than others since it was + # mentioned in the documentation that has to be set to 'y' instead of 'true' to + # enable it. This caused a lot of confusion to users that set the option to 'y', + # 'yes' or 'true'. This was fixed but all of these values must be supported now. + if [ "x${GRUB_DISABLE_SUBMENU}" = xyes ] || [ "x${GRUB_DISABLE_SUBMENU}" = xy ]; then + GRUB_DISABLE_SUBMENU="true" + fi + + if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then + cat << EOF +menuentry '$(echo "$OS $onstr" | grub_quote)' $CLASS --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-simple-$boot_device_id' { +EOF + save_default_entry | grub_add_tab + printf '%s\n' "${prepare_boot_cache}" + cat << EOF + linux ${LKERNEL} ${LPARAMS} +EOF + if [ -n "${LINITRD}" ] ; then + cat << EOF + initrd ${LINITRD} +EOF + fi + cat << EOF +} +EOF + echo "submenu '$(gettext_printf "Advanced options for %s" "${OS} $onstr" | grub_quote)' \$menuentry_id_option 'osprober-gnulinux-advanced-$boot_device_id' {" + is_top_level=false + fi + title="${LLABEL} $onstr" + cat << EOF + menuentry '$(echo "$title" | grub_quote)' --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-$LKERNEL-${recovery_params}-$boot_device_id' { +EOF + save_default_entry | sed -e "s/^/$grub_tab$grub_tab/" + printf '%s\n' "${prepare_boot_cache}" | grub_add_tab + cat << EOF + linux ${LKERNEL} ${LPARAMS} +EOF + if [ -n "${LINITRD}" ] ; then + cat << EOF + initrd ${LINITRD} +EOF + fi + cat << EOF + } +EOF + if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then + replacement_title="$(echo "Advanced options for ${OS} $onstr" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')" + quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" + title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" + grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")" + fi + done + if [ x"$is_top_level" != xtrue ]; then + echo '}' + fi + echo "$title_correction_code" + ;; + macosx) + if [ "${UUID}" ]; then + OSXUUID="${UUID}" + osx_entry xnu_kernel 32 + osx_entry xnu_kernel64 64 + fi + ;; + hurd) + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF +menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' { +EOF + save_default_entry | grub_add_tab + prepare_grub_to_access_device ${DEVICE} | grub_add_tab + grub_device="`${grub_probe} --device ${DEVICE} --target=drive`" + mach_device="`echo "${grub_device}" | sed -e 's/(\(hd.*\),msdos\(.*\))/\1s\2/'`" + grub_fs="`${grub_probe} --device ${DEVICE} --target=fs`" + case "${grub_fs}" in + *fs) hurd_fs="${grub_fs}" ;; + *) hurd_fs="${grub_fs}fs" ;; + esac + cat << EOF + multiboot /boot/gnumach.gz root=device:${mach_device} + 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 + ;; + minix) + cat << EOF +menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" { +EOF + save_default_entry | sed -e "s/^/\t/" + prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/" + cat << EOF + multiboot /boot/image_latest +} +EOF + ;; + *) + # TRANSLATORS: %s is replaced by OS name. + gettext_printf "%s is not yet supported by grub-mkconfig.\n" " ${LONGNAME}" >&2 + ;; + esac +done diff --git a/util/grub.d/30_uefi-firmware.in b/util/grub.d/30_uefi-firmware.in new file mode 100644 index 0000000..d344d38 --- /dev/null +++ b/util/grub.d/30_uefi-firmware.in @@ -0,0 +1,44 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2020 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see <http://www.gnu.org/licenses/>. + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" + +export TEXTDOMAIN=@PACKAGE@ +export TEXTDOMAINDIR="@localedir@" + +. "$pkgdatadir/grub-mkconfig_lib" + +EFI_VARS_DIR=/sys/firmware/efi/efivars +EFI_GLOBAL_VARIABLE=8be4df61-93ca-11d2-aa0d-00e098032b8c +OS_INDICATIONS="$EFI_VARS_DIR/OsIndicationsSupported-$EFI_GLOBAL_VARIABLE" + +if [ -e "$OS_INDICATIONS" ] && \ + [ "$(( $(printf 0x%x \'"$(cat $OS_INDICATIONS | cut -b5)"\') & 1 ))" = 1 ]; then + LABEL="UEFI Firmware Settings" + + gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2 + + cat << EOF +menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' { + fwsetup +} +EOF +fi 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..a08363d --- /dev/null +++ b/util/grub.d/41_custom.in @@ -0,0 +1,9 @@ +#!/bin/sh +cat <<EOF +if [ -f \${config_directory}/custom.cfg ]; then + source \${config_directory}/custom.cfg +elif [ -z "\${config_directory}" -a -f \$prefix/custom.cfg ]; then + source \$prefix/custom.cfg +fi +EOF + diff --git a/util/grub.d/README b/util/grub.d/README new file mode 100644 index 0000000..3ea109d --- /dev/null +++ b/util/grub.d/README @@ -0,0 +1,11 @@ + +All executable files in this directory are processed in shell expansion order. + + 00_*: Reserved for 00_header. + 10_*: Native boot entries. + 20_*: Third party apps (e.g. memtest86+). + +The number namespace in-between is configurable by system installer and/or +administrator. For example, you can add an entry to boot another OS as +01_otheros, 11_otheros, etc, depending on the position you want it to occupy in +the menu; and then adjust the default setting via /etc/default/grub. diff --git a/util/i386/efi/grub-dumpdevtree b/util/i386/efi/grub-dumpdevtree new file mode 100644 index 0000000..51004cc --- /dev/null +++ b/util/i386/efi/grub-dumpdevtree @@ -0,0 +1,22 @@ +#!/bin/sh +# +# 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 <http://www.gnu.org/licenses/>. + +if [ "x$1" = "x" ]; then + echo "Filename required". +fi + +ioreg -lw0 -p IODeviceTree -n efi -r -x |grep device-properties | sed 's/.*<//;s/>.*//;' | xxd -r -p > $1 diff --git a/util/ieee1275/grub-ofpathname.c b/util/ieee1275/grub-ofpathname.c new file mode 100644 index 0000000..300fbdd --- /dev/null +++ b/util/ieee1275/grub-ofpathname.c @@ -0,0 +1,56 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <grub/util/misc.h> +#include <grub/util/ofpath.h> + +#include <grub/i18n.h> + +#include "progname.h" + +#include <string.h> + +int main(int argc, char **argv) +{ + char *of_path; + + grub_util_host_init (&argc, &argv); + + if (argc != 2 || strcmp (argv[1], "--help") == 0) + { + printf(_("Usage: %s DEVICE\n"), program_name); + return 1; + } + if (strcmp (argv[1], "--version") == 0) + { + printf ("%s\n", PACKAGE_STRING); + return 1; + } + + of_path = grub_util_devname_to_ofpath (argv[1]); + + if (of_path) + printf ("%s\n", of_path); + + free (of_path); + + return 0; +} diff --git a/util/import_gcry.py b/util/import_gcry.py new file mode 100644 index 0000000..2b3322d --- /dev/null +++ b/util/import_gcry.py @@ -0,0 +1,659 @@ +#* +#* 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 <http://www.gnu.org/licenses/>. +#* + +import re +import sys +import os +import datetime +import codecs + +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) +mpidir = os.path.join (basedir, "mpi") +try: + os.makedirs (mpidir) +except: + print ("WARNING: %s already exists" % mpidir) + +srcdir = os.path.join (basedir, "src") +try: + os.makedirs (srcdir) +except: + print ("WARNING: %s already exists" % srcdir) + +cipher_files = sorted (os.listdir (cipher_dir_in)) +conf = codecs.open (os.path.join ("grub-core", "Makefile.gcry.def"), "w", "utf-8") +conf.write ("AutoGen definitions Makefile.tpl;\n\n") +confutil = codecs.open ("Makefile.utilgcry.def", "w", "utf-8") +confutil.write ("AutoGen definitions Makefile.tpl;\n\n") +confutil.write ("library = {\n"); +confutil.write (" name = libgrubgcry.a;\n"); +confutil.write (" cflags = '$(CFLAGS_GCRY)';\n"); +confutil.write (" cppflags = '$(CPPFLAGS_GCRY)';\n"); +confutil.write (" extra_dist = grub-core/lib/libgcrypt-grub/cipher/ChangeLog;\n"); +confutil.write ("\n"); +chlog = "" +modules_sym_md = [] + +# 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_tiger1" : 64, + "_gcry_digest_spec_tiger2" : 64, + "_gcry_digest_spec_whirlpool" : 64} + +cryptolist = codecs.open (os.path.join (cipher_dir_out, "crypto.lst"), "w", "utf-8") + +# 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"); + +cryptolist.write ("ADLER32: adler32\n"); +cryptolist.write ("CRC64: crc64\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" or cipher_file == "ChangeLog-2011": + 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) or cipher_file == "kdf.c" or cipher_file == "elgamal.c" or cipher_file == "primegen.c" or cipher_file == "ecc.c" or cipher_file == "test-getrusage.c": + 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 = codecs.open (infile, "r", "utf-8") + fw = codecs.open (outfile, "w", "utf-8") + fw.write ("/* This file was automatically imported with \n") + fw.write (" import_gcry.py. Please don't modify it */\n") + fw.write ("#include <grub/dl.h>\n") + if cipher_file == "camellia.h": + fw.write ("#include <grub/misc.h>\n") + fw.write ("void camellia_setup128(const unsigned char *key, grub_uint32_t *subkey);\n") + fw.write ("void camellia_setup192(const unsigned char *key, grub_uint32_t *subkey);\n") + fw.write ("void camellia_setup256(const unsigned char *key, grub_uint32_t *subkey);\n") + fw.write ("void camellia_encrypt128(const grub_uint32_t *subkey, grub_uint32_t *io);\n") + fw.write ("void camellia_encrypt192(const grub_uint32_t *subkey, grub_uint32_t *io);\n") + fw.write ("void camellia_encrypt256(const grub_uint32_t *subkey, grub_uint32_t *io);\n") + fw.write ("void camellia_decrypt128(const grub_uint32_t *subkey, grub_uint32_t *io);\n") + fw.write ("void camellia_decrypt192(const grub_uint32_t *subkey, grub_uint32_t *io);\n") + fw.write ("void camellia_decrypt256(const grub_uint32_t *subkey, grub_uint32_t *io);\n") + fw.write ("#define memcpy grub_memcpy\n") + # Whole libgcrypt is distributed under GPLv3+ or compatible + if isc: + fw.write ("GRUB_MOD_LICENSE (\"GPLv3+\");\n") + + ciphernames = [] + mdnames = [] + mdctxsizes = [] + pknames = [] + hold = False + skip = 0 + skip2 = False + ismd = False + mdarg = 0 + ispk = False + iscipher = 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: + line = line + if skip_statement: + if not re.search (";", line) is None: + skip_statement = False + continue + if skip > 0: + if line[0] == "}": + skip = skip - 1 + 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: + spl = line.split (",") + if mdarg + len (spl) > 9 and mdarg <= 9 and ("sizeof" in spl[9-mdarg]): + mdctxsizes.append (spl[9-mdarg].lstrip ().rstrip()) + mdarg = mdarg + len (spl) - 1 + if ismd or iscipher or ispk: + if not re.search (" *};", line) is None: + if not iscomma: + fw.write (" ,\n") + fw.write ("#ifdef GRUB_UTIL\n"); + fw.write (" .modname = \"%s\",\n" % modname); + fw.write ("#endif\n"); + if ismd: + if not (mdname in mdblocksizes): + print ("ERROR: Unknown digest blocksize: %s\n" + % mdname) + exit (1) + fw.write (" .blocksize = %s\n" + % mdblocksizes [mdname]) + ismd = False + mdarg = 0 + iscipher = False + ispk = 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 = 1 + 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 and exclude anything needing good + # randomness. + if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer|tripledes_set2keys|do_tripledes_set_extra_info|_gcry_rmd160_mixblock|serpent_test|dsa_generate_ext|test_keys|gen_k|sign|gen_x931_parm_xp|generate_x931|generate_key|dsa_generate|dsa_sign|ecc_sign|generate|generate_fips186|_gcry_register_pk_dsa_progress|_gcry_register_pk_ecc_progress|progress|scanval|ec2os|ecc_generate_ext|ecc_generate|compute_keygrip|ecc_get_param|_gcry_register_pk_dsa_progress|gen_x931_parm_xp|gen_x931_parm_xi|rsa_decrypt|rsa_sign|rsa_generate_ext|rsa_generate|secret|check_exponent|rsa_blind|rsa_unblind|extract_a_from_sexp|curve_free|curve_copy|point_set)", line) is None: + + skip = 1 + if not re.match ("selftest", line) is None and cipher_file == "idea.c": + skip = 3 + + if not re.match ("serpent_test", line) is None: + fw.write ("static const char *serpent_test (void) { return 0; }\n"); + if not re.match ("dsa_generate", line) is None: + fw.write ("#define dsa_generate 0"); + if not re.match ("ecc_generate", line) is None: + fw.write ("#define ecc_generate 0"); + if not re.match ("rsa_generate ", line) is None: + fw.write ("#define rsa_generate 0"); + if not re.match ("rsa_sign", line) is None: + fw.write ("#define rsa_sign 0"); + if not re.match ("rsa_decrypt", line) is None: + fw.write ("#define rsa_decrypt 0"); + if not re.match ("dsa_sign", line) is None: + fw.write ("#define dsa_sign 0"); + if not re.match ("ecc_sign", line) is None: + fw.write ("#define ecc_sign 0"); + 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.groups ()[0] + 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 ismd) + assert (not ispk) + assert (not iscipher) + assert (not iscryptostart) + ciphername = line [len ("gcry_cipher_spec_t"):].strip () + ciphername = re.match("[a-zA-Z0-9_]*",ciphername).group () + ciphernames.append (ciphername) + iscipher = True + iscryptostart = True + + m = re.match ("gcry_pk_spec_t", line) + if isc and not m is None: + assert (not ismd) + assert (not ispk) + assert (not iscipher) + assert (not iscryptostart) + pkname = line [len ("gcry_pk_spec_t"):].strip () + pkname = re.match("[a-zA-Z0-9_]*",pkname).group () + pknames.append (pkname) + ispk = True + iscryptostart = True + + m = re.match ("gcry_md_spec_t", line) + if isc and not m is None: + assert (not ismd) + assert (not ispk) + assert (not iscipher) + 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 + mdarg = 0 + 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 gcry_mpi_t gen_k .*;$", line) + if not m is None: + chmsg = "(gen_k): Removed declaration." + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue + m = re.match ("static (int|void) test_keys .*;$", line) + if not m is None: + chmsg = "(test_keys): Removed declaration." + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue + m = re.match ("static void secret .*;$", line) + if not m is None: + chmsg = "(secret): Removed declaration." + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue + m = re.match ("static void \(\*progress_cb\).*;$", line) + if not m is None: + chmsg = "(progress_cb): Removed declaration." + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue + m = re.match ("static void \*progress_cb_data.*;$", line) + if not m is None: + chmsg = "(progress_cb): Removed declaration." + 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|static gcry_mpi_t|static void|void|static elliptic_curve_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_set3keys \(.*\);", 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 ("static int tripledes_set3keys \(", line) + if not m is None: + skip_statement = True + continue + m = re.match ("static const char sample_secret_key", line) + if not m is None: + skip_statement = True + continue + m = re.match ("static const char sample_public_key", line) + if not m is None: + skip_statement = True + continue + m = re.match ("static void sign|static gpg_err_code_t sign|static gpg_err_code_t generate", + 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 ("pk_extra_spec_t", line) + if isc and not m is None: + skip2 = True + fname = line[len ("pk_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 or len (pknames) > 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 + if len (ciphernames) > 0 or len (mdnames) > 0: + modules_sym_md.append (modname) + 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 ctxsize in mdctxsizes: + fw.write (" COMPILE_TIME_ASSERT(%s <= GRUB_CRYPTO_MAX_MD_CONTEXT_SIZE);\n" % ctxsize) + for mdname in mdnames: + chmsg = "Register digest %s" % mdname + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write (" grub_md_register (&%s);\n" % mdname) + for pkname in pknames: + chmsg = "Register pk %s" % mdname + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write (" grub_crypto_pk_%s = &%s;\n" + % (pkname.replace ("_gcry_pubkey_spec_", ""), pkname)) + 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) + for pkname in pknames: + chmsg = "Unregister pk %s" % mdname + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write (" grub_crypto_pk_%s = 0;\n" + % (pkname.replace ("_gcry_pubkey_spec_", ""))) + fw.write ("}\n") + conf.write ("module = {\n") + conf.write (" name = %s;\n" % modname) + for src in modfiles.split(): + conf.write (" common = %s;\n" % src) + if len (ciphernames) > 0 or len (mdnames) > 0: + confutil.write (" common = grub-core/%s;\n" % src) + if modname == "gcry_ecc": + conf.write (" common = lib/libgcrypt-grub/mpi/ec.c;\n") + conf.write (" cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';\n") + elif modname == "gcry_rijndael" or modname == "gcry_md4" or modname == "gcry_md5" or modname == "gcry_rmd160" or modname == "gcry_sha1" or modname == "gcry_sha256" or modname == "gcry_sha512" or modname == "gcry_tiger": + # Alignment checked by hand + conf.write (" cflags = '$(CFLAGS_GCRY) -Wno-cast-align';\n"); + else: + conf.write (" cflags = '$(CFLAGS_GCRY)';\n"); + conf.write (" cppflags = '$(CPPFLAGS_GCRY)';\n"); + conf.write ("};\n\n") + f.close () + fw.close () + if nch: + chlog = "%s%s\n" % (chlog, chlognew) + elif isc and cipher_file != "camellia.c": + print ("WARNING: C file isn't a module: %s" % cipher_file) + f.close () + fw.close () + os.remove (outfile) + chlog = "%s\n * %s: Removed" % (chlog, cipher_file) + continue + chlog = "%s%sSkipped unknown file\n" % (chlog, chlognew) + print ("WARNING: unknown file %s" % cipher_file) + +cryptolist.close () + +for src in sorted (os.listdir (os.path.join (indir, "src"))): + if src == "versioninfo.rc.in" or src == "ath.c" or src == "ChangeLog-2011" \ + or src == "dumpsexp.c" or src == "fips.c" or src == "gcrypt.h.in" \ + or src == "gcryptrnd.c"or src == "getrandom.c" \ + or src == "global.c" or src == "hmac256.c" \ + or src == "hwfeatures.c" or src == "libgcrypt-config.in" \ + or src == "libgcrypt.def" or src == "libgcrypt.m4" \ + or src == "libgcrypt.vers" or src == "Makefile.am" \ + or src == "Manifest" or src == "misc.c" \ + or src == "missing-string.c" or src == "module.c" \ + or src == "secmem.c" or src == "sexp.c" \ + or src == "stdmem.c" or src == "visibility.c": + continue + outfile = os.path.join (basedir, "src", src) + infile = os.path.join (indir, "src", src) + if os.path.isdir (infile): + continue + fw = codecs.open (outfile, "w", "utf-8") + if src == "gcrypt-module.h": + fw.close () + continue + if src == "visibility.h": + fw.write ("# include <grub/gcrypt/gcrypt.h>\n") + fw.close () + continue + f = codecs.open (infile, "r", "utf-8") + if src == "types.h": + fw.write (f.read ().replace ("float f;", "").replace ("double g;", "")) + f.close () + fw.close () + continue + + if src == "g10lib.h": + fw.write (f.read ().replace ("(printf,f,a)", "(__printf__,f,a)")) + f.close () + fw.close () + continue + + fw.write (f.read ()) + f.close () + fw.close () + +for src in sorted (os.listdir (os.path.join (indir, "mpi"))): + if src == "config.links" or src == "ChangeLog-2011" \ + or src == "mpi-scan.c" or src == "Manifest" \ + or src == "Makefile.am": + continue + infile = os.path.join (indir, "mpi", src) + outfile = os.path.join (basedir, "mpi", src) + if os.path.isdir (infile): + continue + f = codecs.open (infile, "r", "utf-8") + fw = codecs.open (outfile, "w", "utf-8") + fw.write ("/* This file was automatically imported with \n") + fw.write (" import_gcry.py. Please don't modify it */\n") + hold = False + skip = 0 + for line in f: + if skip > 0: + if line[0] == "}": + skip = skip - 1 + continue + if hold: + hold = False + # We're optimising for size and exclude anything needing good + # randomness. + if not re.match ("(_gcry_mpi_get_hw_config|gcry_mpi_randomize)", line) is None: + skip = 1 + continue + else: + fw.write (holdline) + m = re.match ("(const char( |)\*|void) *$", line) + if not m is None: + hold = True + holdline = line + continue + m = re.match ("#include \"mod-source-info\.h\"", line) + if not m is None: + continue + fw.write (line) + +chlog = "%s * crypto.lst: New file.\n" % chlog + +outfile = os.path.join (cipher_dir_out, "types.h") +fw=codecs.open (outfile, "w", "utf-8") +fw.write ("#include <grub/types.h>\n") +fw.write ("#include <cipher_wrap.h>\n") +chlog = "%s * types.h: New file.\n" % chlog +fw.close () + +outfile = os.path.join (cipher_dir_out, "memory.h") +fw=codecs.open (outfile, "w", "utf-8") +fw.write ("#include <cipher_wrap.h>\n") +chlog = "%s * memory.h: New file.\n" % chlog +fw.close () + + +outfile = os.path.join (cipher_dir_out, "cipher.h") +fw=codecs.open (outfile, "w", "utf-8") +fw.write ("#include <grub/crypto.h>\n") +fw.write ("#include <cipher_wrap.h>\n") +chlog = "%s * cipher.h: Likewise.\n" % chlog +fw.close () + +outfile = os.path.join (cipher_dir_out, "g10lib.h") +fw=codecs.open (outfile, "w", "utf-8") +fw.write ("#include <cipher_wrap.h>\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") + +conf.close (); + +initfile = codecs.open (os.path.join (cipher_dir_out, "init.c"), "w", "utf-8") +initfile.write ("#include <grub/crypto.h>\n") +for module in modules_sym_md: + initfile.write ("extern void grub_%s_init (void);\n" % module) + initfile.write ("extern void grub_%s_fini (void);\n" % module) +initfile.write ("\n") +initfile.write ("void\n") +initfile.write ("grub_gcry_init_all (void)\n") +initfile.write ("{\n") +for module in modules_sym_md: + initfile.write (" grub_%s_init ();\n" % module) +initfile.write ("}\n") +initfile.write ("\n") +initfile.write ("void\n") +initfile.write ("grub_gcry_fini_all (void)\n") +initfile.write ("{\n") +for module in modules_sym_md: + initfile.write (" grub_%s_fini ();\n" % module) +initfile.write ("}\n") +initfile.close () + +confutil.write (" common = grub-core/lib/libgcrypt-grub/cipher/init.c;\n") +confutil.write ("};\n"); +confutil.close (); + + +f=codecs.open (infile, "r", "utf-8") +fw=codecs.open (outfile, "w", "utf-8") +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_gcrypth.sed b/util/import_gcrypth.sed new file mode 100644 index 0000000..fe6d1a0 --- /dev/null +++ b/util/import_gcrypth.sed @@ -0,0 +1,18 @@ +/^#@INSERT_SYS_SELECT_H@/ d +/^@FALLBACK_SOCKLEN_T@/ d +/^# *include <stdlib\.h>/ d +/^# *include <string\.h>/ d +/^# *include <winsock2\.h>/ d +/^# *include <ws2tcpip\.h>/ d +/^# *include <time\.h>/ d +/^# *include <sys\/socket\.h>/ d +/^# *include <sys\/time\.h>/ d +/^ typedef long ssize_t;/ d +/^ typedef int pid_t;/ d +/^# *include <gpg-error\.h>/ s,#include <gpg-error.h>,#include <grub/gcrypt/gpg-error.h>, +/^typedef gpg_error_t gcry_error_t;/ d +/^typedef gpg_err_code_t gcry_err_code_t;/ d +/^typedef struct gcry_mpi \*gcry_mpi_t;/ d +/^struct gcry_thread_cbs/ d +s,_gcry_mpi_invm,gcry_mpi_invm,g +p
\ No newline at end of file diff --git a/util/import_unicode.py b/util/import_unicode.py new file mode 100644 index 0000000..08f8059 --- /dev/null +++ b/util/import_unicode.py @@ -0,0 +1,193 @@ +#* +#* GRUB -- GRand Unified Bootloader +#* Copyright (C) 2010 Free Software Foundation, Inc. +#* +#* GRUB is free software: you can redistribute it and/or modify +#* it under the terms of the GNU General Public License as published by +#* the Free Software Foundation, either version 3 of the License, or +#* (at your option) any later version. +#* +#* GRUB is distributed in the hope that it will be useful, +#* but WITHOUT ANY WARRANTY; without even the implied warranty of +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#* GNU General Public License for more details. +#* +#* You should have received a copy of the GNU General Public License +#* along with GRUB. If not, see <http://www.gnu.org/licenses/>. +#* + +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 <grub/unicode.h>\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 - begincode + 1, \ + lastbiditype, \ + lastcombtype, lastmirrortype, \ + lastjoin))) + if lastcode - begincode + 1 >= 0x200: + print ("Too long range") + raise + 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/misc.c b/util/misc.c new file mode 100644 index 0000000..d545212 --- /dev/null +++ b/util/misc.c @@ -0,0 +1,225 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <errno.h> +#include <setjmp.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#include <time.h> + +#include <grub/kernel.h> +#include <grub/dl.h> +#include <grub/misc.h> +#include <grub/cache.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/mm.h> +#include <grub/term.h> +#include <grub/time.h> +#include <grub/i18n.h> +#include <grub/script_sh.h> +#include <grub/emu/hostfile.h> + +#define ENABLE_RELOCATABLE 0 +#ifdef GRUB_BUILD +const char *program_name = GRUB_BUILD_PROGRAM_NAME; +#else +#include "progname.h" +#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; +} + +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 = grub_util_fopen (path, "rb"); + if (! fp) + grub_util_error (_("cannot open `%s': %s"), path, + strerror (errno)); + + if (fread (img, 1, size, fp) != size) + grub_util_error (_("cannot read `%s': %s"), path, + strerror (errno)); + + fclose (fp); + + return img; +} + +void +grub_util_write_image_at (const void *img, size_t size, off_t offset, FILE *out, + const char *name) +{ + grub_util_info ("writing 0x%" GRUB_HOST_PRIxLONG_LONG " bytes at offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) size, (unsigned long long) offset); + if (fseeko (out, offset, SEEK_SET) == -1) + grub_util_error (_("cannot seek `%s': %s"), + name, strerror (errno)); + if (fwrite (img, 1, size, out) != size) + grub_util_error (_("cannot write to `%s': %s"), + name, strerror (errno)); +} + +void +grub_util_write_image (const char *img, size_t size, FILE *out, + const char *name) +{ + grub_util_info ("writing 0x%" GRUB_HOST_PRIxLONG_LONG " bytes", (unsigned long long) size); + if (fwrite (img, 1, size, out) != size) + { + if (!name) + grub_util_error (_("cannot write to the stdout: %s"), + strerror (errno)); + else + grub_util_error (_("cannot write to `%s': %s"), + name, strerror (errno)); + } +} + +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 (struct grub_script *script) +{ + if (script == 0 || script->cmd == 0) + return 0; + + return script->cmd->exec (script->cmd); +} + +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) +{ +} + +/* Used in comparison of arrays of strings with qsort */ +int +grub_qsort_strcmp (const void *p1, const void *p2) +{ + return strcmp(*(char *const *)p1, *(char *const *)p2); +} + diff --git a/util/mkimage.c b/util/mkimage.c new file mode 100644 index 0000000..a26cf76 --- /dev/null +++ b/util/mkimage.c @@ -0,0 +1,1791 @@ +/* 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 <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/elf.h> +#include <grub/aout.h> +#include <grub/i18n.h> +#include <grub/kernel.h> +#include <grub/disk.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/util/resolve.h> +#include <grub/misc.h> +#include <grub/offsets.h> +#include <grub/crypto.h> +#include <grub/dl.h> +#include <time.h> +#include <multiboot.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include <grub/efi/pe32.h> +#include <grub/uboot/image.h> +#include <grub/arm/reloc.h> +#include <grub/arm64/reloc.h> +#include <grub/ia64/reloc.h> +#include <grub/osdep/hostfile.h> +#include <grub/util/install.h> +#include <grub/util/mkimage.h> + +#define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof)) + +#ifdef USE_LIBLZMA +#include <lzma.h> +#endif + +#pragma GCC diagnostic ignored "-Wcast-align" + +#define TARGET_NO_FIELD 0xffffffff + +/* use 2015-01-01T00:00:00+0000 as a stock timestamp */ +#define STABLE_EMBEDDING_TIMESTAMP 1420070400 + +#define EFI32_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_FILE_ALIGNMENT) + +#define EFI64_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_FILE_ALIGNMENT) + +static const struct grub_install_image_target_desc image_targets[] = + { + { + .dirname = "i386-coreboot", + .names = { "i386-coreboot", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_COREBOOT, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .reloc_table_offset = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .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 + }, + { + .dirname = "i386-multiboot", + .names = { "i386-multiboot", NULL}, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_COREBOOT, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .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 + }, + { + .dirname = "i386-pc", + .names = { "i386-pc", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_PC, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR, + .default_compression = GRUB_COMPRESSION_LZMA + }, + { + .dirname = "i386-xen_pvh", + .names = { "i386-xen_pvh", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_XEN_PVH, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .elf_target = EM_386, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_XEN_PVH_LINK_ADDR, + .mod_align = GRUB_KERNEL_I386_XEN_PVH_MOD_ALIGN, + .link_align = 4 + }, + { + .dirname = "i386-pc", + .names = { "i386-pc-pxe", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_PC_PXE, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR, + .default_compression = GRUB_COMPRESSION_LZMA + }, + { + .dirname = "i386-pc", + .names = { "i386-pc-eltorito", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_PC_ELTORITO, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR, + .default_compression = GRUB_COMPRESSION_LZMA + }, + { + .dirname = "i386-efi", + .names = { "i386-efi", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI32_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_I386, + .elf_target = EM_386, + }, + { + .dirname = "i386-ieee1275", + .names = { "i386-ieee1275", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_IEEE1275, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .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, + }, + { + .dirname = "i386-qemu", + .names = { "i386-qemu", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_QEMU, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_QEMU_LINK_ADDR + }, + { + .dirname = "x86_64-efi", + .names = { "x86_64-efi", NULL }, + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI64_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_X86_64, + .elf_target = EM_X86_64, + }, + { + .dirname = "i386-xen", + .names = { "i386-xen", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_XEN, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = 0, + .elf_target = EM_386, + .mod_gap = GRUB_KERNEL_I386_XEN_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_XEN_MOD_ALIGN, + .link_align = 4 + }, + { + .dirname = "x86_64-xen", + .names = { "x86_64-xen", NULL }, + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_XEN, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = 0, + .elf_target = EM_X86_64, + .mod_gap = GRUB_KERNEL_X86_64_XEN_MOD_GAP, + .mod_align = GRUB_KERNEL_X86_64_XEN_MOD_ALIGN, + .link_align = 8 + }, + { + .dirname = "mipsel-loongson", + .names = { "mipsel-yeeloong-flash", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_YEELOONG_FLASH, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mipsel-loongson", + .names = { "mipsel-fuloong2f-flash", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_FULOONG2F_FLASH, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mipsel-loongson", + .names = { "mipsel-loongson-elf", "mipsel-yeeloong-elf", + "mipsel-fuloong2f-elf", "mipsel-fuloong2e-elf", + "mipsel-fuloong-elf", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_LOONGSON_ELF, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "powerpc-ieee1275", + .names = { "powerpc-ieee1275", NULL }, + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_PPC, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .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 + }, + { + .dirname = "sparc64-ieee1275", + .names = { "sparc64-ieee1275-raw", NULL }, + .voidp_sizeof = 8, + .bigendian = 1, + .id = IMAGE_SPARC64_RAW, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR, + .mod_align = GRUB_KERNEL_SPARC64_IEEE1275_MOD_ALIGN, + }, + { + .dirname = "sparc64-ieee1275", + .names = { "sparc64-ieee1275-cdcore", NULL }, + .voidp_sizeof = 8, + .bigendian = 1, + .id = IMAGE_SPARC64_CDCORE, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR, + .mod_align = GRUB_KERNEL_SPARC64_IEEE1275_MOD_ALIGN, + }, + { + .dirname = "sparc64-ieee1275", + .names = { "sparc64-ieee1275-aout", NULL }, + .voidp_sizeof = 8, + .bigendian = 1, + .id = IMAGE_SPARC64_AOUT, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR, + .mod_align = GRUB_KERNEL_SPARC64_IEEE1275_MOD_ALIGN, + }, + { + .dirname = "ia64-efi", + .names = {"ia64-efi", NULL}, + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI64_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_IA64, + .elf_target = EM_IA_64, + }, + { + .dirname = "mips-arc", + .names = {"mips-arc", NULL}, + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_MIPS_ARC, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_ARC_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mipsel-arc", + .names = {"mipsel-arc", NULL}, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_MIPS_ARC, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPSEL_ARC_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mipsel-qemu_mips", + .names = { "mipsel-qemu_mips-elf", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_LOONGSON_ELF, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mips-qemu_mips", + .names = { "mips-qemu_mips-flash", NULL }, + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_QEMU_MIPS_FLASH, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mipsel-qemu_mips", + .names = { "mipsel-qemu_mips-flash", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_QEMU_MIPS_FLASH, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mips-qemu_mips", + .names = { "mips-qemu_mips-elf", NULL }, + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_LOONGSON_ELF, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "arm-uboot", + .names = { "arm-uboot", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_UBOOT, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = GRUB_KERNEL_ARM_UBOOT_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN, + .vaddr_offset = 0, + .elf_target = EM_ARM, + .mod_gap = GRUB_KERNEL_ARM_UBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN, + .link_align = 4 + }, + /* For coreboot versions that don't support self-relocating images. */ + { + .dirname = "arm-coreboot-vexpress", + .names = { "arm-coreboot-vexpress", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_COREBOOT, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = GRUB_KERNEL_ARM_COREBOOT_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN, + .vaddr_offset = 0, + .elf_target = EM_ARM, + .mod_gap = GRUB_KERNEL_ARM_COREBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN, + .link_align = 4, + .link_addr = 0x62000000, + }, + { + .dirname = "arm-coreboot-veyron", + .names = { "arm-coreboot-veyron", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_COREBOOT, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = GRUB_KERNEL_ARM_COREBOOT_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN, + .vaddr_offset = 0, + .elf_target = EM_ARM, + .mod_gap = GRUB_KERNEL_ARM_COREBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN, + .link_align = 4, + .link_addr = 0x43000000, + }, + { + .dirname = "arm-efi", + .names = { "arm-efi", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI32_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_ARMTHUMB_MIXED, + .elf_target = EM_ARM, + }, + { + .dirname = "arm64-efi", + .names = { "arm64-efi", NULL }, + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI64_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_ARM64, + .elf_target = EM_AARCH64, + }, + { + .dirname = "riscv32-efi", + .names = { "riscv32-efi", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI32_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_RISCV32, + .elf_target = EM_RISCV, + }, + { + .dirname = "riscv64-efi", + .names = { "riscv64-efi", NULL }, + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI64_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_RISCV64, + .elf_target = EM_RISCV, + }, + }; + +#include <grub/lib/LzmaEnc.h> + +static void *SzAlloc(void *p __attribute__ ((unused)), size_t size) { return xmalloc(size); } +static void SzFree(void *p __attribute__ ((unused)), void *address) { 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) +{ + 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; + + *core_img = xmalloc (kernel_size); + + *core_size = kernel_size; + if (LzmaEncode ((unsigned char *) *core_img, core_size, + (unsigned char *) kernel_img, + kernel_size, + &props, out_props, &out_props_size, + 0, NULL, &g_Alloc, &g_Alloc) != SZ_OK) + grub_util_error ("%s", _("cannot compress the kernel image")); +} + +#ifdef USE_LIBLZMA +static void +compress_kernel_xz (char *kernel_img, size_t kernel_size, + char **core_img, size_t *core_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} + }; + + xzret = lzma_stream_encoder (&strm, fltrs, LZMA_CHECK_NONE); + if (xzret != LZMA_OK) + grub_util_error ("%s", _("cannot compress the kernel image")); + + *core_img = xmalloc (kernel_size); + + *core_size = kernel_size; + strm.next_in = (unsigned char *) kernel_img; + strm.avail_in = kernel_size; + strm.next_out = (unsigned char *) *core_img; + 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 ("%s", _("cannot compress the kernel image")); + } + + *core_size -= strm.avail_out; +} +#endif + +static void +compress_kernel (const struct grub_install_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_DECOMPRESSORS + && (comp == GRUB_COMPRESSION_LZMA)) + { + compress_kernel_lzma (kernel_img, kernel_size, core_img, + core_size); + return; + } + +#ifdef USE_LIBLZMA + if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS + && (comp == GRUB_COMPRESSION_XZ)) + { + compress_kernel_xz (kernel_img, kernel_size, core_img, + core_size); + return; + } +#endif + + if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS + && (comp != GRUB_COMPRESSION_NONE)) + grub_util_error (_("unknown compression %d"), comp); + + *core_img = xmalloc (kernel_size); + memcpy (*core_img, kernel_img, kernel_size); + *core_size = kernel_size; +} + +const struct grub_install_image_target_desc * +grub_install_get_image_target (const char *arg) +{ + unsigned i, j; + for (i = 0; i < ARRAY_SIZE (image_targets); i++) + for (j = 0; j < ARRAY_SIZE (image_targets[i].names) && + image_targets[i].names[j]; j++) + if (strcmp (arg, image_targets[i].names[j]) == 0) + return &image_targets[i]; + return NULL; +} + +const char * +grub_util_get_target_dirname (const struct grub_install_image_target_desc *t) +{ + return t->dirname; +} + +const char * +grub_util_get_target_name (const struct grub_install_image_target_desc *t) +{ + return t->names[0]; +} + +char * +grub_install_get_image_targets_string (void) +{ + 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].names[0]) + 2; + ptr = formats = xmalloc (format_len); + for (i = 0; i < ARRAY_SIZE (image_targets); i++) + { + strcpy (ptr, image_targets[i].names[0]); + ptr += strlen (image_targets[i].names[0]); + *ptr++ = ','; + *ptr++ = ' '; + } + ptr[-2] = 0; + + return formats; +} + +/* + * The image_target parameter is used by the grub_host_to_target32() macro. + */ +static struct grub_pe32_section_table * +init_pe_section(const struct grub_install_image_target_desc *image_target, + struct grub_pe32_section_table *section, + const char * const name, + grub_uint32_t *vma, grub_uint32_t vsz, grub_uint32_t valign, + grub_uint32_t *rda, grub_uint32_t rsz, + grub_uint32_t characteristics) +{ + size_t len = strlen (name); + + if (len > sizeof (section->name)) + grub_util_error (_("section name %s length is bigger than %lu"), + name, (unsigned long) sizeof (section->name)); + + memcpy (section->name, name, len); + + section->virtual_address = grub_host_to_target32 (*vma); + section->virtual_size = grub_host_to_target32 (vsz); + (*vma) = ALIGN_UP (*vma + vsz, valign); + + section->raw_data_offset = grub_host_to_target32 (*rda); + section->raw_data_size = grub_host_to_target32 (rsz); + (*rda) = ALIGN_UP (*rda + rsz, GRUB_PE32_FILE_ALIGNMENT); + + section->characteristics = grub_host_to_target32 (characteristics); + + return section + 1; +} + +/* + * tmp_ is just here so the compiler knows we'll never derefernce a NULL. + * It should get fully optimized away. + */ +#define PE_OHDR(o32, o64, field) (*( \ +{ \ + __typeof__((o64)->field) tmp_; \ + __typeof__((o64)->field) *ret_ = &tmp_; \ + if (o32) \ + ret_ = (void *)(&((o32)->field)); \ + else if (o64) \ + ret_ = (void *)(&((o64)->field)); \ + ret_; \ +})) + +void +grub_install_generate_image (const char *dir, const char *prefix, + FILE *out, const char *outname, char *mods[], + char *memdisk_path, char **pubkey_paths, + size_t npubkeys, char *config_path, + const struct grub_install_image_target_desc *image_target, + int note, grub_compression_t comp, const char *dtb_path, + const char *sbat_path, int disable_shim_lock) +{ + char *kernel_img, *core_img; + size_t total_module_size, core_size; + size_t memdisk_size = 0, config_size = 0; + size_t prefix_size = 0, dtb_size = 0, sbat_size = 0; + char *kernel_path; + size_t offset; + struct grub_util_path_list *path_list, *p; + size_t decompress_size = 0; + struct grub_mkimage_layout layout; + + if (comp == GRUB_COMPRESSION_AUTO) + comp = image_target->default_compression; + + if (image_target->id == IMAGE_I386_PC + || image_target->id == IMAGE_I386_PC_PXE + || image_target->id == IMAGE_I386_PC_ELTORITO) + comp = GRUB_COMPRESSION_LZMA; + + 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); + + { + size_t i; + for (i = 0; i < npubkeys; i++) + { + size_t curs; + curs = ALIGN_ADDR (grub_util_get_image_size (pubkey_paths[i])); + grub_util_info ("the size of public key %u is 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned) i, (unsigned long long) curs); + total_module_size += curs + sizeof (struct grub_module_header); + } + } + + 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%" GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) memdisk_size); + total_module_size += memdisk_size + sizeof (struct grub_module_header); + } + + if (dtb_path) + { + dtb_size = ALIGN_ADDR(grub_util_get_image_size (dtb_path)); + total_module_size += dtb_size + sizeof (struct grub_module_header); + } + + if (sbat_path != NULL && image_target->id != IMAGE_EFI) + grub_util_error (_(".sbat section can be embedded into EFI images only")); + + if (disable_shim_lock) + total_module_size += sizeof (struct grub_module_header); + + if (config_path) + { + config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1); + grub_util_info ("the size of config file is 0x%" GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) config_size); + total_module_size += config_size + sizeof (struct grub_module_header); + } + + if (prefix) + { + prefix_size = ALIGN_ADDR (strlen (prefix) + 1); + total_module_size += prefix_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%" GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) total_module_size); + + if (image_target->voidp_sizeof == 4) + kernel_img = grub_mkimage_load_image32 (kernel_path, total_module_size, + &layout, image_target); + else + kernel_img = grub_mkimage_load_image64 (kernel_path, total_module_size, + &layout, image_target); + if ((image_target->id == IMAGE_XEN || image_target->id == IMAGE_XEN_PVH) && + layout.align < 4096) + layout.align = 4096; + + 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); + + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + { + memmove (kernel_img + total_module_size, kernel_img, layout.kernel_size); + memset (kernel_img, 0, total_module_size); + } + + if (image_target->voidp_sizeof == 8) + { + /* Fill in the grub_module_info structure. */ + struct grub_module_info64 *modinfo; + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + modinfo = (struct grub_module_info64 *) kernel_img; + else + modinfo = (struct grub_module_info64 *) (kernel_img + layout.kernel_size); + 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); + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + offset = sizeof (struct grub_module_info64); + else + offset = layout.kernel_size + sizeof (struct grub_module_info64); + } + else + { + /* Fill in the grub_module_info structure. */ + struct grub_module_info32 *modinfo; + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + modinfo = (struct grub_module_info32 *) kernel_img; + else + modinfo = (struct grub_module_info32 *) (kernel_img + layout.kernel_size); + 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); + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + offset = sizeof (struct grub_module_info32); + else + offset = layout.kernel_size + sizeof (struct grub_module_info32); + } + + for (p = path_list; p; p = p->next) + { + struct grub_module_header *header; + size_t mod_size; + + mod_size = ALIGN_ADDR (grub_util_get_image_size (p->name)); + + header = (struct grub_module_header *) (kernel_img + offset); + header->type = grub_host_to_target32 (OBJ_TYPE_ELF); + header->size = grub_host_to_target32 (mod_size + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (p->name, kernel_img + offset); + offset += mod_size; + } + + { + size_t i; + for (i = 0; i < npubkeys; i++) + { + size_t curs; + struct grub_module_header *header; + + curs = grub_util_get_image_size (pubkey_paths[i]); + + header = (struct grub_module_header *) (kernel_img + offset); + header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY); + header->size = grub_host_to_target32 (curs + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (pubkey_paths[i], kernel_img + offset); + offset += ALIGN_ADDR (curs); + } + } + + if (memdisk_path) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + 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 (dtb_path) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + header->type = grub_host_to_target32 (OBJ_TYPE_DTB); + header->size = grub_host_to_target32 (dtb_size + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (dtb_path, kernel_img + offset); + offset += dtb_size; + } + + if (disable_shim_lock) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + header->type = grub_host_to_target32 (OBJ_TYPE_DISABLE_SHIM_LOCK); + header->size = grub_host_to_target32 (sizeof (*header)); + offset += sizeof (*header); + } + + if (config_path) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + 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); + offset += config_size; + } + + if (prefix) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + header->type = grub_host_to_target32 (OBJ_TYPE_PREFIX); + header->size = grub_host_to_target32 (prefix_size + sizeof (*header)); + offset += sizeof (*header); + + grub_strcpy (kernel_img + offset, prefix); + offset += prefix_size; + } + + grub_util_info ("kernel_img=%p, kernel_size=0x%" GRUB_HOST_PRIxLONG_LONG, + kernel_img, + (unsigned long long) layout.kernel_size); + compress_kernel (image_target, kernel_img, layout.kernel_size + total_module_size, + &core_img, &core_size, comp); + free (kernel_img); + + grub_util_info ("the core size is 0x%" GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) 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->flags & PLATFORM_FLAGS_DECOMPRESSORS) + { + char *full_img; + size_t full_size; + char *decompress_path, *decompress_img; + const char *name; + + switch (comp) + { + case GRUB_COMPRESSION_XZ: + name = "xz_decompress.img"; + break; + case GRUB_COMPRESSION_LZMA: + name = "lzma_decompress.img"; + break; + case GRUB_COMPRESSION_NONE: + name = "none_decompress.img"; + break; + default: + grub_util_error (_("unknown compression %d"), 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); + + if ((image_target->id == IMAGE_I386_PC + || image_target->id == IMAGE_I386_PC_PXE + || image_target->id == IMAGE_I386_PC_ELTORITO) + && decompress_size > GRUB_KERNEL_I386_PC_LINK_ADDR - 0x8200) + grub_util_error ("%s", _("Decompressor is too big")); + + if (image_target->decompressor_compressed_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (decompress_img + + image_target->decompressor_compressed_size)) + = grub_host_to_target32 (core_size); + + if (image_target->decompressor_uncompressed_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (decompress_img + + image_target->decompressor_uncompressed_size)) + = grub_host_to_target32 (layout.kernel_size + total_module_size); + + if (image_target->decompressor_uncompressed_addr != TARGET_NO_FIELD) + { + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr)) + = grub_host_to_target_addr (image_target->link_addr - total_module_size); + else + *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr)) + = grub_host_to_target_addr (image_target->link_addr); + } + full_size = core_size + decompress_size; + + full_img = xmalloc (full_size); + + memcpy (full_img, decompress_img, decompress_size); + + memcpy (full_img + decompress_size, core_img, core_size); + + free (core_img); + core_img = full_img; + core_size = full_size; + free (decompress_img); + free (decompress_path); + } + + switch (image_target->id) + { + case IMAGE_I386_PC: + case IMAGE_I386_PC_PXE: + case IMAGE_I386_PC_ELTORITO: + if (GRUB_KERNEL_I386_PC_LINK_ADDR + core_size > 0x78000 + || (core_size > (0xffff << GRUB_DISK_SECTOR_BITS)) + || (layout.kernel_size + layout.bss_size + + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000)) + grub_util_error (_("core image is too big (0x%x > 0x%x)"), + GRUB_KERNEL_I386_PC_LINK_ADDR + (unsigned) core_size, + 0x78000); + /* fallthrough */ + case IMAGE_COREBOOT: + case IMAGE_QEMU: + if (image_target->elf_target != EM_ARM && layout.kernel_size + layout.bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000) + grub_util_error (_("kernel image is too big (0x%x > 0x%x)"), + (unsigned) layout.kernel_size + (unsigned) layout.bss_size + + GRUB_KERNEL_I386_PC_LINK_ADDR, + 0x68000); + break; + case IMAGE_LOONGSON_ELF: + case IMAGE_YEELOONG_FLASH: + case IMAGE_FULOONG2F_FLASH: + case IMAGE_EFI: + case IMAGE_MIPS_ARC: + case IMAGE_QEMU_MIPS_FLASH: + case IMAGE_XEN: + case IMAGE_XEN_PVH: + break; + case IMAGE_SPARC64_AOUT: + case IMAGE_SPARC64_RAW: + case IMAGE_SPARC64_CDCORE: + case IMAGE_I386_IEEE1275: + case IMAGE_PPC: + case IMAGE_UBOOT: + break; + } + + switch (image_target->id) + { + case IMAGE_I386_PC: + case IMAGE_I386_PC_PXE: + case IMAGE_I386_PC_ELTORITO: + { + unsigned num; + char *boot_path, *boot_img; + size_t boot_size; + + num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); + if (image_target->id == IMAGE_I386_PC_PXE) + { + char *pxeboot_path, *pxeboot_img; + size_t pxeboot_size; + grub_uint32_t *ptr; + + 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, + outname); + free (pxeboot_img); + free (pxeboot_path); + + /* Remove Multiboot header to avoid confusing ipxe. */ + for (ptr = (grub_uint32_t *) core_img; + ptr < (grub_uint32_t *) (core_img + MULTIBOOT_SEARCH); ptr++) + if (*ptr == grub_host_to_target32 (MULTIBOOT_HEADER_MAGIC) + && grub_target_to_host32 (ptr[0]) + + grub_target_to_host32 (ptr[1]) + + grub_target_to_host32 (ptr[2]) == 0) + { + *ptr = 0; + break; + } + } + + if (image_target->id == IMAGE_I386_PC_ELTORITO) + { + char *eltorito_path, *eltorito_img; + size_t eltorito_size; + + eltorito_path = grub_util_get_path (dir, "cdboot.img"); + eltorito_size = grub_util_get_image_size (eltorito_path); + eltorito_img = grub_util_read_image (eltorito_path); + + grub_util_write_image (eltorito_img, eltorito_size, out, + outname); + free (eltorito_img); + free (eltorito_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, outname); + free (boot_img); + free (boot_path); + } + break; + case IMAGE_EFI: + { + char *pe_img, *pe_sbat, *header; + struct grub_pe32_section_table *section; + size_t n_sections = 4; + size_t scn_size; + grub_uint32_t vma, raw_data; + size_t pe_size, header_size; + struct grub_pe32_coff_header *c; + static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB; + struct grub_pe32_optional_header *o32 = NULL; + struct grub_pe64_optional_header *o64 = NULL; + + if (image_target->voidp_sizeof == 4) + header_size = EFI32_HEADER_SIZE; + else + header_size = EFI64_HEADER_SIZE; + + vma = raw_data = header_size; + + if (sbat_path != NULL) + { + sbat_size = ALIGN_ADDR (grub_util_get_image_size (sbat_path)); + sbat_size = ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT); + } + + pe_size = ALIGN_UP (header_size + core_size, GRUB_PE32_FILE_ALIGNMENT) + + ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT) + sbat_size; + header = pe_img = xcalloc (1, pe_size); + + memcpy (pe_img + raw_data, core_img, core_size); + + /* 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); + c->machine = grub_host_to_target16 (image_target->pe_target); + + if (sbat_path != NULL) + n_sections++; + + c->num_sections = grub_host_to_target16 (n_sections); + c->time = grub_host_to_target32 (STABLE_EMBEDDING_TIMESTAMP); + 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) + { + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe32_optional_header)); + + o32 = (struct grub_pe32_optional_header *) + (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header)); + o32->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); + o32->data_base = grub_host_to_target32 (header_size + layout.exec_size); + + section = (struct grub_pe32_section_table *)(o32 + 1); + } + else + { + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header)); + o64 = (struct grub_pe64_optional_header *) + (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header)); + o64->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); + + section = (struct grub_pe32_section_table *)(o64 + 1); + } + + PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); + PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address); + PE_OHDR (o32, o64, image_base) = 0; + PE_OHDR (o32, o64, image_size) = grub_host_to_target32 (pe_size); + PE_OHDR (o32, o64, section_alignment) = grub_host_to_target32 (image_target->section_align); + PE_OHDR (o32, o64, file_alignment) = grub_host_to_target32 (GRUB_PE32_FILE_ALIGNMENT); + PE_OHDR (o32, o64, subsystem) = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); + + /* Do these really matter? */ + PE_OHDR (o32, o64, stack_reserve_size) = grub_host_to_target32 (0x10000); + PE_OHDR (o32, o64, stack_commit_size) = grub_host_to_target32 (0x10000); + PE_OHDR (o32, o64, heap_reserve_size) = grub_host_to_target32 (0x10000); + PE_OHDR (o32, o64, heap_commit_size) = grub_host_to_target32 (0x10000); + + PE_OHDR (o32, o64, num_data_directories) = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); + + /* The sections. */ + PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (vma); + PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); + section = init_pe_section (image_target, section, ".text", + &vma, layout.exec_size, + image_target->section_align, + &raw_data, layout.exec_size, + GRUB_PE32_SCN_CNT_CODE | + GRUB_PE32_SCN_MEM_EXECUTE | + GRUB_PE32_SCN_MEM_READ); + + scn_size = ALIGN_UP (layout.kernel_size - layout.exec_size, GRUB_PE32_FILE_ALIGNMENT); + /* ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT) is done earlier. */ + PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + sbat_size + + ALIGN_UP (total_module_size, + GRUB_PE32_FILE_ALIGNMENT)); + + section = init_pe_section (image_target, section, ".data", + &vma, scn_size, image_target->section_align, + &raw_data, scn_size, + GRUB_PE32_SCN_CNT_INITIALIZED_DATA | + GRUB_PE32_SCN_MEM_READ | + GRUB_PE32_SCN_MEM_WRITE); + + scn_size = pe_size - layout.reloc_size - sbat_size - raw_data; + section = init_pe_section (image_target, section, "mods", + &vma, scn_size, image_target->section_align, + &raw_data, scn_size, + GRUB_PE32_SCN_CNT_INITIALIZED_DATA | + GRUB_PE32_SCN_MEM_READ | + GRUB_PE32_SCN_MEM_WRITE); + + if (sbat_path != NULL) + { + pe_sbat = pe_img + raw_data; + grub_util_load_image (sbat_path, pe_sbat); + + section = init_pe_section (image_target, section, ".sbat", + &vma, sbat_size, + image_target->section_align, + &raw_data, sbat_size, + GRUB_PE32_SCN_CNT_INITIALIZED_DATA | + GRUB_PE32_SCN_MEM_READ); + } + + scn_size = layout.reloc_size; + PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (vma); + PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (scn_size); + memcpy (pe_img + raw_data, layout.reloc_section, scn_size); + init_pe_section (image_target, section, ".reloc", + &vma, scn_size, image_target->section_align, + &raw_data, scn_size, + 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; + grub_memset (aout_head, 0, sizeof (*aout_head)); + 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 ((char *) 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 size must be %u bytes"), + GRUB_DISK_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, outname); + free (boot_img); + free (boot_path); + } + break; + case IMAGE_SPARC64_CDCORE: + break; + case IMAGE_YEELOONG_FLASH: + case IMAGE_FULOONG2F_FLASH: + { + char *rom_img; + size_t rom_size; + char *boot_path, *boot_img; + size_t boot_size; + /* fwstart.img is the only part which can't be tested by using *-elf + target. Check it against the checksum. */ + const grub_uint8_t yeeloong_fwstart_good_hash[512 / 8] = + { + 0x5f, 0x67, 0x46, 0x57, 0x31, 0x30, 0xc5, 0x0a, + 0xe9, 0x98, 0x18, 0xc9, 0xf3, 0xca, 0x45, 0xa5, + 0x75, 0x64, 0x6b, 0xbb, 0x24, 0xcd, 0xb4, 0xbc, + 0xf2, 0x3e, 0x23, 0xf9, 0xc2, 0x6a, 0x8c, 0xde, + 0x3b, 0x94, 0x9c, 0xcc, 0xa5, 0xa7, 0x58, 0xb1, + 0xbe, 0x8b, 0x3d, 0x73, 0x98, 0x18, 0x7e, 0x68, + 0x5e, 0x5f, 0x23, 0x7d, 0x7a, 0xe8, 0x51, 0xf7, + 0x1a, 0xaf, 0x2f, 0x54, 0x11, 0x2e, 0x5c, 0x25 + }; + const grub_uint8_t fuloong2f_fwstart_good_hash[512 / 8] = + { + 0x76, 0x9b, 0xad, 0x6e, 0xa2, 0x39, 0x47, 0x62, + 0x1f, 0xc9, 0x3a, 0x6d, 0x05, 0x5c, 0x43, 0x5c, + 0x29, 0x4a, 0x7e, 0x08, 0x2a, 0x31, 0x8f, 0x5d, + 0x02, 0x84, 0xa0, 0x85, 0xf2, 0xd1, 0xb9, 0x53, + 0xa2, 0xbc, 0xf2, 0xe1, 0x39, 0x1e, 0x51, 0xb5, + 0xaf, 0xec, 0x9e, 0xf2, 0xf1, 0xf3, 0x0a, 0x2f, + 0xe6, 0xf1, 0x08, 0x89, 0xbe, 0xbc, 0x73, 0xab, + 0x46, 0x50, 0xd6, 0x21, 0xce, 0x8e, 0x24, 0xa7 + }; + const grub_uint8_t *fwstart_good_hash; + grub_uint8_t fwstart_hash[512 / 8]; + + if (image_target->id == IMAGE_FULOONG2F_FLASH) + { + fwstart_good_hash = fuloong2f_fwstart_good_hash; + boot_path = grub_util_get_path (dir, "fwstart_fuloong2f.img"); + } + else + { + fwstart_good_hash = yeeloong_fwstart_good_hash; + 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_crypto_hash (GRUB_MD_SHA512, fwstart_hash, boot_img, boot_size); + + if (grub_memcmp (fwstart_hash, fwstart_good_hash, + GRUB_MD_SHA512->mdlen) != 0) + /* TRANSLATORS: fwstart.img may still be good, just it wasn't checked. */ + grub_util_warn ("%s", + _("fwstart.img doesn't match the known good version. " + "proceed at your own risk")); + + if (core_size + boot_size > 512 * 1024) + grub_util_error ("%s", _("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; + free (boot_img); + free (boot_path); + } + break; + case IMAGE_QEMU_MIPS_FLASH: + { + char *rom_img; + size_t rom_size; + + if (core_size > 512 * 1024) + grub_util_error ("%s", _("firmware image is too big")); + rom_size = 512 * 1024; + + rom_img = xmalloc (rom_size); + memset (rom_img, 0, rom_size); + + memcpy (rom_img, core_img, core_size); + + memset (rom_img + core_size, 0, + rom_size - core_size); + + free (core_img); + core_img = rom_img; + core_size = rom_size; + } + break; + + case IMAGE_UBOOT: + { + struct grub_uboot_image_header *hdr; + + hdr = xmalloc (core_size + sizeof (struct grub_uboot_image_header)); + memcpy (hdr + 1, core_img, core_size); + + memset (hdr, 0, sizeof (*hdr)); + hdr->ih_magic = grub_cpu_to_be32_compile_time (GRUB_UBOOT_IH_MAGIC); + hdr->ih_time = grub_cpu_to_be32 (STABLE_EMBEDDING_TIMESTAMP); + hdr->ih_size = grub_cpu_to_be32 (core_size); + hdr->ih_load = 0; + hdr->ih_ep = 0; + hdr->ih_type = GRUB_UBOOT_IH_TYPE_KERNEL_NOLOAD; + hdr->ih_os = GRUB_UBOOT_IH_OS_LINUX; + hdr->ih_arch = GRUB_UBOOT_IH_ARCH_ARM; + hdr->ih_comp = GRUB_UBOOT_IH_COMP_NONE; + + grub_crypto_hash (GRUB_MD_CRC32, &hdr->ih_dcrc, hdr + 1, core_size); + grub_crypto_hash (GRUB_MD_CRC32, &hdr->ih_hcrc, hdr, sizeof (*hdr)); + + free (core_img); + core_img = (char *) hdr; + core_size += sizeof (struct grub_uboot_image_header); + } + break; + + case IMAGE_MIPS_ARC: + { + char *ecoff_img; + struct ecoff_header { + grub_uint16_t magic; + grub_uint16_t nsec; + grub_uint32_t time; + grub_uint32_t syms; + grub_uint32_t nsyms; + grub_uint16_t opt; + grub_uint16_t flags; + grub_uint16_t magic2; + grub_uint16_t version; + grub_uint32_t textsize; + grub_uint32_t datasize; + grub_uint32_t bsssize; + grub_uint32_t entry; + grub_uint32_t text_start; + grub_uint32_t data_start; + grub_uint32_t bss_start; + grub_uint32_t gprmask; + grub_uint32_t cprmask[4]; + grub_uint32_t gp_value; + }; + struct ecoff_section + { + char name[8]; + grub_uint32_t paddr; + grub_uint32_t vaddr; + grub_uint32_t size; + grub_uint32_t file_offset; + grub_uint32_t reloc; + grub_uint32_t gp; + grub_uint16_t nreloc; + grub_uint16_t ngp; + grub_uint32_t flags; + }; + struct ecoff_header *head; + struct ecoff_section *section; + grub_uint32_t target_addr; + size_t program_size; + + program_size = ALIGN_ADDR (core_size); + if (comp == GRUB_COMPRESSION_NONE) + target_addr = (image_target->link_addr - decompress_size); + else + target_addr = ALIGN_UP (image_target->link_addr + + layout.kernel_size + total_module_size, 32); + + ecoff_img = xmalloc (program_size + sizeof (*head) + sizeof (*section)); + grub_memset (ecoff_img, 0, program_size + sizeof (*head) + sizeof (*section)); + head = (void *) ecoff_img; + section = (void *) (head + 1); + head->magic = image_target->bigendian ? grub_host_to_target16 (0x160) + : grub_host_to_target16 (0x166); + head->nsec = grub_host_to_target16 (1); + head->time = grub_host_to_target32 (0); + head->opt = grub_host_to_target16 (0x38); + head->flags = image_target->bigendian + ? grub_host_to_target16 (0x207) + : grub_host_to_target16 (0x103); + head->magic2 = grub_host_to_target16 (0x107); + head->textsize = grub_host_to_target32 (program_size); + head->entry = grub_host_to_target32 (target_addr); + head->text_start = grub_host_to_target32 (target_addr); + head->data_start = grub_host_to_target32 (target_addr + program_size); + grub_memcpy (section->name, ".text", sizeof (".text") - 1); + section->vaddr = grub_host_to_target32 (target_addr); + section->size = grub_host_to_target32 (program_size); + section->file_offset = grub_host_to_target32 (sizeof (*head) + sizeof (*section)); + if (!image_target->bigendian) + { + section->paddr = grub_host_to_target32 (0xaa60); + section->flags = grub_host_to_target32 (0x20); + } + memcpy (section + 1, core_img, core_size); + free (core_img); + core_img = ecoff_img; + core_size = program_size + sizeof (*head) + sizeof (*section); + } + break; + case IMAGE_LOONGSON_ELF: + case IMAGE_PPC: + case IMAGE_XEN: + case IMAGE_XEN_PVH: + case IMAGE_COREBOOT: + case IMAGE_I386_IEEE1275: + { + grub_uint64_t target_addr; + if (image_target->id == IMAGE_LOONGSON_ELF) + { + if (comp == GRUB_COMPRESSION_NONE) + target_addr = (image_target->link_addr - decompress_size); + else + target_addr = ALIGN_UP (image_target->link_addr + + layout.kernel_size + total_module_size, 32); + } + else + target_addr = image_target->link_addr; + if (image_target->voidp_sizeof == 4) + grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size, + target_addr, &layout); + else + grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size, + target_addr, &layout); + } + break; + } + + grub_util_write_image (core_img, core_size, out, outname); + free (core_img); + free (kernel_path); + free (layout.reloc_section); + + grub_util_free_path_list (path_list); +} diff --git a/util/probe.c b/util/probe.c new file mode 100644 index 0000000..fa7ca34 --- /dev/null +++ b/util/probe.c @@ -0,0 +1,172 @@ +/* grub-probe.c - probe device information for a given path */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007,2008,2009,2010,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/device.h> +#include <grub/disk.h> +#include <grub/file.h> +#include <grub/fs.h> +#include <grub/partition.h> +#include <grub/msdos_partition.h> +#include <grub/gpt_partition.h> +#include <grub/emu/hostdisk.h> +#include <grub/emu/getroot.h> +#include <grub/term.h> +#include <grub/env.h> +#include <grub/diskfilter.h> +#include <grub/i18n.h> +#include <grub/emu/misc.h> +#include <grub/util/ofpath.h> +#include <grub/crypto.h> +#include <grub/cryptodisk.h> + +#include <string.h> + +/* 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 *) xstrdup (orig_path); + + new_path = xmalloc (strlen (orig_path) * 2 + 1); + + p = orig_path; + d = new_path; + while ((c = *p++) != '\0') + { + if (c == ',') + *d++ = '\\'; + *d++ = c; + } + *d = 0; + + return new_path; +} + +char * +grub_util_guess_bios_drive (const char *orig_path) +{ + char *canon; + char *ptr; + canon = grub_canonicalize_file_name (orig_path); + if (!canon) + return NULL; + ptr = strrchr (orig_path, '/'); + if (ptr) + ptr++; + else + ptr = canon; + if ((ptr[0] == 's' || ptr[0] == 'h') && ptr[1] == 'd') + { + int num = ptr[2] - 'a'; + free (canon); + return xasprintf ("hd%d", num); + } + if (ptr[0] == 'f' && ptr[1] == 'd') + { + int num = atoi (ptr + 2); + free (canon); + return xasprintf ("fd%d", num); + } + free (canon); + return NULL; +} + +char * +grub_util_guess_efi_drive (const char *orig_path) +{ + char *canon; + char *ptr; + canon = grub_canonicalize_file_name (orig_path); + if (!canon) + return NULL; + ptr = strrchr (orig_path, '/'); + if (ptr) + ptr++; + else + ptr = canon; + if ((ptr[0] == 's' || ptr[0] == 'h') && ptr[1] == 'd') + { + int num = ptr[2] - 'a'; + free (canon); + return xasprintf ("hd%d", num); + } + if (ptr[0] == 'f' && ptr[1] == 'd') + { + int num = atoi (ptr + 2); + free (canon); + return xasprintf ("fd%d", num); + } + free (canon); + return NULL; +} + +char * +grub_util_guess_baremetal_drive (const char *orig_path) +{ + char *canon; + char *ptr; + canon = grub_canonicalize_file_name (orig_path); + if (!canon) + return NULL; + ptr = strrchr (orig_path, '/'); + if (ptr) + ptr++; + else + ptr = canon; + if (ptr[0] == 'h' && ptr[1] == 'd') + { + int num = ptr[2] - 'a'; + free (canon); + return xasprintf ("ata%d", num); + } + if (ptr[0] == 's' && ptr[1] == 'd') + { + int num = ptr[2] - 'a'; + free (canon); + return xasprintf ("ahci%d", num); + } + free (canon); + return NULL; +} + +void +grub_util_fprint_full_disk_name (FILE *f, + const char *drive, grub_device_t dev) +{ + char *dname = escape_of_path (drive); + if (dev->disk->partition) + { + char *pname = grub_partition_get_name (dev->disk->partition); + fprintf (f, "%s,%s", dname, pname); + free (pname); + } + else + fprintf (f, "%s", dname); + free (dname); +} diff --git a/util/render-label.c b/util/render-label.c new file mode 100644 index 0000000..91c080c --- /dev/null +++ b/util/render-label.c @@ -0,0 +1,215 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2012,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include <config.h> + +#include <grub/util/misc.h> +#include <grub/util/install.h> +#include <grub/i18n.h> +#include <grub/term.h> +#include <grub/font.h> +#include <grub/gfxmenu_view.h> +#include <grub/color.h> +#include <grub/emu/hostdisk.h> + +#define _GNU_SOURCE 1 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +struct header +{ + grub_uint8_t magic; + grub_uint16_t width; + grub_uint16_t height; +} GRUB_PACKED; + +static struct grub_video_palette_data ieee1275_palette[256]; + +void +grub_util_render_label (const char *label_font, + const char *label_bgcolor, + const char *label_color, + const char *text, + const char *output) +{ + struct header head; + FILE *out; + int i, j, k, cptr = 0; + grub_font_t font; + char *fontfull; + const grub_uint8_t vals[] = { 0xff, 0xda, 0xb3, 0x87, 0x54, 0x00 }; + const grub_uint8_t vals2[] = { 0xf3, 0xe7, 0xcd, 0xc0, 0xa5, 0x96, + 0x77, 0x66, 0x3f, 0x27 }; + int width, height; + grub_uint8_t bg, fg; + struct grub_video_mode_info mode_info; + grub_err_t err; + grub_video_rgba_color_t fgcolor; + grub_video_rgba_color_t bgcolor; + + if (output) + out = grub_util_fopen (output, "wb"); + else + out = stdout; + if (!out) + { + grub_util_error (_("cannot open `%s': %s"), output ? : "stdout", + strerror (errno)); + } + + if (label_color) + { + err = grub_video_parse_color (label_color, &fgcolor); + if (err) + grub_util_error (_("invalid color specification `%s'"), label_color); + } + else + { + fgcolor.red = 0x00; + fgcolor.green = 0x00; + fgcolor.blue = 0x00; + fgcolor.alpha = 0xff; + } + + if (label_bgcolor) + { + err = grub_video_parse_color (label_bgcolor, &bgcolor); + if (err) + grub_util_error (_("invalid color specification `%s'"), label_bgcolor); + } + else + { + bgcolor.red = 0xff; + bgcolor.green = 0xff; + bgcolor.blue = 0xff; + bgcolor.alpha = 0xff; + } + + for (i = 0; i < 256; i++) + ieee1275_palette[i].a = 0xff; + + for (i = 0; i < 6; i++) + for (j = 0; j < 6; j++) + for (k = 0; k < 6; k++) + { + ieee1275_palette[cptr].r = vals[i]; + ieee1275_palette[cptr].g = vals[j]; + ieee1275_palette[cptr].b = vals[k]; + ieee1275_palette[cptr].a = 0xff; + cptr++; + } + cptr--; + for (i = 0; i < 10; i++) + { + ieee1275_palette[cptr].r = vals2[i]; + ieee1275_palette[cptr].g = 0; + ieee1275_palette[cptr].b = 0; + ieee1275_palette[cptr].a = 0xff; + cptr++; + } + for (i = 0; i < 10; i++) + { + ieee1275_palette[cptr].r = 0; + ieee1275_palette[cptr].g = vals2[i]; + ieee1275_palette[cptr].b = 0; + ieee1275_palette[cptr].a = 0xff; + cptr++; + } + for (i = 0; i < 10; i++) + { + ieee1275_palette[cptr].r = 0; + ieee1275_palette[cptr].g = 0; + ieee1275_palette[cptr].b = vals2[i]; + ieee1275_palette[cptr].a = 0xff; + cptr++; + } + for (i = 0; i < 10; i++) + { + ieee1275_palette[cptr].r = vals2[i]; + ieee1275_palette[cptr].g = vals2[i]; + ieee1275_palette[cptr].b = vals2[i]; + ieee1275_palette[cptr].a = 0xff; + cptr++; + } + ieee1275_palette[cptr].r = 0; + ieee1275_palette[cptr].g = 0; + ieee1275_palette[cptr].b = 0; + ieee1275_palette[cptr].a = 0xff; + + char * t; + t = grub_canonicalize_file_name (label_font); + if (!t) + { + grub_util_error (_("cannot open `%s': %s"), label_font, + strerror (errno)); + } + + fontfull = xasprintf ("(host)/%s", t); + free (t); + + grub_font_loader_init (); + font = grub_font_load (fontfull); + if (!font) + { + grub_util_error (_("cannot open `%s': %s"), label_font, + grub_errmsg); + } + + width = grub_font_get_string_width (font, text) + 10; + height = grub_font_get_height (font); + + mode_info.width = width; + mode_info.height = height; + mode_info.pitch = width; + + mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + mode_info.bpp = 8; + mode_info.bytes_per_pixel = 1; + mode_info.number_of_colors = 256; + + grub_video_capture_start (&mode_info, ieee1275_palette, + ARRAY_SIZE (ieee1275_palette)); + + fg = grub_video_map_rgb (fgcolor.red, + fgcolor.green, + fgcolor.blue); + bg = grub_video_map_rgb (bgcolor.red, + bgcolor.green, + bgcolor.blue); + + grub_memset (grub_video_capture_get_framebuffer (), bg, height * width); + grub_font_draw_string (text, font, fg, + 5, grub_font_get_ascent (font)); + + head.magic = 1; + head.width = grub_cpu_to_be16 (width); + head.height = grub_cpu_to_be16 (height); + fwrite (&head, 1, sizeof (head), out); + fwrite (grub_video_capture_get_framebuffer (), 1, width * height, out); + + grub_video_capture_end (); + if (out != stdout) + fclose (out); + + free (fontfull); +} diff --git a/util/resolve.c b/util/resolve.c new file mode 100644 index 0000000..3e887d2 --- /dev/null +++ b/util/resolve.c @@ -0,0 +1,287 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2007 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> + +#include <grub/emu/misc.h> +#include <grub/misc.h> +#include <grub/util/misc.h> +#include <grub/util/resolve.h> +#include <grub/i18n.h> + +/* 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 && grub_isspace (*p)) + p++; + + if (! *p) + break; + + name = p; + + /* Skip non-whitespace. */ + while (*p && ! grub_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 = grub_util_fopen (path, "r"); + if (! fp) + grub_util_error (_("cannot open `%s': %s"), path, strerror (errno)); + + 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; + } +} + +void +grub_util_free_path_list (struct grub_util_path_list *path_list) +{ + struct grub_util_path_list *next; + + while (path_list) + { + next = path_list->next; + free ((void *) path_list->name); + free (path_list); + path_list = next; + } +} diff --git a/util/setup.c b/util/setup.c new file mode 100644 index 0000000..da5f2c0 --- /dev/null +++ b/util/setup.c @@ -0,0 +1,877 @@ +/* grub-setup.c - make GRUB usable */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/emu/misc.h> +#include <grub/util/misc.h> +#include <grub/device.h> +#include <grub/disk.h> +#include <grub/file.h> +#include <grub/fs.h> +#include <grub/partition.h> +#include <grub/env.h> +#include <grub/emu/hostdisk.h> +#include <grub/term.h> +#include <grub/i18n.h> + +#ifdef GRUB_SETUP_SPARC64 +#include <grub/util/ofpath.h> +#include <grub/sparc64/ieee1275/boot.h> +#include <grub/sparc64/ieee1275/kernel.h> +#else +#include <grub/i386/pc/boot.h> +#include <grub/i386/pc/kernel.h> +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <assert.h> +#include <grub/emu/getroot.h> +#include "progname.h" +#include <grub/reed_solomon.h> +#include <grub/msdos_partition.h> +#include <grub/crypto.h> +#include <grub/util/install.h> +#include <grub/emu/hostfile.h> + +#include <errno.h> + +/* 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. + */ + +#ifdef GRUB_SETUP_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_SETUP_BIOS) +#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 (grub_device_t root_dev, + char *boot_img, grub_uint64_t first_sector) +{ +#ifdef GRUB_SETUP_BIOS + { + grub_uint8_t *boot_drive; + void *kernel_sector; + boot_drive = (grub_uint8_t *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE); + kernel_sector = (boot_img + GRUB_BOOT_MACHINE_KERNEL_SECTOR); + + /* FIXME: can this be skipped? */ + *boot_drive = 0xFF; + + grub_set_unaligned64 (kernel_sector, grub_cpu_to_le64 (first_sector)); + } +#endif +#ifdef GRUB_SETUP_SPARC64 + { + void *kernel_byte; + kernel_byte = (boot_img + GRUB_BOOT_AOUT_HEADER_SIZE + + GRUB_BOOT_MACHINE_KERNEL_BYTE); + grub_set_unaligned64 (kernel_byte, + grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS)); + } +#endif +} + +#ifdef GRUB_SETUP_SPARC64 +#define BOOT_SECTOR 1 +#else +#define BOOT_SECTOR 0 +#endif + +/* Helper for setup. */ + +struct blocklists +{ + struct grub_boot_blocklist *first_block, *block; +#ifdef GRUB_SETUP_BIOS + grub_uint16_t current_segment; +#endif +#ifdef GRUB_SETUP_SPARC64 + grub_uint64_t gpt_offset; +#endif + grub_uint16_t last_length; + grub_disk_addr_t first_sector; +}; + +/* Helper for setup. */ +static void +save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length, + void *data) +{ + struct blocklists *bl = data; + struct grub_boot_blocklist *prev = bl->block + 1; + grub_uint64_t seclen; + +#ifdef GRUB_SETUP_SPARC64 + sector -= bl->gpt_offset; +#endif + + grub_util_info ("saving <%" GRUB_HOST_PRIuLONG_LONG ",%u,%u>", + (unsigned long long) sector, offset, length); + + if (bl->first_sector == (grub_disk_addr_t) -1) + { + if (offset != 0 || length < GRUB_DISK_SECTOR_SIZE) + grub_util_error ("%s", _("the first sector of the core file is not sector-aligned")); + + bl->first_sector = sector; + sector++; + length -= GRUB_DISK_SECTOR_SIZE; + if (!length) + return; + } + + if (offset != 0 || bl->last_length != 0) + grub_util_error ("%s", _("non-sector-aligned data is found in the core file")); + + seclen = (length + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS; + + if (bl->block != bl->first_block + && (grub_target_to_host64 (prev->start) + + grub_target_to_host16 (prev->len)) == sector) + { + grub_uint16_t t = grub_target_to_host16 (prev->len); + t += seclen; + prev->len = grub_host_to_target16 (t); + } + else + { + bl->block->start = grub_host_to_target64 (sector); + bl->block->len = grub_host_to_target16 (seclen); +#ifdef GRUB_SETUP_BIOS + bl->block->segment = grub_host_to_target16 (bl->current_segment); +#endif + + bl->block--; + if (bl->block->len) + grub_util_error ("%s", _("the sectors of the core file are too fragmented")); + } + + bl->last_length = length & (GRUB_DISK_SECTOR_SIZE - 1); +#ifdef GRUB_SETUP_BIOS + bl->current_segment += seclen << (GRUB_DISK_SECTOR_BITS - 4); +#endif +} + +/* Context for setup/identify_partmap. */ +struct identify_partmap_ctx +{ + grub_partition_map_t dest_partmap; + grub_partition_t container; + int multiple_partmaps; +}; + +/* Helper for setup. + Unlike root_dev, with dest_dev we're interested in the partition map even + if dest_dev itself is a whole disk. */ +static int +identify_partmap (grub_disk_t disk __attribute__ ((unused)), + const grub_partition_t p, void *data) +{ + struct identify_partmap_ctx *ctx = data; + + if (p->parent != ctx->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 (ctx->dest_partmap == NULL) + { + ctx->dest_partmap = p->partmap; + return 0; + } + if (ctx->dest_partmap == p->partmap) + return 0; + ctx->multiple_partmaps = 1; + return 1; +} + +#ifdef GRUB_SETUP_BIOS +#define SETUP grub_util_bios_setup +#elif GRUB_SETUP_SPARC64 +#define SETUP grub_util_sparc_setup +#else +#error "Shouldn't happen" +#endif + +void +SETUP (const char *dir, + const char *boot_file, const char *core_file, + const char *dest, int force, + int fs_probe, int allow_floppy, + int add_rs_codes __attribute__ ((unused)), /* unused on sparc64 */ + int warn_small) +{ + char *core_path; + char *boot_img, *core_img, *boot_path; + char *root = 0; + size_t boot_size, core_size; + grub_uint16_t core_sectors; + grub_device_t root_dev = 0, dest_dev, core_dev; + grub_util_fd_t fp; + struct blocklists bl; + + bl.first_sector = (grub_disk_addr_t) -1; + +#ifdef GRUB_SETUP_BIOS + bl.current_segment = + GRUB_BOOT_I386_PC_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4); +#endif +#ifdef GRUB_SETUP_SPARC64 + bl.gpt_offset = 0; +#endif + bl.last_length = 0; + + /* 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_SETUP_BIOS + 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. */ + bl.first_block = (struct grub_boot_blocklist *) (core_img + + GRUB_DISK_SECTOR_SIZE + - sizeof (*bl.block)); + + grub_util_info ("Opening dest `%s'", dest); + dest_dev = grub_device_open (dest); + if (! dest_dev) + grub_util_error ("%s", grub_errmsg); + + core_dev = dest_dev; + + { + char **root_devices = grub_guess_root_devices (dir); + char **cur; + int found = 0; + + if (!root_devices) + grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), dir); + + for (cur = root_devices; *cur; cur++) + { + char *drive; + grub_device_t try_dev; + + drive = grub_util_get_grub_dev (*cur); + if (!drive) + continue; + try_dev = grub_device_open (drive); + if (! try_dev) + { + free (drive); + continue; + } + if (!found && try_dev->disk->id == dest_dev->disk->id + && try_dev->disk->dev->id == dest_dev->disk->dev->id) + { + if (root_dev) + grub_device_close (root_dev); + free (root); + root_dev = try_dev; + root = drive; + found = 1; + continue; + } + if (!root_dev) + { + root_dev = try_dev; + root = drive; + continue; + } + grub_device_close (try_dev); + free (drive); + } + if (!root_dev) + { + grub_util_error ("guessing the root device failed, because of `%s'", + grub_errmsg); + } + grub_util_info ("guessed root_dev `%s' from " + "dir `%s'", root_dev->disk->name, dir); + + for (cur = root_devices; *cur; cur++) + free (*cur); + free (root_devices); + } + + 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_SETUP_BIOS + char *tmp_img; + grub_uint8_t *boot_drive_check; + + /* 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); + + boot_drive_check = (grub_uint8_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[0] = 0x90; + boot_drive_check[1] = 0x90; + } +#endif + + struct identify_partmap_ctx ctx = { + .dest_partmap = NULL, + .container = dest_dev->disk->partition, + .multiple_partmaps = 0 + }; + int is_ldm; + grub_err_t err; + grub_disk_addr_t *sectors; + int i; + grub_fs_t fs; + unsigned int nsec, maxsec; + + grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx); + +#ifdef GRUB_SETUP_BIOS + /* Copy the partition table. */ + if (ctx.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); +#endif + + if (ctx.container + && grub_strcmp (ctx.container->partmap->name, "msdos") == 0 + && ctx.dest_partmap + && (ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_NETBSD + || ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_OPENBSD)) + { + grub_util_warn ("%s", _("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; + + is_ldm = grub_util_is_ldm (dest_dev->disk); + + if (fs_probe) + { + if (!fs && !ctx.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) + /* TRANSLATORS: Filesystem may reserve the space just GRUB isn't sure about it. */ + 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 (ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0 + && strcmp (ctx.dest_partmap->name, "gpt") != 0 + && strcmp (ctx.dest_partmap->name, "bsd") != 0 + && strcmp (ctx.dest_partmap->name, "netbsd") != 0 + && strcmp (ctx.dest_partmap->name, "openbsd") != 0 + && strcmp (ctx.dest_partmap->name, "sunpc") != 0) + /* TRANSLATORS: Partition map may reserve the space just GRUB isn't sure about it. */ + 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, ctx.dest_partmap->name); + if (is_ldm && ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0 + && strcmp (ctx.dest_partmap->name, "gpt") != 0) + grub_util_error (_("%s appears to contain a %s partition map and " + "LDM which isn't known to be a safe combination." + " 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, ctx.dest_partmap->name); + + } + + if (! ctx.dest_partmap && ! fs && !is_ldm) + { + grub_util_warn ("%s", _("Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea.")); + goto unable_to_embed; + } + if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && fs)) + { + grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels. This is not supported yet.")); + goto unable_to_embed; + } + + if (ctx.dest_partmap && !ctx.dest_partmap->embed) + { + grub_util_warn (_("Partition style `%s' doesn't support embedding"), + ctx.dest_partmap->name); + goto unable_to_embed; + } + + if (fs && !fs->fs_embed) + { + grub_util_warn (_("File system `%s' doesn't support embedding"), + fs->name); + goto unable_to_embed; + } + + nsec = core_sectors; + + if (add_rs_codes) + maxsec = 2 * core_sectors; + else + maxsec = core_sectors; + +#ifdef GRUB_SETUP_BIOS + if (maxsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR) + >> GRUB_DISK_SECTOR_BITS)) + maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR) + >> GRUB_DISK_SECTOR_BITS); +#endif + +#ifdef GRUB_SETUP_SPARC64 + /* + * On SPARC we need two extra. One is because we are combining the + * core.img with the boot.img. The other is because the boot sector + * starts at 1. + */ + nsec += 2; + maxsec += 2; +#endif + + if (is_ldm) + err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec, + GRUB_EMBED_PCBIOS, §ors); + else if (ctx.dest_partmap) + err = ctx.dest_partmap->embed (dest_dev->disk, &nsec, maxsec, + GRUB_EMBED_PCBIOS, §ors, warn_small); + else + err = fs->fs_embed (dest_dev, &nsec, maxsec, + GRUB_EMBED_PCBIOS, §ors); + if (!err && nsec < core_sectors) + { + err = grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("Your embedding area is unusually small. " + "core.img won't fit in it.")); + } + + if (err) + { + grub_util_warn ("%s", grub_errmsg); + grub_errno = GRUB_ERR_NONE; + goto unable_to_embed; + } + + assert (nsec <= maxsec); + + /* Clean out the blocklists. */ + bl.block = bl.first_block; + while (bl.block->len) + { + grub_memset (bl.block, 0, sizeof (*bl.block)); + + bl.block--; + + if ((char *) bl.block <= core_img) + grub_util_error ("%s", _("no terminator in the core image")); + } + + bl.block = bl.first_block; + for (i = 0; i < nsec; i++) + save_blocklists (sectors[i] + grub_partition_get_start (ctx.container), + 0, GRUB_DISK_SECTOR_SIZE, &bl); + + /* Make sure that the last blocklist is a terminator. */ + if (bl.block == bl.first_block) + bl.block--; + bl.block->start = 0; + bl.block->len = 0; +#ifdef GRUB_SETUP_BIOS + bl.block->segment = 0; +#endif + +#ifdef GRUB_SETUP_SPARC64 + { + /* + * On SPARC, the block-list entries need to be based off the beginning + * of the parition, not the beginning of the disk. + */ + struct grub_boot_blocklist *block; + block = bl.first_block; + + while (block->len) + { + block->start -= bl.first_sector; + block--; + } + } + + /* + * Reserve space for the boot block since it can not be in the + * Parition table on SPARC. + */ + assert (bl.first_block->len > 2); + bl.first_block->start += 2; + bl.first_block->len -= 2; + write_rootdev (root_dev, boot_img, sectors[BOOT_SECTOR + 1] - bl.first_sector); +#endif + +#ifdef GRUB_SETUP_BIOS + write_rootdev (root_dev, boot_img, bl.first_sector); +#endif + + /* Round up to the nearest sector boundary, and zero the extra memory */ + core_img = xrealloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE); + assert (core_img && (nsec * GRUB_DISK_SECTOR_SIZE >= core_size)); + memset (core_img + core_size, 0, nsec * GRUB_DISK_SECTOR_SIZE - core_size); + + bl.first_block = (struct grub_boot_blocklist *) (core_img + + GRUB_DISK_SECTOR_SIZE + - sizeof (*bl.block)); +#if GRUB_SETUP_BIOS + grub_size_t no_rs_length; + no_rs_length = grub_target_to_host16 + (grub_get_unaligned16 (core_img + + GRUB_DISK_SECTOR_SIZE + + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH)); + + if (no_rs_length == 0xffff) + grub_util_error ("%s", _("core.img version mismatch")); + + if (add_rs_codes) + { + grub_set_unaligned32 ((core_img + GRUB_DISK_SECTOR_SIZE + + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY), + grub_host_to_target32 (nsec * GRUB_DISK_SECTOR_SIZE - core_size)); + + void *tmp = xmalloc (core_size); + grub_memcpy (tmp, core_img, core_size); + grub_reed_solomon_add_redundancy (core_img + no_rs_length + GRUB_DISK_SECTOR_SIZE, + core_size - no_rs_length - GRUB_DISK_SECTOR_SIZE, + nsec * GRUB_DISK_SECTOR_SIZE + - core_size); + assert (grub_memcmp (tmp, core_img, core_size) == 0); + free (tmp); + } + + /* 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); +#endif + +#ifdef GRUB_SETUP_SPARC64 + { + int isec = BOOT_SECTOR; + + /* Write the boot image onto the disk. */ + if (grub_disk_write (dest_dev->disk, sectors[isec++], 0, + GRUB_DISK_SECTOR_SIZE, boot_img)) + grub_util_error ("%s", grub_errmsg); + + /* Write the core image onto the disk. */ + for (i = 0 ; isec < nsec; i++, isec++) + { + if (grub_disk_write (dest_dev->disk, sectors[isec], 0, + GRUB_DISK_SECTOR_SIZE, + core_img + i * GRUB_DISK_SECTOR_SIZE)) + grub_util_error ("%s", grub_errmsg); + } + } + +#endif + grub_free (sectors); + + goto finish; + } + +unable_to_embed: + + if (dest_dev->disk->dev->id != root_dev->disk->dev->id) + grub_util_error ("%s", _("embedding is not possible, but this is required for " + "RAID and LVM install")); + + { + grub_fs_t fs; + fs = grub_fs_probe (root_dev); + if (!fs) + grub_util_error (_("can't determine filesystem on %s"), root); + + if (!fs->blocklist_install) + grub_util_error (_("filesystem `%s' doesn't support blocklists"), + fs->name); + } + +#ifdef GRUB_SETUP_BIOS + if (dest_dev->disk->id != root_dev->disk->id + || dest_dev->disk->dev->id != root_dev->disk->dev->id) + /* TRANSLATORS: cross-disk refers to /boot being on one disk + but MBR on another. */ + grub_util_error ("%s", _("embedding is not possible, but this is required for " + "cross-disk install")); +#else + core_dev = root_dev; +#endif + + grub_util_warn ("%s", _("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) + /* TRANSLATORS: Here GRUB refuses to continue with blocklist install. */ + grub_util_error ("%s", _("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"); + + grub_util_biosdisk_flush (root_dev->disk); + + /* Clean out the blocklists. */ + bl.block = bl.first_block; + while (bl.block->len) + { + bl.block->start = 0; + bl.block->len = 0; +#ifdef GRUB_SETUP_BIOS + bl.block->segment = 0; +#endif + + bl.block--; + + if ((char *) bl.block <= core_img) + grub_util_error ("%s", _("no terminator in the core image")); + } + + bl.block = bl.first_block; + +#ifdef GRUB_SETUP_SPARC64 + { + grub_partition_t container = root_dev->disk->partition; + + if (grub_strstr (container->partmap->name, "gpt")) + bl.gpt_offset = grub_partition_get_start (container); + } +#endif + + grub_install_get_blocklist (root_dev, core_path, core_img, core_size, + save_blocklists, &bl); + + if (bl.first_sector == (grub_disk_addr_t)-1) + grub_util_error ("%s", _("can't retrieve blocklists")); + +#ifdef GRUB_SETUP_SPARC64 + { + char *boot_devpath; + boot_devpath = (char *) (boot_img + + GRUB_BOOT_AOUT_HEADER_SIZE + + GRUB_BOOT_MACHINE_BOOT_DEVPATH); + if (dest_dev->disk->id != root_dev->disk->id + || dest_dev->disk->dev->id != root_dev->disk->dev->id) + { + char *dest_ofpath; + dest_ofpath + = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (root_dev->disk)); + /* FIXME handle NULL result */ + 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; + free (dest_ofpath); + } + 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 + + write_rootdev (root_dev, boot_img, bl.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 = grub_util_fd_open (core_path, GRUB_UTIL_FD_O_WRONLY); + if (! GRUB_UTIL_FD_IS_VALID (fp)) + grub_util_error (_("cannot open `%s': %s"), core_path, + grub_util_fd_strerror ()); + + if (grub_util_fd_write (fp, core_img, GRUB_DISK_SECTOR_SIZE * 2) + != GRUB_DISK_SECTOR_SIZE * 2) + grub_util_error (_("cannot write to `%s': %s"), + core_path, strerror (errno)); + if (grub_util_fd_sync (fp) < 0) + grub_util_error (_("cannot sync `%s': %s"), core_path, strerror (errno)); + if (grub_util_fd_close (fp) < 0) + grub_util_error (_("cannot close `%s': %s"), core_path, strerror (errno)); + grub_util_biosdisk_flush (root_dev->disk); + + grub_disk_cache_invalidate_all (); + + { + char *buf, *ptr = core_img; + size_t len = core_size; + grub_uint64_t blk, offset = 0; + grub_partition_t container = core_dev->disk->partition; + grub_err_t err; + + core_dev->disk->partition = 0; +#ifdef GRUB_SETUP_SPARC64 + offset = bl.gpt_offset; +#endif + + buf = xmalloc (core_size); + blk = bl.first_sector; + err = grub_disk_read (core_dev->disk, blk + offset, 0, GRUB_DISK_SECTOR_SIZE, buf); + if (err) + grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name, + grub_errmsg); + if (grub_memcmp (buf, ptr, GRUB_DISK_SECTOR_SIZE) != 0) + grub_util_error ("%s", _("blocklists are invalid")); + + ptr += GRUB_DISK_SECTOR_SIZE; + len -= GRUB_DISK_SECTOR_SIZE; + + bl.block = bl.first_block; + while (bl.block->len) + { + size_t cur = grub_target_to_host16 (bl.block->len) << GRUB_DISK_SECTOR_BITS; + blk = grub_target_to_host64 (bl.block->start); + + if (cur > len) + cur = len; + + err = grub_disk_read (core_dev->disk, blk + offset, 0, cur, buf); + if (err) + grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name, + grub_errmsg); + + if (grub_memcmp (buf, ptr, cur) != 0) + grub_util_error ("%s", _("blocklists are invalid")); + + ptr += cur; + len -= cur; + bl.block--; + + if ((char *) bl.block <= core_img) + grub_util_error ("%s", _("no terminator in the core image")); + } + if (len) + grub_util_error ("%s", _("blocklists are incomplete")); + core_dev->disk->partition = container; + free (buf); + } + +#ifdef GRUB_SETUP_BIOS + finish: +#endif + + /* 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); + +#ifdef GRUB_SETUP_SPARC64 + finish: +#endif + + 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); +} + diff --git a/util/setup_bios.c b/util/setup_bios.c new file mode 100644 index 0000000..38f4d5e --- /dev/null +++ b/util/setup_bios.c @@ -0,0 +1,2 @@ +#define GRUB_SETUP_BIOS 1 +#include "setup.c" diff --git a/util/setup_sparc.c b/util/setup_sparc.c new file mode 100644 index 0000000..89310a2 --- /dev/null +++ b/util/setup_sparc.c @@ -0,0 +1,2 @@ +#define GRUB_SETUP_SPARC64 1 +#include "setup.c" diff --git a/util/spkmodem-recv.c b/util/spkmodem-recv.c new file mode 100644 index 0000000..9083c1a --- /dev/null +++ b/util/spkmodem-recv.c @@ -0,0 +1,115 @@ +/* spkmodem-recv.c - decode spkmodem signals */ +/* + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * spkmodem-recv is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * spkmodem-recv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with spkmodem-recv. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* Compilation: gcc -o spkmodem-recv spkmodem-recv */ +/* Usage: parecord --channels=1 --rate=48000 --format=s16le | ./spkmodem-recv */ + +#define SAMPLES_PER_TRAME 240 +#define FREQ_SEP_MIN 5 +#define FREQ_SEP_MAX 15 +#define FREQ_DATA_MIN 15 +#define FREQ_DATA_THRESHOLD 25 +#define FREQ_DATA_MAX 60 +#define THRESHOLD 500 + +#define DEBUG 0 +#define FLUSH_TIMEOUT 1 + +static signed short trame[2 * SAMPLES_PER_TRAME]; +static signed short pulse[2 * SAMPLES_PER_TRAME]; +static int ringpos = 0; +static int pos, f1, f2; +static int amplitude = 0; +static int lp = 0; + +static void +read_sample (void) +{ + amplitude -= abs (trame[ringpos]); + f1 -= pulse[ringpos]; + f1 += pulse[(ringpos + SAMPLES_PER_TRAME) % (2 * SAMPLES_PER_TRAME)]; + f2 -= pulse[(ringpos + SAMPLES_PER_TRAME) % (2 * SAMPLES_PER_TRAME)]; + fread (trame + ringpos, 1, sizeof (trame[0]), stdin); + amplitude += abs (trame[ringpos]); + + if (pos ? (trame[ringpos] < -THRESHOLD) + : (trame[ringpos] > +THRESHOLD)) + { + pulse[ringpos] = 1; + pos = !pos; + f2++; + } + else + pulse[ringpos] = 0; + ringpos++; + ringpos %= 2 * SAMPLES_PER_TRAME; + lp++; +} + +int +main () +{ + int bitn = 7; + char c = 0; + int i; + int llp = 0; + while (!feof (stdin)) + { + if (lp > 3 * SAMPLES_PER_TRAME) + { + bitn = 7; + c = 0; + lp = 0; + llp++; + } + if (llp == FLUSH_TIMEOUT) + fflush (stdout); + if (f2 > FREQ_SEP_MIN && f2 < FREQ_SEP_MAX + && f1 > FREQ_DATA_MIN && f1 < FREQ_DATA_MAX) + { +#if DEBUG + printf ("%d %d %d @%d\n", f1, f2, FREQ_DATA_THRESHOLD, + ftell (stdin) - sizeof (trame)); +#endif + if (f1 < FREQ_DATA_THRESHOLD) + c |= (1 << bitn); + bitn--; + if (bitn < 0) + { +#if DEBUG + printf ("<%c, %x>", c, c); +#else + printf ("%c", c); +#endif + bitn = 7; + c = 0; + } + lp = 0; + llp = 0; + for (i = 0; i < SAMPLES_PER_TRAME; i++) + read_sample (); + continue; + } + read_sample (); + } + return 0; +} |