commit 3e5d681a2e88dc3706234638569f344e76c06c5a95c070abbfb55a66a68aa489 Author: Marcus Meissner Date: Thu Aug 1 19:46:31 2024 +0000 Accepting request 1189763 from home:fkastl:gcc14 - Add elilo-c99.patch so that the package conforms to the C99 standard and builds on i586 with GCC 14. If the request is OK, please forward it to factory soon-ish so that we can switch the default compiler. OBS-URL: https://build.opensuse.org/request/show/1189763 OBS-URL: https://build.opensuse.org/package/show/Base:System/elilo?expand=0&rev=26 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9b03811 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,23 @@ +## Default LFS +*.7z filter=lfs diff=lfs merge=lfs -text +*.bsp filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.gem filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.jar filter=lfs diff=lfs merge=lfs -text +*.lz filter=lfs diff=lfs merge=lfs -text +*.lzma filter=lfs diff=lfs merge=lfs -text +*.obscpio filter=lfs diff=lfs merge=lfs -text +*.oxt filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.rpm filter=lfs diff=lfs merge=lfs -text +*.tbz filter=lfs diff=lfs merge=lfs -text +*.tbz2 filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text +*.txz filter=lfs diff=lfs merge=lfs -text +*.whl filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57affb6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.osc diff --git a/3.16-release-notes.txt b/3.16-release-notes.txt new file mode 100644 index 0000000..e66cc59 --- /dev/null +++ b/3.16-release-notes.txt @@ -0,0 +1,119 @@ +3 . 1 6 R E L E A S E N O T E S +=================================== + +QUICK CHANGE SUMMARY +==================== + * Adds native x86x crossbuild functionality + build 32bit or 64bit versions from either environment via + make ARCH=ia32|x86_64 (the ARCH IS case sensitive). + make by itself will default to the native host arch. + * Add console reset call during initialization. thanks A. Steinmetz + * simplify output of no GOP warning text so it no longer looks like an error. + * MAJOR: Fixed Fault crash when EFI memory map changes from under elilo. + (from an outside interrupt in this case). When the EFI Memory map + changes after elilo has already built boot params to pass to the + kernel the EFI call to ExitBootSvcs just prior to boot will fail + because elilo has the old map key. This is valid EFI behavior, elilo + retries to pick up the new memory map and key but had already freed + the start params portion of boot params resulting in a NULL DEREF + crash reset once it hands the now bogus boot params to the kernel on + the 2nd successful call to exit efi and boot. + Thanks to Jerry Hoemann @ HP for reporting this bug. + * minor bugfix, fixed -m option broken. thanks Allan-lsk. + +BUILD NOTES +==================== + You will need the following toolchain to build elilo-3.14 from source + the elilo build environment is optimized for Debian and Debian based distros. + elilo-3.16 was built in the squeeze+(ubuntu 11.x) build environments except + for itanium which is unchanged to best support legacy enterprise configs. + Toolchain versions for this release were: + x86x(32 & 64bit versions) + * gnu-efi --> 3.0i-3 + * gcc ------> 4:4.4.4-1ubuntu2 + * binutils -> 2.20.51.20100908-0ubuntu2 + ia64 + * gnu-efi --> 3.0e-2 + * gcc ------> 4.3.2-2 + * binutils -> 2.18.1~cvs20080103-7 + + * if you use a debian based build environment you will have no problems + and setting it up is simple. you will be able to build elilo in 3 steps: + 1. apt-get install gnu-efi, gcc, binutils + 2. apt-get source elilo (or download elilo-3.16 source from SourceForge.) + 3. extract source tarball and cd to ./$your-elilo-source and type $> make + + + ** If you use the upstream toolchain tarballs(i.e. pre distro) you will need + to move some files around for elilo build to work. + GNU-EFI (provides the efi 1.10 and uefi 2.x libraries & api) + ------- + gnu-efi libraries are installed to /usr/local/lib by the + upstream gnu-efi source package. elilo expects them to be in system location + /usr/lib. efi includes may be located in /usr/local/include/efi. elilo + expects them to be in system location /usr/include/efi. + [ The reason is LSB compliance ]. + + BINUTILS (provides the elf conversion utility to produce efi bins) + -------- + binutils provides objcopy which is installed to /usr/local/bin by binutils, + elilo source expects it to be in /usr/bin. + + again this LSB compliance is taken care of by the distro's that fix + the toolchains to install to the correct compliant system locations + instead of the "user optional" location. + +ELILO ON EFI X86_64 +===================== +HARD REQUIREMENTS + EFI + x86_64 REQUIRES an efi64 enabled linux kernel i.e. 2.6.21 or newer + nothing earlier will work, 2.6.21 was the earliest kernel that efi64 + support went into. You need to compile the kernel with CONFIG_EFI + kernel option ON. + x86_64 platforms with UEFI 2.0 firmware deprecate UGA protocol + and therefore only the Graphics Output Protocol (GOP) is supported. For + such platforms, the kernel must be compiled with EFI_FB option ON. This + will enable early boot messages on the console. Elilo for x86_64 + attempts to query EFI for GOP support and if it fails it defaults to + text mode which may or may not show you early console ouput depends on + your efi console settings and physical setup. Elilo has no way to know + if your console settings are messed up. + +WORKING ELILO.CONF FOR EFI X86_64 EXAMPLE + Here is my elilo.conf from my UEFI2.0/x86_64 (with nvidia pcie add on + card, i.e. your vga= kernel param may be different) workstation which uses GOP. + Here is a partial kernel vga table I was able to find and add here. +Colours 640x400 640x480 800x600 1024x768 1152x864 1280x1024 1600x1200 + -------+-------------------------------------------------------------- + 4 bits | ? ? 0x302 ? ? ? ? + 8 bits | 0x300 0x301 0x303 0x305 0x161 0x307 0x31C + 15 bits | ? 0x310 0x313 0x316 0x162 0x319 0x31D + 16 bits | ? 0x311 0x314 0x317 0x163 0x31A 0x31E + decimal | d785 d788 d791 + 24 bits | ? 0x312 0x315 0x318 ? 0x31B 0x31F + +Additionally from ...kernel-source/Documentation/Boot.txt... + vga= + here is either an integer (in C notation, either + decimal, octal, or hexadecimal) or one of the strings + "normal" (meaning 0xFFFF), "ext" (meaning 0xFFFE) or "ask" + (meaning 0xFFFD). This value should be entered into the + vid_mode field, as it is used by the kernel before the command + line is parsed. + + example below shows me console output, what elilo is doing, and kernel boot. + vga=normal with efi console input output directed to graphics card should + work as well. + + default=UBUNTU + chooser=simple + verbose=5 + delay=30 + append="root=/dev/sda3 vga=0x31e splash showopts" + + image=/vmlinuz-2.6.32-27-generic + label="UBUNTU" + description="Ubuntu 2.6.32-27-generic kernel" + initrd=/initrd.img-2.6.32-27-generic + + diff --git a/debian.eliloalt.man8 b/debian.eliloalt.man8 new file mode 100644 index 0000000..88afd17 --- /dev/null +++ b/debian.eliloalt.man8 @@ -0,0 +1,20 @@ +.TH ELILOALT 8 "18 Mar 2002" +.SH NAME +eliloalt \- manipulate elilo alternate +.SH SYNOPSIS +.B eliloalt +.RI [ options ] +.SH DESCRIPTION +The +.B eliloalt +command makes it possible to coerce elilo to boot an alternate +kernel configuration one time only, as when engaging in kernel development or +debugging. +.sp +.SH SEE ALSO +Additional information about +.B eliloalt +is available in the /usr/share/doc/packages/elilo directory. +.SH AUTHOR +This manual page was written by Bdale Garbee +for the Debian GNU/Linux system (but may be used by others). diff --git a/elilo-3.16-source.tar.xz b/elilo-3.16-source.tar.xz new file mode 100644 index 0000000..a6391b0 --- /dev/null +++ b/elilo-3.16-source.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c0b247d96cfa9067e6728ebc95d511ffda9f47af4831c2ec7c19dfa2ea5f9a0 +size 147468 diff --git a/elilo-auto-add_efi_memmap.diff b/elilo-auto-add_efi_memmap.diff new file mode 100644 index 0000000..4040f12 --- /dev/null +++ b/elilo-auto-add_efi_memmap.diff @@ -0,0 +1,149 @@ +--- + bootparams.c | 15 ++++----------- + x86_64/config.c | 18 ++++++++++++++++++ + x86_64/sysdeps.h | 5 ++++- + x86_64/system.c | 30 +++++++++++++++++++++++++----- + 4 files changed, 51 insertions(+), 17 deletions(-) + +--- a/x86_64/system.c ++++ b/x86_64/system.c +@@ -953,6 +953,11 @@ do_memmap: + #endif + if (e820_map_overflow && !e820_map_overflow_warned) { + CHAR8 *aem = (CHAR8 *)"add_efi_memmap"; ++ UINTN al = strlena( aem) + 1; ++ UINTN cl = strlena( (CHAR8 *)cmdline); ++ INT8 autoadd = (x86_64_auto_add_efi_memmap() && ++ (cl + al) < CMDLINE_MAXLEN); ++ CHAR16 *severity = (autoadd) ? L"Notice" : L"CAUTION"; + e820_map_overflow_warned++; + + #if DEBUG_CREATE_BOOT_PARAMS +@@ -964,11 +969,26 @@ do_memmap: + goto do_memmap; + } + +- Print(L"\nCAUTION: EFI memory map has %d more entr%a" +- " than E820 map supports.\n" +- "To access all memory, '%a' may be necessary.\n\n", +- e820_map_overflow, (e820_map_overflow==1)?"y":"ies", +- aem); ++ Print(L"\n%s: EFI memory map has %d more entr%a than E820 map" ++ " supports.\n", severity, e820_map_overflow, ++ (e820_map_overflow==1)?"y":"ies"); ++ ++ if (autoadd) { ++ strcpya( cmdline + cl, (CHAR8 *)" "); ++ strcpya( cmdline + cl + 1, aem); ++ Print(L"To allow access to all memory, '%a' has been" ++ " auto-added!\n\n", aem); ++ wait_timeout(30); ++ goto do_memmap; ++ } ++ if ((cl + al) >= CMDLINE_MAXLEN) ++ Print(L"But adding '%a' would exceed the maximum" ++ " command-line length", aem); ++ else ++ Print(L"But auto-adding of '%a' is disabled in" ++ " 'elilo.conf'", aem); ++ wait_timeout(60); ++ Print(L"\n\n"); + goto do_memmap; + } + +--- a/x86_64/config.c ++++ b/x86_64/config.c +@@ -34,6 +34,7 @@ + typedef struct { + UINTN legacy_free_boot; + UINTN text_mode; ++ CHAR16 add_efi_memmap[MAX_STRING]; + } x86_64_global_config_t; + + +@@ -42,10 +43,14 @@ typedef struct { + static x86_64_global_config_t x86_64_gconf; + + static config_option_t sysdeps_global_options[]={ ++ {OPT_STR, OPT_GLOBAL, L"add-efi-memmap", ++ NULL, NULL, &x86_64_gconf.add_efi_memmap}, + {OPT_BOOL, OPT_GLOBAL, L"legacy-free", NULL, NULL, &x86_64_gconf.legacy_free_boot} + }; + + static config_option_t sysdeps_image_options[]={ ++ {OPT_STR, OPT_IMAGE_SYS, L"add-efi-memmap", ++ NULL, NULL, x86_64_opt_offsetof(add_efi_memmap)}, + {OPT_BOOL, OPT_IMAGE_SYS, L"text-mode", NULL, NULL, x86_64_opt_offsetof(text_mode)} + }; + +@@ -89,6 +94,19 @@ x86_64_use_legacy_free_boot(VOID) + return x86_64_gconf.legacy_free_boot ? 1 : 0; + } + ++INT8 ++x86_64_auto_add_efi_memmap(VOID) ++{ ++ if (elilo_opt.sys_img_opts) { ++ if (!StrCmp(elilo_opt.sys_img_opts->add_efi_memmap, L"false")) ++ return 0; ++ if (!StrCmp(elilo_opt.sys_img_opts->add_efi_memmap, L"auto")) ++ return 1; ++ } ++ if (!StrCmp(x86_64_gconf.add_efi_memmap, L"false")) ++ return 0; ++ return 1; ++} + + INTN + x86_64_text_mode(VOID) +--- a/x86_64/sysdeps.h ++++ b/x86_64/sysdeps.h +@@ -365,6 +365,7 @@ extern UINTN rmswitch_size; + + extern INTN x86_64_use_legacy_free_boot(); + extern INTN x86_64_text_mode(); ++extern INT8 x86_64_auto_add_efi_memmap(); + + /* + * How to jump to kernel code +@@ -457,9 +458,11 @@ start_kernel(VOID *kentry, boot_params_t + /* Never come back to here. */ + } + ++#define MAX_STRING 512 /* ToDo: move to 'config.h' */ + typedef struct sys_img_options { + UINT8 dummy; /* forces non-zero offset for first field */ +- UINT8 text_mode; /* do not try to initialize Graphics Output Protocol */ ++ UINT8 text_mode; /* don't try to initialize GraphicsOutputProtocol */ ++ CHAR16 add_efi_memmap[MAX_STRING]; /* "false" | "auto" */ + } sys_img_options_t; + + #endif /* __ELILO_SYSDEPS_X86_64_H__ */ +--- a/bootparams.c ++++ b/bootparams.c +@@ -93,21 +93,14 @@ create_boot_params(CHAR16 *args, memdesc + */ + Memset(bp, 0, BOOT_PARAM_MEMSIZE); + ++ /* ++ * Convert kernel command line args from UNICODE to ASCII ++ * and put them where the kernel expects them: ++ */ + U2ascii(args, cp, cmdline_size); + + if (sysdeps_create_boot_params(bp, cp, initrd, vmcode, cookie) == -1) return 0; + +- /* +- * Convert kernel command line args from UNICODE to ASCII and put them where +- * the kernel expects them: +- */ +- while (1) { +- ch = *args++; +- if (!ch) break; +- *cp++ = ch; +- } +- *cp++ = '\0'; +- + return bp; + } + diff --git a/elilo-binutils-2.36-fix.patch b/elilo-binutils-2.36-fix.patch new file mode 100644 index 0000000..b7eec8e --- /dev/null +++ b/elilo-binutils-2.36-fix.patch @@ -0,0 +1,26 @@ +diff --git a/ia32/Makefile b/ia32/Makefile +index 46609c4..078efc9 100644 +--- a/ia32/Makefile ++++ b/ia32/Makefile +@@ -43,7 +43,7 @@ system.o: rmswitch.h + + rmswitch.h: bin_to_h.c rmswitch.S + $(CC) $(OPTIMFLAGS) -o bin_to_h $(SRCDIR)/bin_to_h.c +- $(AS) -o rmswitch.o $(SRCDIR)/rmswitch.S ++ $(AS) -mx86-used-note=no -o rmswitch.o $(SRCDIR)/rmswitch.S + $(LD) -Ttext 0x0 -s --oformat binary -o rmswitch rmswitch.o + ./bin_to_h rmswitch.h + +diff --git a/x86_64/Makefile b/x86_64/Makefile +index e7c81f8..a3f2411 100644 +--- a/x86_64/Makefile ++++ b/x86_64/Makefile +@@ -44,7 +44,7 @@ system.o: rmswitch.h + + rmswitch.h: bin_to_h.c rmswitch.S + $(CC) $(OPTIMFLAGS) -o bin_to_h $(SRCDIR)/bin_to_h.c +- $(AS) -o rmswitch.o $(SRCDIR)/rmswitch.S ++ $(AS) -mx86-used-note=no -o rmswitch.o $(SRCDIR)/rmswitch.S + $(LD) -Ttext 0x0 -s --oformat binary -o rmswitch rmswitch.o + ./bin_to_h rmswitch.h + diff --git a/elilo-blocksize.diff b/elilo-blocksize.diff new file mode 100644 index 0000000..df35744 --- /dev/null +++ b/elilo-blocksize.diff @@ -0,0 +1,56 @@ +--- + config.c | 4 ++++ + elilo.h | 2 ++ + fs/netfs.c | 3 ++- + 3 files changed, 8 insertions(+), 1 deletion(-) + +--- a/config.c ++++ b/config.c +@@ -119,6 +119,7 @@ typedef struct { + UINTN timeout; + UINTN verbose; + UINTN edd30_no_force; /* don't force EDD30 if not set */ ++ UINTN blocksize; + } global_config_t; + + /* +@@ -143,6 +144,7 @@ static config_option_t global_common_opt + {OPT_STR, OPT_GLOBAL, L"default", NULL, NULL, global_config.default_image_name}, + {OPT_NUM, OPT_GLOBAL, L"timeout", NULL, NULL, &global_config.timeout}, + {OPT_NUM, OPT_GLOBAL, L"delay", NULL, NULL, &global_config.delay}, ++{OPT_NUM, OPT_GLOBAL, L"block-size", NULL, NULL, &global_config.blocksize}, + {OPT_BOOL, OPT_GLOBAL, L"debug", NULL, NULL, &global_config.debug}, + {OPT_BOOL, OPT_GLOBAL, L"prompt", NULL, NULL, &global_config.prompt}, + {OPT_NUM, OPT_GLOBAL, L"verbose", NULL, check_verbosity, &global_config.verbose}, +@@ -827,6 +829,8 @@ update_elilo_opt(VOID) + + if (global_config.debug) elilo_opt.debug = 1; + if (global_config.prompt) elilo_opt.prompt = 1; ++ if (global_config.blocksize) ++ elilo_opt.blocksize = global_config.blocksize; + + /* + * update only if not set on command line +--- a/elilo.h ++++ b/elilo.h +@@ -105,6 +105,8 @@ typedef struct { + UINTN prompt; /* enter interactive mode */ + UINTN parse_only; /* only parses the config file */ + UINTN timeout; /* timeout before leaving interactive mode*/ ++ UINTN blocksize; /* user-specified block-size for I/O */ ++ /* (currently only used for TFTP!) */ + + image_opt_t img_opt; /* architecture independent per image options*/ + +--- a/fs/netfs.c ++++ b/fs/netfs.c +@@ -517,7 +517,8 @@ netfs_open(netfs_interface_t *this, CHAR + netfs_fd_t *f; + EFI_STATUS status; + CHAR8 ascii_name[FILENAME_MAXLEN]; +- UINTN blocksize = NETFS_DEFAULT_BLOCKSIZE; ++ UINTN blocksize = (elilo_opt.blocksize > 0) ? ++ elilo_opt.blocksize : NETFS_DEFAULT_BLOCKSIZE; + UINTN prev_netbufsize, retries = 0; + BOOLEAN server_provided_filesize = FALSE; + diff --git a/elilo-c99.patch b/elilo-c99.patch new file mode 100644 index 0000000..85e0bfa --- /dev/null +++ b/elilo-c99.patch @@ -0,0 +1,13 @@ +Index: elilo-3.16-source/fs/netfs.c +=================================================================== +--- elilo-3.16-source.orig/fs/netfs.c ++++ elilo-3.16-source/fs/netfs.c +@@ -55,7 +55,7 @@ typedef struct _netfs_fd { + + CHAR8 *netbuf; + UINT64 netbuf_maxsize; /* currently allocated buffer */ +- UINTN netbuf_size; /* number of bytes currently used in the buffer */ ++ UINT64 netbuf_size; /* number of bytes currently used in the buffer */ + UINT64 netbuf_pos; /* current position in the buffer */ + BOOLEAN is_valid; /* avoid conflicting opens */ + BOOLEAN netbuf_reuse; diff --git a/elilo-de-debianify.diff b/elilo-de-debianify.diff new file mode 100644 index 0000000..7b6b6de --- /dev/null +++ b/elilo-de-debianify.diff @@ -0,0 +1,42 @@ +--- + Make.defaults | 5 +++-- + ia32/Makefile | 2 +- + x86_64/Makefile | 2 +- + 3 files changed, 5 insertions(+), 4 deletions(-) + +--- a/Make.defaults ++++ b/Make.defaults +@@ -63,8 +63,9 @@ CDIR := $(shell if [ "$$PWD" != "" ]; + TOPDIR = + ALLSUBDIRS = ia32 ia64 x86_64 fs choosers devschemes tools + +-HOSTARCH = $(shell dpkg-architecture -qDEB_BUILD_ARCH | sed s,i[3456789]86,ia32, | sed s,amd64,x86_64, ) +-ARCH := $(shell dpkg-architecture -qDEB_BUILD_ARCH | sed s,i[3456789]86,ia32, | sed s,amd64,x86_64, ) ++HOSTARCH := $(shell if ! dpkg-architecture -qDEB_BUILD_ARCH 2>/dev/null; then \ ++ uname -m; fi | sed -e s,i[3456789]86,ia32, -e s,amd64,x86_64, ) ++ARCH := $(HOSTARCH) + INCDIR = -I. -I$(TOPDIR) -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol -I$(TOPDIR)/efi110 + CPPFLAGS = -DCONFIG_$(ARCH) + +--- a/x86_64/Makefile ++++ b/x86_64/Makefile +@@ -43,7 +43,7 @@ all: $(TARGET) + system.o: rmswitch.h + + rmswitch.h: bin_to_h.c rmswitch.S +- $(CC) -o bin_to_h $(SRCDIR)/bin_to_h.c ++ $(CC) $(OPTIMFLAGS) -o bin_to_h $(SRCDIR)/bin_to_h.c + $(AS) -o rmswitch.o $(SRCDIR)/rmswitch.S + $(LD) -Ttext 0x0 -s --oformat binary -o rmswitch rmswitch.o + ./bin_to_h rmswitch.h +--- a/ia32/Makefile ++++ b/ia32/Makefile +@@ -42,7 +42,7 @@ all: $(TARGET) + system.o: rmswitch.h + + rmswitch.h: bin_to_h.c rmswitch.S +- $(CC) -o bin_to_h $(SRCDIR)/bin_to_h.c ++ $(CC) $(OPTIMFLAGS) -o bin_to_h $(SRCDIR)/bin_to_h.c + $(AS) -o rmswitch.o $(SRCDIR)/rmswitch.S + $(LD) -Ttext 0x0 -s --oformat binary -o rmswitch rmswitch.o + ./bin_to_h rmswitch.h diff --git a/elilo-high_base_mem.diff b/elilo-high_base_mem.diff new file mode 100644 index 0000000..900281c --- /dev/null +++ b/elilo-high_base_mem.diff @@ -0,0 +1,66 @@ +--- + x86_64/system.c | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +--- a/x86_64/system.c ++++ b/x86_64/system.c +@@ -44,7 +44,9 @@ + #include "loader.h" + #include "rmswitch.h" + ++#ifndef DEBUG_CREATE_BOOT_PARAMS + #define DEBUG_CREATE_BOOT_PARAMS 0 ++#endif + #if DEBUG_CREATE_BOOT_PARAMS + #define DPR(a) do { if (elilo_opt.debug) { Print a; } } while ( 0 ) + #else +@@ -100,6 +102,7 @@ UINTN sizeof_init_gdt = sizeof init_gdt; + */ + + UINTN high_base_mem = 0x90000; ++VOID *high_base_mem_address = NULL; + + /* + * Highest available extended memory address. +@@ -128,6 +131,30 @@ sysdeps_init(EFI_HANDLE dev) + { + DBG_PRT((L"sysdeps_init()\n")); + ++ DBG_PRT((L"fix high_base_mem and gdt_addr\n")); ++ while (!high_base_mem_address) { ++ high_base_mem_address = alloc_pages(5, EfiLoaderData, ++ AllocateAddress, ++ (void *)high_base_mem); ++ if (!high_base_mem_address) { ++ if (high_base_mem > (1 << 16)) { ++ high_base_mem -= (1 << 16); ++ } else { ++ /* fall back to previous behavior */ ++ high_base_mem = 0x90000; ++ break; ++ } ++ } ++ } ++ if (high_base_mem_address) { ++ VERB_PRT(3, Print(L"high_base_mem="PTR_FMT"\n", ++ high_base_mem_address)); ++ gdt_addr.base = high_base_mem + 0x4000; ++ } else { ++ ERR_PRT((L"Failed to allocate high_base_mem, " ++ "stomping over heritage 0x90000.\n")); ++ } ++ + /* + * Register our loader(s)... + */ +@@ -624,6 +651,10 @@ sysdeps_create_boot_params( + ERR_PRT((L"bp="PTR_FMT" cmdline="PTR_FMT" initrd="PTR_FMT" cookie="PTR_FMT"", + bp, cmdline, initrd, cookie)); + ++ if (high_base_mem_address != NULL) { ++ free(high_base_mem_address); ++ high_base_mem_address = NULL; ++ } + if (param_start != NULL) { + free(param_start); + param_start = NULL; diff --git a/elilo-ipv6.diff b/elilo-ipv6.diff new file mode 100644 index 0000000..eea8271 --- /dev/null +++ b/elilo-ipv6.diff @@ -0,0 +1,458 @@ +--- + fs/netfs.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- + glue_netfs.c | 53 ++++++++++-- + strops.c | 11 ++ + strops.h | 1 + 4 files changed, 302 insertions(+), 20 deletions(-) + +--- a/glue_netfs.c ++++ b/glue_netfs.c +@@ -133,6 +133,17 @@ netfs_set_default_path(netfs_interface_t + return EFI_SUCCESS; + } + ++static INTN ++non_zero(UINT8 *c, UINTN len) ++{ ++ int i; ++ for (i=0 ; i < len ; i++) { ++ if (c[i]) ++ return 1; ++ } ++ return 0; ++} ++ + static EFI_STATUS + netfs_setdefaults(VOID *intf, config_file_t *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath) + { +@@ -140,7 +151,7 @@ netfs_setdefaults(VOID *intf, config_fil + netfs_info_t info; + EFI_STATUS status; + UINT8 *ipaddr; +- UINTN m; ++ UINTN m, i; + CHAR16 ip_var[64], str[64]; + UINT8 *ip; + +@@ -165,6 +176,9 @@ netfs_setdefaults(VOID *intf, config_fil + set_var(VAR_NETFS_HOSTNAME, info.hostname); + set_var(VAR_NETFS_DOMAINAME, info.domainame); + ++ DBG_PRT((L"netfs_setdefaults: hostname=%s (IPv%a)", info.hostname, ++ (info.using_ipv6 ? "6" : "4"))); ++ + if (info.using_pxe) { + DBG_PRT((L"netfs_setdefaults: using_pxe")); + +@@ -184,13 +198,10 @@ netfs_setdefaults(VOID *intf, config_fil + + # if defined(CONFIG_ia64) + # define CONFIG_ARCH_EXTENSION L"-ia64.conf\0" +-# define EXTENSION_LENGTH 11 + # elif defined (CONFIG_ia32) + # define CONFIG_ARCH_EXTENSION L"-ia32.conf\0" +-# define EXTENSION_LENGTH 11 + # elif defined (CONFIG_x86_64) + # define CONFIG_ARCH_EXTENSION L"-x86_64.conf\0" +-# define EXTENSION_LENGTH 13 + # else + # error "You need to specfy your default arch config file" + # endif +@@ -203,31 +214,57 @@ netfs_setdefaults(VOID *intf, config_fil + * the filenames are constructed based on the IP(v4) address + */ + convert_ip2hex(ipaddr, m, str); ++#if 1 ++ i = 0; ++ if (non_zero(ipaddr, m)) { ++ int nr = (m==16)? 10 : 6; ++ int st = (m==16)? 2 : 1; ++ m <<= 1; ++ StrnCpy(config[i].fname, str, m); ++ StrnCat(config[i++].fname, ++ CONFIG_EXTENSION, maxlen - m); ++ while (i <= nr) { ++ int stub = m - (i+1)*st; ++ StrnCpy(config[i].fname, str, stub); ++ StrnCat(config[i++].fname, ++ CONFIG_ARCH_EXTENSION, maxlen - m); ++ StrnCpy(config[i].fname, str, stub); ++ StrnCat(config[i++].fname, ++ CONFIG_EXTENSION, maxlen - m); ++ } ++ } ++ if (non_zero(info.hw_addr, 6)) { ++ convert_mac2hex(info.hw_addr,6,str); ++ StrnCpy(config[i].fname, str, maxlen-1); ++ StrnCpy(config[i++].fname+17, CONFIG_EXTENSION, 6); ++ } ++#else + StrnCpy(config[0].fname, str, maxlen-1); + StrnCpy(config[0].fname+8, CONFIG_EXTENSION, 6); + + StrnCpy(config[1].fname, str, maxlen-1); +- StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); ++ StrnCpy(config[1].fname+6, CONFIG_ARCH_EXTENSION, maxlen-7); + + StrnCpy(config[2].fname, str, maxlen-1); + StrnCpy(config[2].fname+6, CONFIG_EXTENSION, 6); + + StrnCpy(config[3].fname, str, maxlen-1); +- StrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); ++ StrnCpy(config[3].fname+4, CONFIG_ARCH_EXTENSION, maxlen-5); + + StrnCpy(config[4].fname, str, maxlen-1); + StrnCpy(config[4].fname+4, CONFIG_EXTENSION, 6); + + StrnCpy(config[5].fname, str, maxlen-1); +- StrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, EXTENSION_LENGTH); ++ StrnCpy(config[5].fname+2, CONFIG_ARCH_EXTENSION, maxlen-3); + + StrnCpy(config[6].fname, str, maxlen-1); +- StrnCpy(config[6].fname+2, CONFIG_EXTENSION, 6); ++ StrnCpy(config[6].fname+2, CONFIG_EXTENSION, maxlen-3); + + /* use the MAC address as a possible file name as well */ + convert_mac2hex(info.hw_addr,6,str); + StrnCpy(config[7].fname, str, maxlen-1); + StrnCpy(config[7].fname+17, CONFIG_EXTENSION, 6); ++#endif + + #else + StrnCpy(config[0].fname, NETFS_DEFAULT_CONFIG, maxlen-1); +--- a/strops.c ++++ b/strops.c +@@ -50,6 +50,17 @@ StrnCpy(OUT CHAR16 *dst, IN const CHAR16 + return res; + } + ++CHAR16 * ++StrnCat(OUT CHAR16 *dst, IN const CHAR16 *src, IN UINTN size) ++{ ++ CHAR16 *res; ++ ++ while (size && size-- && (*dst++) != CHAR_NULL); ++ res = StrnCpy(--dst, src, size); ++ ++ return res; ++} ++ + CHAR8 * + StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, IN UINTN size) + { +--- a/strops.h ++++ b/strops.h +@@ -28,6 +28,7 @@ + + extern CHAR16 *StrChr(IN const CHAR16 *s, const CHAR16 c); + extern CHAR16 *StrnCpy(OUT CHAR16 *dst, IN const CHAR16 *src, UINTN count); ++extern CHAR16 *StrnCat(OUT CHAR16 *dst, IN const CHAR16 *src, UINTN count); + extern CHAR8 *StrnXCpy(OUT CHAR8 *dst, IN const CHAR16 *src, UINTN count); + + extern CHAR8 *strtok_simple(CHAR8 *in, CHAR8 c); +--- a/fs/netfs.c ++++ b/fs/netfs.c +@@ -75,6 +75,8 @@ typedef struct { + EFI_IP_ADDRESS netmask; + UINT8 hw_addr[16]; + ++ CHAR8 bootfile[NETFS_BOOTFILE_MAXLEN]; ++ + netfs_fd_t fd_tab[NETFS_FD_MAX]; + netfs_fd_t *free_fd; + UINTN free_fd_count; +@@ -206,11 +208,239 @@ netfs_name(netfs_interface_t *this, CHAR + return EFI_SUCCESS; + } + ++typedef struct { ++ UINT16 code; ++ UINT16 len; ++ UINT8 data[]; ++} DHCPv6_OPTION; ++ ++#define DHCPv6_REPLY 7 ++#define OPT_BOOTFILE_URL 59 ++#define PROTO "tftp://" /* only TFTP supported for now */ ++ ++static inline UINT16 ++bswap16(UINT16 x) ++{ ++ return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)); ++} ++#if __BYTE_ORDER == __LITTLE_ENDIAN ++# define ntohs(x) bswap16(x) ++# define htons(x) bswap16(x) ++#else ++# if __BYTE_ORDER == __BIG_ENDIAN ++# define ntohs(x) (x) ++# define htons(x) (x) ++# endif ++#endif ++/* string 2 net short */ ++static UINT16 ++stra2ns(CHAR8 *str) ++{ ++ UINT16 ret = 0; ++ UINT8 v; ++ for(;*str;str++) { ++ if ('0' <= *str && *str <= '9') ++ v = *str - '0'; ++ else if ('A' <= *str && *str <= 'F') ++ v = *str - 'A' + 10; ++ else if ('a' <= *str && *str <= 'f') ++ v = *str - 'a' + 10; ++ else ++ v = 0; ++ ret = (ret << 4) + v; ++ } ++ /* DBG_PRT((L"stra2ns: '%a'='%d'", str, ret)); */ ++ return htons(ret); ++} ++ ++/* IPv4/6 address to string */ ++static CHAR8 * ++ip2stra(UINT8 octets, UINT8 *ip) ++{ ++ int i, j; ++ static CHAR8 *hexa= (CHAR8 *)"0123456789ABCDEF"; ++ static CHAR8 str[42]; ++ ++ if (octets == 16) { ++ for(i=j=0; i < 16; i++) { ++ str[j++] = hexa[(ip[i] & 0xf0)>>4]; ++ str[j++] = hexa[ip[i] & 0x0f]; ++ if (i && i%2 == 0) ++ str[j++] = ':'; ++ } ++ } else if (octets == 4) { ++ int val, v; ++ for(i=j=0; i < 4; i++) { ++ val = ip[i]; ++ v = val / 100; ++ if (v) ++ str[j++] = '0' + v; ++ v = (val % 100) / 10; ++ if (v || val > 99) ++ str[j++] = '0' + v; ++ val %= 10; ++ str[j++] = '0' + val; ++ str[j++] = '.'; ++ } ++ } else ++ j = 1; ++ str[--j] = '\0'; ++ /* DBG_PRT((L"ip2stra: '%a'", str)); */ ++ return str; ++} ++ ++/* string 2 IPv6 address */ ++static UINT8 * ++stra2ip6(CHAR8 *str) ++{ ++ UINTN i, j, p, len; ++ CHAR8 *a, *b, t; ++ static UINT16 ip[8]; ++ ++ for(i=0; i < 8; i++) { ++ ip[i] = 0; ++ } ++ len = strlena( str); ++ a = b = str; ++ for(i=p=0; i < len; i++, b++) { ++ if (*b != ':') ++ continue; ++ *b = '\0'; ++ ip[p++] = stra2ns(a); ++ *b = ':'; ++ a = b + 1; ++ if ( *(b+1) == ':' ) ++ break; ++ } ++ a = b = str + len; ++ for(j=len, p=7; j > i; j--, a--) { ++ if (*a != ':') ++ continue; ++ t = *b; ++ *b = '\0'; ++ ip[p--] = stra2ns(a+1); ++ *b = t; ++ b = a; ++ } ++ DBG_PRT((L"stra2ip6: '%a'='%a'", str, ip2stra(16, (UINT8 *)ip))); ++ return (UINT8 *)ip; ++} ++ ++static VOID ++hexdump(UINT8 *dp, int size) ++{ ++ int i = 0, j; ++ unsigned char *d = (unsigned char *)dp; ++ char hex[64], chr[17]; ++ static CHAR8 *hexa= (CHAR8 *)"0123456789ABCDEF"; ++ ++ hex[58] = '\0'; ++ chr[16] = '\0'; ++ while ( i < size ) { ++ if ( i > 0 && i % 16 == 0 ) ++ Print(L"%a >%a<\n", hex, chr); ++ if ( i % 16 == 0 ) { ++ Memset( hex, ' ', 58); ++ hex[56] = '\0'; ++ if (i>0xFFFFFF) return; ++ for (j = 0; j < 6; j++) ++ hex[j] = hexa[(i>>(4*(5-j))) & 0xF]; ++ } ++#define pos(i) ((((i%16)<8)?8:9)+(i%16)*3) ++ hex[pos(i)] = hexa[d[i]>>4&0xF]; ++ hex[pos(i)+1] = hexa[d[i]&0xF]; ++ ++ chr[i%16] = ((d[i]>31&&d[i]<127)?d[i]:'.'); ++ i++; ++ } ++ if ( i % 16 != 1 ) { ++ chr[(i%16)] = '\0'; ++ Print(L"%a >%a<\n", hex, chr); ++ } ++} ++ ++static INTN ++find_dhcp6_option( ++ EFI_PXE_BASE_CODE_PACKET *packet, ++ UINT8 option, ++ CHAR8 *str, ++ INTN *length) ++{ ++ EFI_PXE_BASE_CODE_DHCPV6_PACKET *v6 = ++ (EFI_PXE_BASE_CODE_DHCPV6_PACKET *)packet->Raw; ++ int code, len; ++ DHCPv6_OPTION *p; ++ ++ /* Consistency check */ ++ if (v6->MessageType != DHCPv6_REPLY) { ++ VERB_PRT(2, Print(L"DHCPv6: MessageType: %d != %d\n", ++ v6->MessageType, DHCPv6_REPLY)); ++ VERB_PRT(3, hexdump( (UINT8 *)v6, 1024)); ++ return -1; ++ } ++ p = (DHCPv6_OPTION *)&v6->DhcpOptions; ++ while (0 != (code = ntohs(p->code))) { ++ len = ntohs(p->len); ++ ++ VERB_PRT(4, { Print(L"DHCPv6: REPLY: Code=%d Len=%d\n", ++ code, len); ++ hexdump( p->data, (len<1020)?len:144); ++ }); ++ if ( code == option ) { ++ len = (len > *length - 1) ? *length - 1 : len; ++ Memcpy(str, p->data, len); ++ str[len] = '\0'; ++ *length = len; ++ } ++ p = (DHCPv6_OPTION *)((UINT8 *)p + len + 2*sizeof(UINT16)); ++ } ++ return 0; ++} ++static INTN ++parse_bootfile_url(netfs_priv_state_t *nfs, CHAR8 *url) { ++ CHAR8 *end; ++ VERB_PRT(3, Print(L"DHCPv6: bootfile-url: '%a'\n", url)); ++ ++ /* check protocol */ ++ if (strncmpa(url, (CHAR8 *)PROTO, sizeof(PROTO)-1)) { ++ ERR_PRT((L"Warning: bootfile-url must use TFTP for now! (%a)\n", ++ PROTO)); ++ return -1; ++ } ++ /* fill in v6 address */ ++ end = url+sizeof(PROTO); ++ while (*end != ']' && *end != '\0') ++ ++end; ++ if (url[sizeof(PROTO)-1] != '[' || *end != ']') { ++ ERR_PRT((L"Warning: bootfile-url must use '[IPv6::addr]'!\n")); ++ return -1; ++ } ++ *end = '\0'; ++ Memcpy( nfs->srv_ip.v6.Addr, stra2ip6(url+sizeof(PROTO)), 16); ++ *end = ']'; ++ ++ /* remember bootfile path */ ++ strncpya( nfs->bootfile, end + 1, NETFS_BOOTFILE_MAXLEN); ++ return 0; ++} ++ + static VOID + netfs_extract_ip(netfs_priv_state_t *nfs) + { + EFI_PXE_BASE_CODE *pxe = nfs->pxe; + ++ Memcpy(&nfs->cln_ip, &pxe->Mode->StationIp, sizeof(EFI_IP_ADDRESS)); ++ ++ if (pxe->Mode->UsingIpv6) { ++ CHAR8 str[NETFS_BOOTFILE_MAXLEN]; ++ INTN len = NETFS_BOOTFILE_MAXLEN; ++ if (find_dhcp6_option(&nfs->pxe->Mode->DhcpAck, ++ OPT_BOOTFILE_URL, str, &len) != 0) ++ return; ++ parse_bootfile_url(nfs, str); ++ return; ++ } ++ + if (pxe->Mode->PxeDiscoverValid) { + nfs->using_pxe = TRUE; + Memcpy(&nfs->srv_ip, pxe->Mode->PxeReply.Dhcpv4.BootpSiAddr, sizeof(EFI_IP_ADDRESS)); +@@ -218,9 +453,9 @@ netfs_extract_ip(netfs_priv_state_t *nfs + } else { + Memcpy(&nfs->srv_ip, pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr, sizeof(EFI_IP_ADDRESS)); + Memcpy(&nfs->hw_addr, pxe->Mode->DhcpAck.Dhcpv4.BootpHwAddr, sizeof(nfs->hw_addr)); ++ strncpya(nfs->bootfile, pxe->Mode->DhcpAck.Dhcpv4.BootpBootFile, NETFS_BOOTFILE_MAXLEN); + } + +- Memcpy(&nfs->cln_ip, &pxe->Mode->StationIp, sizeof(EFI_IP_ADDRESS)); + Memcpy(&nfs->netmask, &pxe->Mode->SubnetMask, sizeof(EFI_IP_ADDRESS)); + + /* +@@ -326,11 +561,9 @@ netfs_open(netfs_interface_t *this, CHAR + + U2ascii(name, ascii_name, FILENAME_MAXLEN); + +- VERB_PRT(2, Print(L"downloading %a from %d.%d.%d.%d...\n", ascii_name, +- nfs->srv_ip.v4.Addr[0], +- nfs->srv_ip.v4.Addr[1], +- nfs->srv_ip.v4.Addr[2], +- nfs->srv_ip.v4.Addr[3])); ++ VERB_PRT(2, Print(L"downloading %a from %a...\n", ascii_name, ++ ip2stra((nfs->pxe->Mode->UsingIpv6 ? 16 : 4), ++ (UINT8 *)nfs->srv_ip.Addr))); + retry: + if (retries == 2) { + netfs_fd_free(nfs, f); +@@ -571,6 +804,9 @@ find_dhcp_option(EFI_PXE_BASE_CODE_PACKE + UINT8 tag, length; + UINT8 *opts = packet->Dhcpv4.DhcpOptions; + ++ if (use_ipv6) ++ return find_dhcp6_option(packet, option, str, len); ++ + *len = 0; + + for(;;) { +@@ -637,15 +873,12 @@ netfs_getinfo(netfs_interface_t *this, n + + VERB_PRT(3, Print(L"hostname(12): %a\n", str)); + +- /* +- * extract bootfile name from DHCP exchanges +- */ +- if (nfs->using_pxe == 0) { +- ascii2U(nfs->pxe->Mode->DhcpAck.Dhcpv4.BootpBootFile, info->bootfile, NETFS_BOOTFILE_MAXLEN); ++skip_options: ++ if (!info->using_pxe && nfs->bootfile) { ++ ascii2U(nfs->bootfile, info->bootfile, NETFS_BOOTFILE_MAXLEN); + VERB_PRT(3, Print(L"bootfile: %s\n", info->bootfile)); + } + +-skip_options: + return EFI_SUCCESS; + } + diff --git a/elilo-mac-conf.diff b/elilo-mac-conf.diff new file mode 100644 index 0000000..8017a77 --- /dev/null +++ b/elilo-mac-conf.diff @@ -0,0 +1,67 @@ +--- + glue_netfs.c | 37 ++++++++++++++++++++----------------- + 1 file changed, 20 insertions(+), 17 deletions(-) + +--- a/glue_netfs.c ++++ b/glue_netfs.c +@@ -72,7 +72,7 @@ convert_mac2hex(UINT8 *hw_addr,INTN l, C + for (i=0 ; i < l; i++) { + str[3*i] = hexa[(hw_addr[i] & 0xf0)>>4]; + str[3*i+1] = hexa[hw_addr[i] & 0x0f]; +- str[3*i+2] = ':'; ++ str[3*i+2] = '-'; + } + str[3*l-1]='\0'; + } +@@ -213,32 +213,35 @@ netfs_setdefaults(VOID *intf, config_fil + * will try machine/subnet specific files first. + * the filenames are constructed based on the IP(v4) address + */ +- convert_ip2hex(ipaddr, m, str); + #if 1 + i = 0; ++ if (non_zero(info.hw_addr, 6)) { ++ convert_mac2hex(info.hw_addr,6,str); ++ /* Blindly prepend ARP type code for Ethernet (0x01) ++ * (at least for now...) ++ */ ++ StrnCpy(config[i].fname, L"01-", 3); ++ StrnCat(config[i].fname, str, maxlen-10); ++ StrnCat(config[i++].fname, CONFIG_EXTENSION, maxlen-1); ++ } + if (non_zero(ipaddr, m)) { +- int nr = (m==16)? 10 : 6; +- int st = (m==16)? 2 : 1; +- m <<= 1; +- StrnCpy(config[i].fname, str, m); +- StrnCat(config[i++].fname, +- CONFIG_EXTENSION, maxlen - m); +- while (i <= nr) { +- int stub = m - (i+1)*st; ++ int step = (m==16)? 4 : 2; ++ int stub = m<<1; ++ convert_ip2hex(ipaddr, stub, str); ++ StrnCpy(config[i].fname, str, stub); ++ StrnCat(config[i++].fname, CONFIG_EXTENSION, maxlen-1); ++ while ( i+3 < MAX_DEFAULT_CONFIGS && stub > step) { ++ stub -= step; + StrnCpy(config[i].fname, str, stub); + StrnCat(config[i++].fname, +- CONFIG_ARCH_EXTENSION, maxlen - m); ++ CONFIG_ARCH_EXTENSION, maxlen-1); + StrnCpy(config[i].fname, str, stub); + StrnCat(config[i++].fname, +- CONFIG_EXTENSION, maxlen - m); ++ CONFIG_EXTENSION, maxlen-1); + } + } +- if (non_zero(info.hw_addr, 6)) { +- convert_mac2hex(info.hw_addr,6,str); +- StrnCpy(config[i].fname, str, maxlen-1); +- StrnCpy(config[i++].fname+17, CONFIG_EXTENSION, 6); +- } + #else ++ convert_ip2hex(ipaddr, m, str); + StrnCpy(config[0].fname, str, maxlen-1); + StrnCpy(config[0].fname+8, CONFIG_EXTENSION, 6); + diff --git a/elilo-max-conf.diff b/elilo-max-conf.diff new file mode 100644 index 0000000..07bb4b9 --- /dev/null +++ b/elilo-max-conf.diff @@ -0,0 +1,33 @@ +--- + fileops.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/fileops.c ++++ b/fileops.c +@@ -396,12 +396,13 @@ fops_setdefaults(struct config_file *def + boot_dev->fops->setdefaults(boot_dev->fops->intf, defconf, kname, maxlen, devpath); + } + i=0; while (i= MAX_DEFAULT_CONFIGS) { + #ifdef ELILO_DEBUG +- if ((i+3) >= MAX_DEFAULT_CONFIGS) { +- Print(L"ERROR: i = %d, MAX_DEFAULT_CONFIGS is not large enough\n", i); +- return EFI_INVALID_PARAMETER; +- } ++ Print(L"Warning: MAX_DEFAULT_CONFIGS(%d) is not large enough\n", ++ MAX_DEFAULT_CONFIGS); + #endif ++ i = MAX_DEFAULT_CONFIGS-2; ++ } + StrnCpy(defconf[i].fname, FILEOPS_ARCH_DEFAULT_CONFIG, maxlen-1); + StrnCpy(defconf[i+1].fname, FILEOPS_DEFAULT_CONFIG, maxlen-1); + +@@ -409,7 +410,7 @@ fops_setdefaults(struct config_file *def + VERB_PRT(3,Print(L"Default config filename list:\n")); + for (i=0; i + +- Add elilo-c99.patch so that the package conforms to the C99 + standard and builds on i586 with GCC 14. + +------------------------------------------------------------------- +Thu Feb 22 11:34:21 UTC 2024 - Dominique Leuenberger + +- Use %autosetup macro. Allows to eliminate the usage of deprecated + %patchN + +------------------------------------------------------------------- +Tue Aug 16 14:30:43 UTC 2022 - rw@suse.com + +- elilo.spec, elilo.pl + * Move to '/usr/sbin'. (bsc#1191059) + +------------------------------------------------------------------- +Wed Feb 3 12:32:12 UTC 2021 - Martin Liška + +- Add elilo-binutils-2.36-fix.patch in order to fix build + with binutils 2.36. + +------------------------------------------------------------------- +Fri Nov 23 14:29:41 UTC 2018 - rw@suse.com + +- elilo.efi + * Try to properly allocate high_base_mem. (bsc#1000769) + (elilo-high_base_mem.diff) + +------------------------------------------------------------------- +Thu Nov 22 16:17:20 UTC 2018 - rw@suse.com + +- elilo.spec + * Work around glitches introduced by gnu-efi. + * Add '-mno-red-zone' to work around Microsoft/SystemV AMD64 ABI + discrepancies. (bsc#953502) +- elilo.pl + * Support 'ucode=' for XEN. (bsc#1102567) + * SecureBoot: Support detached configuration template. + * Add support for 'UUID='/'LABEL=' to specify EFI system partition + and fix bug introduced by NVMe device handling. (bsc#917195) + * Handle NVMe device names. (fate#317591) + * Don't abort, when "skip" is announced. (bsc#917130) +- elilo.efi + * Remove special handling for '?' in textmenu-mode. (bsc#928546) + (elilo-textmenu-disable-print-devices.diff) + +------------------------------------------------------------------- +Sat Mar 3 11:12:54 UTC 2018 - bwiedemann@suse.com + +- Do not include rebuild counter in rpm to make build-compare happy + +------------------------------------------------------------------- +Thu Jul 31 12:41:32 UTC 2014 - dimstar@opensuse.org + +- Rename rpmlintrc to %{name}-rpmlintrc. + Follow the packaging guidelines. + +------------------------------------------------------------------- +Fri Oct 25 13:37:55 UTC 2013 - rw@suse.de + +- elilo.efi + * Update to elilo-3.16 to fix OBS download check. + Essentially "white-space" changes, plus bumping version number, + minus Debian idiosyncrasies. +- elilo.spec + * Remove date string from 'eliloalt'. + * Avoid duplication of 'elilo.txt'. +- elilo.pl + * Support for 'UUID=' and 'LABEL=' to specify root file-system. + +------------------------------------------------------------------- +Thu Oct 24 17:18:48 UTC 2013 - rw@suse.de + +- elilo.spec + * Add perl modules to 'PreReq'. (bnc#842183) +- Update openSUSE to elilo-3.14 from SLE11. + +------------------------------------------------------------------- +Fri Aug 16 12:01:42 UTC 2013 - rw@suse.de + +- elilo.pl + * SecureBoot: cope with separate '/boot' file-system. (bnc#825932) + * SecureBoot: improve detection of file-system UUIDs. (bnc#828835) + * Correctly handle installation to 'BOOT'. + +------------------------------------------------------------------- +Wed May 29 15:10:40 UTC 2013 - rw@suse.com + +- elilo.pl + * Always delete old EBM entries to fix ordering. (bnc#819900) + * Prevent XEN 'default' in 'elilo.conf'. (bnc#819900c5) + * Add man-page section about '--refresh-EBM' failure. (bnc#821109) + +------------------------------------------------------------------- +Wed May 8 13:30:02 UTC 2013 - rw@suse.com + +- elilo.pl + * SecureBoot: create only one Boot Manager entry. (bnc#818961) + +------------------------------------------------------------------- +Fri Apr 19 13:28:08 UTC 2013 - rw@suse.com + +- elilo.efi + * Clear console on startup. (bnc#812799) + * Avoid crash caused by EFI memory map changes. (bnc#800035) +- elilo.pl + * Work around chainloading issue with XEN. (bnc#812109) + +------------------------------------------------------------------- +Wed Mar 27 21:40:29 UTC 2013 - rw@suse.com + +- elilo.pl + * Fix handling of missing 'default' again. + +------------------------------------------------------------------- +Wed Mar 27 20:42:50 UTC 2013 - rw@suse.com + +- elilo.pl + * Implement chainloading of XEN for SecureBoot. (bnc#809702) + * Maintain 'default' in SecureBoot config. (bnc#811608c28) + * Handle failure of 'efibootmgr'. (bnc#809702c10) + * Improve verbose messages to be less alarming. + +------------------------------------------------------------------- +Fri Mar 8 14:06:28 UTC 2013 - rw@suse.com + +- elilo.efi + * Force default configs at the end of the network search list. + (bnc#789137) +- elilo.pl + * Disable use of 'shim'-loader options. (bnc#798043) + * Fix solitary 'secure-boot' for real. + +------------------------------------------------------------------- +Tue Feb 12 17:00:32 UTC 2013 - rw@suse.com + +- elilo.pl + * Revert work-around for 'shim'-loader option parsing. (bnc#798043) + * Treat 'secure-boot' identical to 'secure-boot = on'. + * Fix 'SecureBoot' sysfs variable reading. + +------------------------------------------------------------------- +Fri Feb 8 18:42:49 UTC 2013 - rw@suse.com + +- elilo.efi + * Now really introduce 'block-size'. (bnc#681242) + * Clarify warning message on GOP failure. +- elilo.pl + * Synchronize check for "Secure Boot" with YaST. + +------------------------------------------------------------------- +Fri Jan 18 15:00:44 UTC 2013 - rw@suse.com + +- elilo.efi + * Make automatic appending of 'add_efi_memmap' to kernel command + line default, and introduce config-file option (add-efi-memmap) + to control this (auto|false). (fate#314210, bnc#772245) + * Bring network search list more in line with 'PXELINUX'. (bnc#789137) + * Introduce 'block-size' as global option in 'elilo.conf'. (bnc#681242) +- elilo.pl + * Work around limitations in 'shim'-loader option parsing. (bnc#798043) + * Don't use temporary file to establish load options. + +------------------------------------------------------------------- +Wed Dec 19 21:20:25 UTC 2012 - rw@suse.com + +- elilo.pl + * Add support UEFI Secure Boot (via 'grub.efi'). (fate#314485) + * Don't try to write 'xen.cfg', if no valid XEN section is found + and treat "VMM" EFI-binaries as "mandatory". (bnc#792100) + * Support more than 10 EFI Boot Manager (EBM) entries. + * Stop using '--write-signature' for 'efibootmgr' (as non-GPT + disk-labels aren't supported anyway). + * Sort creation of EBM entries according to default boot section. + * Fix initial handling of obsolete files. + +------------------------------------------------------------------- +Mon Jan 16 15:21:24 UTC 2012 - rw@suse.de + +- elilo.pl + * Cope with misguided '/dev/mapper/' entries in 'fstab'. (bnc#717828) + +------------------------------------------------------------------- +Fri Nov 25 17:12:38 UTC 2011 - rw@suse.de + +- elilo.pl + * Allow empty 'vmmopts' for 'xen.efi'. (bnc#731288) + * Implement refreshing of EFI Boot Manager entries. (bnc#717828) + +------------------------------------------------------------------- +Mon Sep 19 14:53:06 UTC 2011 - rw@suse.de + +- elilo.pl + * Fix handling of 'xen.cfg'. (bnc#706110) + * Record installed files and remove only those in the future. + +------------------------------------------------------------------- +Sun Sep 18 17:17:12 UTC 2011 - jengelh@medozas.de + +- elilo.spec + * Remove redundant/obsolete tags/sections from specfile + (cf. packaging guidelines) + +------------------------------------------------------------------- +Mon Aug 1 12:43:45 UTC 2011 - rw@suse.de + +- elilo.efi + * Allow booting in an IPv6 network environment. (fate#311995) +- elilo.pl + * Add support for 'xen.efi'. (fate#311376) + +------------------------------------------------------------------- +Fri Jun 17 12:54:53 UTC 2011 - rw@suse.de + +- elilo.efi + * Update to elilo-3.14. (fate#311532) +- elilo.spec + * Follow openSUSE migration from libexecdir to libdir. +- elilo.pl + * Don't initialize '$[' to 0. + * Adapt to replacement of libexecdir with libdir. + +------------------------------------------------------------------- +Fri Dec 17 10:51:23 UTC 2010 - coolo@novell.com + +- Update openSUSE to elilo-3.12 from SLE11 to fix EFI boot (bnc#659368) + (see ChangeLog for a detailed log) + +------------------------------------------------------------------- +Mon Apr 12 16:59:30 CEST 2010 - rw@suse.de + +- elilo.efi + * Handle EFI memory maps larger than E820_MAX. (bnc#594516) + +------------------------------------------------------------------- +Tue Mar 30 11:42:43 CEST 2010 - rw@suse.de + +- elilo.efi + * Update boot protocol for 2.6.30. (bnc#560443) + * Allocate initrd below kernel specified limit. (bnc#577570) + * Load kernel relocated. (bnc#447843, 516215, 568848, 587858) +- elilo.pl + * Add handling of VMM for XEN. (bnc#578926) + +------------------------------------------------------------------- +Tue Jan 26 12:14:57 CET 2010 - rw@suse.de + +- elilo.efi + * PRELIMINARY debugging patch for x86_64. (bnc#560443) + +------------------------------------------------------------------- +Fri Nov 20 13:10:51 CET 2009 - rw@suse.de + +- elilo.efi + * Update to elilo-3.12. + +------------------------------------------------------------------- +Tue Sep 22 18:30:29 CEST 2009 - rw@suse.de + +- elilo.spec + * Submit to SLE11. (bnc#494042) + +------------------------------------------------------------------- +Mon Jul 20 08:16:44 CEST 2009 - coolo@novell.com + +- elilo.spec + * replace libexecdir with libdir + +------------------------------------------------------------------- +Thu May 28 13:05:25 CEST 2009 - ro@suse.de + +- elilo.spec + * Use binutils219 on SLE10 SP3. + +------------------------------------------------------------------- +Fri May 15 13:47:44 CEST 2009 - rw@suse.de + +- elilo.efi + * Update to elilo-3.10. (fate#306032) + +------------------------------------------------------------------- +Thu Apr 30 15:24:26 CEST 2009 - ro@suse.de + +- elilo.spec + * Submit to SLE10 SP3. (fate#306032) + +------------------------------------------------------------------- +Mon Feb 9 15:36:39 CET 2009 - rw@suse.de + +- elilo.efi + * Allow booting x86_64 from network. (bnc#473914) + * Introduce new per-image option 'text-mode' for x86_64, which can + be used to sidestep "dubious" GOP implementations. (bnc#466570) + * Minor cleanup. + +------------------------------------------------------------------- +Tue Dec 9 16:34:53 CET 2008 - rw@suse.de + +- elilo.efi + * Second attempt to work around firmware problem. (bnc#437486) +- elilo.conf + * Provide stub man page. (bnc#435648) + +------------------------------------------------------------------- +Fri Nov 21 15:56:50 CET 2008 - rw@suse.de + +- elilo.efi + * Significant code cleanup from CVS. (bnc#443565) + * First attempt to work around firmware problem. (bnc#437486) +- elilo.pl + * Improve removal of obsolete files. (bnc#398416) +- eliloalt + * Support sysfs interface. (bnc#440489) + * Provide man page. (bnc#440197) + +------------------------------------------------------------------- +Mon Oct 27 18:16:02 CET 2008 - rw@suse.de + +- elilo.pl + * Mask 'relocatable' (unless supported). (bnc#438276) + * Remove old files from target directory. (bnc#398416) + +------------------------------------------------------------------- +Fri Oct 17 08:52:44 CEST 2008 - olh@suse.de + +- elilo.spec + * Add ExclusiveArch ia64 x86 x86_64 + +------------------------------------------------------------------- +Wed Jul 31 10:22:56 CEST 2008 - rw@suse.de + +- elilo.efi + * Update to final elilo-3.8 for uEFI support. (fate#301882) +- elilo.pl + * Preserve time-stamps but not permissions. (bnc#394331) + * Unconditionally strip deprecated 'read-only' from 'elilo.conf'. + * Support '$LIBEXECDIR' to please uEFI/x86_64 and + relocate efi-binaries from 'elilo' to 'efi'. (fate#301882) + +------------------------------------------------------------------- +Thu Feb 28 17:48:31 CET 2008 - ro@suse.de + +- elilo.spec + * No strip for elilo.efi during install (unknown binary format). + +------------------------------------------------------------------- +Sun May 27 00:56:14 CEST 2007 - schwab@suse.de + +- elilo.spec + * Revert last change. + +------------------------------------------------------------------- +Sat May 26 23:55:13 CEST 2007 - ro@suse.de + +- elilo.spec + * Added gnu-efi-devel to buildreq. + +------------------------------------------------------------------- +Wed May 9 14:29:40 CEST 2007 - rw@suse.de + +- elilo.efi + * Reduce non-"command line" strings back to 512. (#256676) + * Fix another buffer overrun. (#256676) + +------------------------------------------------------------------- +Fri Feb 23 10:44:35 CET 2007 - schwab@suse.de + +- elilo.spec + * Disable stack protector. + +------------------------------------------------------------------- +Tue Feb 6 18:33:55 CET 2007 - bwalle@suse.de + +- elilo.efi + * Increase command line size to 2048. (#242702) + +------------------------------------------------------------------- +Fri Nov 10 10:37:13 CET 2006 - schwab@suse.de + +- elilo.efi + * Fix spelling. + +------------------------------------------------------------------- +Thu Feb 2 17:33:57 CET 2006 - rw@suse.de + +- elilo.efi + * Update to final 3.6 + (Fixed vmcode_name initialization in textmenu chooser) + +------------------------------------------------------------------- +Wed Jan 25 21:44:13 CET 2006 - mls@suse.de + +- elilo.spec + * Converted neededforbuild to BuildRequires. + +------------------------------------------------------------------- +Fri Jan 20 12:51:08 CET 2006 - schwab@suse.de + +- elilo.spec + * Don't strip binaries. + +------------------------------------------------------------------- +Mon Jan 9 18:57:56 CET 2006 - rw@suse.de + +- elilo.efi + * Fix vmcode_name initialization in textmenu chooser. (#140519) + +------------------------------------------------------------------- +Fri Dec 9 16:37:17 CET 2005 - rw@suse.de + +- elilo.pl + * Fix formatting of man-page. + +------------------------------------------------------------------- +Wed Dec 7 16:31:04 CET 2005 - rw@suse.de + +- elilo.efi + * Update to 3.5-pre2. +- elilo.pl + * Make "best effort" instead of giving up early. + +------------------------------------------------------------------- +Sat Aug 13 16:03:14 CEST 2005 - schwab@suse.de + +- elilo.pl + * Check that the default label is defined. + +------------------------------------------------------------------- +Fri Aug 5 18:14:04 CEST 2005 - schwab@suse.de + +- elilo.pl + * Barf on duplicate labels. + +------------------------------------------------------------------- +Wed Apr 13 17:41:15 CEST 2005 - schwab@suse.de + +- elilo.efi + * Fix for new assembler. + +------------------------------------------------------------------- +Sat Feb 19 00:36:17 CET 2005 - schwab@suse.de + +- elilo.efi + * Clear extra memory in initrd block so that initramfs works. + +------------------------------------------------------------------- +Wed Oct 6 17:10:32 CEST 2004 - rw@suse.de + +- elilo.efi + * Fix simple-chooser (#45493) + +------------------------------------------------------------------- +Thu May 27 17:39:05 CEST 2004 - rw@suse.de + +- elilo.pl + * Make all image-objects (kernel/initrd) *optional* by default (#41315) + +------------------------------------------------------------------ +Mon Feb 23 15:32:53 CET 2004 - rw@suse.de + +- elilo.efi + * Use '$RPM_OPT_FLAGS' with '-fno-strict-aliasing' appended. +- elilo.pl + * Take care of FPSWA. + * Try to avoid copying the same files more than once. + +------------------------------------------------------------------- +Mon Nov 24 13:59:08 CET 2003 - rw@suse.de + +- Provide '/sbin/elilo' to simplify separation of '/boot' and the + EFI FAT-partition (bug #21644) +- Move 'elilo.efi' to '/usr/lib/elilo' + +------------------------------------------------------------------- +Mon Sep 1 17:45:41 CEST 2003 - schwab@suse.de + +- Update to final 3.4 to remove extraneous debug output. + +------------------------------------------------------------------- +Tue Aug 26 19:33:50 CEST 2003 - rw@suse.de + +- Add patch from Greg Edwards (SGI) (#29340) + +------------------------------------------------------------------- +Fri Aug 22 12:02:33 CEST 2003 - schwab@suse.de + +- Update to elilo 3.4. + * Improved netbooting. + +------------------------------------------------------------------- +Tue Jun 10 13:24:05 CEST 2003 - schwab@suse.de + +- Add fix for netbooting. + +------------------------------------------------------------------- +Tue Apr 8 17:34:48 CEST 2003 - schwab@suse.de + +- Add two fixes from author. + +------------------------------------------------------------------- +Thu Oct 17 11:17:23 CEST 2002 - schwab@suse.de + +- Update to elilo 3.3a. + * More memory management bugs fixed. + +------------------------------------------------------------------- +Fri Sep 13 12:01:47 CEST 2002 - schwab@suse.de + +- Fix %post. +- Fix eliloalt. + +------------------------------------------------------------------- +Wed Sep 11 20:24:52 CEST 2002 - schwab@suse.de + +- Fix buffer overrun. + +------------------------------------------------------------------- +Mon Sep 2 17:08:05 CEST 2002 - schwab@suse.de + +- Move elilo.conf to /boot/efi/SuSE. + +------------------------------------------------------------------- +Tue Aug 27 17:11:26 CEST 2002 - schwab@suse.de + +- Update to elilo 3.3. + +------------------------------------------------------------------- +Thu May 16 17:30:11 CEST 2002 - schwab@suse.de + +- Move boot loader to /boot/efi/SuSE. + +------------------------------------------------------------------- +Tue Mar 5 11:22:09 CET 2002 - schwab@suse.de + +- Update to elilo 3.2. +- Make elilo.conf and startup.nsh %ghost files. + +------------------------------------------------------------------- +Sat Aug 18 20:41:52 CEST 2001 - schwab@suse.de + +- Update to elilo 3.1. + +------------------------------------------------------------------- +Wed Jul 25 19:43:04 CEST 2001 - schwab@suse.de + +- Add two patches from author. + +------------------------------------------------------------------- +Wed Jul 18 14:33:22 CEST 2001 - schwab@suse.de + +- Split from gnu-efi packages. +- New version 3.0. + diff --git a/elilo.conf.man5 b/elilo.conf.man5 new file mode 100644 index 0000000..5819dd2 --- /dev/null +++ b/elilo.conf.man5 @@ -0,0 +1,11 @@ +.TH ELILO.CONF 5 "2008-12-06" +.SH NAME +elilo.conf \- elilo configuration file +.SH SYNOPSIS +/etc/elilo.conf +.SH FILES +.IR /etc/elilo.conf , +.I /boot/efi/efi/SuSE/elilo.conf +.SH SEE ALSO +.IR /usr/share/doc/packages/elilo/elilo.txt +(Section III) diff --git a/elilo.pl b/elilo.pl new file mode 100644 index 0000000..2423e29 --- /dev/null +++ b/elilo.pl @@ -0,0 +1,1393 @@ +#!/usr/bin/perl -w +# $Id: elilo.pl,v 0.94 2018/11/22 15:48:50 rw Exp $ +use strict; + +my $C = $0; $C =~ s{^.*/}{}; + +my $dbg = (exists( $ENV{"ELILO_DEBUG"})) ? $ENV{"ELILO_DEBUG"} : ""; +my $Edition = q(@EDITION@); +my $Arch = q(@ARCH@); +my $LibD = q(@LIBDIR@); +my $MPold = "$dbg/boot"; +my $MPnew = "$dbg/boot/efi"; +my $Dlibold = "$dbg$LibD/elilo"; +my $Dlib = "$dbg$LibD/efi"; +my $Fconf = "elilo.conf"; +my $Flist = "elilo.list"; +my %Flist = (); +my $Sconf = "$dbg/etc/" . $Fconf; +my $Xconf = "xen.cfg"; +my $Gconf = "grub.cfg"; +my $GconfT = "$dbg/etc/default/elilo2grub.in"; + +my @eBinaries = ("elilo.efi", "xen.efi", "shim.efi"); +my ($elilo, $xen, $shim) = @eBinaries; +my @sBinaries = ($shim, "grub.efi", "MokManager.efi"); # hardcoded for now! + +my $Reserved = qr{(efi-mountpoint|vendor-directory|elilo-origin|precious| + (?:y|e)bm-label|static-description|secure-boot| + SB-(?:fallback|direct2xen|))}ox; +my %Sconf = (); +my %Econf = (); +my @Econf = (); +my %Xconf = (); +my %Xsonf = (); +my @Xconf = (); +my @Gconf = (); +my %Labels = (); +my @Labels = (); +my @Files = (); + +my $keep = -1; +my $test = 0; +my $verbose = 0; +my $warn = 0; +my $optional = 1; +my $MP = ""; # Mount-Point for EFI/FAT partition +my $VD = "SuSE"; # vendor-specific directory in $MP/efi +my $D = ""; # will be $MP.$VD +my $EFIarch = ""; + +my $Disclaimer = <= $_[0] ); +} +sub Warn ($) { + print STDERR "$C: Warning: $_[0]"; + $warn ++; +} +sub Panic ($$) { + print STDERR "$C: $_[1]"; + exit( $_[0]) if ( $_[0] ); + $warn ++; + print STDERR "...trying to proceed anyway!\n"; +} +sub System($@) { + my( $fatal, @C) = @_; + my $cmd = $C[0]; + + foreach my $c ( @C[1..$#C] ) { + if ( $c =~ /[\s\\]/ ) { + $cmd .= " '$c'"; + } else { + $cmd .= " $c"; + } + } + Info( 1, "> $cmd\n"); + return 0 if ( $test ); + + system @C; + if ($? == -1) { + Panic( $fatal, "$C[0]: failed to execute: $!\n"); + } elsif ($? & 127) { + Panic( $fatal, sprintf( "$C[0]: died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without')); + } elsif ( $? >> 8 != 0 ) { + Panic( $fatal, "$C[0]: failed\n"); + } +} +sub Rename($$$) { + my( $loglvl, $oldname, $newname) = @_; + Info( $loglvl, "> mv $oldname $newname\n"); + if ( -e $newname ) { + Info( $loglvl+1, ">> unlink( $newname)\n"); + unlink( "$newname") unless ($test); + } + Info( $loglvl+1, ">> rename( $oldname, $newname)\n"); + rename( $oldname, $newname) unless ($test); + # fixme: add failure-detection and handling? +} +sub Write($$$$@) { + my( $loglvl, $msg, $mode, $file, @lines) = @_; + my $tmp = ($mode ne ">>"); + my $out = ($tmp) ? "$file.tmp" : "$file"; + my $mstr = ($tmp) ? "create" : "append"; + my $fh; + + Info( $loglvl, $msg); + if ( $test && $verbose >= $loglvl + 1 ) { + Info( $loglvl, " STDOUT\n"); + open( $fh, ">&STDOUT"); + } elsif ( $test ) { + Info( $loglvl, " nowhere\n"); + open( $fh, ">> /dev/null"); + } elsif ( ! open( $fh, "$mode $out") ) { + Warn( "$out: failed to $mstr: $!\n"); + return 1; + } elsif ( $verbose > $loglvl ) { + Info( $loglvl, " '$out'\n"); + } else { + Info( $loglvl, " '$file'\n"); + } + + print( $fh @lines) || Panic( 1, "$out: failed to write: $!\n"); + close( $fh); + + if ( ! $test && $mode ne ">>" ) { + Rename( $loglvl+1, $out, $file); + } +} +sub Merge($$) { + my( $target, $source) = @_; + my $in; + my @l = (); + + Info( 2, "### check file list of previous installs:"); + if ( ! open( $in, "< $source") ) { + Warn( "could not open < '$source': $!\n"); + return 1; + } + while ( <$in> ) { + chomp; + next if (m{/} || exists( $Flist{$_})); + push @l, "$_\n"; + } + close( $in); + if ( $#l < 0) { + Info( 2, " none!\n"); + } else { + my $n = $#l + 1; + Info( 2, " $n missing\n"); + Write( 2, "### appending to", ">>", $target, @l); + } +} +sub Install($$$$) { + my( $f, $o, $s, $d) = @_; + my @C = ( "install", $o, $s, $d); + + if ( $o eq "-p" ) { + @C = ( "cp", "--preserve=timestamps", $s, $d); + } + System( $f, @C); +} + +my $labelc = 0; +sub mkLabel($$) { + my( $label, $namespace) = @_; + + if (exists( $Labels{$namespace}{$label})) { + my $t = 1; + my $l = $label; + while ( exists $Labels{$namespace}{$l} ) { + $l = sprintf "%s.%d", $label, $t++; + } + Warn( "duplicate label '$label', replaced with '$l' in $namespace\n"); + $label = $l; + } + $Labels{$namespace}{$label} = ++$labelc; + push @Labels, "$namespace $label"; + Info(4,"L($namespace)= ".join(", ",sort(keys(%{$Labels{$namespace}})))."\n"); + return $label; +} +my $sections = 0; +sub section2Econf($$%) { + my( $in, $lnr, %current) = @_; + + if ( $current{xencfg} && ! $current{precious} ) { + Info( 3, "=== Econf: skipping $current{label} for $Fconf.\n"); + return( 0 ); + } + if ( exists( $current{label}) ) { + my $l = mkLabel( $current{label}, "Econf"); + if ( $l ne $current{label} ) { + $current{Econf}[$current{label_loc}] = $current{label_pre} . $l ."\n"; + } + Info( 2, sprintf "=== %2d. Econf: $l\n", ++$sections); + $Econf{$l}{options} = (exists( $current{append}) ? $current{append} : + (exists( $Sconf{append}) ? $Sconf{append} : "")); + $Econf{$l}{kernel} = $current{image}; + $Econf{$l}{ramdisk} = (exists( $current{initrd}) ? $current{initrd} : ""); + $Econf{$l}{root} = (exists( $current{root}) ? $current{root} : + (exists( $Sconf{root}) ? $Sconf{root} : "")); + $Econf{$l}{description} = (exists( $current{description}) ? $current{description} : $l); + if ( exists($Sconf{default}) && $current{label} eq $Sconf{default} ) { + $Sconf{grubdefault} = $Econf{$l}{description}; + } + } + foreach my $l ( @{$current{Econf}} ) { + push @Econf, $l; + } + return( 0 ); +} +my $Xsections = 0; +sub section2Xconf($$%) { + my( $in, $lnr, %current) = @_; + my( $label, $image, $initrd, $append, $root, $vmm, $vmmopts, $ucode, $desc); + + if ( ! $current{xencfg} ) { + Info( 3, "=== Xconf: skipping ". + (exists( $current{label}) ? $current{label} : "section") + ." for $Xconf.\n"); + return( 0 ); + } + if ( ! exists( $current{image}) ) { + Warn( "$in: $lnr: no image: incomplete section skipped\n"); + return( 1 ); + } + if ( ! exists( $current{image}) || ! exists( $current{label}) ) { + Warn( "$in: $lnr: incomplete section skipped\n"); + return( 1 ); + } + + $label = mkLabel( $current{label}, "Xconf"); + $image = $current{image}; + $initrd = (exists( $current{initrd}) ? $current{initrd} : + (exists( $Sconf{initrd}) ? $Sconf{initrd} : "")); + $append = (exists( $current{append}) ? $current{append} : + (exists( $Sconf{append}) ? $Sconf{append} : "")); + $vmmopts = (exists( $current{vmmopts}) ? $current{vmmopts} : + (exists( $Sconf{vmmopts}) ? $Sconf{vmmopts} : "")); + $root = (exists( $current{root}) ? $current{root} : + (exists( $Sconf{root}) ? $Sconf{root} : "")); + $root = ($root ? " root=$root " : " "); + $vmm = (exists( $current{VMM}) ? $current{VMM} : + (exists( $Sconf{vmm}) ? $Sconf{vmm} : "")); + $ucode = (exists( $current{ucode}) ? $current{ucode} : + (exists( $Sconf{ucode}) ? $Sconf{ucode} : "")); + if ( exists( $current{description}) ) { + $desc = $current{description}; + } else { + my $vers = $image; + $vers =~ s{^[^-]+-}{}; + $desc = "$label ($vers)"; + } + + if ( ! $vmm ) { + Warn( "$in: $lnr: no vmm?!\n"); + return( 1 ); + } + if ( exists( $current{vmm}) ) { + Info( 1, "$in: $lnr: legacy vmm ($current{vmm}) skipped for $Xconf.\n"); + return( 0 ); + } + Info( 2, sprintf "=== %2d. Xconf: $label\n", ++$sections); + $Xconf{$label}{ucode} = $ucode if ($ucode); + $Xconf{$label}{vmm} = $vmm; + $Xconf{$label}{options} = $vmmopts; + $Xconf{$label}{kernel} = $image; + $Xconf{$label}{append} = $root . $append; + $Xconf{$label}{ramdisk} = $initrd if ( $initrd); + $Xconf{$label}{description} = $desc; + if ( exists($Sconf{default}) && $current{label} eq $Sconf{default} ) { + $Xconf{$label}{cfg} = $Xconf; + $Sconf{grubdefault} = $desc; + } elsif ( $Sconf{xencfg} != 2 && $Xsections == 0 ) { + $Xconf{$label}{cfg} = $Xconf; + ++$Xsections; + } else { + $Xconf{$label}{cfg} = "xen". ++$Xsections .".cfg"; + } + + return( 0 ); +} + +sub Parse($$) { + my( $in, $verbosity) = @_; + my $ov = $verbose; + $verbose = ($verbosity < 0 ) ? $ov : $verbosity; + + $Sconf{xencfg} = 0; + open( IN, "< $in") || Panic(1, "$in: failed to open: $!\n"); + Info( 1, "## parsing '$in'...\n"); + Info( 3, "### pick up global settings...\n"); + while ( ) { + chomp; + s{^##YaST - boot_efilabel =}{ybm-label=}; + if ( m/^$Reserved\s*(?:\=\s*(?|"([^"]+)"|([^"].*?)))?\s*$/xo ) { + $Sconf{$1} = (defined($2)) ? $2 : "true"; + } elsif ( m/^(append|root|timeout)\s*=\s*(?|"([^"]+)"|([^"].*?))\s*$/xo ) { + $Sconf{$1} = $2; + } elsif ( m/^(default|prompt|relocatable)\s*(?:\=\s*(.+))?\s*$/xo ) { + $Sconf{$1} = (defined($2)) ? $2 : "true"; + } elsif ( m/^(vmm)\s*\=\s*(?|"([^"]+)"|([^"].*?))\s*$/xo ) { + my ($k, $v) = ($1, $2); + next unless (defined( $v)); + $Sconf{$k} = $v; + if ( $v =~ m/^(\S+.efi)(?:\s+(.*))?$/ ) { + $Sconf{vmm} = $1; + $Sconf{vmmopts} = (defined( $2) ? $2 : ""); + $Sconf{xencfg} = 1; + } else { + Info( 1, "$C: $in: $.: ignoring non-efi based VMM. ($Sconf{vmm})\n"); + } + } elsif ( m/^image\s*=/ ) { + last; + } else { + next; + } + Info( 3, ">>> $1 = '$Sconf{$1}'\n"); + } + my( $c, %f, $opt); + my $default_label = ""; + my $default_loc; + my $image = ""; + my %current = (); + my %fp = (); + Info( 3, "### start over...\n"); + seek( IN, 0, 0); + $. = 0; + while ( ) { + $opt = $optional; + if ( m/^\s*$Reserved\s*(?:\=\s*(.+))?\s*$/xo ) { + $current{$1} = (defined($2)) ? $2 : "true"; + next; + } + if ( m{^\s*(?:image|initrd|vmm|ucode)\s*=\s*} ) { + my $orig = $_; + chomp; + s{(vmm\s*=\s*)"([^"]+)"\s*(#.*)?$}{$1$2}; + s{^(\s*(image|initrd|vmm|ucode)\s*=\s*)(/\S+/)?([^/\s]+)\s*(.*?)\s*$}{$1$4}; + my( $k, $p, $f, $o) = ($2, $3, $4, $5); + #Info( 8, ">>> $.: k=$k p=$p f=$f\n"); + $_ .= "\n"; + if ( $k eq "image" ) { + # new "image=" => finish up the previous one... + $c += section2Econf( $in, $., %current); + $c += section2Xconf( $in, $., %current) if (exists( $current{image})); + %current = (); + } + if ( $k eq "vmm" && $f =~ m/\.efi$/ ) { + $k = "VMM"; + $p = $Dlib . "/" unless (defined( $p)); + $p =~ s{^$dbg}{}o if ($dbg); + $current{vmmopts} = $o; + $current{xencfg} = $Sconf{xencfg} = 1; + $opt = 0; # 'xen.efi' is *never* optional! + } elsif ( defined( $o) && $o ) { + Warn( "$in: $.: ignoring trailing garbage...\n"); + } + if ( $k eq "ucode" ) { + $Sconf{$k} = $f if (!exists( $current{image}) && !exists( $Sconf{$k})); + $_ = "# $_"; # hide 'ucode' from elilo.conf -- it's only for XEN! + $opt = 0; # ucode is *never* optional! + } + if ( ! defined( $p) ) { + $p = "/boot/"; + } + if ( ! defined( $f) ) { + Warn( "$in: $.: invalid file-specification\n" . + ">> $orig"); + $c++; + } elsif ( exists( $f{$f}) ) { + if ( "$p$f" eq $fp{$f} ) { + Info( 4, ">>> $.: copy only once (previous: line $f{$f})\n" . + ">> $orig"); + } else { + Warn( "$in: $.: ambigous target '$f' (previous: $f{$f}: $fp{$f})\n" . + ">> $orig" . "=> first wins\n"); + } + $current{$k} = $f; + $current{"path2$k"} = $fp{$f}; + } else { + my $fp = "$dbg$p$f"; + if ( -r $fp ) { + $current{$k} = $f; + $current{"path2$k"} = $fp; + push @Files, $fp; + $fp{$f} = $p . $f; + $f{$f} = $.; + } elsif ( $opt ) { + Info( 0, "$C: Info: $in: $.: missing optional '$p$f' skipped\n"); + } else { + Warn( "$in: $.: missing '$p$f'\n"); + } + } + next if ( $k eq "VMM" ); # omit efi-based "vmm" lines from elilo.conf! + } elsif ( exists( $current{image}) && + m{^(\s*description\s*=\s*)(?|"([^"]+)"|([^"].*?))\s*$}xo ) { + my( $p, $d) = ($1, $2); + my $image = $current{path2image}; + my $t = ""; + my $od = $d; + $d .= " (%G)" if ( $d =~ m{^(Linux|Failsafe)$} ); + if ( $d =~ m{\%L} ) { + if ( -l $image ) { + ($t = readlink( $image)) =~ s{^vmlinuz-}{}; + } else { + #($t = $image) =~ s{^.*vmlinux-}{}; + $t = "no symlink"; + } + Info( 3, ">>> $.: \%L => '$t'\n"); + $d =~ s{\%L}{$t}; + } elsif ( $d =~ m{\%G} ) { + my $cmd = "/sbin/get_kernel_version"; + if ( -x $cmd ) { + chomp( $t = qx{$cmd $image}); + } else { + $t = ""; + } + $d =~ s{\%G}{$t}; + Info( 3, ">>> $.: \%G => '$t'\n"); + } + if ( $Sconf{'static-description'} ) { + $d = $od; + } else { + $_ = $p . q{"} . $d . q{"} . "\n"; + } + $current{description} = $d; + } elsif (m{^\s*(append|root)\s*=\s*(?|"([^"]+)"|([^"].*?))\s*$}xo ) { + my( $k, $v) = ($1, $2); + Info( 0, "$C: $in: $.: duplicate option (last wins)\n") + if (exists( $current{$k})); + $current{$k} = $v; + } elsif (m{^(\s*label\s*=\s*)(\S+)}) { + my ($pre, $label) = ($1, $2); + $current{label_pre} = $pre; + $current{label} = $label; + $current{label_loc} = $#{$current{Econf}} + 1; + } elsif (m{^\s*default\s*=\s*(\S+)}) { + $default_label = $1; + $default_loc = $#{$current{Econf}} + 1; + } elsif (m{^\s*read-only\s*$}) { + $_ = "#read-only # Deprecated!" . + " (Add comment in '$Sconf' to overrule.)" . + "\n"; + Info( 2, " $in: $.: deprecated 'read-only' ignored.\n"); + } elsif (m{^\s*relocatable\s*$} && $Arch =~ m{86}) { + $_ = "#relocatable # Unsupported on this architecture!\n" . + "# (May be forced by adding a comment in '$Sconf'.)\n"; + Info( 2, " $in: $.: unsupported 'relocatable' ignored.\n"); + } + push @{$current{Econf}}, $_; + } + if ( exists( $current{image})) { + $c += section2Econf( $in, $., %current); + $c += section2Xconf( $in, $., %current); + } + if ($default_label ne "" && exists( $Labels{Xconf}{$default_label})) { + $Sconf{xencfg} = 2; + $Econf[$default_loc] = "#" . $Econf[$default_loc]; + Info( 1, ">>> default label '$default_label' points to a XEN section\n"); + } elsif ($default_label ne "" && !exists $Labels{Econf}{$default_label}) { + $Econf[$default_loc] = "#" . $Econf[$default_loc]; + Info( 1, ">>> default label '$default_label' undefined in $Fconf\n"); + } elsif ($default_label eq "" && $Labels[0] =~ m{^Xconf }) { + $Sconf{xencfg} = 2; + Info( 1, ">>> first section (implicit default) points to a XEN section\n"); + } + close( IN); + $Sconf{'__warn-count'} = $c; + + Info( 2, "## end of parsing $in\n") unless $test; + $verbose = $ov; +} + +sub addList($) { + my( $f) = @_; + $f =~ s{^.*/([^/]+)$}{$1}; + print( LIST "$f\n") if ( fileno( LIST) ); + $Flist{$f} = $_[0]; +} +sub Output($$@) { + my( $dir, $file, @lines) = @_; + my $out = "$dir/$file"; + + if ( (! $test || $verbose > 3) && $file ne $Gconf ) { + unshift @lines, $Disclaimer; + } + Write( 1, "## writing '$file' to", ">", $out, @lines); + addList( $out); +} +my %GconfFSuuid = (); +sub canonicalize($$) { + my( $base, $rel) = @_; + + return( $rel ) unless( defined( $rel) ); + Info( 9, "canonicalize($base, $rel): "); + $base = "" if ($rel =~ m{^/}); + $base =~ s{/[^/]+$}{}; + + while ( $rel =~ s{^(\.\.?)/}{} ) { + $base =~ s{/[^/]+$}{} if ( $1 eq ".." ); + } + $rel =~ s{^/}{}; + Info( 9, "'$base/$rel'\n"); + return ( "$base/$rel" ); +} +sub readLink($) { + my( $lnk) = @_; + + my $tgt = readlink( $lnk); + Info( 9, "readLink($lnk): ".(defined($tgt) ? $tgt : "(--undef--)")."\n"); + $tgt = canonicalize( $lnk, $tgt); + Info( 8, "readLink($lnk): ".(defined($tgt) ? $tgt : "(--undef--)")."\n") + unless ($verbose > 8); + return( $tgt ); +} +sub GconfProbeFSuuid($) { + my( $dev) = @_; + my $udir = "/dev/disk/by-uuid"; + my $ldir = "/dev/disk/by-label"; + my $uuid = ""; + my $tgt = ""; + + Info( 5, "GconfProbeFSuuid($dev): \n"); + if ( ! -b $dev ) { + if ( $dev =~ m{^UUID=([0-9A-Fa-f-]+)$} ) { + return ( (-b "$udir/$1") ? $1 : "" ); + } elsif ( $dev =~ m{^LABEL=([0-9A-Fa-f-]+)$} ) { + $dev = readLink( "$ldir/$1"); + return ( "" ) unless ( defined( $dev) ); + } + } + while ( -l $dev ) { + $_ = readLink( $dev); + return ( "" ) unless ( defined( $_) ); + Info( 5, " $dev => $_\n"); + $dev = $_; + } + Info( 5, " looking for: $dev\n"); + if ( opendir( my $fh, $udir) ) { + while ( ($_ = readdir( $fh)) ) { + $_ = "$udir/$_"; + next unless ( -l $_ ); + $tgt = readLink( $_); + next unless (defined( $tgt) ); + Info( 5, " looking at: $_ => $tgt\n"); + next unless ( $dev eq $tgt ); + s{^$udir/}{}; + $uuid = $_; + Info( 5, " found: $uuid!\n"); + last; + } + closedir( $fh); + } + return ( $uuid ); +} +sub GconfFSuuid($) { + my( $spec) = @_; + return ( "" ) unless ( $Sconf{SB} ); + $spec =~ s{^UUID=}{/dev/disk/by-uuid/}; + return ( $GconfFSuuid{$spec} ) if ( exists( $GconfFSuuid{$spec}) ); + + my $uuid = ""; + my $cmd = "/usr/sbin/grub2-probe"; + if ( -x $cmd ) { + my $dop = (-b $spec) ? "--device" : ""; + chomp( $uuid = qx{$cmd --target=fs_uuid $dop "$spec"}); + } + if ( ! defined( $uuid) || ! $uuid ) { + $uuid = GconfProbeFSuuid( $spec); + } + if ( ! defined( $uuid) || ! $uuid ) { + Warn( "couldn't determine fs_uuid -- skip SecureBoot/grub2 config!\n"); + $Sconf{SB} = ""; + return ( "" ); + } + $GconfFSuuid{$spec} = $uuid; + return ( $uuid ); +} +sub Gconf($) { + my ($data) = @_; + my @parts = ("pre", "Econf", "Xconf", "post"); + my @keys = ("label", "kernel", "ramdisk", "options", "description", + "rootfsuuid", "bootfsuuid", "disknr", "partnr", "vmm", "cfg"); + my %S = (); + my $re = join( '|', @parts); + my $current = ""; + my $lines = ""; + my %Gconf; + + $re = qr{^\>\>grub\.($re|.*)\<\<}ox; + + while ( <$data> ) { + if ( m{^__(END)__} || ($current && m{$re}o) ) { + Info( 9, "<<$current\n$lines>>$current => $_"); + $S{$current} = $lines; + $lines = ""; + last if ( $1 eq "END" ); + } + if ( m{$re}o ) { + $current = $1; + next; + } + $lines .= $_; + } + + $lines = $S{pre}; + foreach my $k ( "timeout" ) { + my $val = (exists( $Sconf{$k})) ? $Sconf{$k} : "80"; + $val /= 10; + $lines =~ s{\<$k\>}{$val}gm; + } + foreach my $k ( "grubdefault" ) { + if (exists( $Sconf{$k})) { + $lines =~ s{\<$k\>}{$Sconf{$k}}gm; + } else { + $lines =~ s{^set default='\<$k\>'$}{}gm; + } + } + push @Gconf, $lines; + Info( 8, "<>pre\n"); + foreach my $l ( @Labels ) { + my ($ns, $lbl) = ($l =~ m{^(\S+) (.+)$}); + %Gconf = (); + Info( 8, "ns=$ns lbl=$lbl\n"); + if ( $ns eq "Econf" ) { + foreach my $k ( "kernel", "ramdisk", "options", "description") { + $Gconf{$k} = $Econf{$lbl}{$k} if (exists( $Econf{$lbl}{$k})); + } + $Gconf{rootfsuuid} = GconfFSuuid( $Econf{$lbl}{root}); + #TODO: $Gconf{bootfsuuid} = GconfFSuuid( "/boot"); + } elsif ( $ns eq "Xconf" ) { + foreach my $k ( "vmm", "kernel", "cfg", "description") { + $Gconf{$k} = $Xconf{$lbl}{$k} if (exists( $Xconf{$lbl}{$k})); + } + $Gconf{cfg} = $Xconf unless ( exists($Gconf{cfg}) ); + } else { + next; + } + + $lines = $S{$ns}; + $Gconf{label} = $lbl; + foreach my $k ( @keys ) { + my $val = (exists( $Gconf{$k})) ? $Gconf{$k} : "{{$k}}"; + $lines =~ s{\<$k\>}{$val}gm; + } + push @Gconf, $lines; + Info( 8, "<<$lbl\n$lines>>$lbl\n"); + } + $lines = $S{post}; + push @Gconf, $lines; + Info( 8, "<>post\n"); +} +sub Xconf() { + my $l = "global"; + my $k = "default"; + my %Xlabels = %{$Labels{Xconf}}; + my @Xgc = (); + + push @Xgc, "[$l]\n"; + push @Xconf, "[$l]\n"; + push @Xconf, "#" if (exists( $Sconf{$k}) && + ! exists( $Xconf{$Sconf{$k}}{kernel})); + push @Xconf, "$k=$Sconf{$k}\n" if (exists( $Sconf{$k})); + foreach my $k ( ("time-out", "gfx-mode") ) { + push @Xgc, "$k=$Sconf{$k}\n" if (exists( $Sconf{$k})); + push @Xconf, "$k=$Sconf{$k}\n" if (exists( $Sconf{$k})); + } + push @Xgc, "\n"; + push @Xconf, "\n"; + foreach my $l ( sort { $Xlabels{$a} <=> $Xlabels{$b} } keys %Xlabels ) { + next unless (exists( $Xconf{$l}{kernel})); + my @Xlc = (); + push @Xlc, "[$l]\n"; + if ( exists($Xconf{$l}{append}) ) { + $Xconf{$l}{kernel} .= " " . $Xconf{$l}{append}; + } + foreach my $k ( sort( keys( %{ $Xconf{$l} })) ) { + next if ( $k =~ m{^(?:append|description|vmm|cfg)$} ); + push @Xlc, "$k=$Xconf{$l}{$k}\n"; + } + push @Xconf, @Xlc; + push @Xconf, "\n"; + if ( $Xconf{$l}{cfg} ne $Xconf ) { + my $cfg = $Xconf{$l}{cfg}; + unshift @Xlc, @Xgc; + @{$Xsonf{$cfg}} = @Xlc; + } + } +} +sub Transfer ($$) { + my( $in, $dir) = @_; + my $c = $Sconf{'__warn-count'}; + + if ( $Sconf{SB} ) { + my $fh; + if ( -r $GconfT ) { + open( $fh, "< $GconfT") || Panic( 1, "$GconfT: failed to open: $!\n"); + } else { + open( $fh, "<&DATA") || Panic( 1, ": failed to dup: $!\n"); + } + Gconf($fh) if ( $Sconf{SB} ); + close( $fh); + } + + Warn( "no complete section for $Xconf!\n") + if ( $Sconf{xencfg} && ! exists( $Labels{Xconf}) ); + Xconf() if ( exists( $Labels{Xconf}) ); + + foreach ( @Files ) { + if ( ! -r $_ ) { + Warn( "$_: not found\n"); + $c++; + } + } + if ( $c ) { + Panic( 2, "$in: broken references\n"); + } + + Output( $dir, $Fconf, @Econf); + + # create xen.cfg + if ( $Sconf{xencfg} ) { + Output( $dir, $Xconf, @Xconf); + foreach my $x ( keys( %Xsonf) ) { + Output( $dir, $x, @{$Xsonf{$x}}); + } + } + + # create grub.cfg + Output( $dir, $Gconf, @Gconf) if ( $Sconf{SB} ); + + $Sconf{'__warn-count'} = $c; +} + +# remove old files (legacy!) +sub Purge($) { + my( $d) = @_; + + if ( -r "$d/$Flist" ) { + Info( 6, "## skip pattern-based removal of files from '$d'\n"); + return 0; + } + if ( $keep > 0) { + Info( 1, "## skip pattern-based removal of old files from '$d'\n"); + return 0; + } + Info( 1, "## remove old files from '$d' by pattern\n"); + my @F = glob( "$d/*"); + foreach my $f ( @F ) { + next if ( $f !~ m{.*/(((vm|)linu(x|z)|initrd)(|[-.]\S+)|xen.cfg)$} ); + Info( 1, "> rm $f\n"); + unlink( $f) unless ($test); + } +} + +# remove old files (list-based!) +sub Obsolete($$) { + my( $d, $init) = @_; + my $fh; + my $F = "$d/$Flist"; + my $Fn = "$F.new"; + my $verb = "refresh"; + + if ( $init ) { + $verb = "establish new"; + # skip to end... + } elsif ( $keep > 0 && -r $F ) { + Info( 1, "## skip list-based removal of obsolete files from '$d'\n"); + Merge( $Fn, $F); + } elsif ( ! -r $F ) { + Info( 2, "## no list-based removal of obsolete files during migration\n"); + } else { + my @obs = (); + if ( ! open( $fh, "< $F") ) { + Warn( "could not open '$F' for reading: $!\n"); + } + while ( <$fh> ) { + chomp; + next if (m{/} || exists( $Flist{$_})); + push @obs, $_; + } + close( $fh); + Info( 1, "## remove obsolete files based on '$F'\n") + if ( $#obs >= 0 ); + foreach ( @obs ) { + Info( 1, "> rm $d/$_\n"); + unlink( "$d/$_") unless ($test); + } + } + Info( 2, "## $verb file-list in '$d'\n"); + Rename( 2, $Fn, $F); +} + +sub InstallFPSWA($) { + my ( $d) = @_; + my $Dfpswa = $Dlib; + + $d .= "/efi/Intel Firmware"; + $Dfpswa = $Dlibold unless ( -r "$Dfpswa/fpswa.efi" ); + + return 0 unless ( -r "$Dfpswa/fpswa.efi" ); + + my $head = "## fpswa: Floating Point Software Assist\n"; + if ( -d $d && -r "$d/fpswa.efi" ) { + # check, if we need to update and failing that do nothing?! + my $c = "$Dfpswa/fpswa-cmp-version"; + if ( -x $c ) { + my $chk = qx{$c "$d/fpswa.efi" "$Dfpswa/fpswa.efi"}; + if ( $chk =~ /older/ ) { + Info( 1, $head . + "## Update '$d/fpswa.efi'.\n"); + Info( 2, + "## $chk"); + Install( 0, "-p", "$Dfpswa/fpswa.efi", $d); + } else { + Info( 1, $head . + "## Do NOT update '$d/fpswa.efi'.\n"); + Info( 2, + "## $chk"); + } + } else { + use File::Compare; + if ( compare( "$d/fpswa.efi", "$Dfpswa/fpswa.efi") == 0 ) { + Info( 2, $head . + "## Already installed.\n"); + } else { + Info( 1, $head . + "## Unable to compare versions.\n" . + "## Installation skipped!\n"); + } + } + } else { + Info( 1, $head . "## Install 'fpswa.efi' to '$d'.\n"); + System( 0, "mkdir", $d) unless ( -d $d ); + Install( 0, "-p", "$Dfpswa/fpswa.efi", $d); + } +} + + +sub isMounted($) { + my ( $d) = @_; + my @D = stat( $d); + my @P = stat( $d . "/.."); + return( $D[0] != $P[0] ); +} + +sub MP($) { + my ( $d) = @_; + my @I = ("/etc/fstab", "/proc/mounts", "/etc/mtab"); + Info( 3, "### MP($d):"); + SOURCE: foreach my $f ( @I ) { + open( IN, "< $f") || next; + while ( ) { + chomp; + next if ( m{^#} ); + my @F = split; + my $lno; + if ( $F[1] eq $d ) { + my $dev = $F[0]; + $dev =~ s{^UUID=}{/dev/disk/by-uuid/}; + $dev =~ s{^LABEL=}{/dev/disk/by-label/}; + $lno = $.; + close( IN); + while ( -l $dev ) { + my $t = `readlink -en "$dev"`; + if ( ! defined( $t) ) { + Info( 0, "readlink failed for line $lno in '$f'.\n"); + next SOURCE; + } + if ( ! -b $dev ) { + Info( 0, "no block-device on line $lno in '$f': $dev.\n"); + next SOURCE; + } + if ( $t =~ m{^(/dev/|(../)*)dm-[0-9a-f]+$}i ) { + last; + } + $dev = $t; + } + Info( 3, " found '$dev' in '$f' line $lno => true\n"); + return( $dev); + } + } + close( IN); + } + Info( 3, " not found in [" . join( ", ", @I) . "] => false\n"); + return( 0); +} + +sub backslash($) { + my( $p) = @_; + $p =~ s{\/}{\\}g; + return ( $p ); +} +sub ebc($$$$$) { + my( $label, $dev, $part, $path, $extra) = @_; + my @C = ("efibootmgr", "-v", "-cL", $label, + "-d", "$dev", "-p", $part, "-l", backslash($path)); + my @out; + + if ( $extra ) { + #push @C, "--unicode", $extra; + push @C, "-u", $extra; + } + my $cmd = $C[0]; + foreach my $c ( @C[1..$#C] ) { + if ( $c =~ /[\s\\]/ ) { + $cmd .= " '$c'"; + } else { + $cmd .= " $c"; + } + } + Info( 1, "> $cmd\n"); + return (undef()) if ( $test ); + + open( EBM, "-|", @C) ; + while () { + print if ($verbose > 1); + chomp; + push @out, $_; + } + close( EBM); + return( @out ); +} +sub ebr($) { + my( $num) = @_; + my @C = ("efibootmgr", "-q", "-B", "-b" , sprintf( "%x", $num)); + + $C[1] = "-v" if ( $verbose > 2 ); + System( 0, @C); +} +sub hwpEqual($$) { + my( $s1, $s2) = @_; + my $hex = qr{[0-9a-f]+}i; + my $hexi = qr{[0-9a-f-]+}i; + my @S1 = ($s1 =~ m{HD\(($hex),($hex),($hex),($hexi)\)}o); + my @S2 = ($s2 =~ m{HD\(($hex),($hex),($hex),($hexi)\)}o); + Info( 5, sprintf( "'%s' - '%s'\n", $S1[3], $S2[3])); + return( $s1 eq $s2 ); +} +sub ebm($$$$$); +sub ebm($$$$$) { + my( $label, $dev, $part, $path, $extra) = @_; + my @out; + my $entry; + + if ( ! -r "$MP$path" ) { + #Warn( "refusing to create EBM for non-existent binary ($MP$path).\n"); + Warn( "refusing to create EBM for non-existent binary.\n"); + return unless ( $test ); + Info( 1, "#"); + } + @out = ebc( $label, $dev, $part, $path, $extra); + return if ( $test ); + + $entry = pop @out; + Panic( 2, "Unexpected failure of 'efibootmgr' (see elilo(8)). Giving up!\n") + unless (defined( $entry)); + Panic( 2, "Unexpected output from 'efibootmgr':\n '$entry'\n") + if ($entry !~ m{^Boot([0-9A-F]{4})[\* ] (.*?)\s+((?:HD|ACPI).+)File(.+)$}i); + my ( $num, $lbl, $hwp, $file) = (hex($1), $2, $3, $4); + Info( 1, sprintf( "# num=%d (0x%04X) hwp=%s\n", $num, $num, $hwp)); + + foreach my $e ( @out) { + $e =~ m{^Boot([0-9A-Fa-f]{4})[\* ] (.*?)\s+((?:HD|ACPI).+)File(.+)$} || + next; + next unless ( hwpEqual( $hwp, $3) ); + if ( $file eq $4 ) { + my $c = hex($1); +# This effort below to eliminate holes in the boot entry list voids +# the attempt to order EBM entries by simply calling '--refresh-EBM'. +# The full solution would require adding an interface to 'efibootmgr -o', +# which is unfortunately not feasible this late in the release cycle. +# if ( $lbl eq $2 ) { +# # delete label with higher number +# my $n = ($num < $c) ? $c : $num; +# ebr( $n); +# $num = $c; +# } else { +# # delete old/invalid label +# ebr( $c); +# if ( $num > $c ) { +# # now we have a hole! +# ebr( $num); +# ebm( $label, $dev, $part, $path, $extra); +# return; +# } +# } + # delete old/invalid labels *irrespective* of holes + ebr( $c); + } + } +} + +sub Refresh($$) { + my ( $device, $dir) = @_; + my ($dev, $sep, $part, $path, $label, $ret); + my $shim_opts = ""; #$sBinaries[1]; + + # device & partition + if ( $device =~ m{^(.*)([-_]part)(\d+)$} ) { + $dev = $1; + $sep = $2; + $part = $3; + } elsif ( $device =~ m{^(.*/[a-z0-9]+)(p)(\d+)$}i ) { + # accept things like 'c0d0p1' or 'nvme0n0p1' + $dev = $1; + $sep = $2; + $part = $3; + } elsif ( $device =~ m{^(/dev/[a-z]+)(\d+)$}i ) { + # accept '/dev/sda1', but refuse '/dev/dm-1' + $dev = $1; + $sep = ""; + $part = $2; + } else { + Panic( 2, "parse error on EFI partition $device.\n"); + } + if ( ! -b $dev ) { + Panic( 2, "EFI partition parent device $dev not found.\n"); + } + if ( ! -b "$dev$sep$part" ) { + Panic( 2, "EFI partition $part on device $dev not found.\n"); + } + Info( 4, "#### dev=$dev, part=$part\n"); + # path + $path = "/efi/$VD/"; + Info( 4, "#### path=$path\n"); + # label + if ( exists( $Sconf{'ebm-label'}) ) { + $label = $Sconf{'ebm-label'}; + } elsif ( exists( $Sconf{'ybm-label'}) ) { + $label = $Sconf{'ybm-label'}; + } else { + $label = "SUSE Linux Enterprise"; + } + Info( 4, "#### label=$label\n"); + if ( $Sconf{SB} && ! exists($Sconf{'SB-fallback'}) && + ! -r "$MP$path$shim" ) { + # try to force "fallback" when primary target went missing! + $Sconf{'SB-fallback'} = "true"; + } + if ( ! $Sconf{SB} || exists($Sconf{'SB-fallback'}) ) { + my $lbl = $label . ($Sconf{'SB'} ? " (fallback)" : ""); + $ret = ebm( "XEN ".$lbl, $dev, $part, $path . $xen, "") + if ( $Sconf{xencfg} == 1 ); + + $ret = ebm( $lbl, $dev, $part, $path . $elilo, ""); + + $ret = ebm( "XEN ".$lbl, $dev, $part, $path . $xen, "") + if ( $Sconf{xencfg} == 2 ); + } + if ( $Sconf{SB} ) { + $ret = ebm( "XEN ".$label, $dev, $part, $path . $shim, " $xen") + if ( $Sconf{xencfg} == 1 && exists( $Sconf{'SB-direct2xen'}) ); + + $ret = ebm( $label, $dev, $part, $path . $shim, $shim_opts); + + $ret = ebm( "XEN ".$label, $dev, $part, $path . $shim, " $xen") + if ( $Sconf{xencfg} == 2 && exists( $Sconf{'SB-direct2xen'}) ); + } +} + +sub CheckSB() { + my $fh; + my $sev = "/sys/firmware/efi/vars"; + my $sbd = "$sev/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c/data"; + my $comment = ""; + $Sconf{SB} = ""; + $Sconf{'secure-boot'} = "auto" unless ( exists( $Sconf{'secure-boot'}) ); + if ( $Sconf{'secure-boot'} =~ m{^(off|false)$} ) { + $comment = " (forced off)"; + } elsif ( $Sconf{'secure-boot'} =~ m{^(on|true|try)$} ) { + $Sconf{SB} = "forced on"; + } elsif ( ! -r "$sbd" ) { + $comment = " (not supported)"; + } elsif ( ! open( $fh, "< $sbd") ) { + Warn( "$sbd: open: $!\n"); + $Sconf{SB} = "try"; + $comment = " (failed to open)"; + } else { + my $val = <$fh>; + if ( ! defined( $val) ) { + Warn( "$sbd: read: $!\n"); + $Sconf{SB} = "try"; + $comment = " (failed to read)"; + } elsif ( unpack( "c", $val) == 0 ) { + $comment = " (supported but inactive)" + } else { + $Sconf{SB} = "auto"; + $comment = sprintf( " (data=%d)", unpack( "c", $val)) if ($verbose > 2); + } + } + Info( 2, "## SecureBoot: '$Sconf{SB}'$comment\n"); +} + +my %Opt = (); +{ + use Getopt::Long; + use Pod::Usage; + $Getopt::Long::debug = 0; + $Getopt::Long::ignorecase = 0; + $Getopt::Long::bundling = 1; + $Getopt::Long::passthrough = 0; + + pod2usage(2) unless ( GetOptions( \%Opt, + 'help|h', 'man|m', 'version|V', 'verbose|v+', + 'test|t', 'keep|k', 'purge|K', "refresh-EBM") && + ( ! $Opt{'purge'} || ! $Opt{'keep'} ) && + ! $Opt{'help'} ); + + Version() if ( $Opt{'version'} ); + pod2usage(-exitstatus => 0, -verbose => 2) if ( $Opt{'man'} ); + pod2usage(1) if ( $Opt{'help'} ); + $test = 1 if ( $Opt{'test'} ); + $keep = 0 if ( $Opt{'purge'} ); + $keep = 1 if ( $Opt{'keep'} ); + $verbose += $Opt{'verbose'} if ( $Opt{'verbose'} ); +} + +# run-time init +if ( $Arch =~ m{ARCH} ) { + chomp( $Arch = qx{uname -m}); + Info( 3, "### Arch: '$Arch'\n"); +} +if ( ! $EFIarch ) { + $EFIarch = ( $Arch eq "x86_64" ) ? "x64" : + ( $Arch =~ m{86} ) ? "ia32" : $Arch; + Info( 3, "### EFIarch: '$EFIarch'\n"); +} +if ( $Dlib =~ m{LIBDIR} ) { + $Dlib = "$dbg/usr/lib" . (($Arch eq "x86_64") ? "64/" : "/"); + $Dlibold = $Dlib . "elilo"; + $Dlib = $Dlib . "efi"; + $Dlib = $Dlibold if (! -r "$Dlib/elilo.efi" && -r "$Dlibold/elilo.efi"); + Info( 3, "### Dlib: '$Dlib'\n"); +} + +# try to read variables from $Sconf +Parse( $Sconf, ($Opt{'refresh-EBM'}&&!$Opt{test}) ? 0 : -1); + +# check for Secure Boot +CheckSB(); + +# check environment +if ( exists( $Sconf{"efi-mountpoint"}) ) { + $MP = $dbg . $Sconf{"efi-mountpoint"}; + Panic( 2, "EFI partition specification in $Sconf invalid.\n") + unless ( -d $MP ); # or is it "$MP/efi"? +} elsif ( -d $MPnew . "/efi/" . $VD || MP($MPnew) ) { + $MP = $MPnew; +} elsif ( -d $MPold . "/efi/" . $VD ) { + $MP = $MPold; +} else { + Info( 1, "## Neither new ($MPnew/efi/$VD) nor old ($MPold/efi/$VD)?\n"); + Panic( 2, "EFI partition not found.\n"); +} +Info( 3, "### Mountpoint: '$MP'\n"); + +if ( exists( $Sconf{"vendor-directory"}) ) { + $VD = $Sconf{"vendor-directory"}; + Info( 1, "## To apply changes of '$VD' run 'elilo --refresh-EBM'!\n") + unless ( $VD =~ m{^(SuSE|boot)$}i || $Opt{'refresh-EBM'} ); +} +if ( exists( $Sconf{"precious"}) && $keep < 0 ) { + $keep = 1; +} +if ( ! isMounted( $MP) ) { + Panic( 2, "EFI partition (". MP( $MP) .") not mounted at $MP.\n"); +} + + +$D = $MP . "/efi/" . $VD; +Info( 2, "## Output directory: '$D'\n"); +System( 2, "mkdir", "-p", $D) unless ( -d $D ); + +if ( $Opt{'refresh-EBM'} ) { + Refresh( MP( $MP), $D); + exit 0; +} +if ( -r $Sconf ) { + my $initializing = ( ! -r "$D/elilo.efi" && ! -r "$D/$Fconf" ); + if ( ! $test ) { + open( LIST, "> $D/$Flist.new") || + Warn( "cannot open '$D/$Flist.new' for writing: $!\n"); + } + # extract kernels, etc. and write fixed .conf + Transfer( $Sconf, $D); + # remove old files (legacy!) + Purge( $D) unless ($initializing); + # copy stuff + Info( 1, "## copy files to '$D'\n"); + @sBinaries = () unless ( $Sconf{SB} ); + foreach ( reverse( $elilo, @sBinaries) ) { + unshift @Files, "$Dlib/$_"; + } + foreach ( @Files ) { + Install( 0, "-p", $_, $D); + addList( $_); + } + if ( $VD =~ m{^boot$}i ) { + my $b = ( $Sconf{SB} ) ? $shim : $elilo; + $b = $xen if ($Sconf{xencfg} == 2 && + (!$Sconf{SB} || exists( $Sconf{'SB-direct2xen'}))); + + Install( 0, "-p", "$Dlib/$b", "$D/boot$EFIarch.efi"); + addList( "boot$EFIarch.efi"); + } + close( LIST); + # remove old files (list-based!) + Obsolete( $D, $initializing); + # take care of FPSWA + InstallFPSWA( $MP); +} elsif ( $MP eq $MPold && -r "$D/$Fconf" ) { + # assume old setup with only '/vmlinuz' and '/initrd' + Install( 2, "-p", "$Dlib/elilo.efi", $D); + InstallFPSWA( $MP); +} elsif ( $MP eq $MPold ) { + Panic( 2, "$D/$Fconf: not found\n"); +} elsif ( ! -e $Sconf ) { + Panic( 2, "$Sconf: not found\n"); +} else { + Panic( 2, "$Sconf: not readable\n"); +} + +if ( $warn > 0 ) { + Panic( 1, sprintf("%d warning%s encountered.\n", $warn, ($warn==1)?"":"s")); +} +exit( 0); + +__DATA__ +>>grub.pre<< +# +# DO NOT EDIT THIS FILE +# +# It is automatically generated by /sbin/elilo using +# settings from /etc/elilo.conf (and maybe /etc/default/grub) +# +### BEGIN 00 simplified header ### +if [ x"${feature_menuentry_id}" = xy ]; then + menuentry_id_option="--id" +else + menuentry_id_option="" +fi + +if [ x${boot_once} = xtrue ]; then + set timeout=0 +elif sleep --interruptible 0 ; then + set timeout= +fi + +set efibootdir=$prefix +set default='' +### END 00 simplified header ### + +### BEGIN 10 elilo ### +>>grub.Econf-full<< # TODO: track down "disknr" and "partnr" +menuentry '