Update FAQ
[grml2usb.git] / grml2usb
index 55f24bb..ec3ba3b 100755 (executable)
--- a/grml2usb
+++ b/grml2usb
@@ -18,7 +18,7 @@ from inspect import isroutine, isclass
 import datetime, logging, os, re, subprocess, sys, tempfile, time
 
 # global variables
 import datetime, logging, os, re, subprocess, sys, tempfile, time
 
 # global variables
-PROG_VERSION = "0.9.2(pre2)"
+PROG_VERSION = "0.9.2"
 MOUNTED = set()  # register mountpoints
 TMPFILES = set() # register tmpfiles
 DATESTAMP = time.mktime(datetime.datetime.now().timetuple()) # unique identifier for syslinux.cfg
 MOUNTED = set()  # register mountpoints
 TMPFILES = set() # register tmpfiles
 DATESTAMP = time.mktime(datetime.datetime.now().timetuple()) # unique identifier for syslinux.cfg
@@ -26,10 +26,11 @@ DATESTAMP = time.mktime(datetime.datetime.now().timetuple()) # unique identifier
 # cmdline parsing
 USAGE = "Usage: %prog [options] <[ISO[s] | /live/image]> </dev/sdX#>\n\
 \n\
 # cmdline parsing
 USAGE = "Usage: %prog [options] <[ISO[s] | /live/image]> </dev/sdX#>\n\
 \n\
-%prog installs a grml ISO to an USB device to be able to boot from it.\n\
+%prog installs grml ISO[s] to an USB device to be able to boot from it.\n\
 Make sure you have at least one grml ISO or a running grml system (/live/image),\n\
 Make sure you have at least one grml ISO or a running grml system (/live/image),\n\
-syslinux (just run 'aptitude install syslinux' on Debian-based systems)\n\
-and root access. Further information can be found in: man grml2usb"
+grub or syslinux and root access.\n\
+\n\
+Execute %prog --help for usage hints, further information can be found in: man grml2usb"
 
 # pylint: disable-msg=C0103
 parser = OptionParser(usage=USAGE)
 
 # pylint: disable-msg=C0103
 parser = OptionParser(usage=USAGE)
@@ -46,28 +47,28 @@ parser.add_option("--fat16", dest="fat16", action="store_true",
                   help="format specified partition with FAT16")
 parser.add_option("--force", dest="force", action="store_true",
                   help="force any actions requiring manual interaction")
                   help="format specified partition with FAT16")
 parser.add_option("--force", dest="force", action="store_true",
                   help="force any actions requiring manual interaction")
-parser.add_option("--grub", dest="grub", action="store_true",
-                  help="install grub bootloader instead of syslinux")
-parser.add_option("--initrd", dest="initrd", action="store", type="string",
-                  help="install specified initrd instead of the default [TODO]")
-parser.add_option("--kernel", dest="kernel", action="store", type="string",
-                  help="install specified kernel instead of the default [TODO]")
-parser.add_option("--lilo", dest="lilo",  action="store", type="string",
+#parser.add_option("--initrd", dest="initrd", action="store", type="string",
+#                  help="install specified initrd instead of the default [TODO - not implemented yet]")
+#parser.add_option("--kernel", dest="kernel", action="store", type="string",
+#                  help="install specified kernel instead of the default [TODO - not implemented yet]")
+parser.add_option("--lilo-binary", dest="lilobin",  action="store", type="string",
                   help="lilo executable to be used for installing MBR")
 parser.add_option("--mbr-manager", dest="mbrmgr", action="store_true",
                   help="lilo executable to be used for installing MBR")
 parser.add_option("--mbr-manager", dest="mbrmgr", action="store_true",
-                  help="enable boot manager menu in MBR")
+                  help="enable interactive boot manager menu in MBR")
 parser.add_option("--quiet", dest="quiet", action="store_true",
                   help="do not output anything but just errors on console")
 parser.add_option("--skip-addons", dest="skipaddons", action="store_true",
                   help="do not install /boot/addons/ files")
 parser.add_option("--skip-mbr", dest="skipmbr", action="store_true",
                   help="do not install a master boot record (MBR) on the device")
 parser.add_option("--quiet", dest="quiet", action="store_true",
                   help="do not output anything but just errors on console")
 parser.add_option("--skip-addons", dest="skipaddons", action="store_true",
                   help="do not install /boot/addons/ files")
 parser.add_option("--skip-mbr", dest="skipmbr", action="store_true",
                   help="do not install a master boot record (MBR) on the device")
+parser.add_option("--syslinux", dest="syslinux", action="store_true",
+                  help="install syslinux bootloader instead of grub")
 parser.add_option("--syslinux-mbr", dest="syslinuxmbr", action="store_true",
                   help="install syslinux master boot record (MBR) instead of default")
 parser.add_option("--syslinux-mbr", dest="syslinuxmbr", action="store_true",
                   help="install syslinux master boot record (MBR) instead of default")
-parser.add_option("--squashfs", dest="squashfs", action="store", type="string",
-                  help="install specified squashfs file instead of the default [TODO]")
-parser.add_option("--uninstall", dest="uninstall", action="store_true",
-                  help="remove grml ISO files from specified device [TODO]")
+#parser.add_option("--squashfs", dest="squashfs", action="store", type="string",
+#                  help="install specified squashfs file instead of the default [TODO - not implemented yet]")
+#parser.add_option("--uninstall", dest="uninstall", action="store_true",
+#                  help="remove grml ISO files from specified device [TODO - not implemented yet]")
 parser.add_option("--verbose", dest="verbose", action="store_true",
                   help="enable verbose mode")
 parser.add_option("-v", "--version", dest="version", action="store_true",
 parser.add_option("--verbose", dest="verbose", action="store_true",
                   help="enable verbose mode")
 parser.add_option("-v", "--version", dest="version", action="store_true",
@@ -99,14 +100,16 @@ def cleanup():
 
 
 def register_tmpfile(path):
 
 
 def register_tmpfile(path):
-    """TODO
+    """
+    TODO - not implemented yet
     """
 
     TMPFILES.add(path)
 
 
 def unregister_tmpfile(path):
     """
 
     TMPFILES.add(path)
 
 
 def unregister_tmpfile(path):
-    """TODO
+    """
+    TODO - not implemented yet
     """
 
     if path in TMPFILES:
     """
 
     if path in TMPFILES:
@@ -114,14 +117,18 @@ def unregister_tmpfile(path):
 
 
 def register_mountpoint(target):
 
 
 def register_mountpoint(target):
-    """TODO
+    """register specified target in a set() for handling clean exiting
+
+    @target: destination target of mountpoint
     """
 
     MOUNTED.add(target)
 
 
 def unregister_mountpoint(target):
     """
 
     MOUNTED.add(target)
 
 
 def unregister_mountpoint(target):
-    """TODO
+    """unregister specified target in a set() for handling clean exiting
+
+    @target: destination target of mountpoint
     """
 
     if target in MOUNTED:
     """
 
     if target in MOUNTED:
@@ -214,15 +221,15 @@ def mkfs_fat16(device):
     proc = subprocess.Popen(["mkfs.vfat", "-F", "16", device])
     proc.wait()
     if proc.returncode != 0:
     proc = subprocess.Popen(["mkfs.vfat", "-F", "16", device])
     proc.wait()
     if proc.returncode != 0:
-        raise Exception("error executing mkfs.vfat")
+        raise CriticalException("error executing mkfs.vfat")
 
 
 def generate_main_grub2_config(grml_flavour, install_partition, bootoptions):
     """Generate grub2 configuration for use via grub.cfg
 
 
 
 def generate_main_grub2_config(grml_flavour, install_partition, bootoptions):
     """Generate grub2 configuration for use via grub.cfg
 
-    TODO
-
-    @grml_flavour: name of grml flavour the configuration should be generated for"""
+    @grml_flavour: name of grml flavour the configuration should be generated for
+    @install_partition: partition number for use in (hd0,X)
+    @bootoptions: additional bootoptions that should be used by default"""
 
     local_datestamp = DATESTAMP
 
 
     local_datestamp = DATESTAMP
 
@@ -233,13 +240,20 @@ set timeout=5
 
 insmod fat
 
 
 insmod fat
 
-insmod png
-if background_image (hd0, %(install_partition)s)/boot/grub/grml.png ; then
+if font (hd0,%(install_partition)s)/boot/grub/ascii.pff ; then
+   insmod png
+   set gfxmode=640x480
+   insmod gfxterm
+   insmod vbe
+   terminal gfxterm
+fi
+
+if background_image (hd0,%(install_partition)s)/boot/grub/grml.png ; then
   set color_normal=black/black
   set color_normal=black/black
-  set color_highlight=magenta/black
+  set color_highlight=red/black
 else
 else
-  set menu_color_normal=cyan/blue
-  set menu_color_highlight=white/blue
+  set menu_color_normal=white/black
+  set menu_color_highlight=black/yellow
 fi
 
 menuentry "%(grml_flavour)s (default)" {
 fi
 
 menuentry "%(grml_flavour)s (default)" {
@@ -265,20 +279,26 @@ menuentry "FreeDOS" {
     initrd  /boot/addons/balder10.imz
 }
 
     initrd  /boot/addons/balder10.imz
 }
 
-menuentry "Boot Operating System on first partition of first disk" {
+menuentry "MirBSD" {
+    set root=(hd0,%(install_partition)s)
+    linux   /boot/addons/bsd4grml/ldbsd.com
+}
+
+menuentry "Boot OS of first partition on first disk" {
     set root=(hd0,1)
     chainloader +1
 }
 
     set root=(hd0,1)
     chainloader +1
 }
 
-""" % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp, 'bootoptions': bootoptions, 'install_partition': install_partition } )
+""" % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
+        'bootoptions': bootoptions, 'install_partition': install_partition } )
 
 
 def generate_flavour_specific_grub2_config(grml_flavour, install_partition, bootoptions):
     """Generate grub2 configuration for use via grub.cfg
 
 
 
 def generate_flavour_specific_grub2_config(grml_flavour, install_partition, bootoptions):
     """Generate grub2 configuration for use via grub.cfg
 
-    TODO
-
-    @grml_flavour: name of grml flavour the configuration should be generated for"""
+    @grml_flavour: name of grml flavour the configuration should be generated for
+    @install_partition: partition number for use in (hd0,X)
+    @bootoptions: additional bootoptions that should be used by default"""
 
     local_datestamp = DATESTAMP
 
 
     local_datestamp = DATESTAMP
 
@@ -339,10 +359,65 @@ menuentry "%(grml_flavour)s-serial" {
     initrd /boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce quiet module=%(grml_flavour)s vga=normal video=vesafb:off console=tty1 console=ttyS0,9600n8 %(bootoptions)s
 }
 
     initrd /boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce quiet module=%(grml_flavour)s vga=normal video=vesafb:off console=tty1 console=ttyS0,9600n8 %(bootoptions)s
 }
 
-""" % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp, 'bootoptions': bootoptions, 'install_partition': install_partition } )
+""" % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
+       'bootoptions': bootoptions, 'install_partition': install_partition } )
+
+
+def generate_flavour_specific_grub1_config(grml_flavour, install_partition, bootoptions):
+    """Generate grub1 configuration for use via menu.lst
+
+    @grml_flavour: name of grml flavour the configuration should be generated for
+    @install_partition: partition number for use in (hd0,X)
+    @bootoptions: additional bootoptions that should be used by default"""
+
+    local_datestamp = DATESTAMP
+
+    return("""\
+## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
+title %(grml_flavour)s
+kernel (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce vga=791 quiet module=%(grml_flavour)s %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+
+## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
+title %(grml_flavour)s2ram
+kernel (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce vga=791 quiet module=%(grml_flavour)s toram=%(grml_flavour)s %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+
+## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
+title %(grml_flavour)s-debug
+kernel (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce vga=791 quiet module=%(grml_flavour)s debug boot=live initcall_debug%(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+
+## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
+title %(grml_flavour)s-x
+kernel (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce vga=791 quiet module=%(grml_flavour)s startx=wm-ng %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+
+## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
+title %(grml_flavour)s-nofb
+kernel (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce quiet module=%(grml_flavour)s vga=normal video=ofonly %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+
+## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
+title %(grml_flavour)s-failsafe
+kernel (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce quiet module=%(grml_flavour)s vga=normal lang=us boot=live noautoconfig atapicd noacpi acpi=off nomodules nofirewire noudev nousb nohotplug noapm nopcmcia maxcpus=1 noscsi noagp nodma ide=nodma noswap nofstab nosound nogpm nosyslog nodhcp nocpu nodisc nomodem xmodule=vesa noraid nolvm %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
 
 
+## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
+title %(grml_flavour)s-forensic
+kernel (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce vga=791 quiet module=%(grml_flavour)s nofstab noraid nolvm noautoconfig noswap raid=noautodetect %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+
+## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
+title %(grml_flavour)s-serial
+kernel (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce quiet module=%(grml_flavour)s vga=normal video=vesafb:off console=tty1 console=ttyS0,9600n8 %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
 
 
-def generate_grub1_config(grml_flavour, install_partition, bootoptions):
+""" % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
+       'bootoptions': bootoptions, 'install_partition': install_partition } )
+
+
+def generate_main_grub1_config(grml_flavour, install_partition, bootoptions):
     """Generate grub1 configuration for use via menu.lst
 
     @grml_flavour: name of grml flavour the configuration should be generated for"""
     """Generate grub1 configuration for use via menu.lst
 
     @grml_flavour: name of grml flavour the configuration should be generated for"""
@@ -350,21 +425,35 @@ def generate_grub1_config(grml_flavour, install_partition, bootoptions):
     local_datestamp = DATESTAMP
 
     return("""\
     local_datestamp = DATESTAMP
 
     return("""\
+## main grub1 configuration - generated by grml2usb [main config generated at: %(local_datestamp)s]
 # misc options:
 timeout 30
 # color red/blue green/black
 # misc options:
 timeout 30
 # color red/blue green/black
-splashimage=/boot/grub/splash.xpm.gz
+splashimage=(hd0,%(install_partition)s)/boot/grub/splash.xpm.gz
 foreground  = 000000
 background  = FFCC33
 
 foreground  = 000000
 background  = FFCC33
 
-# root=(hd0,%(install_partition)s)
-
 # define entries:
 title %(grml_flavour)s  - Default boot (using 1024x768 framebuffer)
 # 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
+kernel (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/linux26 apm=power-off lang=us vga=791 quiet boot=live nomce module=%(grml_flavour)s
+initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+
+title Memory test (memtest86+)
+kernel (hd0,%(install_partition)s)/boot/addons/memtest
 
 
-""" % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp, 'bootoptions': bootoptions, 'install_partition': install_partition } )
+title Grub - all in one image
+kernel (hd0,%(install_partition)s)/boot/addons/memdisk
+initrd (hd0,%(install_partition)s)/boot/addons/allinone.img
+
+title FreeDOS
+kernel (hd0,%(install_partition)s)/boot/addons/memdisk
+initrd (hd0,%(install_partition)s)/boot/addons/balder10.imz
+
+title MirBSD
+kernel (hd0,%(install_partition)s)/boot/addons/bsd4grml/ldbsd.com
+
+""" % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
+       'bootoptions': bootoptions, 'install_partition': install_partition } )
 
 
 def generate_isolinux_splash(grml_flavour):
 
 
 def generate_isolinux_splash(grml_flavour):
@@ -388,7 +477,7 @@ def generate_main_syslinux_config(grml_flavour, bootoptions):
     """Generate main configuration for use in syslinux.cfg
 
     @grml_flavour: name of grml flavour the configuration should be generated for
     """Generate main configuration for use in syslinux.cfg
 
     @grml_flavour: name of grml flavour the configuration should be generated for
-    @bootoptions: bootoptions that should be used as a default"""
+    @bootoptions: additional bootoptions that should be used by default"""
 
     local_datestamp = DATESTAMP
 
 
     local_datestamp = DATESTAMP
 
@@ -434,6 +523,11 @@ MENU LABEL dos
 KERNEL /boot/addons/memdisk
 APPEND initrd=/boot/addons/balder10.imz
 
 KERNEL /boot/addons/memdisk
 APPEND initrd=/boot/addons/balder10.imz
 
+# bsd
+LABEL bsd
+MENU LABEL bsd
+KERNEL /boot/addons/bsd4grml/ldbsd.com
+
 ## end of global configuration
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp, 'bootoptions': bootoptions} )
 
 ## end of global configuration
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp, 'bootoptions': bootoptions} )
 
@@ -503,8 +597,9 @@ def install_grub(device):
         register_tmpfile(device_mountpoint)
         try:
             mount(device, device_mountpoint, "")
         register_tmpfile(device_mountpoint)
         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], stdout=file(os.devnull, "r+"))
+            logging.debug("grub-install --recheck --no-floppy --root-directory=%s %s", device_mountpoint, device)
+            proc = subprocess.Popen(["grub-install", "--recheck", "--no-floppy",
+                "--root-directory=%s" % device_mountpoint, device], stdout=file(os.devnull, "r+"))
             proc.wait()
             if proc.returncode != 0:
                 raise Exception("error executing grub-install")
             proc.wait()
             if proc.returncode != 0:
                 raise Exception("error executing grub-install")
@@ -542,26 +637,28 @@ def install_bootloader(device):
 
     @device: partition where bootloader should be installed to"""
 
 
     @device: partition where bootloader should be installed to"""
 
-    # Install bootloader on the device (/dev/sda),
-    # not on the partition itself (/dev/sda1)?
-    #if partition[-1:].isdigit():
-    #    device = re.match(r'(.*?)\d*$', partition).group(1)
-    #else:
-    #    device = partition
-
-    if options.grub:
-        install_grub(device)
-    else:
+    # by default we use grub, so install syslinux only on request
+    if options.syslinux:
         try:
             install_syslinux(device)
         except CriticalException, error:
             logging.critical("Fatal: %s" % error)
             cleanup()
             sys.exit(1)
         try:
             install_syslinux(device)
         except CriticalException, error:
             logging.critical("Fatal: %s" % error)
             cleanup()
             sys.exit(1)
+    else:
+        try:
+            install_grub(device)
+        except CriticalException, error:
+            logging.critical("Fatal: %s" % error)
+            cleanup()
+            sys.exit(1)
 
 
 
 
-def install_lilo_mbr(lilo, device):
-    """TODO"""
+def execute_lilo(lilo, device):
+    """execute lilo for activating the partitions in the MBR
+
+    @lilo: path of lilo executable
+    @device: device where lilo should be executed on"""
 
     # to support -A for extended partitions:
     logging.info("Activating partitions in MBR via lilo")
 
     # to support -A for extended partitions:
     logging.info("Activating partitions in MBR via lilo")
@@ -580,7 +677,9 @@ def install_lilo_mbr(lilo, device):
 
 
 def install_syslinux_mbr(device):
 
 
 def install_syslinux_mbr(device):
-    """TODO"""
+    """install syslinux's master boot record (MBR) on the specified device
+
+    @device: device where MBR of syslinux should be installed to"""
 
     # lilo's mbr is broken, use the one from syslinux instead:
     if not os.path.isfile("/usr/lib/syslinux/mbr.bin"):
 
     # lilo's mbr is broken, use the one from syslinux instead:
     if not os.path.isfile("/usr/lib/syslinux/mbr.bin"):
@@ -598,20 +697,23 @@ def install_syslinux_mbr(device):
 
 
 def install_mir_mbr(mbrtemplate, device, partition, ismirbsdmbr=True):
 
 
 def install_mir_mbr(mbrtemplate, device, partition, ismirbsdmbr=True):
-    """Installs an MBR to a device.
+    """install 'mbr' master boot record (MBR) on 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".
 
 
     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.
+    @mbrtemplate: default MBR file
 
 
-    If "ismirbsdmbr", the partitions' active flags are not changed.
-    Instead, the MBR's default value is set accordingly.
-    """
+    @device: 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 (or 439
+    if ismirbsdmbr) bytes.
+
+    @ismirbsdmbr: if set the partitions' active flags are not changed.
+    Instead, the MBR's default value is set accordingly."""
 
     logging.info("Installing default MBR")
 
 
     logging.info("Installing default MBR")
 
@@ -635,8 +737,10 @@ def install_mir_mbr(mbrtemplate, device, partition, ismirbsdmbr=True):
     if proc.returncode != 0:
         raise Exception("error executing dd (first run)")
 
     if proc.returncode != 0:
         raise Exception("error executing dd (first run)")
 
-    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+"))
+    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)")
     proc.wait()
     if proc.returncode != 0:
         raise Exception("error executing dd (second run)")
@@ -663,7 +767,8 @@ def install_mir_mbr(mbrtemplate, device, partition, ismirbsdmbr=True):
     tmpf.file.close()
 
     logging.debug("executing: dd if='%s' of='%s' bs=512 count=1 conv=notrunc" % (tmpf.name, device))
     tmpf.file.close()
 
     logging.debug("executing: dd if='%s' of='%s' bs=512 count=1 conv=notrunc" % (tmpf.name, device))
-    proc = subprocess.Popen(["dd", "if=%s" % tmpf.name, "of=%s" % device, "bs=512", "count=1", "conv=notrunc"], stderr=file(os.devnull, "r+"))
+    proc = subprocess.Popen(["dd", "if=%s" % tmpf.name, "of=%s" % device, "bs=512", "count=1",
+                            "conv=notrunc"], stderr=file(os.devnull, "r+"))
     proc.wait()
     if proc.returncode != 0:
         raise Exception("error executing dd (third run)")
     proc.wait()
     if proc.returncode != 0:
         raise Exception("error executing dd (third run)")
@@ -689,8 +794,8 @@ def handle_syslinux_mbr(device):
         else:
             lilo = '/usr/share/grml2usb/lilo/lilo.static.i386'
     # finally prefer a specified lilo executable
         else:
             lilo = '/usr/share/grml2usb/lilo/lilo.static.i386'
     # finally prefer a specified lilo executable
-    if options.lilo:
-        lilo = options.lilo
+    if options.lilobin:
+        lilo = options.lilobin
 
     if not is_exe(lilo):
         raise Exception("lilo executable can not be execute")
 
     if not is_exe(lilo):
         raise Exception("lilo executable can not be execute")
@@ -699,7 +804,7 @@ def handle_syslinux_mbr(device):
         logging.info("Would install MBR running lilo and using syslinux.")
         return 0
 
         logging.info("Would install MBR running lilo and using syslinux.")
         return 0
 
-    install_lilo_mbr(lilo, device)
+    execute_lilo(lilo, device)
     install_syslinux_mbr(device)
 
 
     install_syslinux_mbr(device)
 
 
@@ -799,7 +904,7 @@ def check_for_fat(partition):
             raise CriticalException("Failed to read device %s"
                                     " (wrong UID/permissions or device not present?)" % partition)
 
             raise CriticalException("Failed to read device %s"
                                     " (wrong UID/permissions or device not present?)" % partition)
 
-        if filesystem != "vfat":
+        if options.syslinux and filesystem != "vfat":
             raise CriticalException("Partition %s does not contain a FAT16 filesystem. (Use --fat16 or run mkfs.vfat %s)" % (partition, partition))
 
     except OSError:
             raise CriticalException("Partition %s does not contain a FAT16 filesystem. (Use --fat16 or run mkfs.vfat %s)" % (partition, partition))
 
     except OSError:
@@ -819,7 +924,11 @@ def mkdir(directory):
 
 
 def copy_system_files(grml_flavour, iso_mount, target):
 
 
 def copy_system_files(grml_flavour, iso_mount, target):
-    """TODO"""
+    """copy grml's main files (like squashfs, kernel and initrd) to a given target
+
+    @grml_flavour: name of grml flavour the configuration should be generated for
+    @iso_mount: path where a grml ISO is mounted on
+    @target: path where grml's main files should be copied to"""
 
     squashfs = search_file(grml_flavour + '.squashfs', iso_mount)
     if squashfs is None:
 
     squashfs = search_file(grml_flavour + '.squashfs', iso_mount)
     if squashfs is None:
@@ -862,7 +971,10 @@ def copy_system_files(grml_flavour, iso_mount, target):
 
 
 def copy_grml_files(iso_mount, target):
 
 
 def copy_grml_files(iso_mount, target):
-    """TODO"""
+    """copy some minor grml files to a given target
+
+    @iso_mount: path where a grml ISO is mounted on
+    @target: path where grml's main files should be copied to"""
 
     grml_target = target + '/grml/'
     execute(mkdir, grml_target)
 
     grml_target = target + '/grml/'
     execute(mkdir, grml_target)
@@ -902,7 +1014,11 @@ def copy_grml_files(iso_mount, target):
 
 
 def copy_addons(iso_mount, target):
 
 
 def copy_addons(iso_mount, target):
-    """TODO"""
+    """copy grml's addons files (like allinoneimg, bsd4grml,..) to a given target
+
+    @iso_mount: path where a grml ISO is mounted on
+    @target: path where grml's main files should be copied to"""
+
     addons = target + '/boot/addons/'
     execute(mkdir, addons)
 
     addons = target + '/boot/addons/'
     execute(mkdir, addons)
 
@@ -915,6 +1031,15 @@ def copy_addons(iso_mount, target):
         proc = subprocess.Popen(["install", "--mode=664", allinoneimg, addons + 'allinone.img'])
         proc.wait()
 
         proc = subprocess.Popen(["install", "--mode=664", allinoneimg, addons + 'allinone.img'])
         proc.wait()
 
+    # bsd imag
+    bsdimg = search_file('bsd4grml', iso_mount)
+    if bsdimg is None:
+        logging.warn("Warning: bsd4grml not found - can not install it")
+    else:
+        logging.debug("cp -a %s %s" % (bsdimg, addons + '/'))
+        proc = subprocess.Popen(["cp", "-a", bsdimg, addons + '/'])
+        proc.wait()
+
     # freedos image
     balderimg = search_file('balder10.imz', iso_mount)
     if balderimg is None:
     # freedos image
     balderimg = search_file('balder10.imz', iso_mount)
     if balderimg is None:
@@ -944,7 +1069,10 @@ def copy_addons(iso_mount, target):
 
 
 def copy_bootloader_files(iso_mount, target):
 
 
 def copy_bootloader_files(iso_mount, target):
-    """"TODO"""
+    """copy grml's bootloader files to a given target
+
+    @iso_mount: path where a grml ISO is mounted on
+    @target: path where grml's main files should be copied to"""
 
     syslinux_target = target + '/boot/syslinux/'
     execute(mkdir, syslinux_target)
 
     syslinux_target = target + '/boot/syslinux/'
     execute(mkdir, syslinux_target)
@@ -972,20 +1100,29 @@ def copy_bootloader_files(iso_mount, target):
                                 grub_target + 'splash.xpm.gz'])
         proc.wait()
 
                                 grub_target + 'splash.xpm.gz'])
         proc.wait()
 
-    if not os.path.isfile("/usr/share/grml2usb/grub/stage2_eltorito"):
-        logging.critical("Error: /usr/share/grml2usb/grub/stage2_eltorito can not be read.")
-        raise
-    else:
-        logging.debug("cp /usr/share/grml2usb/grub/stage2_eltorito to %s" % grub_target + 'stage2_eltorito')
-        proc = subprocess.Popen(["install", "--mode=664", '/usr/share/grml2usb/grub/stage2_eltorito',
-                                grub_target + 'stage2_eltorito'])
+    # grml splash in grub
+    if os.path.isfile("/usr/share/grml2usb/grub/grml.png"):
+        logging.debug("cp /usr/share/grml2usb/grub/grml.png to %s" % grub_target + 'grml.png')
+        proc = subprocess.Popen(["install", "--mode=664", '/usr/share/grml2usb/grub/grml.png',
+                                grub_target + 'grml.png'])
+        proc.wait()
+
+    # font file for graphical bootsplash in grub
+    if os.path.isfile("/usr/share/grub/ascii.pff"):
+        logging.debug("cp /usr/share/grub/ascii.pff to %s" % grub_target + 'ascii.pff')
+        proc = subprocess.Popen(["install", "--mode=664", '/usr/share/grub/ascii.pff',
+                                grub_target + 'ascii.pff'])
         proc.wait()
 
 
 def install_iso_files(grml_flavour, iso_mount, device, target):
         proc.wait()
 
 
 def install_iso_files(grml_flavour, iso_mount, device, target):
-    """Copy files from ISO on given target"""
+    """Copy files from ISO to given target
+
+    @grml_flavour: name of grml flavour the configuration should be generated for
+    @iso_mount: path where a grml ISO is mounted on
+    @target: path where grml's main files should be copied to"""
 
 
-    # TODO
+    # TODO => several improvements:
     # * 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
     # * 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
@@ -1017,7 +1154,7 @@ def uninstall_files(device):
 
     @device: partition where grml2usb files should be removed from"""
 
 
     @device: partition where grml2usb files should be removed from"""
 
-    # TODO
+    # TODO - not implemented yet
     logging.critical("TODO: uninstalling files from %s not yet implement, sorry." % device)
 
 
     logging.critical("TODO: uninstalling files from %s not yet implement, sorry." % device)
 
 
@@ -1046,36 +1183,58 @@ def identify_grml_flavour(mountpath):
     return grml_flavour
 
 
     return grml_flavour
 
 
-def handle_grub_config(grml_flavour, device, target):
-    """ TODO """
+def handle_grub1_config(grml_flavour, install_partition, grub_target, bootopt):
+    """Main handler for generating grub1 configuration
 
 
-    logging.debug("Generating grub configuration")
-    #with open("...", "w") as f:
-    #f.write("bla bla bal")
+    @grml_flavour: name of grml flavour the configuration should be generated for
+    @install_partition: partition number for use in (hd0,X)
+    @grub_target: path of grub's configuration files
+    @bootoptions: additional bootoptions that should be used by default"""
 
 
-    grub_target = target + '/boot/grub/'
-    # should be present via copy_bootloader_files(), but make sure it exists:
-    execute(mkdir, grub_target)
-    # we have to adjust root() inside grub configuration
-    if device[-1:].isdigit():
-        install_partition = device[-1:]
+    # grub1 config
+    grub1_cfg = grub_target + 'menu.lst'
+    logging.debug("Creating grub1 configuration file (menu.lst)")
 
 
-    # do NOT write "None" in kernel cmdline
-    if options.bootoptions is None:
-        bootopt = ""
+    # install main configuration only *once*, no matter how many ISOs we have:
+    if os.path.isfile(grub1_cfg):
+        string = open(grub1_cfg).readline()
+        main_identifier = re.compile(".*main config generated at: %s.*" % re.escape(str(DATESTAMP)))
+        if not re.match(main_identifier, string):
+            grub1_config_file = open(grub1_cfg, 'w')
+            # logging.info("Note: grml flavour %s is being installed as the default booting system." % grml_flavour)
+            grub1_config_file.write(generate_main_grub1_config(grml_flavour, install_partition, bootopt))
+            grub1_config_file.close()
     else:
     else:
-        bootopt = options.bootoptions
+        grub1_config_file = open(grub1_cfg, 'w')
+        grub1_config_file.write(generate_main_grub1_config(grml_flavour, install_partition, bootopt))
+        grub1_config_file.close()
 
 
-    # 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, bootopt))
-    #grub_config_file.close()
-    # TODO => generate_main_grub1_config() && generate_flavour_specific_grub1_config()
+    grub_flavour_config = True
+    if os.path.isfile(grub1_cfg):
+        string = open(grub1_cfg).readlines()
+        # 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):
+                grub_flavour_config = False
+
+    if grub_flavour_config:
+        grub1_config_file = open(grub1_cfg, 'a')
+        grub1_config_file.write(generate_flavour_specific_grub1_config(grml_flavour, install_partition, bootopt))
+        grub1_config_file.close( )
+
+
+def handle_grub2_config(grml_flavour, install_partition, grub_target, bootopt):
+    """Main handler for generating grub2 configuration
+
+    @grml_flavour: name of grml flavour the configuration should be generated for
+    @install_partition: partition number for use in (hd0,X)
+    @grub_target: path of grub's configuration files
+    @bootoptions: additional bootoptions that should be used by default"""
 
     # grub2 config
     grub2_cfg = grub_target + 'grub.cfg'
 
     # grub2 config
     grub2_cfg = grub_target + 'grub.cfg'
-    logging.debug("Creating grub2 configuration file")
+    logging.debug("Creating grub2 configuration file (grub.lst)")
 
     # install main configuration only *once*, no matter how many ISOs we have:
     if os.path.isfile(grub2_cfg):
 
     # install main configuration only *once*, no matter how many ISOs we have:
     if os.path.isfile(grub2_cfg):
@@ -1106,9 +1265,40 @@ def handle_grub_config(grml_flavour, device, target):
         grub2_config_file.close( )
 
 
         grub2_config_file.close( )
 
 
+def handle_grub_config(grml_flavour, device, target):
+    """Main handler for generating grub (v1 and v2) configuration
+
+    @grml_flavour: name of grml flavour the configuration should be generated for
+    @device: device/partition where grub should be installed to
+    @target: path of grub's configuration files"""
+
+    logging.debug("Generating grub configuration")
+
+    grub_target = target + '/boot/grub/'
+    execute(mkdir, grub_target)
+
+    # we have to adjust root() inside grub configuration
+    if device[-1:].isdigit():
+        install_grub1_partition = int(device[-1:]) - 1
+        install_grub2_partition = device[-1:]
+
+    # do NOT write "None" in kernel cmdline
+    if options.bootoptions is None:
+        bootopt = ""
+    else:
+        bootopt = options.bootoptions
+
+    # write menu.lst
+    handle_grub1_config(grml_flavour, install_grub1_partition, grub_target, bootopt)
+    # write grub.cfg
+    handle_grub2_config(grml_flavour, install_grub2_partition, grub_target, bootopt)
+
+
 def handle_syslinux_config(grml_flavour, target):
 def handle_syslinux_config(grml_flavour, target):
-    """ TODO
-    """
+    """Main handler for generating syslinux configuration
+
+    @grml_flavour: name of grml flavour the configuration should be generated for
+    @target: path of syslinux's configuration files"""
 
     # do NOT write "None" in kernel cmdline
     if options.bootoptions is None:
 
     # do NOT write "None" in kernel cmdline
     if options.bootoptions is None:
@@ -1159,12 +1349,16 @@ def handle_syslinux_config(grml_flavour, target):
 
 
 def handle_bootloader_config(grml_flavour, device, target):
 
 
 def handle_bootloader_config(grml_flavour, device, target):
-    """TODO"""
+    """Main handler for generating bootloader's configuration
 
 
-    if options.grub:
-        handle_grub_config(grml_flavour, device, target)
-    else:
+    @grml_flavour: name of grml flavour the configuration should be generated for
+    @device: device/partition where bootloader should be installed to
+    @target: path of bootloader's configuration files"""
+
+    if options.syslinux:
         handle_syslinux_config(grml_flavour, target)
         handle_syslinux_config(grml_flavour, target)
+    else:
+        handle_grub_config(grml_flavour, device, target)
 
 
 def handle_iso(iso, device):
 
 
 def handle_iso(iso, device):
@@ -1176,7 +1370,7 @@ def handle_iso(iso, device):
     logging.info("Using ISO %s" % iso)
 
     if os.path.isdir(iso):
     logging.info("Using ISO %s" % iso)
 
     if os.path.isdir(iso):
-        logging.critical("TODO: /live/image handling not yet implemented - sorry") # TODO
+        logging.critical("TODO: /live/image handling not yet implemented - sorry")
         sys.exit(1)
 
     iso_mountpoint = tempfile.mkdtemp()
         sys.exit(1)
 
     iso_mountpoint = tempfile.mkdtemp()
@@ -1230,16 +1424,11 @@ def handle_iso(iso, device):
 
 
 def handle_mbr(device):
 
 
 def handle_mbr(device):
-    """TODO"""
+    """Main handler for installing master boot record (MBR)
 
 
-    # install MBR
-    # if not options.mbr:
-    #     logging.info("You are NOT using the --mbr option. Consider using it if your device does not boot.")
-    # else:
-    # make sure we install MBR on /dev/sdX and not /dev/sdX#
+    @device: device where the MBR should be installed to"""
 
     # make sure we have syslinux available
 
     # make sure we have syslinux available
-    # if options.mbr:
     if not options.skipmbr:
         if not which("syslinux") and not options.copyonly and not options.dryrun:
             logging.critical('Sorry, syslinux not available. Exiting.')
     if not options.skipmbr:
         if not which("syslinux") and not options.copyonly and not options.dryrun:
             logging.critical('Sorry, syslinux not available. Exiting.')
@@ -1268,7 +1457,9 @@ def handle_mbr(device):
 
 
 def handle_vfat(device):
 
 
 def handle_vfat(device):
-    """TODO"""
+    """Check for FAT specific settings and options
+
+    @device: device that should checked / formated"""
 
     # make sure we have mkfs.vfat available
     if options.fat16 and not options.force:
 
     # make sure we have mkfs.vfat available
     if options.fat16 and not options.force:
@@ -1278,10 +1469,14 @@ def handle_vfat(device):
             sys.exit(1)
 
         # make sure the user is aware of what he is doing
             sys.exit(1)
 
         # make sure the user is aware of what he is doing
-        f = raw_input("Are you sure you want to format the device with a fat16 filesystem? y/N ")
+        f = raw_input("Are you sure you want to format the specified partition with fat16? y/N ")
         if f == "y" or f == "Y":
             logging.info("Note: you can skip this question using the option --force")
         if f == "y" or f == "Y":
             logging.info("Note: you can skip this question using the option --force")
-            mkfs_fat16(device)
+            try:
+                mkfs_fat16(device)
+            except CriticalException, error:
+                logging.critical("Execution failed: %s", error)
+                sys.exit(1)
         else:
             sys.exit(1)
 
         else:
             sys.exit(1)
 
@@ -1303,7 +1498,9 @@ def handle_vfat(device):
 
 
 def handle_compat_warning(device):
 
 
 def handle_compat_warning(device):
-    """TODO"""
+    """Backwards compatible checks
+
+    @device: device that should be checked"""
 
     # make sure we can replace old grml2usb script and warn user when using old way of life:
     if device.startswith("/mnt/external") or device.startswith("/mnt/usb") and not options.force:
 
     # make sure we can replace old grml2usb script and warn user when using old way of life:
     if device.startswith("/mnt/external") or device.startswith("/mnt/usb") and not options.force:
@@ -1319,7 +1516,7 @@ def handle_compat_warning(device):
 
 
 def handle_logging():
 
 
 def handle_logging():
-    """TODO"""
+    """Log handling and configuration"""
 
     if options.verbose:
         FORMAT = "%(asctime)-15s %(message)s"
 
     if options.verbose:
         FORMAT = "%(asctime)-15s %(message)s"
@@ -1333,7 +1530,10 @@ def handle_logging():
 
 
 def handle_bootloader(device):
 
 
 def handle_bootloader(device):
-    """TODO"""
+    """wrapper for installing bootloader
+
+    @device: device where bootloader should be installed to"""
+
     # Install bootloader only if not using the --copy-only option
     if options.copyonly:
         logging.info("Not installing bootloader and its files as requested via option copyonly.")
     # Install bootloader only if not using the --copy-only option
     if options.copyonly:
         logging.info("Not installing bootloader and its files as requested via option copyonly.")
@@ -1366,10 +1566,10 @@ def main():
 
     if device[-1:].isdigit():
         if int(device[-1:]) > 4:
 
     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.)")
+            logging.critical("Fatal: installation on partition number >4 not supported. (BIOS won't support it.)")
             sys.exit(1)
     else:
             sys.exit(1)
     else:
-        logging.critical("Fatal: installation on raw device not supported. (As the BIOS won't support it.)")
+        logging.critical("Fatal: installation on raw device not supported. (BIOS won't support it.)")
         sys.exit(1)
 
     # provide upgrade path
         sys.exit(1)
 
     # provide upgrade path