Updated version
[grml2usb.git] / grml2usb
index 5457a60..b4edca4 100755 (executable)
--- a/grml2usb
+++ b/grml2usb
@@ -12,18 +12,31 @@ This script installs a grml system (either a running system or ISO[s]) to a USB
 
 """
 
 
 """
 
-# from __future__ import with_statement
 from optparse import OptionParser
 from inspect import isroutine, isclass
 import datetime, logging, os, re, subprocess, sys, tempfile, time, os.path
 from optparse import OptionParser
 from inspect import isroutine, isclass
 import datetime, logging, os, re, subprocess, sys, tempfile, time, os.path
+import fileinput
+import glob
+import uuid
 
 # global variables
 
 # global variables
-PROG_VERSION = "0.9.10"
+PROG_VERSION = "0.9.24"
 MOUNTED = set()  # register mountpoints
 TMPFILES = set() # register tmpfiles
 DATESTAMP = time.mktime(datetime.datetime.now().timetuple()) # unique identifier for syslinux.cfg
 GRML_FLAVOURS = set() # which flavours are being installed?
 MOUNTED = set()  # register mountpoints
 TMPFILES = set() # register tmpfiles
 DATESTAMP = time.mktime(datetime.datetime.now().timetuple()) # unique identifier for syslinux.cfg
 GRML_FLAVOURS = set() # which flavours are being installed?
-global GRML_DEFAULT
+GRML_DEFAULT = None
+UUID = None
+
+def syslinux_warning(option, opt, value, parser):
+    sys.stderr.write("Note: the --syslinux option is deprecated as syslinux " +
+                     "is grml2usb's default. Continuing anyway.\n")
+    setattr(parser.values, option.dest, True)
+
+# if grub option is set, unset syslinux option
+def grub_option(option, opt, value, parser):
+    setattr(parser.values, option.dest, True)
+    setattr(parser.values, 'syslinux', False)
 
 # cmdline parsing
 USAGE = "Usage: %prog [options] <[ISO[s] | /live/image]> </dev/sdX#>\n\
 
 # cmdline parsing
 USAGE = "Usage: %prog [options] <[ISO[s] | /live/image]> </dev/sdX#>\n\
@@ -49,16 +62,19 @@ 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("--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("--grub", dest="grub", action="callback",
+                  callback=grub_option,
+                  help="install grub bootloader instead of (default) syslinux")
+parser.add_option("--grub-mbr", dest="grubmbr", action="store_true",
+                  help="install grub into MBR instead of (default) PBR")
 parser.add_option("--lilo-binary", dest="lilobin",  action="store", type="string",
                   help="lilo executable to be used for installing MBR")
 parser.add_option("--mbr-menu", dest="mbrmenu", action="store_true",
                   help="enable interactive boot 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("--lilo-binary", dest="lilobin",  action="store", type="string",
                   help="lilo executable to be used for installing MBR")
 parser.add_option("--mbr-menu", dest="mbrmenu", action="store_true",
                   help="enable interactive boot 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("--remove-bootoption", dest="removeoption", action="append",
+                  help="regex for removing existing bootoptions")
 parser.add_option("--skip-addons", dest="skipaddons", action="store_true",
                   help="do not install /boot/addons/ files")
 parser.add_option("--skip-grub-config", dest="skipgrubconfig", action="store_true",
 parser.add_option("--skip-addons", dest="skipaddons", action="store_true",
                   help="do not install /boot/addons/ files")
 parser.add_option("--skip-grub-config", dest="skipgrubconfig", action="store_true",
@@ -67,20 +83,18 @@ 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("--skip-syslinux-config", dest="skipsyslinuxconfig", action="store_true",
                   help="skip generation of syslinux configuration files")
                   help="do not install a master boot record (MBR) on the device")
 parser.add_option("--skip-syslinux-config", dest="skipsyslinuxconfig", action="store_true",
                   help="skip generation of syslinux configuration files")
-parser.add_option("--syslinux", dest="syslinux", action="store_true",
-                  help="install syslinux bootloader instead of grub")
+parser.add_option("--syslinux", dest="syslinux", action="callback", default=True,
+                  callback=syslinux_warning,
+                  help="install syslinux bootloader (deprecated as it's the default)")
 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 - 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",
                   help="display version and exit")
 (options, args) = parser.parse_args()
 
 parser.add_option("--verbose", dest="verbose", action="store_true",
                   help="enable verbose mode")
 parser.add_option("-v", "--version", dest="version", action="store_true",
                   help="display version and exit")
 (options, args) = parser.parse_args()
 
+
 GRML2USB_BASE = '/usr/share/grml2usb'
 if not os.path.isdir(GRML2USB_BASE):
     GRML2USB_BASE = os.path.dirname(os.path.realpath(__file__))
 GRML2USB_BASE = '/usr/share/grml2usb'
 if not os.path.isdir(GRML2USB_BASE):
     GRML2USB_BASE = os.path.dirname(os.path.realpath(__file__))
@@ -93,6 +107,23 @@ class CriticalException(Exception):
     pass
 
 
     pass
 
 
+# The following two functions help to operate on strings as
+# array (list) of bytes (octets). In Python 3000, the bytes
+# datatype will need to be used. This is intended for using
+# with manipulation of files on the octet level, like shell
+# arrays, e.g. in MBR creation.
+
+
+def array2string(a):
+    """Convert a list of integers [0;255] to a string."""
+    return struct.pack("%sB" % len(a), *a)
+
+
+def string2array(s):
+    """Convert a (bytes) string into a list of integers."""
+    return struct.unpack("%sB" % len(s), s)
+
+
 def cleanup():
     """Cleanup function to make sure there aren't any mounted devices left behind.
     """
 def cleanup():
     """Cleanup function to make sure there aren't any mounted devices left behind.
     """
@@ -163,7 +194,7 @@ def execute(f, *exec_arguments):
     # TODO: doesn't work for proc = execute(subprocess.Popen...() -> any ideas?
     if options.dryrun:
         # pylint: disable-msg=W0141
     # TODO: doesn't work for proc = execute(subprocess.Popen...() -> any ideas?
     if options.dryrun:
         # pylint: disable-msg=W0141
-        logging.debug('dry-run only: %s(%s)' % (get_function_name(f), ', '.join(map(repr, exec_arguments))))
+        logging.debug('dry-run only: %s(%s)', get_function_name(f), ', '.join(map(repr, exec_arguments)))
     else:
         # pylint: disable-msg=W0142
         return f(*exec_arguments)
     else:
         # pylint: disable-msg=W0142
         return f(*exec_arguments)
@@ -194,6 +225,17 @@ def which(program):
     return None
 
 
     return None
 
 
+def get_defaults_file(iso_mount, flavour, name):
+    """get the default file for syslinux
+    """
+    bootloader_dirs = ['/boot/isolinux/', '/boot/syslinux/']
+    for dir in bootloader_dirs:
+        for name in name, \
+        "%s_%s" % (flavour_filename(flavour), name):
+            if os.path.isfile(iso_mount + dir + name):
+                return (dir, name)
+    return ('','')
+
 def search_file(filename, search_path='/bin' + os.pathsep + '/usr/bin'):
     """Given a search path, find file
 
 def search_file(filename, search_path='/bin' + os.pathsep + '/usr/bin'):
     """Given a search path, find file
 
@@ -202,10 +244,18 @@ def search_file(filename, search_path='/bin' + os.pathsep + '/usr/bin'):
     file_found = 0
     paths = search_path.split(os.pathsep)
     current_dir = '' # make pylint happy :)
     file_found = 0
     paths = search_path.split(os.pathsep)
     current_dir = '' # make pylint happy :)
+
+    def match_file(cwd):
+        return  os.path.exists(os.path.join(cwd, filename))
+
     for path in paths:
     for path in paths:
+        current_dir = path
+        if match_file(current_dir):
+            file_found = 1
+            break
         # pylint: disable-msg=W0612
         for current_dir, directories, files in os.walk(path):
         # pylint: disable-msg=W0612
         for current_dir, directories, files in os.walk(path):
-            if os.path.exists(os.path.join(current_dir, filename)):
+            if match_file(current_dir):
                 file_found = 1
                 break
     if file_found:
                 file_found = 1
                 break
     if file_found:
@@ -225,13 +275,12 @@ def mkfs_fat16(device):
 
     @device: partition that should be formated"""
 
 
     @device: partition that should be formated"""
 
-    # syslinux -d boot/isolinux /dev/sdb1
     if options.dryrun:
         logging.info("Would execute mkfs.vfat -F 16 %s now.", device)
         return 0
 
     logging.info("Formating partition with fat16 filesystem")
     if options.dryrun:
         logging.info("Would execute mkfs.vfat -F 16 %s now.", device)
         return 0
 
     logging.info("Formating partition with fat16 filesystem")
-    logging.debug("mkfs.vfat -F 16 %s" % device)
+    logging.debug("mkfs.vfat -F 16 %s", 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:
@@ -275,8 +324,8 @@ fi
 
 menuentry "%(grml_flavour)s (default)" {
     set gfxpayload=1024x768x16,1024x768
 
 menuentry "%(grml_flavour)s (default)" {
     set gfxpayload=1024x768x16,1024x768
-    linux   /boot/release/%(grml_flavour)s/linux26 apm=power-off quiet boot=live nomce live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
-    initrd  /boot/release/%(grml_flavour)s/initrd.gz
+    linux   /boot/release/%(flavour_filename)s/linux26 apm=power-off quiet boot=live nomce live-media-path=/live/%(grml_flavour)s/ bootid=%(uid)s %(bootoptions)s
+    initrd  /boot/release/%(flavour_filename)s/initrd.gz
 }
 
 menuentry "Memory test (memtest86+)" {
 }
 
 menuentry "Memory test (memtest86+)" {
@@ -311,7 +360,8 @@ menuentry "Boot OS of first partition on first disk" {
 }
 
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
 }
 
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
-        'bootoptions': bootoptions } )
+       'flavour_filename': grml_flavour.replace('-', ''),
+       'uid': UUID, 'bootoptions': bootoptions } )
 
 
 def generate_flavour_specific_grub2_config(grml_flavour, bootoptions):
 
 
 def generate_flavour_specific_grub2_config(grml_flavour, bootoptions):
@@ -326,59 +376,60 @@ def generate_flavour_specific_grub2_config(grml_flavour, bootoptions):
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s            - boot in default mode" {
     set gfxpayload=1024x768x16,1024x768
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s            - boot in default mode" {
     set gfxpayload=1024x768x16,1024x768
-    linux  /boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
-    initrd /boot/release/%(grml_flavour)s/initrd.gz
+    linux  /boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ bootid=%(uid)s %(bootoptions)s
+    initrd /boot/release/%(flavour_filename)s/initrd.gz
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s-persistent - enable persistency feature" {
     set gfxpayload=1024x768x16,1024x768
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s-persistent - enable persistency feature" {
     set gfxpayload=1024x768x16,1024x768
-    linux  /boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce quiet persistent live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
-    initrd /boot/release/%(grml_flavour)s/initrd.gz
+    linux  /boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet persistent live-media-path=/live/%(grml_flavour)s/ bootid=%(uid)s %(bootoptions)s
+    initrd /boot/release/%(flavour_filename)s/initrd.gz
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s2ram        - copy compressed grml file to RAM" {
     set gfxpayload=1024x768x16,1024x768
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s2ram        - copy compressed grml file to RAM" {
     set gfxpayload=1024x768x16,1024x768
-    linux  /boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ toram=%(grml_flavour)s.squashfs %(bootoptions)s
-    initrd /boot/release/%(grml_flavour)s/initrd.gz
+    linux  /boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ toram=%(grml_flavour)s.squashfs bootid=%(uid)s %(bootoptions)s
+    initrd /boot/release/%(flavour_filename)s/initrd.gz
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s-debug      - enable debugging options" {
     set gfxpayload=1024x768x16,1024x768
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s-debug      - enable debugging options" {
     set gfxpayload=1024x768x16,1024x768
-    linux /boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ debug boot=live initcall_debug%(bootoptions)s
-    initrd /boot/release/%(grml_flavour)s/initrd.gz
+    linux /boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ debug bootid=%(uid)s initcall_debug %(bootoptions)s
+    initrd /boot/release/%(flavour_filename)s/initrd.gz
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s-x          - start X Window System" {
     set gfxpayload=1024x768x16,1024x768
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s-x          - start X Window System" {
     set gfxpayload=1024x768x16,1024x768
-    linux  /boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ startx=wm-ng %(bootoptions)s
-    initrd /boot/release/%(grml_flavour)s/initrd.gz
+    linux  /boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ startx=wm-ng bootid=%(uid)s %(bootoptions)s
+    initrd /boot/release/%(flavour_filename)s/initrd.gz
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s-nofb       - disable framebuffer" {
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s-nofb       - disable framebuffer" {
-    linux  /boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ vga=normal video=ofonly %(bootoptions)s
-    initrd /boot/release/%(grml_flavour)s/initrd.gz
+    linux  /boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ vga=normal video=ofonly bootid=%(uid)s %(bootoptions)s
+    initrd /boot/release/%(flavour_filename)s/initrd.gz
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s-failsafe   - disable hardware detection" {
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s-failsafe   - disable hardware detection" {
-    linux /boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ vga=normal boot=live noautoconfig atapicd noapic noacpi acpi=off nomodules nofirewire noudev nousb nohotplug noapm nopcmcia nosmp maxcpus=0 noscsi noagp nodma ide=nodma noswap nofstab nosound nogpm nosyslog nodhcp nocpu nodisc nomodem xmodule=vesa noraid nolvm noresume selinux=0 edd=off %(bootoptions)s
-    initrd /boot/release/%(grml_flavour)s/initrd.gz
+    linux /boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ vga=normal noautoconfig atapicd noapic noacpi acpi=off nomodules nofirewire noudev nousb nohotplug noapm nopcmcia nosmp maxcpus=0 noscsi noagp nodma ide=nodma noswap nofstab nosound nogpm nosyslog nodhcp nocpu nodisc nomodem xmodule=vesa noraid nolvm noresume selinux=0 edd=off pci=nomsi bootid=%(uid)s %(bootoptions)s
+    initrd /boot/release/%(flavour_filename)s/initrd.gz
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s-forensic   - do not touch harddisks during hw recognition" {
     set gfxpayload=1024x768x16,1024x768
 }
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 menuentry "%(grml_flavour)s-forensic   - do not touch harddisks during hw recognition" {
     set gfxpayload=1024x768x16,1024x768
-    linux /boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ nofstab noraid nolvm noautoconfig noswap raid=noautodetect forensic readonly %(bootoptions)s
-    initrd /boot/release/%(grml_flavour)s/initrd.gz
+    linux /boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ nofstab noraid nolvm noautoconfig noswap raid=noautodetect forensic readonly bootid=%(uid)s %(bootoptions)s
+    initrd /boot/release/%(flavour_filename)s/initrd.gz
 }
 
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
 }
 
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
-       'bootoptions': bootoptions } )
+       'flavour_filename': grml_flavour.replace('-', ''),
+       'uid': UUID, 'bootoptions': bootoptions } )
 
 
 def generate_flavour_specific_grub1_config(grml_flavour, install_partition, bootoptions):
 
 
 def generate_flavour_specific_grub1_config(grml_flavour, install_partition, bootoptions):
@@ -393,50 +444,51 @@ def generate_flavour_specific_grub1_config(grml_flavour, install_partition, boot
     return("""\
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 title %(grml_flavour)s
     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 live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
-initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+kernel (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce vga=791 quiet live-media-path=/live/%(grml_flavour)s/ bootid=%(uid)s %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/initrd.gz
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 title %(grml_flavour)s-persistent
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 title %(grml_flavour)s-persistent
-kernel (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/linux26 apm=power-off boot=live nomce vga=791 quiet persistent live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
-initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+kernel (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce vga=791 quiet persistent live-media-path=/live/%(grml_flavour)s/ bootid=%(uid)s %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/initrd.gz
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 title %(grml_flavour)s2ram
 
 ## 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 live-media-path=/live/%(grml_flavour)s/ toram=%(grml_flavour)s.squashfs %(bootoptions)s
-initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+kernel (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce vga=791 quiet live-media-path=/live/%(grml_flavour)s/ toram=%(grml_flavour)s.squashfs bootid=%(uid)s %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/initrd.gz
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 title %(grml_flavour)s-debug
 
 ## 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 live-media-path=/live/%(grml_flavour)s/ debug boot=live initcall_debug%(bootoptions)s
-initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+kernel (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce vga=791 quiet live-media-path=/live/%(grml_flavour)s/ debug initcall_debug bootid=%(uid)s %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/initrd.gz
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 title %(grml_flavour)s-x
 
 ## 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 live-media-path=/live/%(grml_flavour)s/ startx=wm-ng %(bootoptions)s
-initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+kernel (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce vga=791 quiet live-media-path=/live/%(grml_flavour)s/ startx=wm-ng bootid=%(uid)s %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/initrd.gz
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 title %(grml_flavour)s-nofb
 
 ## 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 live-media-path=/live/%(grml_flavour)s/ vga=normal video=ofonly %(bootoptions)s
-initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+kernel (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ vga=normal video=ofonly bootid=%(uid)s %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/initrd.gz
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 title %(grml_flavour)s-failsafe
 
 ## 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 live-media-path=/live/%(grml_flavour)s/ vga=normal boot=live noautoconfig atapicd noapic noacpi acpi=off nomodules nofirewire noudev nousb nohotplug noapm nopcmcia nosmp maxcpus=0 noscsi noagp nodma ide=nodma noswap nofstab nosound nogpm nosyslog nodhcp nocpu nodisc nomodem xmodule=vesa noraid nolvm noresume selinux=0 edd=off %(bootoptions)s
-initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+kernel (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ vga=normal noautoconfig atapicd noapic noacpi acpi=off nomodules nofirewire noudev nousb nohotplug noapm nopcmcia nosmp maxcpus=0 noscsi noagp nodma ide=nodma noswap nofstab nosound nogpm nosyslog nodhcp nocpu nodisc nomodem xmodule=vesa noraid nolvm noresume selinux=0 edd=off pci=nomsi bootid=%(uid)s %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/initrd.gz
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 title %(grml_flavour)s-forensic
 
 ## 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 live-media-path=/live/%(grml_flavour)s/ nofstab noraid nolvm noautoconfig noswap raid=noautodetect forensic readonly %(bootoptions)s
-initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+kernel (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce vga=791 quiet live-media-path=/live/%(grml_flavour)s/ nofstab noraid nolvm noautoconfig noswap raid=noautodetect forensic readonly bootid=%(uid)s %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/initrd.gz
 
 ## flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
 title %(grml_flavour)s-serial
 
 ## 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 live-media-path=/live/%(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
+kernel (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ vga=normal video=vesafb:off console=tty1 console=ttyS0,9600n8 bootid=%(uid)s %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/initrd.gz
 
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
 
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
+       'flavour_filename': grml_flavour.replace('-', ''), 'uid': UUID,
        'bootoptions': bootoptions, 'install_partition': install_partition } )
 
 
        'bootoptions': bootoptions, 'install_partition': install_partition } )
 
 
@@ -458,8 +510,8 @@ background  = FFCC33
 
 # define entries:
 title %(grml_flavour)s  - Default boot (using 1024x768 framebuffer)
 
 # define entries:
 title %(grml_flavour)s  - Default boot (using 1024x768 framebuffer)
-kernel (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/linux26 apm=power-off vga=791 quiet boot=live nomce live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
-initrd (hd0,%(install_partition)s)/boot/release/%(grml_flavour)s/initrd.gz
+kernel (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/linux26 apm=power-off vga=791 quiet boot=live nomce live-media-path=/live/%(grml_flavour)s/ bootid=%(uid)s %(bootoptions)s
+initrd (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/initrd.gz
 
 title Memory test (memtest86+)
 kernel (hd0,%(install_partition)s)/boot/addons/memtest
 
 title Memory test (memtest86+)
 kernel (hd0,%(install_partition)s)/boot/addons/memtest
@@ -476,6 +528,7 @@ title MirOS BSD
 kernel (hd0,%(install_partition)s)/boot/addons/bsd4grml/ldbsd.com
 
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
 kernel (hd0,%(install_partition)s)/boot/addons/bsd4grml/ldbsd.com
 
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
+       'flavour_filename': grml_flavour.replace('-', ''), 'uid': UUID,
        'bootoptions': bootoptions, 'install_partition': install_partition } )
 
 
        'bootoptions': bootoptions, 'install_partition': install_partition } )
 
 
@@ -496,125 +549,64 @@ Some information and boot options available via keys F2 - F10. http://grml.org/
 """ % {'grml_name': grml_name} )
 
 
 """ % {'grml_name': grml_name} )
 
 
-def generate_main_syslinux_config(grml_flavour, bootoptions):
+def generate_main_syslinux_config(*args):
     """Generate main configuration for use in syslinux.cfg
 
     """Generate main configuration for use in syslinux.cfg
 
-    @grml_flavour: name of grml flavour the configuration should be generated for
-    @bootoptions: additional bootoptions that should be used by default"""
+    @*args: just for backward compatibility"""
 
     local_datestamp = DATESTAMP
 
     return("""\
 
     local_datestamp = DATESTAMP
 
     return("""\
-## main syslinux configuration - generated by grml2usb [main config generated at: %(local_datestamp)s]
-# use this to control the bootup via a serial port
-# SERIAL 0 9600
-DEFAULT grml
-TIMEOUT 300
-PROMPT 1
-DISPLAY /boot/syslinux/boot.msg
-F1 /boot/syslinux/boot.msg
-F2 /boot/syslinux/f2
-F3 /boot/syslinux/f3
-F4 /boot/syslinux/f4
-F5 /boot/syslinux/f5
-F6 /boot/syslinux/f6
-F7 /boot/syslinux/f7
-F8 /boot/syslinux/f8
-F9 /boot/syslinux/f9
-F10 /boot/syslinux/f10
-## end of main configuration
-
-## global configuration
-# the default option (using %(grml_flavour)s)
-LABEL  grml
-KERNEL /boot/release/%(grml_flavour)s/linux26
-APPEND initrd=/boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce vga=791 quiet live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
-
-# memtest
-LABEL  memtest
-KERNEL /boot/addons/memtest
-
-# grub
-LABEL grub
-MENU LABEL grub
-KERNEL /boot/addons/memdisk
-APPEND initrd=/boot/addons/allinone.img
-
-# dos
-LABEL dos
-MENU LABEL dos
-KERNEL /boot/addons/memdisk
-APPEND initrd=/boot/addons/balder10.imz
-
-# bsd
-LABEL bsd
-MENU LABEL bsd
-KERNEL /boot/addons/bsd4grml/ldbsd.com
-
-# hardware detection tool
-MENU LABEL hdt
-KERNEL /boot/addons/hdt.c32
-APPEND pciids=/boot/addons/pci.ids
-
-## end of global configuration
-""" % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp, 'bootoptions': bootoptions} )
-
-
-def generate_flavour_specific_syslinux_config(grml_flavour, bootoptions):
+label -
+menu label Default boot modes:
+menu disable
+include defaults.cfg
+
+menu end
+menu separator
+
+# flavours:
+label -
+menu label Additional boot entries for:
+menu disable
+include additional.cfg
+
+menu separator
+include options.cfg
+include addons.cfg
+
+label help
+  include promptname.cfg
+  config prompt.cfg
+  text help
+                                        Jump to old style isolinux prompt
+                                        featuring further information
+                                        regarding available boot options.
+  endtext
+
+
+include hiddens.cfg
+""")
+
+
+def generate_flavour_specific_syslinux_config(grml_flavour):
     """Generate flavour specific configuration for use in syslinux.cfg
 
     """Generate flavour specific 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"""
+    @grml_flavour: name of grml flavour the configuration should be generated for"""
 
 
-    local_datestamp = DATESTAMP
 
     return("""\
 
     return("""\
-
-# flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
-LABEL  %(grml_flavour)s
-KERNEL /boot/release/%(grml_flavour)s/linux26
-APPEND initrd=/boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce vga=791 quiet live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
-
-# flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
-LABEL  %(grml_flavour)s-persistent
-KERNEL /boot/release/%(grml_flavour)s/linux26
-APPEND initrd=/boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce vga=791 quiet persistent live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
-
-# flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
-LABEL  %(grml_flavour)s2ram
-KERNEL /boot/release/%(grml_flavour)s/linux26
-APPEND initrd=/boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce vga=791 quiet live-media-path=/live/%(grml_flavour)s/ toram=%(grml_flavour)s.squashfs %(bootoptions)s
-
-# flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
-LABEL  %(grml_flavour)s-debug
-KERNEL /boot/release/%(grml_flavour)s/linux26
-APPEND initrd=/boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce vga=791 quiet live-media-path=/live/%(grml_flavour)s/ debug boot=live initcall_debug%(bootoptions)s
-
-# flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
-LABEL  %(grml_flavour)s-x
-KERNEL /boot/release/%(grml_flavour)s/linux26
-APPEND initrd=/boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce vga=791 quiet live-media-path=/live/%(grml_flavour)s/ startx=wm-ng %(bootoptions)s
-
-# flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
-LABEL  %(grml_flavour)s-nofb
-KERNEL /boot/release/%(grml_flavour)s/linux26
-APPEND initrd=/boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ vga=normal video=ofonly %(bootoptions)s
-
-# flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
-LABEL  %(grml_flavour)s-failsafe
-KERNEL /boot/release/%(grml_flavour)s/linux26
-APPEND initrd=/boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ vga=normal boot=live noautoconfig atapicd noapic noacpi acpi=off nomodules nofirewire noudev nousb nohotplug noapm nopcmcia nosmp maxcpus=0 noscsi noagp nodma ide=nodma noswap nofstab nosound nogpm nosyslog nodhcp nocpu nodisc nomodem xmodule=vesa noraid nolvm noresume selinux=0 edd=off %(bootoptions)s
-
-# flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
-LABEL  %(grml_flavour)s-forensic
-KERNEL /boot/release/%(grml_flavour)s/linux26
-APPEND initrd=/boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce vga=791 quiet live-media-path=/live/%(grml_flavour)s/ nofstab noraid nolvm noautoconfig noswap raid=noautodetect forensic readonly %(bootoptions)s
-
-# flavour specific configuration for %(grml_flavour)s [grml2usb for %(grml_flavour)s: %(local_datestamp)s]
-LABEL  %(grml_flavour)s-serial
-KERNEL /boot/release/%(grml_flavour)s/linux26
-APPEND initrd=/boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce quiet live-media-path=/live/%(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} )
+menu begin grml %(grml_flavour)s
+    menu title %(display_name)s
+    label mainmenu
+    menu label ^Back to main menu...
+    menu exit
+    menu separator
+    # include config for boot parameters from disk
+    include %(grml_flavour)s_grml.cfg
+    menu hide
+menu end
+""" % {'grml_flavour': grml_flavour, 'display_name' : grml_flavour.replace('_', '-') } )
 
 
 def install_grub(device):
 
 
 def install_grub(device):
@@ -631,17 +623,32 @@ def install_grub(device):
         try:
             try:
                 mount(device, device_mountpoint, "")
         try:
             try:
                 mount(device, device_mountpoint, "")
-                logging.debug("grub-install --recheck --no-floppy --root-directory=%s %s", device_mountpoint, device)
+
+                # If using --grub-mbr then make sure we install grub in MBR instead of PBR
+                # Thanks to grub2. NOT.
+                if options.grubmbr:
+                    logging.debug("Using option --grub-mbr ...")
+                    if device[-1:].isdigit():
+                        grub_device = re.match(r'(.*?)\d*$', device).group(1)
+                    else:
+                        grub_device = device
+                else:
+                    grub_device = device
+
+                logging.info("Installing grub as bootloader")
+                logging.debug("grub-install --recheck --no-floppy --root-directory=%s %s",
+                              device_mountpoint, grub_device)
                 proc = subprocess.Popen(["grub-install", "--recheck", "--no-floppy",
                 proc = subprocess.Popen(["grub-install", "--recheck", "--no-floppy",
-                    "--root-directory=%s" % device_mountpoint, device], stdout=file(os.devnull, "r+"))
+                                         "--root-directory=%s" % device_mountpoint, grub_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")
-                    logging.critical("Fatal: error executing grub-install (please check the grml2usb FAQ)")
+                    logging.critical("Fatal: error executing grub-install (please check the grml2usb FAQ or drop the --grub option)")
+                    logging.critical("Note:  if using grub2 consider using the --grub-mbr option because grub2's PBR feature is broken.")
                     cleanup()
                     sys.exit(1)
             except CriticalException, error:
                     cleanup()
                     sys.exit(1)
             except CriticalException, error:
-                logging.critical("Fatal: %s" % error)
+                logging.critical("Fatal: %s", error)
                 cleanup()
                 sys.exit(1)
 
                 cleanup()
                 sys.exit(1)
 
@@ -662,11 +669,11 @@ def install_syslinux(device):
 
     # syslinux -d boot/isolinux /dev/sdb1
     logging.info("Installing syslinux as bootloader")
 
     # syslinux -d boot/isolinux /dev/sdb1
     logging.info("Installing syslinux as bootloader")
-    logging.debug("syslinux -d boot/syslinux %s" % device)
+    logging.debug("syslinux -d boot/syslinux %s", device)
     proc = subprocess.Popen(["syslinux", "-d", "boot/syslinux", device])
     proc.wait()
     if proc.returncode != 0:
     proc = subprocess.Popen(["syslinux", "-d", "boot/syslinux", device])
     proc.wait()
     if proc.returncode != 0:
-        raise CriticalException("Error executing syslinux (either try --fat16 or --grub?)")
+        raise CriticalException("Error executing syslinux (either try --fat16 or use grub?)")
 
 
 def install_bootloader(device):
 
 
 def install_bootloader(device):
@@ -675,14 +682,7 @@ def install_bootloader(device):
     @device: partition where bootloader should be installed to"""
 
     # by default we use grub, so install syslinux only on request
     @device: partition where bootloader should be installed to"""
 
     # 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)
-    else:
+    if options.grub:
         if not which("grub-install"):
             logging.critical("Fatal: grub-install not available (please install the grub package or use the --syslinux option)")
             cleanup()
         if not which("grub-install"):
             logging.critical("Fatal: grub-install not available (please install the grub package or use the --syslinux option)")
             cleanup()
@@ -691,9 +691,16 @@ def install_bootloader(device):
             try:
                 install_grub(device)
             except CriticalException, error:
             try:
                 install_grub(device)
             except CriticalException, error:
-                logging.critical("Fatal: %s" % error)
+                logging.critical("Fatal: %s", error)
                 cleanup()
                 sys.exit(1)
                 cleanup()
                 sys.exit(1)
+    else:
+        try:
+            install_syslinux(device)
+        except CriticalException, error:
+            logging.critical("Fatal: %s", error)
+            cleanup()
+            sys.exit(1)
 
 
 def execute_lilo(lilo, device):
 
 
 def execute_lilo(lilo, device):
@@ -704,14 +711,14 @@ def execute_lilo(lilo, device):
 
     # 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")
-    logging.debug("%s -S /dev/null -M %s ext" % (lilo, device))
+    logging.debug("%s -S /dev/null -M %s ext", lilo, device)
     proc = subprocess.Popen([lilo, "-S", "/dev/null", "-M", device, "ext"])
     proc.wait()
     if proc.returncode != 0:
         raise Exception("error executing lilo")
 
     # activate partition:
     proc = subprocess.Popen([lilo, "-S", "/dev/null", "-M", device, "ext"])
     proc.wait()
     if proc.returncode != 0:
         raise Exception("error executing lilo")
 
     # activate partition:
-    logging.debug("%s -S /dev/null -A %s 1" % (lilo, device))
+    logging.debug("%s -S /dev/null -A %s 1", lilo, device)
     proc = subprocess.Popen([lilo, "-S", "/dev/null", "-A", device, "1"])
     proc.wait()
     if proc.returncode != 0:
     proc = subprocess.Popen([lilo, "-S", "/dev/null", "-A", device, "1"])
     proc.wait()
     if proc.returncode != 0:
@@ -725,21 +732,21 @@ def install_syslinux_mbr(device):
 
     # make sure we have syslinux available
     if not which("syslinux") and not options.copyonly:
 
     # make sure we have syslinux available
     if not which("syslinux") and not options.copyonly:
-        raise Exception("syslinux not available (either install it or consider dropping the --syslinux option)")
+        raise Exception("syslinux not available (either install it or consider using the --grub option)")
 
     # lilo's mbr is broken, use the one from syslinux instead:
     if not os.path.isfile("/usr/lib/syslinux/mbr.bin"):
         raise Exception("/usr/lib/syslinux/mbr.bin can not be read")
 
     logging.info("Installing syslinux MBR")
 
     # lilo's mbr is broken, use the one from syslinux instead:
     if not os.path.isfile("/usr/lib/syslinux/mbr.bin"):
         raise Exception("/usr/lib/syslinux/mbr.bin can not be read")
 
     logging.info("Installing syslinux MBR")
-    logging.debug("cat /usr/lib/syslinux/mbr.bin > %s" % device)
+    logging.debug("cat /usr/lib/syslinux/mbr.bin > %s", device)
     try:
         # TODO -> use Popen instead?
         retcode = subprocess.call("cat /usr/lib/syslinux/mbr.bin > "+ device, shell=True)
         if retcode < 0:
     try:
         # TODO -> use Popen instead?
         retcode = subprocess.call("cat /usr/lib/syslinux/mbr.bin > "+ device, shell=True)
         if retcode < 0:
-            logging.critical("Error copying MBR to device (%s)" % retcode)
+            logging.critical("Error copying MBR to device (%s)", retcode)
     except OSError, error:
     except OSError, error:
-        logging.critical("Execution failed:", error)
+        logging.critical("Execution failed: %s", error)
 
 
 def install_mir_mbr(mbrtemplate, device, partition, ismirbsdmbr=True):
 
 
 def install_mir_mbr(mbrtemplate, device, partition, ismirbsdmbr=True):
@@ -769,7 +776,7 @@ def install_mir_mbr(mbrtemplate, device, partition, ismirbsdmbr=True):
     logging.info("Installing default MBR")
 
     if not os.path.isfile(mbrtemplate):
     logging.info("Installing default MBR")
 
     if not os.path.isfile(mbrtemplate):
-        logging.critical("Error: %s can not be read." % mbrtemplate)
+        logging.critical("Error: %s can not be read.", mbrtemplate)
         raise CriticalException("Error installing MBR (either try --syslinux-mbr or install missing file?)")
 
     if (partition < 0) or (partition > 3):
         raise CriticalException("Error installing MBR (either try --syslinux-mbr or install missing file?)")
 
     if (partition < 0) or (partition > 3):
@@ -782,16 +789,16 @@ def install_mir_mbr(mbrtemplate, device, partition, ismirbsdmbr=True):
 
     tmpf = tempfile.NamedTemporaryFile()
 
 
     tmpf = tempfile.NamedTemporaryFile()
 
-    logging.debug("executing: dd if='%s' of='%s' bs=512 count=1" % (device, tmpf.name))
+    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)")
 
     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)")
 
-    logging.debug("executing: dd if=%s of=%s bs=%s count=1 conv=notrunc" % (mbrtemplate,
-        tmpf.name, nmbrbytes))
+    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,
     proc = subprocess.Popen(["dd", "if=%s" % mbrtemplate, "of=%s" % tmpf.name, "bs=%s" % nmbrbytes,
-        "count=1", "conv=notrunc"], stderr=file(os.devnull, "r+"))
+                             "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)")
@@ -802,24 +809,24 @@ def install_mir_mbr(mbrtemplate, device, partition, ismirbsdmbr=True):
 
     if ismirbsdmbr:
         mbrcode = mbrcode[0:439] + chr(partition) + \
 
     if ismirbsdmbr:
         mbrcode = mbrcode[0:439] + chr(partition) + \
-          mbrcode[440:510] + "\x55\xAA"
+                mbrcode[440:510] + "\x55\xAA"
     else:
         actives = ["\x00", "\x00", "\x00", "\x00"]
         actives[partition] = "\x80"
         mbrcode = mbrcode[0:446] + actives[0] + \
     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"
+                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()
 
 
     tmpf.file.seek(0)
     tmpf.file.truncate()
     tmpf.file.write(mbrcode)
     tmpf.file.close()
 
-    logging.debug("executing: 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, device)
     proc = subprocess.Popen(["dd", "if=%s" % tmpf.name, "of=%s" % device, "bs=512", "count=1",
     proc = subprocess.Popen(["dd", "if=%s" % tmpf.name, "of=%s" % device, "bs=512", "count=1",
-                            "conv=notrunc"], stderr=file(os.devnull, "r+"))
+                             "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)")
@@ -889,16 +896,16 @@ def mount(source, target, mount_options):
             raise CriticalException("Error executing mount: %s already mounted - please unmount before invoking grml2usb" % source)
 
     if os.path.isdir(source):
             raise CriticalException("Error executing mount: %s already mounted - please unmount before invoking grml2usb" % source)
 
     if os.path.isdir(source):
-        logging.debug("Source %s is not a device, therefore not mounting." % source)
+        logging.debug("Source %s is not a device, therefore not mounting.", source)
         return 0
 
         return 0
 
-    logging.debug("mount %s %s %s" % (mount_options, source, target))
+    logging.debug("mount %s %s %s", mount_options, source, target)
     proc = subprocess.Popen(["mount"] + list(mount_options) + [source, target])
     proc.wait()
     if proc.returncode != 0:
         raise CriticalException("Error executing mount (no filesystem on the partition?)")
     else:
     proc = subprocess.Popen(["mount"] + list(mount_options) + [source, target])
     proc.wait()
     if proc.returncode != 0:
         raise CriticalException("Error executing mount (no filesystem on the partition?)")
     else:
-        logging.debug("register_mountpoint(%s)" % target)
+        logging.debug("register_mountpoint(%s)", target)
         register_mountpoint(target)
 
 
         register_mountpoint(target)
 
 
@@ -917,15 +924,15 @@ def unmount(target, unmount_options):
             target_unmount = True
 
     if not target_unmount:
             target_unmount = True
 
     if not target_unmount:
-        logging.debug("%s not mounted anymore" % target)
+        logging.debug("%s not mounted anymore", target)
     else:
     else:
-        logging.debug("umount %s %s" % (list(unmount_options), target))
+        logging.debug("umount %s %s", list(unmount_options), target)
         proc = subprocess.Popen(["umount"] + list(unmount_options) + [target])
         proc.wait()
         if proc.returncode != 0:
             raise Exception("Error executing umount")
         else:
         proc = subprocess.Popen(["umount"] + list(unmount_options) + [target])
         proc.wait()
         if proc.returncode != 0:
             raise Exception("Error executing umount")
         else:
-            logging.debug("unregister_mountpoint(%s)" % target)
+            logging.debug("unregister_mountpoint(%s)", target)
             unregister_mountpoint(target)
 
 
             unregister_mountpoint(target)
 
 
@@ -957,14 +964,14 @@ def check_for_fat(partition):
 
     try:
         udev_info = subprocess.Popen(["/sbin/blkid", "-s", "TYPE", "-o", "value", partition],
 
     try:
         udev_info = subprocess.Popen(["/sbin/blkid", "-s", "TYPE", "-o", "value", partition],
-                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+                                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         filesystem = udev_info.communicate()[0].rstrip()
 
         if udev_info.returncode == 2:
             raise CriticalException("Failed to read device %s"
                                     " (wrong UID/permissions or device/directory not present?)" % partition)
 
         filesystem = udev_info.communicate()[0].rstrip()
 
         if udev_info.returncode == 2:
             raise CriticalException("Failed to read device %s"
                                     " (wrong UID/permissions or device/directory not present?)" % partition)
 
-        if options.syslinux and filesystem != "vfat":
+        if 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:
@@ -983,6 +990,49 @@ def mkdir(directory):
             pass
 
 
             pass
 
 
+def exec_rsync(source, target):
+    """Simple wrapper around rsync to install files
+
+    @source: source file/directory
+    @target: target file/directory"""
+    logging.debug("Source: %s / Target: %s", source, target)
+    proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", source, target])
+    proc.wait()
+    if proc.returncode == 12:
+        logging.critical("Fatal: No space left on device")
+        cleanup()
+        sys.exit(1)
+
+    if proc.returncode != 0:
+        logging.critical("Fatal: could not install %s", source)
+        cleanup()
+        sys.exit(1)
+
+
+def write_uuid(target_file):
+    file = open(target_file, 'w')
+    uid = str(uuid.uuid4())
+    file.write(uid)
+    file.close()
+    return uid
+
+
+def get_uuid(target):
+    conf_target = target + "/conf/"
+    uuid_file_name = conf_target + "/bootid.txt"
+    if os.path.isdir(conf_target):
+        if os.path.isfile(uuid_file_name):
+            uuid_file = open(uuid_file_name, 'r')
+            uid = uuid_file.readline().strip()
+            uuid_file.close()
+            return uid
+        else:
+            return write_uuid(uuid_file_name)
+    else:
+        execute(mkdir, conf_target)
+        return write_uuid(uuid_file_name)
+
+
 def copy_system_files(grml_flavour, iso_mount, target):
     """copy grml's main files (like squashfs, kernel and initrd) to a given target
 
 def copy_system_files(grml_flavour, iso_mount, target):
     """copy grml's main files (like squashfs, kernel and initrd) to a given target
 
@@ -997,36 +1047,39 @@ def copy_system_files(grml_flavour, iso_mount, target):
     else:
         squashfs_target = target + '/live/' + grml_flavour + '/'
         execute(mkdir, squashfs_target)
     else:
         squashfs_target = target + '/live/' + grml_flavour + '/'
         execute(mkdir, squashfs_target)
-        logging.debug("rsync -rlptDH --inplace %s %s" % (squashfs, squashfs_target + grml_flavour + '.squashfs'))
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", squashfs, squashfs_target + grml_flavour + ".squashfs"])
-        proc.wait()
+    exec_rsync(squashfs, squashfs_target + grml_flavour + '.squashfs')
 
 
-    filesystem_module = search_file('filesystem.module', iso_mount)
+    for prefix in grml_flavour + "/", "":
+        filesystem_module = search_file(prefix + 'filesystem.module', iso_mount)
+        if filesystem_module: break
     if filesystem_module is None:
         logging.critical("Fatal: filesystem.module not found")
     if filesystem_module is None:
         logging.critical("Fatal: filesystem.module not found")
+        raise CriticalException("error locating filesystem.module file")
     else:
     else:
-        logging.debug("rsync -rlptDH --inplace %s %s" % (filesystem_module, squashfs_target + 'filesystem.module'))
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", filesystem_module, squashfs_target + 'filesystem.module'])
-        proc.wait()
+        exec_rsync(filesystem_module, squashfs_target + 'filesystem.module')
+
 
 
-    release_target = target + '/boot/release/' + grml_flavour
+    release_path = 'boot/release/' + grml_flavour.replace('-', '')
+    release_target = target + "/" + release_path
     execute(mkdir, release_target)
 
     execute(mkdir, release_target)
 
-    kernel = search_file('linux26', iso_mount)
+    prefix = ""
+    if os.path.isdir(iso_mount + '/boot/release'):
+        prefix = release_path + '/'
+
+    kernel = search_file(prefix + 'linux26', iso_mount)
     if kernel is None:
         logging.critical("Fatal kernel not found")
     if kernel is None:
         logging.critical("Fatal kernel not found")
+        raise CriticalException("error locating kernel file")
     else:
     else:
-        logging.debug("rsync -rlptDH --inplace %s %s" % (kernel, release_target + '/linux26'))
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", kernel, release_target + '/linux26'])
-        proc.wait()
+        exec_rsync(kernel, release_target + '/linux26')
 
 
-    initrd = search_file('initrd.gz', iso_mount)
+    initrd = search_file(prefix + 'initrd.gz', iso_mount)
     if initrd is None:
         logging.critical("Fatal: initrd not found")
     if initrd is None:
         logging.critical("Fatal: initrd not found")
+        raise CriticalException("error locating initrd file")
     else:
     else:
-        logging.debug("rsync -rlptDH --inplace %s %s" % (initrd, release_target + '/initrd.gz'))
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", initrd, release_target + '/initrd.gz'])
-        proc.wait()
+        exec_rsync(initrd, release_target + '/initrd.gz')
 
 
 def copy_grml_files(iso_mount, target):
 
 
 def copy_grml_files(iso_mount, target):
@@ -1038,14 +1091,38 @@ def copy_grml_files(iso_mount, target):
     grml_target = target + '/grml/'
     execute(mkdir, grml_target)
 
     grml_target = target + '/grml/'
     execute(mkdir, grml_target)
 
-    for myfile in 'grml-cheatcodes.txt', 'grml-version', 'LICENSE.txt', 'md5sums', 'README.txt':
+    copy_files = [ 'grml-cheatcodes.txt', 'LICENSE.txt', 'md5sums', 'README.txt' ]
+    # handle grml-version
+    new_grml_version = search_file('grml-version', grml_target)
+    if new_grml_version:
+        orig_grml_version = search_file('grml-version', iso_mount)
+        if not orig_grml_version:
+            logging.warn("Warning: %s could not be found - can not install it", orig_grml_version)
+        else:
+            try:
+                new_file = open(new_grml_version, 'a+')
+                new_flavours = [ get_flavour(l) for l in new_file.readlines() ]
+
+                old_file = open(orig_grml_version, 'r')
+                old_lines = old_file.readlines()
+                for line in old_lines:
+                    if not get_flavour(line) in new_flavours:
+                        new_file.write(line)
+
+            except IOError, e:
+                logging.warn("Warning: Could not write file")
+            finally:
+                new_file.close()
+                old_file.close()
+    else:
+        copy_files.append('grml-version')
+
+    for myfile in copy_files:
         grml_file = search_file(myfile, iso_mount)
         if grml_file is None:
             logging.warn("Warning: myfile %s could not be found - can not install it", myfile)
         else:
         grml_file = search_file(myfile, iso_mount)
         if grml_file is None:
             logging.warn("Warning: myfile %s could not be found - can not install it", myfile)
         else:
-            logging.debug("rsync -rlptDH --inplace %s %s" % (grml_file, grml_target + grml_file))
-            proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", grml_file, grml_target + myfile])
-            proc.wait()
+            exec_rsync(grml_file, grml_target + myfile)
 
     grml_web_target = grml_target + '/web/'
     execute(mkdir, grml_web_target)
 
     grml_web_target = grml_target + '/web/'
     execute(mkdir, grml_web_target)
@@ -1055,9 +1132,7 @@ def copy_grml_files(iso_mount, target):
         if grml_file is None:
             logging.warn("Warning: myfile %s could not be found - can not install it")
         else:
         if grml_file is None:
             logging.warn("Warning: myfile %s could not be found - can not install it")
         else:
-            logging.debug("rsync -rlptDH --inplace %s %s" % (grml_file, grml_web_target + grml_file))
-            proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", grml_file, grml_web_target + myfile])
-            proc.wait()
+            exec_rsync(grml_file, grml_web_target + myfile)
 
     grml_webimg_target = grml_web_target + '/images/'
     execute(mkdir, grml_webimg_target)
 
     grml_webimg_target = grml_web_target + '/images/'
     execute(mkdir, grml_webimg_target)
@@ -1067,9 +1142,7 @@ def copy_grml_files(iso_mount, target):
         if grml_file is None:
             logging.warn("Warning: myfile %s could not be found - can not install it")
         else:
         if grml_file is None:
             logging.warn("Warning: myfile %s could not be found - can not install it")
         else:
-            logging.debug("rsync -rlptDH --inplace %s %s" % (grml_file, grml_webimg_target + grml_file))
-            proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", grml_file, grml_webimg_target + myfile])
-            proc.wait()
+            exec_rsync(grml_file, grml_webimg_target + myfile)
 
 
 def copy_addons(iso_mount, target):
 
 
 def copy_addons(iso_mount, target):
@@ -1086,62 +1159,54 @@ def copy_addons(iso_mount, target):
     if allinoneimg is None:
         logging.warn("Warning: allinone.img not found (that's fine if you don't need it)")
     else:
     if allinoneimg is None:
         logging.warn("Warning: allinone.img not found (that's fine if you don't need it)")
     else:
-        logging.debug("rsync -rlptDH --inplace %s %s" % (allinoneimg, addons + '/allinone.img'))
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", allinoneimg, addons + 'allinone.img'])
-        proc.wait()
+        exec_rsync(allinoneimg, addons + 'allinone.img')
 
     # bsd imag
     bsdimg = search_file('bsd4grml', iso_mount)
     if bsdimg is None:
         logging.warn("Warning: bsd4grml not found (that's fine if you don't need it)")
     else:
 
     # bsd imag
     bsdimg = search_file('bsd4grml', iso_mount)
     if bsdimg is None:
         logging.warn("Warning: bsd4grml not found (that's fine if you don't need it)")
     else:
-        logging.debug("rsync -rlptDH --inplace %s %s" % (bsdimg, addons + '/'))
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", bsdimg, addons + '/'])
-        proc.wait()
+        exec_rsync(bsdimg, addons + '/')
 
     # freedos image
     balderimg = search_file('balder10.imz', iso_mount)
     if balderimg is None:
         logging.warn("Warning: balder10.imz not found (that's fine if you don't need it)")
     else:
 
     # freedos image
     balderimg = search_file('balder10.imz', iso_mount)
     if balderimg is None:
         logging.warn("Warning: balder10.imz not found (that's fine if you don't need it)")
     else:
-        logging.debug("rsync -rlptDH --inplace %s %s" % (balderimg, addons + '/balder10.imz'))
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", balderimg, addons + 'balder10.imz'])
-        proc.wait()
+        exec_rsync(balderimg, addons + 'balder10.imz')
 
     # install hdt and pci.ids only when using syslinux (grub doesn't support it)
     if options.syslinux:
         # hdt (hardware detection tool) image
         hdtimg = search_file('hdt.c32', iso_mount)
         if hdtimg:
 
     # install hdt and pci.ids only when using syslinux (grub doesn't support it)
     if options.syslinux:
         # hdt (hardware detection tool) image
         hdtimg = search_file('hdt.c32', iso_mount)
         if hdtimg:
-            logging.debug("rsync -rlptDH --inplace %s %s" % (hdtimg, addons + '/hdt.c32'))
-            proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", hdtimg, addons + '/hdt.c32'])
-            proc.wait()
+            exec_rsync(hdtimg, addons + '/hdt.c32')
 
         # pci.ids file
         picids = search_file('pci.ids', iso_mount)
         if picids:
 
         # pci.ids file
         picids = search_file('pci.ids', iso_mount)
         if picids:
-            logging.debug("rsync -rlptDH --inplace %s %s" % (picids, addons + '/pci.ids'))
-            proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", picids, addons + '/pci.ids'])
-            proc.wait()
+            exec_rsync(picids, addons + '/pci.ids')
 
     # memdisk image
     memdiskimg = search_file('memdisk', iso_mount)
     if memdiskimg is None:
         logging.warn("Warning: memdisk not found (that's fine if you don't need it)")
     else:
 
     # memdisk image
     memdiskimg = search_file('memdisk', iso_mount)
     if memdiskimg is None:
         logging.warn("Warning: memdisk not found (that's fine if you don't need it)")
     else:
-        logging.debug("rsync -rlptDH --inplace %s %s" % (memdiskimg, addons + '/memdisk'))
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", memdiskimg, addons + 'memdisk'])
-        proc.wait()
+        exec_rsync(memdiskimg, addons + 'memdisk')
 
     # memtest86+ image
     memtestimg = search_file('memtest', iso_mount)
     if memtestimg is None:
         logging.warn("Warning: memtest not found (that's fine if you don't need it)")
     else:
 
     # memtest86+ image
     memtestimg = search_file('memtest', iso_mount)
     if memtestimg is None:
         logging.warn("Warning: memtest not found (that's fine if you don't need it)")
     else:
-        logging.debug("rsync -rlptDH --inplace %s %s" % (memtestimg, addons + '/memtest'))
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", memtestimg, addons + 'memtest'])
-        proc.wait()
+        exec_rsync(memtestimg, addons + 'memtest')
 
 
+    # gpxe.lkrn
+    gpxeimg = search_file('gpxe.lkrn', iso_mount)
+    if gpxeimg is None:
+        logging.warn("Warning: gpxe.lkrn not found (that's fine if you don't need it)")
+    else:
+        exec_rsync(gpxeimg, addons + 'gpxe.lkrn')
 
 def copy_bootloader_files(iso_mount, target):
     """copy grml's bootloader files to a given target
 
 def copy_bootloader_files(iso_mount, target):
     """copy grml's bootloader files to a given target
@@ -1153,43 +1218,83 @@ def copy_bootloader_files(iso_mount, target):
     execute(mkdir, syslinux_target)
 
     logo = search_file('logo.16', iso_mount)
     execute(mkdir, syslinux_target)
 
     logo = search_file('logo.16', iso_mount)
-    logging.debug("rsync -rlptDH --inplace %s %s" % (logo, syslinux_target + 'logo.16'))
-    proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", logo, syslinux_target + 'logo.16'])
-    proc.wait()
+    exec_rsync(logo, syslinux_target + 'logo.16')
 
 
-    for ffile in 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10':
+
+    for ffile in ['f%d' % number for number in range(1,11) ]:
         bootsplash = search_file(ffile, iso_mount)
         bootsplash = search_file(ffile, iso_mount)
-        logging.debug("rsync -rlptDH --inplace %s %s" % (bootsplash, syslinux_target + ffile))
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", bootsplash, syslinux_target + ffile])
-        proc.wait()
+        if not bootsplash:
+            continue
+        exec_rsync(bootsplash, syslinux_target + ffile)
+
+    loopback_cfg = search_file("loopback.cfg", iso_mount)
+    if loopback_cfg:
+        directory = os.path.dirname(loopback_cfg)
+        directory = directory.replace(iso_mount, "")
+        if not os.path.isdir(target + "/" + directory):
+            os.mkdir(target + os.path.sep + directory)
+        exec_rsync(loopback_cfg, target + os.path.sep + directory)
+
+    # avoid the "file is read only, overwrite anyway (y/n) ?" question
+    # of mtools by syslinux ("mmove -D o -D O s:/ldlinux.sys $target_file")
+    if os.path.isfile(syslinux_target + 'ldlinux.sys'):
+        os.unlink(syslinux_target + 'ldlinux.sys')
+
+    source_dir, name = get_defaults_file(iso_mount, GRML_DEFAULT, "default.cfg")
+    (source_dir,options) = get_defaults_file(iso_mount, GRML_DEFAULT, "grml.cfg")
+
+    if not source_dir:
+        logging.critical("Fatal: file default.cfg could not be found.")
+        logging.critical("Note:  this grml2usb version requires an ISO generated by grml-live >=0.9.24 ...")
+        logging.critical("       ... either use grml releases >=2009.10 or switch to an older grml2usb version.")
+        logging.critical("       Please visit http://grml.org/grml2usb/#grml2usb-compat for further information.")
+        raise
+
+    for expr in name, 'distri.cfg', \
+        options, 'grml.png', 'hd.cfg', 'isolinux.cfg', 'isolinux.bin', \
+        'isoprompt.cfg', 'options.cfg', \
+        'prompt.cfg', 'vesamenu.c32', 'vesamenu.cfg', 'grml.png', '*.c32':
+        files = glob.glob(iso_mount + source_dir + expr)
+        for path in files:
+            filename = os.path.basename(path)
+            exec_rsync(path, syslinux_target + filename)
+
+    # copy the addons_*.cfg file to the new syslinux directory
+    for filename in glob.glob(iso_mount + source_dir + 'addon*.cfg'):
+        exec_rsync(filename, syslinux_target)
+
+    path = search_file('hidden.cfg', iso_mount + source_dir)
+    if path:
+        exec_rsync(path, syslinux_target + "new_" + 'hidden.cfg')
+
 
     grub_target = target + '/boot/grub/'
     execute(mkdir, grub_target)
 
     if not os.path.isfile(GRML2USB_BASE + "/grub/splash.xpm.gz"):
 
     grub_target = target + '/boot/grub/'
     execute(mkdir, grub_target)
 
     if not os.path.isfile(GRML2USB_BASE + "/grub/splash.xpm.gz"):
-        logging.critical("Error: %s/grub/splash.xpm.gz can not be read." % (GRML2USB_BASE, ))
-        logging.critical("Please make sure you've the grml2usb Debian package installed!")
+        logging.critical("Error: %s/grub/splash.xpm.gz can not be read.", GRML2USB_BASE)
+        logging.critical("Please make sure you've installed the grml2usb (Debian) package!")
         raise
     else:
         raise
     else:
-        logging.debug("rsync -rlptDH --inplace %s/grub/splash.xpm.gz %s%s" % (GRML2USB_BASE, grub_target, 'splash.xpm.gz'))
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", GRML2USB_BASE + '/grub/splash.xpm.gz',
-                                grub_target + 'splash.xpm.gz'])
-        proc.wait()
+        exec_rsync(GRML2USB_BASE + '/grub/splash.xpm.gz', grub_target + 'splash.xpm.gz')
 
     # grml splash in grub
     if os.path.isfile(GRML2USB_BASE + "/grub/grml.png"):
 
     # grml splash in grub
     if os.path.isfile(GRML2USB_BASE + "/grub/grml.png"):
-        logging.debug("rsync -rlptDH --inplace %s/grub/grml.png to %s%s" % (GRML2USB_BASE, grub_target, 'grml.png'))
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", GRML2USB_BASE + '/grub/grml.png',
-                                grub_target + 'grml.png'])
-        proc.wait()
+        exec_rsync(GRML2USB_BASE + '/grub/grml.png', grub_target + 'grml.png')
 
     # font file for graphical bootsplash in grub
     if os.path.isfile("/usr/share/grub/ascii.pf2"):
 
     # font file for graphical bootsplash in grub
     if os.path.isfile("/usr/share/grub/ascii.pf2"):
-        logging.debug("rsync -rlptDH --inplace /usr/share/grub/ascii.pf2 to %s" % grub_target + 'ascii.pf2')
-        proc = subprocess.Popen(["rsync", "-rlptDH", "--inplace", '/usr/share/grub/ascii.pf2',
-                                grub_target + 'ascii.pf2'])
-        proc.wait()
+        exec_rsync('/usr/share/grub/ascii.pf2', grub_target + 'ascii.pf2')
+
+    # always copy grub content as it might be useful
+    for file in glob.glob(iso_mount + '/boot/grub/*.mod'):
+        exec_rsync(file, grub_target)
+
+    for file in glob.glob(iso_mount + '/boot/grub/*.img'):
+        exec_rsync(file, grub_target)
 
 
+    for file in glob.glob(iso_mount + '/boot/grub/stage*'):
+        exec_rsync(file, grub_target)
 
 def install_iso_files(grml_flavour, iso_mount, device, target):
     """Copy files from ISO to given target
 
 def install_iso_files(grml_flavour, iso_mount, device, target):
     """Copy files from ISO to given target
@@ -1204,6 +1309,8 @@ def install_iso_files(grml_flavour, iso_mount, device, target):
     # * provide alternative search_file() if file information is stored in a config.ini file?
     # * catch "install: .. No space left on device" & CO
 
     # * provide alternative search_file() if file information is stored in a config.ini file?
     # * catch "install: .. No space left on device" & CO
 
+    global GRML_DEFAULT
+    GRML_DEFAULT = grml_flavour
     if options.dryrun:
         return 0
     elif not options.bootloaderonly:
     if options.dryrun:
         return 0
     elif not options.bootloaderonly:
@@ -1216,8 +1323,8 @@ def install_iso_files(grml_flavour, iso_mount, device, target):
             sys.exit(1)
 
     if not options.skipaddons:
             sys.exit(1)
 
     if not options.skipaddons:
-        if grml_flavour.endswith('-small'):
-            logging.info("Note: grml-small doesn't provide any addons, not installing them therefore.")
+        if not search_file('addons', iso_mount):
+            logging.info("Could not find addons, therefore not installing.")
         else:
             copy_addons(iso_mount, target)
 
         else:
             copy_addons(iso_mount, target)
 
@@ -1238,8 +1345,13 @@ def uninstall_files(device):
     @device: partition where grml2usb files should be removed from"""
 
     # TODO - not implemented yet
     @device: partition where grml2usb files should be removed from"""
 
     # 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)
+
 
 
+def get_flavour(str):
+    """Returns the flavour of a grml version string
+    """
+    return re.match(r'[\w-]*', str).group()
 
 def identify_grml_flavour(mountpath):
     """Get name of grml flavour
 
 def identify_grml_flavour(mountpath):
     """Get name of grml flavour
@@ -1253,18 +1365,39 @@ def identify_grml_flavour(mountpath):
         logging.critical("Error: could not find grml-version file.")
         raise
 
         logging.critical("Error: could not find grml-version file.")
         raise
 
+    flavours = []
+    tmpfile = None
     try:
         tmpfile = open(version_file, 'r')
     try:
         tmpfile = open(version_file, 'r')
-        grml_info = tmpfile.readline()
-        grml_flavour = re.match(r'[\w-]*', grml_info).group()
-    except TypeError:
+        for line in tmpfile.readlines():
+            flavours.append(get_flavour(line))
+    except TypeError, e:
         raise
         raise
-    except:
-        logging.critical("Unexpected error:", sys.exc_info()[0])
+    except Exception, e:
+        logging.critical("Unexpected error: %s", e)
         raise
         raise
+    finally:
+        if tmpfile: tmpfile.close()
+
+    return flavours
 
 
-    return grml_flavour
 
 
+def modify_grub_config(filename):
+    if options.removeoption:
+        regexe = []
+        for regex in options.removeoption:
+            regexe.append(re.compile(r'%s' % regex))
+
+        option_re = re.compile(r'(.*/boot/release/.*linux26.*)')
+
+        for line in fileinput.input(filename, inplace=1):
+            if regexe and option_re.search(line):
+                for regex in regexe:
+                    line = regex.sub(' ', line)
+
+            sys.stdout.write(line)
+
+        fileinput.close()
 
 def handle_grub1_config(grml_flavour, install_partition, grub_target, bootopt):
     """Main handler for generating grub1 configuration
 
 def handle_grub1_config(grml_flavour, install_partition, grub_target, bootopt):
     """Main handler for generating grub1 configuration
@@ -1304,6 +1437,16 @@ def handle_grub1_config(grml_flavour, install_partition, grub_target, bootopt):
         grub1_config_file.write(generate_flavour_specific_grub1_config(grml_flavour, install_partition, bootopt))
         grub1_config_file.close()
 
         grub1_config_file.write(generate_flavour_specific_grub1_config(grml_flavour, install_partition, bootopt))
         grub1_config_file.close()
 
+    modify_grub_config(grub1_cfg)
+
+    # make sure grub.conf isn't a symlink but a plain file instead,
+    # otherwise it will break on FAT16 filesystems
+    # this works around grub-install of (at least) Fedora 10
+    if os.path.isfile(grub1_cfg):
+        grubconf = grub_target + 'grub.conf'
+        if not os.path.islink(grubconf):
+            import shutil
+            shutil.copyfile(grub1_cfg, grub_target + 'grub.conf')
 
 def handle_grub2_config(grml_flavour, grub_target, bootopt):
     """Main handler for generating grub2 configuration
 
 def handle_grub2_config(grml_flavour, grub_target, bootopt):
     """Main handler for generating grub2 configuration
@@ -1353,6 +1496,8 @@ def handle_grub2_config(grml_flavour, grub_target, bootopt):
         grub2_config_file.write(generate_flavour_specific_grub2_config(grml_flavour, bootopt))
         grub2_config_file.close()
 
         grub2_config_file.write(generate_flavour_specific_grub2_config(grml_flavour, bootopt))
         grub2_config_file.close()
 
+    modify_grub_config(grub2_cfg)
+
 
 def handle_grub_config(grml_flavour, device, target):
     """Main handler for generating grub (v1 and v2) configuration
 
 def handle_grub_config(grml_flavour, device, target):
     """Main handler for generating grub (v1 and v2) configuration
@@ -1386,6 +1531,110 @@ def handle_grub_config(grml_flavour, device, target):
     handle_grub2_config(grml_flavour, grub_target, bootopt)
 
 
     handle_grub2_config(grml_flavour, grub_target, bootopt)
 
 
+def initial_syslinux_config(target):
+    """Generates intial syslinux configuration
+
+    @target path of syslinux's configuration files"""
+
+    target = target + "/"
+    filename = target + "grmlmain.cfg"
+    if os.path.isfile(target + "grmlmain.cfg"):
+        return
+    data = open(filename, "w")
+    data.write(generate_main_syslinux_config())
+    data.close
+
+    filename = target + "hiddens.cfg"
+    data = open(filename, "w")
+    data.write("include hidden.cfg\n")
+    data.close()
+
+def add_entry_if_not_present(filename, entry):
+    data = open(filename, "a+")
+    for line in data:
+        if line == entry:
+            break
+    else:
+        data.write(entry)
+
+    data.close()
+
+def flavour_filename(flavour):
+    return flavour.replace('-', '_')
+
+def adjust_syslinux_bootoptions(src, flavour):
+    append_re = re.compile("^(\s*append.*/boot/release.*)$", re.I)
+    boot_re = re.compile("/boot/([a-zA-Z0-9_]+/)+([a-zA-Z0-9._]+)")
+    # flavour_re = re.compile("(label.*)(grml\w+)")
+    default_re = re.compile("(default.cfg)")
+    bootid_re = re.compile("bootid=[\w_-]+")
+    live_media_path_re = re.compile("live-media-path=[\w_/-]+")
+
+    # do NOT write "None" in kernel cmdline
+    if options.bootoptions is None:
+        bootopt = ""
+    else:
+        bootopt = options.bootoptions
+
+    regexe = []
+    option_re = None
+    if options.removeoption:
+        option_re = re.compile(r'/boot/release/.*/initrd.gz')
+
+        for regex in options.removeoption:
+            regexe.append(re.compile(r'%s' % regex))
+
+    global UUID
+    for line in fileinput.input(src, inplace=1):
+        line = boot_re.sub(r'/boot/release/%s/\2 ' % flavour.replace('-', ''), line)
+        # line = flavour_re.sub(r'\1 %s-\2' % flavour, line)
+        line = default_re.sub(r'%s-\1' % flavour, line)
+        line = bootid_re.sub('', line)
+        line = live_media_path_re.sub('', line)
+        line = append_re.sub(r'\1 live-media-path=/live/%s/ ' % flavour, line)
+        line = append_re.sub(r'\1 boot=live %s ' % bootopt, line)
+        line = append_re.sub(r'\1 %s=%s ' % ("bootid", UUID), line)
+        if option_re and option_re.search(line):
+            for regex in regexe:
+                line = regex.sub(' ', line)
+        sys.stdout.write(line)
+    fileinput.close()
+
+def adjust_labels(src, replacement):
+    label_re = re.compile("^(\s*label\s*) ([a-zA-Z0-9_-]+)", re.I)
+    for line in fileinput.input(src, inplace=1):
+        line = label_re.sub(replacement, line)
+        sys.stdout.write(line)
+    fileinput.close()
+
+
+def add_syslinux_entry(filename, grml_flavour):
+    entry_filename = "option_%s.cfg" % grml_flavour
+    entry = "include %s\n" % entry_filename
+
+    add_entry_if_not_present(filename, entry)
+    path = os.path.dirname(filename)
+
+    data = open(path + "/" + entry_filename, "w")
+    data.write(generate_flavour_specific_syslinux_config(grml_flavour))
+    data.close()
+
+def modify_filenames(grml_flavour, target, filenames):
+    grml_filename = grml_flavour.replace('-', '_')
+    for filename in filenames:
+        old_filename = "%s/%s" % (target, filename)
+        new_filename = "%s/%s_%s" % (target, grml_filename, filename)
+        os.rename(old_filename, new_filename)
+
+
+def remove_default_entry(filename):
+    default_re = re.compile("^(\s*menu\s*default\s*)$", re.I)
+    for line in fileinput.input(filename, inplace=1):
+        if default_re.match(line): continue
+        sys.stdout.write(line)
+    fileinput.close()
+
+
 def handle_syslinux_config(grml_flavour, target):
     """Main handler for generating syslinux configuration
 
 def handle_syslinux_config(grml_flavour, target):
     """Main handler for generating syslinux configuration
 
@@ -1408,43 +1657,62 @@ def handle_syslinux_config(grml_flavour, target):
 
     # install main configuration only *once*, no matter how many ISOs we have:
     syslinux_flavour_is_default = False
 
     # install main configuration only *once*, no matter how many ISOs we have:
     syslinux_flavour_is_default = False
-    if os.path.isfile(syslinux_cfg):
-        string = open(syslinux_cfg).readline()
-        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')
-            GRML_DEFAULT = grml_flavour
-            syslinux_flavour_is_default = True
-            syslinux_config_file.write(generate_main_syslinux_config(grml_flavour, bootopt))
-            syslinux_config_file.close()
+    syslinux_config_file = open(syslinux_cfg, 'w')
+    syslinux_config_file.write("TIMEOUT 300\n")
+    syslinux_config_file.write("include vesamenu.cfg\n")
+    syslinux_config_file.close()
+
+    prompt_name = open(syslinux_target + 'promptname.cfg', 'w')
+    prompt_name.write('menu label S^yslinux prompt\n')
+    prompt_name.close()
+
+    initial_syslinux_config(syslinux_target)
+    flavour_filename = grml_flavour.replace('-', '_')
+
+    if search_file('default.cfg', syslinux_target):
+        modify_filenames(grml_flavour, syslinux_target, ['grml.cfg', 'default.cfg'])
+
+    filename = search_file("new_hidden.cfg", syslinux_target)
+
+
+    # process hidden file
+    if not search_file("hidden.cfg", syslinux_target):
+        new_hidden = syslinux_target + "hidden.cfg"
+        os.rename(filename, new_hidden)
+        adjust_syslinux_bootoptions(new_hidden, grml_flavour)
     else:
     else:
-        syslinux_config_file = open(syslinux_cfg, 'w')
-        GRML_DEFAULT = grml_flavour
-        syslinux_flavour_is_default = True
-        syslinux_config_file.write(generate_main_syslinux_config(grml_flavour, bootopt))
-        syslinux_config_file.close()
+        new_hidden =  "%s_hidden.cfg" % (flavour_filename)
+        new_hidden_file =  "%s/%s" % (syslinux_target, new_hidden)
+        os.rename(filename, new_hidden_file)
+        adjust_labels(new_hidden_file, r'\1 %s-\2' % grml_flavour)
+        adjust_syslinux_bootoptions(new_hidden_file, grml_flavour)
+        entry = 'include %s\n' % new_hidden
+        add_entry_if_not_present("%s/hiddens.cfg" % syslinux_target, entry)
 
 
-    # install flavour specific configuration only *once* as well
-    syslinux_flavour_config = True
-    if os.path.isfile(syslinux_cfg):
-        string = open(syslinux_cfg).readlines()
-        flavour = re.compile("grml2usb for %s: %s" % (re.escape(grml_flavour), re.escape(str(DATESTAMP))))
-        for line in string:
-            if flavour.match(line):
-                syslinux_flavour_config = False
 
 
-    if syslinux_flavour_config:
-        syslinux_config_file = open(syslinux_cfg, 'a')
-        # display only if the grml flavour isn't the default
-        if not syslinux_flavour_is_default:
-            GRML_FLAVOURS.add(grml_flavour)
-        syslinux_config_file.write(generate_flavour_specific_syslinux_config(grml_flavour, bootopt))
-        syslinux_config_file.close()
 
 
-    logging.debug("Generating isolinux/syslinux splash %s" % syslinux_target + 'boot.msg')
-    isolinux_splash = open(syslinux_target + 'boot.msg', 'w')
-    isolinux_splash.write(generate_isolinux_splash(grml_flavour))
-    isolinux_splash.close()
+    new_default = "%s_default.cfg" % (flavour_filename)
+    entry = 'include %s\n' % new_default
+    defaults_file = '%s/defaults.cfg' % syslinux_target
+    new_default_with_path = "%s/%s" % (syslinux_target, new_default)
+    new_grml_cfg = "%s/%s_grml.cfg" % ( syslinux_target, flavour_filename)
+
+    if os.path.isfile(defaults_file):
+
+        # remove default menu entry in menu
+        remove_default_entry(new_default_with_path)
+
+        # adjust all labels for additional isos
+        adjust_labels(new_default_with_path, r'\1 %s' % grml_flavour)
+        adjust_labels(new_grml_cfg, r'\1 %s-\2' % grml_flavour)
+
+    # always adjust bootoptions
+    adjust_syslinux_bootoptions(new_default_with_path, grml_flavour)
+    adjust_syslinux_bootoptions(new_grml_cfg, grml_flavour)
+
+    add_entry_if_not_present("%s/defaults.cfg" % syslinux_target, entry)
+
+    add_syslinux_entry("%s/additional.cfg" % syslinux_target, flavour_filename)
 
 
 def handle_bootloader_config(grml_flavour, device, target):
 
 
 def handle_bootloader_config(grml_flavour, device, target):
@@ -1454,13 +1722,15 @@ def handle_bootloader_config(grml_flavour, device, target):
     @device: device/partition where bootloader should be installed to
     @target: path of bootloader's configuration files"""
 
     @device: device/partition where bootloader should be installed to
     @target: path of bootloader's configuration files"""
 
+    global UUID
+    UUID = get_uuid(target)
     if options.skipsyslinuxconfig:
         logging.info("Skipping generation of syslinux configuration as requested.")
     else:
         try:
             handle_syslinux_config(grml_flavour, target)
         except CriticalException, error:
     if options.skipsyslinuxconfig:
         logging.info("Skipping generation of syslinux configuration as requested.")
     else:
         try:
             handle_syslinux_config(grml_flavour, target)
         except CriticalException, error:
-            logging.critical("Fatal: %s" % error)
+            logging.critical("Fatal: %s", error)
             sys.exit(1)
 
     if options.skipgrubconfig:
             sys.exit(1)
 
     if options.skipgrubconfig:
@@ -1469,16 +1739,17 @@ def handle_bootloader_config(grml_flavour, device, target):
         try:
             handle_grub_config(grml_flavour, device, target)
         except CriticalException, error:
         try:
             handle_grub_config(grml_flavour, device, target)
         except CriticalException, error:
-            logging.critical("Fatal: %s" % error)
+            logging.critical("Fatal: %s", error)
             sys.exit(1)
 
             sys.exit(1)
 
+
 def handle_dir(live_image, device):
     """Main logic for copying files of the currently running grml system.
 
     @live_image: directory where currently running live system resides (usually /live/image)
     @device: partition where the specified ISO should be installed to"""
 
 def handle_dir(live_image, device):
     """Main logic for copying files of the currently running grml system.
 
     @live_image: directory where currently running live system resides (usually /live/image)
     @device: partition where the specified ISO should be installed to"""
 
-    logging.info("Using %s as install base" % live_image)
+    logging.info("Using %s as install base", live_image)
 
     if os.path.isdir(device):
         logging.info("Specified target is a directory, therefore not mounting.")
 
     if os.path.isdir(device):
         logging.info("Specified target is a directory, therefore not mounting.")
@@ -1491,15 +1762,21 @@ def handle_dir(live_image, device):
         try:
             mount(device, device_mountpoint, "")
         except CriticalException, error:
         try:
             mount(device, device_mountpoint, "")
         except CriticalException, error:
-            logging.critical("Fatal: %s" % error)
+            logging.critical("Fatal: %s", error)
             cleanup()
             sys.exit(1)
 
     try:
         try:
             cleanup()
             sys.exit(1)
 
     try:
         try:
-            grml_flavour = identify_grml_flavour(live_image)
-            logging.info("Identified grml flavour \"%s\"." % grml_flavour)
-            install_iso_files(grml_flavour, live_image, device, device_mountpoint)
+            grml_flavours = identify_grml_flavour(live_image)
+            worked_flavours = []
+            for flavour in grml_flavours:
+                if flavour in worked_flavours:
+                    continue
+                else:
+                    worked_flavours.append(flavour)
+                logging.info("Identified grml flavour \"%s\".", flavour)
+                install_iso_files(flavour, live_image, device, device_mountpoint)
         except TypeError:
             logging.critical("Fatal: a critical error happend during execution (not a grml ISO?), giving up")
             sys.exit(1)
         except TypeError:
             logging.critical("Fatal: a critical error happend during execution (not a grml ISO?), giving up")
             sys.exit(1)
@@ -1511,7 +1788,7 @@ def handle_dir(live_image, device):
                     os.rmdir(device_mountpoint)
                     unregister_tmpfile(device_mountpoint)
             except CriticalException, error:
                     os.rmdir(device_mountpoint)
                     unregister_tmpfile(device_mountpoint)
             except CriticalException, error:
-                logging.critical("Fatal: %s" % error)
+                logging.critical("Fatal: %s", error)
                 cleanup()
 
 
                 cleanup()
 
 
@@ -1521,21 +1798,21 @@ def handle_iso(iso, device):
     @iso: full path to the ISO that should be installed to the specified device
     @device: partition where the specified ISO should be installed to"""
 
     @iso: full path to the ISO that should be installed to the specified device
     @device: partition where the specified ISO should be installed to"""
 
-    logging.info("Using ISO %s" % iso)
+    logging.info("Using ISO %s", iso)
 
     iso_mountpoint = tempfile.mkdtemp(prefix="grml2usb")
     register_tmpfile(iso_mountpoint)
     remove_iso_mountpoint = True
 
     if not os.path.isfile(iso):
 
     iso_mountpoint = tempfile.mkdtemp(prefix="grml2usb")
     register_tmpfile(iso_mountpoint)
     remove_iso_mountpoint = True
 
     if not os.path.isfile(iso):
-        logging.critical("Fatal: specified ISO %s could not be read" % iso)
+        logging.critical("Fatal: specified ISO %s could not be read", iso)
         cleanup()
         sys.exit(1)
 
     try:
         mount(iso, iso_mountpoint, ["-o", "loop", "-t", "iso9660"])
     except CriticalException, error:
         cleanup()
         sys.exit(1)
 
     try:
         mount(iso, iso_mountpoint, ["-o", "loop", "-t", "iso9660"])
     except CriticalException, error:
-        logging.critical("Fatal: %s" % error)
+        logging.critical("Fatal: %s", error)
         sys.exit(1)
 
     if os.path.isdir(device):
         sys.exit(1)
 
     if os.path.isdir(device):
@@ -1548,17 +1825,27 @@ def handle_iso(iso, device):
         register_tmpfile(device_mountpoint)
         remove_device_mountpoint = True
         try:
         register_tmpfile(device_mountpoint)
         remove_device_mountpoint = True
         try:
-            mount(device, device_mountpoint, "")
+            check_for_fat(device)
+            mount(device, device_mountpoint, ['-o', 'utf8,iocharset=iso8859-1'])
         except CriticalException, error:
         except CriticalException, error:
-            logging.critical("Fatal: %s" % error)
-            cleanup()
-            sys.exit(1)
+            try:
+                mount(device, device_mountpoint, "")
+            except CriticalException, error:
+                logging.critical("Fatal: %s", error)
+                cleanup()
+                sys.exit(1)
 
     try:
         try:
 
     try:
         try:
-            grml_flavour = identify_grml_flavour(iso_mountpoint)
-            logging.info("Identified grml flavour \"%s\"." % grml_flavour)
-            install_iso_files(grml_flavour, iso_mountpoint, device, device_mountpoint)
+            grml_flavours = identify_grml_flavour(iso_mountpoint)
+            worked_flavours = []
+            for flavour in grml_flavours:
+                if flavour in worked_flavours:
+                    continue
+                else:
+                    worked_flavours.append(flavour)
+                logging.info("Identified grml flavour \"%s\".", flavour)
+                install_iso_files(flavour, iso_mountpoint, device, device_mountpoint)
         except TypeError:
             logging.critical("Fatal: a critical error happend during execution (not a grml ISO?), giving up")
             sys.exit(1)
         except TypeError:
             logging.critical("Fatal: a critical error happend during execution (not a grml ISO?), giving up")
             sys.exit(1)
@@ -1574,7 +1861,7 @@ def handle_iso(iso, device):
                     os.rmdir(device_mountpoint)
                     unregister_tmpfile(device_mountpoint)
             except CriticalException, error:
                     os.rmdir(device_mountpoint)
                     unregister_tmpfile(device_mountpoint)
             except CriticalException, error:
-                logging.critical("Fatal: %s" % error)
+                logging.critical("Fatal: %s", error)
                 cleanup()
 
 
                 cleanup()
 
 
@@ -1596,7 +1883,7 @@ def handle_mbr(device):
     # into /dev/loop of course, therefore use /dev/loop1 as mbr_device
     if mbr_device == "/dev/loop":
         mbr_device = device
     # into /dev/loop of course, therefore use /dev/loop1 as mbr_device
     if mbr_device == "/dev/loop":
         mbr_device = device
-        logging.info("Detected loop device - using %s as MBR device therefore" % mbr_device)
+        logging.info("Detected loop device - using %s as MBR device therefore", mbr_device)
         skip_install_mir_mbr = True
 
     try:
         skip_install_mir_mbr = True
 
     try:
@@ -1621,16 +1908,24 @@ def handle_vfat(device):
     @device: device that should checked / formated"""
 
     # make sure we have mkfs.vfat available
     @device: device that should checked / formated"""
 
     # make sure we have mkfs.vfat available
-    if options.fat16 and not options.force:
+    if options.fat16:
         if not which("mkfs.vfat") and not options.copyonly and not options.dryrun:
             logging.critical('Sorry, mkfs.vfat not available. Exiting.')
             logging.critical('Please make sure to install dosfstools.')
             sys.exit(1)
 
         if not which("mkfs.vfat") and not options.copyonly and not options.dryrun:
             logging.critical('Sorry, mkfs.vfat not available. Exiting.')
             logging.critical('Please make sure to install dosfstools.')
             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 specified partition with fat16? y/N ")
-        if f == "y" or f == "Y":
-            logging.info("Note: you can skip this question using the option --force")
+        exec_mkfs = False
+        if options.force:
+            print "Forcing mkfs.fat16 on %s as requested via option --force." % device
+            exec_mkfs = True
+        else:
+            # make sure the user is aware of what he is doing
+            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")
+                exec_mkfs = True
+
+        if exec_mkfs:
             try:
                 mkfs_fat16(device)
             except CriticalException, error:
             try:
                 mkfs_fat16(device)
             except CriticalException, error:
@@ -1642,12 +1937,12 @@ def handle_vfat(device):
     # check for vfat filesystem
     if device is not None and not os.path.isdir(device):
         try:
     # check for vfat filesystem
     if device is not None and not os.path.isdir(device):
         try:
-            check_for_fat(device)
+            if options.syslinux: check_for_fat(device)
         except CriticalException, error:
             logging.critical("Execution failed: %s", error)
             sys.exit(1)
 
         except CriticalException, error:
             logging.critical("Execution failed: %s", error)
             sys.exit(1)
 
-    if not os.path.isdir(device) and not check_for_usbdevice(device):
+    if not os.path.isdir(device) and not check_for_usbdevice(device) and not option.force:
         print "Warning: the specified device %s does not look like a removable usb device." % device
         f = raw_input("Do you really want to continue? y/N ")
         if f == "y" or f == "Y":
         print "Warning: the specified device %s does not look like a removable usb device." % device
         f = raw_input("Do you really want to continue? y/N ")
         if f == "y" or f == "Y":
@@ -1700,13 +1995,16 @@ def handle_bootloader(device):
     if options.copyonly:
         logging.info("Not installing bootloader and its files as requested via option copyonly.")
     elif os.path.isdir(device):
     if options.copyonly:
         logging.info("Not installing bootloader and its files as requested via option copyonly.")
     elif os.path.isdir(device):
-        logging.info("Not installing bootloader as %s is a directory." % device)
+        logging.info("Not installing bootloader as %s is a directory.", device)
     else:
         install_bootloader(device)
 
 
 def main():
     """Main function [make pylint happy :)]"""
     else:
         install_bootloader(device)
 
 
 def main():
     """Main function [make pylint happy :)]"""
+    global GRML_FLAVOURS
+    global GRML_DEFAULT
+    global PROG_VERSION
 
     if options.version:
         print os.path.basename(sys.argv[0]) + " " + PROG_VERSION
 
     if options.version:
         print os.path.basename(sys.argv[0]) + " " + PROG_VERSION
@@ -1726,6 +2024,10 @@ def main():
     if options.dryrun:
         logging.info("Running in simulation mode as requested via option dry-run.")
 
     if options.dryrun:
         logging.info("Running in simulation mode as requested via option dry-run.")
 
+    if options.grubmbr and not options.grub:
+        logging.critical("Error: --grub-mbr requires --grub option.")
+        sys.exit(1)
+
     # specified arguments
     device = args[len(args) - 1]
     isos = args[0:len(args) - 1]
     # specified arguments
     device = args[len(args) - 1]
     isos = args[0:len(args) - 1]
@@ -1764,13 +2066,13 @@ def main():
 
     handle_bootloader(device)
 
 
     handle_bootloader(device)
 
-    logging.info("Note: grml flavour %s was installed as the default booting system." % GRML_DEFAULT)
+    logging.info("Note: grml flavour %s was installed as the default booting system.", GRML_DEFAULT)
 
     for flavour in GRML_FLAVOURS:
 
     for flavour in GRML_FLAVOURS:
-        logging.info("Note: you can boot flavour %s using '%s' on the commandline." % (flavour, flavour))
+        logging.info("Note: you can boot flavour %s using '%s' on the commandline.", flavour, flavour)
 
     # finally be politely :)
 
     # finally be politely :)
-    logging.info("Finished execution of grml2usb (%s). Have fun with your grml system." % PROG_VERSION)
+    logging.info("Finished execution of grml2usb (%s). Have fun with your grml system.", PROG_VERSION)
 
 
 if __name__ == "__main__":
 
 
 if __name__ == "__main__":