local_datestamp = DATESTAMP
return("""\
+## main grub2 configuration - generated by grml2usb [main config generated at: %(local_datestamp)s]
set default=0
set timeout=5
set menu_color_highlight=white/blue
fi
-## main grub2 configuration - generated by grml2usb [main config generated at: %(local_datestamp)s]
menuentry "%(grml_flavour)s (default)" {
set root=(hd0,%(install_partition)s)
linux /boot/release/%(grml_flavour)s/linux26 apm=power-off lang=us vga=791 quiet boot=live nomce module=%(grml_flavour)s %(bootoptions)s
foreground = 000000
background = FFCC33
+# root=(hd0,%(install_partition)s)
+
# define entries:
title %(grml_flavour)s - Default boot (using 1024x768 framebuffer)
kernel /boot/release/%(grml_flavour)s/linux26 apm=power-off lang=us vga=791 quiet boot=live nomce module=%(grml_flavour)s
initrd /boot/release/%(grml_flavour)s/initrd.gz
-""" % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp, 'bootoptions': bootoptions} )
+""" % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp, 'bootoptions': bootoptions, 'install_partition': install_partition } )
def generate_isolinux_splash(grml_flavour):
try:
mount(device, device_mountpoint, "")
logging.debug("grub-install --root-directory=%s %s", device_mountpoint, device)
- proc = subprocess.Popen(["grub-install", "--root-directory=%s" % device_mountpoint, device])
+ proc = subprocess.Popen(["grub-install", "--root-directory=%s" % device_mountpoint, device], stdout=file(os.devnull, "r+"))
proc.wait()
if proc.returncode != 0:
raise Exception("error executing grub-install")
def install_lilo_mbr(lilo, device):
"""TODO"""
- # TODO: check out the *real* difference between:
- # * mbr-install /dev/ice
- # * lilo -S /dev/null -M /dev/ice ext && lilo -S /dev/null -A /dev/ice 1
- # * cat /usr/lib/syslinux/mbr.bin > /dev/ice
- # * syslinux -sf /dev/iceX
- # * ...?
-
# to support -A for extended partitions:
logging.info("Installing MBR")
logging.debug("%s -S /dev/null -M %s ext" % (lilo, device))
logging.critical("Execution failed:", error)
+def InstallMBR(mbrtemplate, device, partition, ismirbsdmbr=True):
+ """Installs an MBR to a device.
+
+ Retrieve the partition table from "device", install an MBR from
+ the "mbrtemplate" file, set the "partition" (0..3) active, and
+ install the result back to "device".
+
+ "device" may be the name of a file assumed to be a hard disc
+ (or USB stick) image, or something like "/dev/sdb". "partition"
+ must be a number between 0 and 3, inclusive. "mbrtemplate" must
+ be a valid MBR file of at least 440 (439 if ismirbsdmbr) bytes.
+
+ If "ismirbsdmbr", the partitions' active flags are not changed.
+ Instead, the MBR's default value is set accordingly.
+ """
+
+ if (partition < 0) or (partition > 3):
+ raise ValueError("partition must be between 0 and 3")
+
+ if ismirbsdmbr:
+ nmbrbytes = 439
+ else:
+ nmbrbytes = 440
+
+ tmpf = tempfile.NamedTemporaryFile()
+
+ logging.debug("executing: dd if='%s' of='%s' bs=512 count=1" % (device, tmpf.name))
+ proc = subprocess.Popen(["dd", "if=%s" % device, "of=%s" % tmpf.name, "bs=512", "count=1"], stderr=file(os.devnull, "r+"))
+ proc.wait()
+ if proc.returncode != 0:
+ raise Exception("error executing dd (first run)")
+ # os.system("dd if='%s' of='%s' bs=512 count=1" % (device, tmpf.name))
+
+ logging.debug("executing: dd if=%s of=%s bs=%s count=1 conv=notrunc" % (mbrtemplate, tmpf.name, nmbrbytes))
+ proc = subprocess.Popen(["dd", "if=%s" % mbrtemplate, "of=%s" % tmpf.name, "bs=%s" % nmbrbytes, "count=1", "conv=notrunc"], stderr=file(os.devnull, "r+"))
+ proc.wait()
+ if proc.returncode != 0:
+ raise Exception("error executing dd (second run)")
+ # os.system("dd if='%s' of='%s' bs=%d count=1 conv=notrunc" % (mbrtemplate, tmpf.name, nmbrbytes))
+
+ mbrcode = tmpf.file.read(512)
+ if len(mbrcode) < 512:
+ raise EOFError("MBR size (%d) < 512" % len(mbrcode))
+
+ if ismirbsdmbr:
+ mbrcode = mbrcode[0:439] + chr(partition) + \
+ mbrcode[440:510] + "\x55\xAA"
+ else:
+ actives = ["\x00", "\x00", "\x00", "\x00"]
+ actives[partition] = "\x80"
+ mbrcode = mbrcode[0:446] + actives[0] + \
+ mbrcode[447:462] + actives[1] + \
+ mbrcode[463:478] + actives[2] + \
+ mbrcode[479:494] + actives[3] + \
+ mbrcode[495:510] + "\x55\xAA"
+
+ tmpf.file.seek(0)
+ tmpf.file.truncate()
+ tmpf.file.write(mbrcode)
+ tmpf.file.close()
+
+ #os.system("dd if='%s' of='%s' bs=512 count=1 conv=notrunc" % (tmpf.name, device))
+ logging.debug("executing: dd if='%s' of='%s' bs=512 count=1 conv=notrunc" % (tmpf.name, "/tmp/mbr"))
+ proc = subprocess.Popen(["dd", "if=%s" % tmpf.name, "of=%s" % "/tmp/mbr", "bs=512", "count=1", "conv=notrunc"], stderr=file(os.devnull, "r+"))
+ proc.wait()
+ if proc.returncode != 0:
+ raise Exception("error executing dd (third run)")
+ # os.system("dd if='%s' of='%s' bs=512 count=1 conv=notrunc" % (tmpf.name, "/tmp/mbr"))
+ del tmpf
+
def install_mbr(device):
"""Install a default master boot record on given device
@target: directory where the ISO should be mounted to
@options: mount specific options"""
- # notice: options.dryrun does not work here, as we have to
+ # note: options.dryrun does not work here, as we have to
# locate files and identify the grml flavour
logging.debug("mount %s %s %s" % (mount_options, source, target))
proc = subprocess.Popen(["mount"] + list(mount_options) + [source, target])
if udev_info.returncode == 2:
raise CriticalException("Failed to read device %s"
- "(wrong UID/permissions or device not present?)" % partition)
+ " (wrong UID/permissions or device not present?)" % partition)
if filesystem != "vfat":
raise CriticalException("Device %s does not contain a FAT16 partition." % partition)
# * make sure grml_flavour, iso_mount, target are set when the function is called, otherwise raise exception
# * provide alternative search_file() if file information is stored in a config.ini file?
# * catch "install: .. No space left on device" & CO
- # * abstract copy logic to make the code shorter and get rid of spaghettis ;)
if options.dryrun:
logging.info("Would copy files to %s", iso_mount)
copy_bootloader_files(iso_mount, target)
if not options.dryrun:
- handle_bootloader_config(grml_flavour, device, target) # FIXME
+ handle_bootloader_config(grml_flavour, device, target)
# make sure we sync filesystems before returning
proc = subprocess.Popen(["sync"])
return grml_flavour
-
-def handle_bootloader_config(grml_flavour, device, target):
- """TODO"""
+def handle_grub_config(grml_flavour, device, target):
+ """ TODO """
logging.debug("Generating grub configuration")
#with open("...", "w") as f:
install_partition = device[-1:]
# grub1 config
- logging.debug("Creating grub1 configuration file")
- grub_config_file = open(grub_target + 'menu.lst', 'w')
- grub_config_file.write(generate_grub1_config(grml_flavour, install_partition, options.bootoptions))
- grub_config_file.close()
-
+ #logging.debug("Creating grub1 configuration file")
+ #grub_config_file = open(grub_target + 'menu.lst', 'w')
+ #grub_config_file.write(generate_grub1_config(grml_flavour, install_partition, options.bootoptions))
+ #grub_config_file.close()
# TODO => generate_main_grub1_config() && generate_flavour_specific_grub1_config()
# grub2 config
main_identifier = re.compile(".*main config generated at: %s.*" % re.escape(str(DATESTAMP)))
if not re.match(main_identifier, string):
grub2_config_file = open(grub2_cfg, 'w')
- logging.info("Notice: grml flavour %s is being installed as the default booting system." % grml_flavour)
+ logging.info("Note: grml flavour %s is being installed as the default booting system." % grml_flavour)
grub2_config_file.write(generate_main_grub2_config(grml_flavour, install_partition, options.bootoptions))
grub2_config_file.close()
else:
grub_flavour_config = True
if os.path.isfile(grub2_cfg):
string = open(grub2_cfg).readlines()
- logging.info("Notice: you can boot flavour %s using '%s' on the commandline." % (grml_flavour, grml_flavour))
+ logging.info("Note: you can boot flavour %s using '%s' on the commandline." % (grml_flavour, grml_flavour))
flavour = re.compile("grml2usb for %s: %s" % (re.escape(grml_flavour), re.escape(str(DATESTAMP))))
for line in string:
if flavour.match(line):
grub2_config_file.close( )
+def handle_syslinux_config(grml_flavour, target):
+ """ TODO
+ """
+
logging.info("Generating syslinux configuration")
syslinux_target = target + '/boot/syslinux/'
# should be present via copy_bootloader_files(), but make sure it exits:
main_identifier = re.compile(".*main config generated at: %s.*" % re.escape(str(DATESTAMP)))
if not re.match(main_identifier, string):
syslinux_config_file = open(syslinux_cfg, 'w')
- logging.info("Notice: grml flavour %s is being installed as the default booting system." % grml_flavour)
+ logging.info("Note: grml flavour %s is being installed as the default booting system." % grml_flavour)
syslinux_config_file.write(generate_main_syslinux_config(grml_flavour, options.bootoptions))
syslinux_config_file.close()
else:
syslinux_flavour_config = True
if os.path.isfile(syslinux_cfg):
string = open(syslinux_cfg).readlines()
- logging.info("Notice: you can boot flavour %s using '%s' on the commandline." % (grml_flavour, grml_flavour))
+ logging.info("Note: you can boot flavour %s using '%s' on the commandline." % (grml_flavour, grml_flavour))
flavour = re.compile("grml2usb for %s: %s" % (re.escape(grml_flavour), re.escape(str(DATESTAMP))))
for line in string:
if flavour.match(line):
isolinux_splash.close( )
+def handle_bootloader_config(grml_flavour, device, target):
+ """TODO"""
+
+ if options.grub:
+ handle_grub_config(grml_flavour, device, target)
+ else:
+ handle_syslinux_config(grml_flavour, target)
+
+
def handle_iso(iso, device):
"""Main logic for mounting ISOs and copying files.
if not options.skipmbr:
if device[-1:].isdigit():
mbr_device = re.match(r'(.*?)\d*$', device).group(1)
+ partition_number = int(device[-1:]) - 1
try:
- install_mbr(mbr_device)
+ # install_mbr(mbr_device)
+ InstallMBR('/usr/share/grml2usb/mbr/mbrmgr', mbr_device, partition_number, True)
except IOError, error:
logging.critical("Execution failed: %s", error)
sys.exit(1)
device = args[len(args) - 1]
isos = args[0:len(args) - 1]
+ if device[-1:].isdigit():
+ if int(device[-1:]) > 4:
+ logging.critical("Fatal: installation on partition number >4 not supported. (As the BIOS won't support it.)")
+ sys.exit(1)
+ else:
+ logging.critical("Fatal: installation on raw device not supported. (As the BIOS won't support it.)")
+ sys.exit(1)
+
# provide upgrade path
handle_compat_warning(device)
--- /dev/null
+/* $MirOS: src/sys/arch/i386/stand/mbr/mbr.S,v 1.12 2009/01/31 23:39:55 tg Exp $ */
+
+/*-
+ * Copyright (c) 2009
+ * Thorsten Glaser <tg@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ *-
+ * Compile commands:
+ * $ gcc -D_ASM_SOURCE -DBOOTMANAGER -D__BOOT_VER=\"0AA6\" -c mbr.S
+ * $ ld -nostdlib -Ttext 0x0600 -N -Bstatic -e _start -o mbrmgr.elf mbr.o
+ * $ objcopy -O binary mbrmgr.elf mbrmgr
+ */
+
+ .intel_syntax noprefix
+ .code16
+ .text
+
+ .globl _start
+_start: xor eax,eax
+ mov ss,ax
+ mov sp,offset Lstack
+ push eax
+ popfd
+ mov ds,ax
+ mov es,ax
+ mov si,offset Lbadr
+ mov di,offset _start
+ mov cx,0x0200 /* size of one sector */
+ push si /* load / return address */
+ push ax
+ push offset Lmain
+ rep movsb
+ lret
+
+ /* entry message */
+Lemsg: .ascii "Mir-"
+ .ascii __BOOT_VER
+#ifdef BOOTMANAGER
+ /* Lem<nn> are patch points */
+ .ascii ": 0="
+Lem00: .ascii "00 1="
+Lem01: .ascii "00 2="
+Lem02: .ascii "00 3="
+Lem03: .ascii "00 4=hd0 5=fd0 Enter=default (timeout)\r\n"
+#endif
+ .asciz ">"
+
+ /* failure message */
+Lfmsg: .asciz "bad magic\r\n"
+
+#if 1
+ /* okay boot message */
+Lbmsg: .asciz " OK\r"
+#endif
+
+ /* output NUL-terminated string from ds:si */
+Lotxt0: mov ah,0x0E
+ mov bx,7
+ int 0x10
+Lotxt: lodsb
+ or al,al
+ jnz Lotxt0
+ ret
+
+Lmain: sti
+#ifdef BOOTMANAGER
+ /* patch the partition type values into the message */
+ mov di,offset Lem00
+ mov al,ds:[Lptab + 0x04]
+ call LpBY
+ mov di,offset Lem01
+ mov al,ds:[Lptab + 0x14]
+ call LpBY
+ mov di,offset Lem02
+ mov al,ds:[Lptab + 0x24]
+ call LpBY
+ mov di,offset Lem03
+ mov al,ds:[Lptab + 0x34]
+ call LpBY
+ mov si,offset Lemsg
+ call Lotxt
+#endif
+
+ /* fake invalid partition entry for MBR/FDD boot */
+ mov di,offset Lptab + 0x40
+ xor eax,eax
+ stosw
+ inc ax
+ stosw
+ dec ax
+ stosd
+ stosd
+
+ /* force bad magic if sector load fails */
+ mov ds:[Lbmag],al
+
+#ifdef BOOTMANAGER
+#if 0 /* see above, eax is already zero here */
+ xor ax,ax /* read CMOS clock ticks since midnight */
+#endif
+ int 0x1A /* 32-bit result in cx:dx */
+ mov di,cx /* save it in edi for later */
+ shl edi,16
+ mov di,dx
+ add edi,183 /* 10 seconds, rounded up one tick */
+ Lptmo = . - 4 /* offset of the "183" above */
+
+ /* input loop with timeout */
+Lwkey: mov ah,1
+ int 0x16 /* check if a key was pressed */
+ jnz Lgkey /* yeap */
+ /* delay loop */
+ xor ax,ax
+ int 0x1A
+ shl ecx,16
+ mov cx,dx
+ or al,al /* past midnight? */
+ jz Lsday /* no */
+ add ecx,1573040 /* should be 1572480, but according to RBIL… */
+Lsday: cmp ecx,edi /* time is over? */
+ mov al,13
+ ja Lfkey /* yep, fake a return keypress */
+ jmp Lwkey
+
+ /* input loop without timeout */
+Lgkey: mov ah,1
+ int 0x16 /* check if a key was pressed */
+ jz Lgkey
+ mov ah,0
+ int 0x16
+#endif /* BOOTMANAGER */
+Lfkey: mov bx,offset Lptab
+ mov dl,0x80 /* drive to load from */
+#ifndef BOOTMANAGER
+ jmp Lscan
+#else
+ sub al,13
+ je Lscan /* CR / Return / Enter */
+ jb Lgkey /* invalid input */
+ sub al,('0' - 13)
+ jb Lgkey /* invalid input */
+ cmp al,5 /* floppy */
+ ja Lgkey /* invalid input */
+ jb LdoHD /* hard disc */
+ mov dl,0 /* drive to load from */
+ dec ax /* 5 -> 4 */
+#endif
+LdoHD: shl al,4 /* 0..4 where 4 is virtual partition */
+ add bl,al /* we boot this one */
+ jmp Lboot
+
+ /* scan the partition table for an active partition */
+Lscan: mov al,[dpart] /* try hard-coded by fdisk(8) 'fdef' first */
+ cmp al,3
+ jbe LdoHD
+Lspar: cmp byte ptr [bx],0x80
+ je Lboot /* found an active partition */
+ add bl,0x10
+ cmp bl,0xFE /* BX = 0x07FE = Lptab + 0x40 */
+ jb Lspar
+ /* boot the virtual partition #4 (MBR) */
+
+Lboot: /* try to boot, first LBA (we're on a HDD) then CHS */
+ mov [bx],dl /* drive (0x80 or 0x00) */
+ mov si,offset Lpblk /* LBA parameter block */
+ mov di,si
+ mov ax,0x0010
+ stosw /* size of LBA parameter block */
+ mov al,1
+ stosw /* number of sectors to load */
+ pop ax
+ push ax
+ push bx
+ stosw /* load address offset */
+ xor ax,ax
+ stosw /* load address segment */
+ mov eax,[bx+8]
+ stosd /* LBA offset of start sector (low 32 bit) */
+ xor ax,ax
+ stosw /* high 32 bit */
+ stosw /* high 32 bit */
+ mov ah,0x42 /* LBA extended read */
+ call Lload /* try to boot that */
+ pop si /* edited partition table entry */
+ pop bx /* load offset (ES=CS=SS=DS=0000h) */
+ push bx
+ push si
+ mov ax,0x0201 /* CHS read 0x01 sectors */
+ mov cx,[si+2] /* cylinder; sector number */
+ mov dx,[si] /* head; drive number */
+ call Lload
+ mov si,offset Lfmsg
+ call Lotxt
+#if 0
+Lfail: jmp Lfail
+#else
+ xor ax,ax
+ int 0x16
+ ljmp 0xF000,0xFFF0
+#endif
+
+Lload: mov bp,4 /* number of tries */
+Lldlp: pusha
+ int 0x13
+ popa
+ jc Lldre /* error, try again */
+ cmp word ptr ds:[Lbmag],0xAA55
+ jne Lldre /* bad magic, try again */
+#if 0
+ mov ax,0x0E0D /* output a carriage return */
+ xor bx,bx
+ int 0x10
+#else
+ mov si,offset Lbmsg
+ call Lotxt
+#endif
+ pop si /* Lload return address */
+ pop si /* partition table entry */
+ mov dl,[si]
+ /* DS:SI point to partition table entry, DL is set */
+ cli /* be nice :) */
+ ret /* jump to 0000:7C00h */
+Lldre: pusha
+ xor ax,ax /* reset drive */
+ int 0x13
+ popa
+ dec bp /* another try left? */
+ jnz Lldlp
+ ret
+
+#ifdef BOOTMANAGER
+LpBY: mov ah,al
+ shr al,4
+ and ah,0x0F
+ add ax,0x3030
+ cmp al,0x39
+ jbe LpBY1
+ add al,7
+LpBY1: cmp ah,0x39
+ jbe LpBY2
+ add ah,7
+LpBY2: stosw
+ ret
+#endif
+
+ . = _start + 0x01B7
+ .globl dpart
+ .size dpart,1
+dpart: .byte 0xFF /* default partition [0..3] or none */
+
+ . = _start + 0x01B8
+Lntid: .long 0 /* Microsoft® NT® volume identifier */
+Lpad1: .byte 0, 0
+
+ . = _start + 0x01BE
+ /* partition table */
+Lptab: .long 0, 0, 0, 0 /* partition entry #0 */
+ .long 0, 0, 0, 0 /* partition entry #1 */
+ .long 0, 0, 0, 0 /* partition entry #2 */
+ /* partition entry #3 + pre-installation hint */
+ .word 0, 0, 0, 0, 0
+ . = _start + 0x01F8
+ .size Lhint,2
+#ifdef BOOTMANAGER
+Lhint: .word (Lptmo - _start)
+#else
+Lhint: .word 0xFFFF
+#endif
+Lpad2: .word 0, 0
+
+ . = _start + 0x01FE
+Lpmag: .word 0xAA55 /* BIOS boot magic */
+
+ Lstack = 0x4000
+ Lpblk = 0x5000
+
+ Lbadr = 0x7C00
+ Lbmag = Lbadr + 0x01FE