Don't nag users about gpxe.lkrn
[grml2usb.git] / grml2usb
index 752e2b5..8987450 100755 (executable)
--- a/grml2usb
+++ b/grml2usb
@@ -1,36 +1,51 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
+# pylint: disable-msg=C0302
 """
 grml2usb
 ~~~~~~~~
 
 This script installs a grml system (either a running system or ISO[s]) to a USB device
 
 """
 grml2usb
 ~~~~~~~~
 
 This script installs a grml system (either a running system or ISO[s]) to a USB device
 
-:copyright: (c) 2009 by Michael Prokop <mika@grml.org>
+:copyright: (c) 2009, 2010, 2011 by Michael Prokop <mika@grml.org>
 :license: GPL v2 or any later version
 :bugreports: http://grml.org/bugs/
 
 """
 
 :license: GPL v2 or any later version
 :bugreports: http://grml.org/bugs/
 
 """
 
-# 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
 import fileinput
 import glob
 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
+import struct
 
 # global variables
 
 # global variables
-PROG_VERSION = "0.9.18-pre1"
+PROG_VERSION = "0.9.31"
 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
+SYSLINUX_LIBS = "/usr/lib/syslinux/"
 
 
-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)
+def syslinux_warning(option, opt, value, opt_parser):
+    """A helper function for printing a warning about deprecated option
+    """
+    # pylint: disable-msg=W0613
+    sys.stderr.write("Note: the --syslinux option is deprecated as syslinux "
+                     "is grml2usb's default. Continuing anyway.\n")
+    setattr(opt_parser.values, option.dest, True)
+
+# if grub option is set, unset syslinux option
+def grub_option(option, opt, value, opt_parser):
+    """A helper function adjusting other option values
+    """
+    # pylint: disable-msg=W0613
+    setattr(opt_parser.values, option.dest, True)
+    setattr(opt_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\
@@ -42,9 +57,10 @@ grub or syslinux and root access.\n\
 Run %prog --help for usage hints, further information via: man grml2usb"
 
 # pylint: disable-msg=C0103
 Run %prog --help for usage hints, further information via: man grml2usb"
 
 # pylint: disable-msg=C0103
+# pylint: disable-msg=W0603
 parser = OptionParser(usage=USAGE)
 parser.add_option("--bootoptions", dest="bootoptions",
 parser = OptionParser(usage=USAGE)
 parser.add_option("--bootoptions", dest="bootoptions",
-                  action="store", type="string",
+                  action="append", type="string",
                   help="use specified bootoptions as default")
 parser.add_option("--bootloader-only", dest="bootloaderonly", action="store_true",
                   help="do not copy files but just install a bootloader")
                   help="use specified bootoptions as default")
 parser.add_option("--bootloader-only", dest="bootloaderonly", action="store_true",
                   help="do not copy files but just install a bootloader")
@@ -56,7 +72,8 @@ parser.add_option("--fat16", dest="fat16", action="store_true",
                   help="format specified partition with FAT16")
 parser.add_option("--force", dest="force", action="store_true",
                   help="force any actions requiring manual interaction")
                   help="format specified partition with FAT16")
 parser.add_option("--force", dest="force", action="store_true",
                   help="force any actions requiring manual interaction")
-parser.add_option("--grub", dest="grub", action="store_true",
+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")
                   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")
@@ -107,7 +124,7 @@ class CriticalException(Exception):
 # arrays, e.g. in MBR creation.
 
 
 # arrays, e.g. in MBR creation.
 
 
-def array2string(a):
+def array2string(*a):
     """Convert a list of integers [0;255] to a string."""
     return struct.pack("%sB" % len(a), *a)
 
     """Convert a list of integers [0;255] to a string."""
     return struct.pack("%sB" % len(a), *a)
 
@@ -128,6 +145,8 @@ def cleanup():
     try:
         for device in MOUNTED:
             unmount(device, "")
     try:
         for device in MOUNTED:
             unmount(device, "")
+        for tmpfile in TMPFILES:
+            os.unlink(tmpfile)
     # ignore: RuntimeError: Set changed size during iteration
     except RuntimeError:
         logging.debug('caught expection RuntimeError, ignoring')
     # ignore: RuntimeError: Set changed size during iteration
     except RuntimeError:
         logging.debug('caught expection RuntimeError, ignoring')
@@ -135,7 +154,7 @@ def cleanup():
 
 def register_tmpfile(path):
     """
 
 def register_tmpfile(path):
     """
-    TODO - not implemented yet
+    register tmpfile
     """
 
     TMPFILES.add(path)
     """
 
     TMPFILES.add(path)
@@ -143,11 +162,13 @@ def register_tmpfile(path):
 
 def unregister_tmpfile(path):
     """
 
 def unregister_tmpfile(path):
     """
-    TODO - not implemented yet
+    remove registered tmpfile
     """
 
     """
 
-    if path in TMPFILES:
+    try:
         TMPFILES.remove(path)
         TMPFILES.remove(path)
+    except KeyError:
+        pass
 
 
 def register_mountpoint(target):
 
 
 def register_mountpoint(target):
@@ -184,7 +205,6 @@ def execute(f, *exec_arguments):
     the command (default) or when using --dry-run commandline option
     just displays what would be executed."""
     # usage: execute(subprocess.Popen, (["ls", "-la"]))
     the command (default) or when using --dry-run commandline option
     just displays what would be executed."""
     # usage: execute(subprocess.Popen, (["ls", "-la"]))
-    # 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)))
     if options.dryrun:
         # pylint: disable-msg=W0141
         logging.debug('dry-run only: %s(%s)', get_function_name(f), ', '.join(map(repr, exec_arguments)))
@@ -218,6 +238,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 directory in bootloader_dirs:
+        for name in name, \
+        "%s_%s" % (get_flavour_filename(flavour), name):
+            if os.path.isfile(iso_mount + directory + name):
+                return (directory, 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
 
@@ -226,10 +257,22 @@ 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):
+        """Helper function ffor testing if specified file exists in cwd
+
+        @cwd: current working directory
+        """
+        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:
@@ -281,7 +324,7 @@ if loadfont /boot/grub/ascii.pf2 ; then
    set gfxmode=640x480
    insmod gfxterm
    insmod vbe
    set gfxmode=640x480
    insmod gfxterm
    insmod vbe
-   if terminal_output.gfxterm ; then true ; else
+   if terminal_output gfxterm ; then true ; else
     # For backward compatibility with versions of terminal.mod that don't
     # understand terminal_output
     terminal gfxterm
     # For backward compatibility with versions of terminal.mod that don't
     # understand terminal_output
     terminal gfxterm
@@ -298,7 +341,7 @@ fi
 
 menuentry "%(grml_flavour)s (default)" {
     set gfxpayload=1024x768x16,1024x768
 
 menuentry "%(grml_flavour)s (default)" {
     set gfxpayload=1024x768x16,1024x768
-    linux   /boot/release/%(flavour_filename)s/linux26 apm=power-off quiet boot=live nomce live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
+    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
 }
 
     initrd  /boot/release/%(flavour_filename)s/initrd.gz
 }
 
@@ -316,17 +359,48 @@ menuentry "Boot FreeDOS" {
     initrd  /boot/addons/balder10.imz
 }
 
     initrd  /boot/addons/balder10.imz
 }
 
-menuentry "Boot MirOS bsd4grml" {
-    multiboot /boot/addons/bsd4grml/ldbsd.com
-    module    /boot/addons/bsd4grml/bsd.rd
-    module    /boot/addons/bsd4grml/boot.1
-    module    /boot/addons/bsd4grml/boot.2
-    module    /boot/addons/bsd4grml/boot.3
-    module    /boot/addons/bsd4grml/boot.4
-    module    /boot/addons/bsd4grml/boot.5
-    module    /boot/addons/bsd4grml/boot.6
-    module    /boot/addons/bsd4grml/boot.cfg
-}
+if [ ${iso_path} ] ; then
+    # assume loopback.cfg boot
+    if [ -e /boot/addons/bsd4grml/loopback.0 ] ; then
+        # bsd4grml 20100815 and later
+        menuentry "Boot MirOS bsd4grml" {
+            multiboot /boot/addons/bsd4grml/ldbsd.com
+            module /boot/addons/bsd4grml/bsd.rd bsd
+            module /boot/addons/bsd4grml/loopback.0 boot.cfg
+            module /boot/addons/bsd4grml/loopback.1 boot.1
+            module /boot/addons/bsd4grml/loopback.2 boot.2
+            module /boot/addons/bsd4grml/loopback.3 boot.3
+            module /boot/addons/bsd4grml/loopback.4 boot.4
+            module /boot/addons/bsd4grml/loopback.5 boot.5
+            module /boot/addons/bsd4grml/loopback.6 boot.6
+        }
+    else
+        # old bsd4grml
+        menuentry "Boot MirOS bsd4grml" {
+            multiboot /boot/addons/bsd4grml/ldbsd.com
+            module /boot/addons/bsd4grml/bsd.rd bsd.rd
+            module /boot/addons/bsd4grml/boot.cfg boot.cfg
+            module /boot/addons/bsd4grml/boot.1 boot.1
+            module /boot/addons/bsd4grml/boot.2 boot.2
+            module /boot/addons/bsd4grml/boot.3 boot.3
+            module /boot/addons/bsd4grml/boot.4 boot.4
+            module /boot/addons/bsd4grml/boot.5 boot.5
+        }
+    fi
+else
+    # assume grub.cfg boot
+    menuentry "Boot MirOS bsd4grml" {
+        multiboot /boot/addons/bsd4grml/ldbsd.com
+        module /boot/addons/bsd4grml/bsd.rd bsd.rd
+        module /boot/addons/bsd4grml/boot.cfg boot.cfg
+        module /boot/addons/bsd4grml/boot.1 boot.1
+        module /boot/addons/bsd4grml/boot.2 boot.2
+        module /boot/addons/bsd4grml/boot.3 boot.3
+        module /boot/addons/bsd4grml/boot.4 boot.4
+        module /boot/addons/bsd4grml/boot.5 boot.5
+        module /boot/addons/bsd4grml/boot.6 boot.6
+    }
+fi
 
 menuentry "Boot OS of first partition on first disk" {
     set root=(hd0,1)
 
 menuentry "Boot OS of first partition on first disk" {
     set root=(hd0,1)
@@ -334,8 +408,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,
-        'flavour_filename': grml_flavour.replace('-', ''),
-        '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):
@@ -350,60 +424,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/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
+    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
     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
-    linux  /boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet persistent live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
+    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
     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
-    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 %(bootoptions)s
+    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
     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
-    linux /boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ debug initcall_debug%(bootoptions)s
+    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
     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
-    linux  /boot/release/%(flavour_filename)s/linux26 apm=power-off boot=live nomce quiet live-media-path=/live/%(grml_flavour)s/ startx=wm-ng %(bootoptions)s
+    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" {
     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" {
-    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 %(bootoptions)s
+    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" {
     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" {
-    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 %(bootoptions)s
+    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
     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
-    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 %(bootoptions)s
+    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,
        'flavour_filename': grml_flavour.replace('-', ''),
     initrd /boot/release/%(flavour_filename)s/initrd.gz
 }
 
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
        'flavour_filename': grml_flavour.replace('-', ''),
-       'bootoptions': bootoptions } )
+       '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):
@@ -418,51 +492,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/%(flavour_filename)s/linux26 apm=power-off boot=live nomce vga=791 quiet live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
+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
 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
-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/ %(bootoptions)s
+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
 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
-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 %(bootoptions)s
+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
 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
-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%(bootoptions)s
+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
 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
-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 %(bootoptions)s
+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
 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
-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 %(bootoptions)s
+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
 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
-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 %(bootoptions)s
+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
 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
-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 %(bootoptions)s
+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
 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
-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 %(bootoptions)s
+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,
 initrd (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/initrd.gz
 
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
-       'flavour_filename': grml_flavour.replace('-', ''),
+       'flavour_filename': grml_flavour.replace('-', ''), 'uid': UUID,
        'bootoptions': bootoptions, 'install_partition': install_partition } )
 
 
        'bootoptions': bootoptions, 'install_partition': install_partition } )
 
 
@@ -484,7 +558,7 @@ 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/%(flavour_filename)s/linux26 apm=power-off vga=791 quiet boot=live nomce live-media-path=/live/%(grml_flavour)s/ %(bootoptions)s
+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+)
 initrd (hd0,%(install_partition)s)/boot/release/%(flavour_filename)s/initrd.gz
 
 title Memory test (memtest86+)
@@ -502,7 +576,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('-', ''),
+       'flavour_filename': grml_flavour.replace('-', ''), 'uid': UUID,
        'bootoptions': bootoptions, 'install_partition': install_partition } )
 
 
        'bootoptions': bootoptions, 'install_partition': install_partition } )
 
 
@@ -511,8 +585,6 @@ def generate_isolinux_splash(grml_flavour):
 
     @grml_flavour: name of grml flavour the configuration should be generated for"""
 
 
     @grml_flavour: name of grml flavour the configuration should be generated for"""
 
-    # TODO: adjust last bootsplash line (the one following the "Some information and boot ...")
-
     grml_name = grml_flavour
 
     return("""\
     grml_name = grml_flavour
 
     return("""\
@@ -523,12 +595,12 @@ 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(*args):
+def generate_main_syslinux_config(*arg):
     """Generate main configuration for use in syslinux.cfg
 
     """Generate main configuration for use in syslinux.cfg
 
-    @*args: just for backward compatibility"""
-
-    local_datestamp = DATESTAMP
+    @*arg: just for backward compatibility"""
+    # pylint: disable-msg=W0613
+    # remove warning about unused arg
 
     return("""\
 label -
 
     return("""\
 label -
@@ -599,7 +671,6 @@ def install_grub(device):
                 mount(device, device_mountpoint, "")
 
                 # If using --grub-mbr then make sure we install grub in MBR instead of PBR
                 mount(device, device_mountpoint, "")
 
                 # 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():
                 if options.grubmbr:
                     logging.debug("Using option --grub-mbr ...")
                     if device[-1:].isdigit():
@@ -610,15 +681,22 @@ def install_grub(device):
                     grub_device = device
 
                 logging.info("Installing grub as bootloader")
                     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",
-                    "--root-directory=%s" % device_mountpoint, grub_device], stdout=file(os.devnull, "r+"))
-                proc.wait()
+                for opt in ["", "--force" ]:
+                    logging.debug("grub-install --recheck %s --no-floppy --root-directory=%s %s",
+                                  opt, device_mountpoint, grub_device)
+                    proc = subprocess.Popen(["grub-install", "--recheck", opt, "--no-floppy",
+                                             "--root-directory=%s" % device_mountpoint, grub_device],
+                                            stdout=file(os.devnull, "r+"))
+                    proc.wait()
+                    if proc.returncode == 0:
+                        break
+
                 if proc.returncode != 0:
                     # raise Exception("error executing grub-install")
                 if proc.returncode != 0:
                     # raise Exception("error executing grub-install")
-                    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.")
+                    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 as grub considers PBR problematic.")
                     cleanup()
                     sys.exit(1)
             except CriticalException, error:
                     cleanup()
                     sys.exit(1)
             except CriticalException, error:
@@ -657,17 +735,12 @@ def install_bootloader(device):
 
     # by default we use grub, so install syslinux only on request
     if options.grub:
 
     # by default we use grub, so install syslinux only on request
     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)")
+        try:
+            install_grub(device)
+        except CriticalException, error:
+            logging.critical("Fatal: %s", error)
             cleanup()
             sys.exit(1)
             cleanup()
             sys.exit(1)
-        else:
-            try:
-                install_grub(device)
-            except CriticalException, error:
-                logging.critical("Fatal: %s", error)
-                cleanup()
-                sys.exit(1)
     else:
         try:
             install_syslinux(device)
     else:
         try:
             install_syslinux(device)
@@ -715,7 +788,6 @@ def install_syslinux_mbr(device):
     logging.info("Installing syslinux MBR")
     logging.debug("cat /usr/lib/syslinux/mbr.bin > %s", device)
     try:
     logging.info("Installing syslinux MBR")
     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:
             logging.critical("Error copying MBR to device (%s)", retcode)
         retcode = subprocess.call("cat /usr/lib/syslinux/mbr.bin > "+ device, shell=True)
         if retcode < 0:
             logging.critical("Error copying MBR to device (%s)", retcode)
@@ -764,15 +836,16 @@ def install_mir_mbr(mbrtemplate, device, partition, ismirbsdmbr=True):
     tmpf = tempfile.NamedTemporaryFile()
 
     logging.debug("executing: dd if='%s' of='%s' bs=512 count=1", device, tmpf.name)
     tmpf = tempfile.NamedTemporaryFile()
 
     logging.debug("executing: dd if='%s' of='%s' bs=512 count=1", device, tmpf.name)
-    proc = subprocess.Popen(["dd", "if=%s" % device, "of=%s" % tmpf.name, "bs=512", "count=1"], stderr=file(os.devnull, "r+"))
+    proc = 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,
     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)
+                  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)")
@@ -783,15 +856,15 @@ 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.seek(0)
     tmpf.file.truncate()
@@ -800,7 +873,7 @@ def install_mir_mbr(mbrtemplate, device, partition, ismirbsdmbr=True):
 
     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",
 
     logging.debug("executing: dd if='%s' of='%s' bs=512 count=1 conv=notrunc", tmpf.name, device)
     proc = subprocess.Popen(["dd", "if=%s" % tmpf.name, "of=%s" % device, "bs=512", "count=1",
-                            "conv=notrunc"], stderr=file(os.devnull, "r+"))
+                             "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)")
@@ -867,7 +940,8 @@ def mount(source, target, mount_options):
 
     for x in file('/proc/mounts').readlines():
         if x.startswith(source):
 
     for x in file('/proc/mounts').readlines():
         if x.startswith(source):
-            raise CriticalException("Error executing mount: %s already mounted - please unmount before invoking grml2usb" % source)
+            raise CriticalException("Error executing mount: %s already mounted - " % source
+                                    + "please unmount before invoking grml2usb")
 
     if os.path.isdir(source):
         logging.debug("Source %s is not a device, therefore not mounting.", source)
 
     if os.path.isdir(source):
         logging.debug("Source %s is not a device, therefore not mounting.", source)
@@ -936,17 +1010,19 @@ def check_for_fat(partition):
 
     @partition: device name of partition"""
 
 
     @partition: device name of partition"""
 
+    if not os.access(partition, os.R_OK):
+        raise CriticalException("Failed to read device %s"
+                " (wrong UID/permissions or device/directory not present?)" % 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()
 
         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":
-            raise CriticalException("Partition %s does not contain a FAT16 filesystem. (Use --fat16 or run mkfs.vfat %s)" % (partition, partition))
+        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("Sorry, /sbin/blkid not available (install e2fsprogs?)")
 
     except OSError:
         raise CriticalException("Sorry, /sbin/blkid not available (install e2fsprogs?)")
@@ -983,6 +1059,40 @@ def exec_rsync(source, target):
         sys.exit(1)
 
 
         sys.exit(1)
 
 
+def write_uuid(target_file):
+    """Generates an returns uuid and write it to the specified file
+
+    @target_file: filename to write the uuid to
+    """
+
+    fileh = open(target_file, 'w')
+    uid = str(uuid.uuid4())
+    fileh.write(uid)
+    fileh.close()
+    return uid
+
+
+def get_uuid(target):
+    """Get the uuid of the specified target. Will generate an uuid if none exist.
+
+    @target: directory/mountpoint containing the grml layout
+    """
+
+    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
 
@@ -992,31 +1102,41 @@ def copy_system_files(grml_flavour, iso_mount, target):
 
     squashfs = search_file(grml_flavour + '.squashfs', iso_mount)
     if squashfs is None:
 
     squashfs = search_file(grml_flavour + '.squashfs', iso_mount)
     if squashfs is None:
-        logging.critical("Fatal: squashfs file not found")
+        logging.critical("Fatal: squashfs file not found"
+        ", please check that your iso is not corrupt")
         raise CriticalException("error locating squashfs file")
     else:
         squashfs_target = target + '/live/' + grml_flavour + '/'
         execute(mkdir, squashfs_target)
     exec_rsync(squashfs, squashfs_target + grml_flavour + '.squashfs')
 
         raise CriticalException("error locating squashfs file")
     else:
         squashfs_target = target + '/live/' + grml_flavour + '/'
         execute(mkdir, squashfs_target)
     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")
         raise CriticalException("error locating filesystem.module file")
     else:
         exec_rsync(filesystem_module, squashfs_target + 'filesystem.module')
 
     if filesystem_module is None:
         logging.critical("Fatal: filesystem.module not found")
         raise CriticalException("error locating filesystem.module file")
     else:
         exec_rsync(filesystem_module, squashfs_target + 'filesystem.module')
 
-    release_target = target + '/boot/release/' + grml_flavour.replace('-', '')
+
+    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")
         raise CriticalException("error locating kernel file")
     else:
         exec_rsync(kernel, release_target + '/linux26')
 
     if kernel is None:
         logging.critical("Fatal kernel not found")
         raise CriticalException("error locating kernel file")
     else:
         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")
         raise CriticalException("error locating initrd file")
     if initrd is None:
         logging.critical("Fatal: initrd not found")
         raise CriticalException("error locating initrd file")
@@ -1024,6 +1144,50 @@ def copy_system_files(grml_flavour, iso_mount, target):
         exec_rsync(initrd, release_target + '/initrd.gz')
 
 
         exec_rsync(initrd, release_target + '/initrd.gz')
 
 
+def update_grml_versions(iso_mount, target):
+    """Update the grml version file on a cd
+    Returns true if version was updated successfully,
+    False if grml-version does not exist yet on the mountpoint
+
+    @iso_mount: string of the iso mount point
+    @target: path of the target mount point
+    """
+    grml_target = target + '/grml/'
+    target_grml_version_file = search_file('grml-version', grml_target)
+    if target_grml_version_file:
+        iso_grml_version_file = search_file('grml-version', iso_mount)
+        if not iso_grml_version_file:
+            logging.warn("Warning: %s could not be found - can not install it", iso_grml_version_file)
+            return False
+        try:
+            # read the flavours from the iso image
+            iso_versions = {}
+            iso_file = open(iso_grml_version_file, 'r')
+            for line in iso_file:
+                iso_versions[get_flavour(line)] = line.strip()
+
+            # update the existing flavours on the target
+            for line in fileinput.input([target_grml_version_file], inplace=1):
+                flavour = get_flavour(line)
+                if flavour in iso_versions.keys():
+                    print iso_versions.pop(flavour)
+                else:
+                    print line.strip()
+            fileinput.close()
+
+            target_file = open(target_grml_version_file, 'a')
+            # add the new flavours from the current iso
+            for flavour in iso_versions:
+                target_file.write("%s\n" % iso_versions[flavour])
+        except IOError:
+            logging.warn("Warning: Could not write file")
+        finally:
+            iso_file.close()
+            target_file.close()
+        return True
+    else:
+        return False
+
 def copy_grml_files(iso_mount, target):
     """copy some minor grml files to a given target
 
 def copy_grml_files(iso_mount, target):
     """copy some minor grml files to a given target
 
@@ -1033,7 +1197,12 @@ 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
+    if not update_grml_versions(iso_mount, target):
+        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)
         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)
@@ -1061,6 +1230,22 @@ def copy_grml_files(iso_mount, target):
             exec_rsync(grml_file, grml_webimg_target + myfile)
 
 
             exec_rsync(grml_file, grml_webimg_target + myfile)
 
 
+def handle_addon_copy(filename, dst, iso_mount, ignore_errors=False):
+    """handle copy of optional addons
+
+    @filename: filename of the addon
+    @dst: destination directory
+    @iso_mount: location of the iso mount
+    @ignore_errors: don't report missing files
+    """
+    file_location = search_file(filename, iso_mount)
+    if file_location is None:
+        if not ignore_errors:
+            logging.warn("Warning: %s not found (that's fine if you don't need it)",  filename)
+    else:
+        exec_rsync(file_location, dst)
+
+
 def copy_addons(iso_mount, target):
     """copy grml's addons files (like allinoneimg, bsd4grml,..) to a given target
 
 def copy_addons(iso_mount, target):
     """copy grml's addons files (like allinoneimg, bsd4grml,..) to a given target
 
@@ -1071,25 +1256,12 @@ def copy_addons(iso_mount, target):
     execute(mkdir, addons)
 
     # grub all-in-one image
     execute(mkdir, addons)
 
     # grub all-in-one image
-    allinoneimg = search_file('allinone.img', iso_mount)
-    if allinoneimg is None:
-        logging.warn("Warning: allinone.img not found (that's fine if you don't need it)")
-    else:
-        exec_rsync(allinoneimg, addons + 'allinone.img')
+    handle_addon_copy('allinone.img', addons, iso_mount)
 
     # bsd imag
 
     # 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:
-        exec_rsync(bsdimg, addons + '/')
+    handle_addon_copy('bsd4grml', addons, iso_mount)
 
 
-    # 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:
-        exec_rsync(balderimg, addons + 'balder10.imz')
+    handle_addon_copy('balder10.imz', addons, iso_mount)
 
     # install hdt and pci.ids only when using syslinux (grub doesn't support it)
     if options.syslinux:
 
     # install hdt and pci.ids only when using syslinux (grub doesn't support it)
     if options.syslinux:
@@ -1104,78 +1276,103 @@ def copy_addons(iso_mount, target):
             exec_rsync(picids, addons + '/pci.ids')
 
     # memdisk image
             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:
-        exec_rsync(memdiskimg, addons + 'memdisk')
+    handle_addon_copy('memdisk', addons, iso_mount)
 
     # memtest86+ image
 
     # 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:
-        exec_rsync(memtestimg, addons + 'memtest')
+    handle_addon_copy('memtest', addons, iso_mount)
 
 
-    # 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')
+    # gpxe.lkrn: got replaced by ipxe
+    handle_addon_copy('gpxe.lkrn', addons, iso_mount, ignore_errors=True)
+
+    # ipxe.lkrn
+    handle_addon_copy('ipxe.lkrn', addons, iso_mount)
+
+def glob_and_copy(filepattern, dst):
+    """Glob on specified filepattern and copy the result to dst
+
+    @filepattern: globbing pattern
+    @dst: target directory
+    """
+    for name in glob.glob(filepattern):
+        copy_if_exist(name, dst)
+
+def search_and_copy(filename, search_path, dst):
+    """Search for the specified filename at searchpath and copy it to dst
+
+    @filename: filename to look for
+    @search_path: base search file
+    @dst: destionation to copy the file to
+    """
+    file_location = search_file(filename, search_path)
+    copy_if_exist(file_location, dst)
+
+def copy_if_exist(filename, dst):
+    """Copy filename to dst if filename is set.
+
+    @filename: a filename
+    @dst: dst file
+    """
+    if filename and (os.path.isfile(filename) or os.path.isdir(filename)):
+        exec_rsync(filename, dst)
 
 
-def copy_bootloader_files(iso_mount, target):
-    """copy grml's bootloader files to a given target
+def copy_bootloader_files(iso_mount, target, grml_flavour):
+    """Copy grml's bootloader files to a given target
 
     @iso_mount: path where a grml ISO is mounted on
 
     @iso_mount: path where a grml ISO is mounted on
-    @target: path where grml's main files should be copied to"""
+    @target: path where grml's main files should be copied to
+    @grml_flavour: name of the current processed grml_flavour
+    """
 
     syslinux_target = target + '/boot/syslinux/'
     execute(mkdir, syslinux_target)
 
 
     syslinux_target = target + '/boot/syslinux/'
     execute(mkdir, syslinux_target)
 
+    grub_target = target + '/boot/grub/'
+    execute(mkdir, grub_target)
+
+
     logo = search_file('logo.16', iso_mount)
     exec_rsync(logo, syslinux_target + 'logo.16')
 
     logo = search_file('logo.16', iso_mount)
     exec_rsync(logo, syslinux_target + 'logo.16')
 
-    for ffile in ['f%d' % number for number in range(1,11) ]:
-        bootsplash = search_file(ffile, iso_mount)
-        if not bootsplash:
-            continue
-        exec_rsync(bootsplash, syslinux_target + ffile)
+
+    for ffile in ['f%d' % number for number in range(1, 11) ]:
+        search_and_copy(ffile, iso_mount, 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, "")
+        mkdir(os.path.join(target, 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')
 
 
     # 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')
 
-    bootloader_dirs = ['/boot/isolinux/', '/boot/syslinux/']
-    source_dir = None
-    for dir in bootloader_dirs:
-        if glob.glob(iso_mount + dir + '*default.cfg'):
-            source_dir = dir
-            break
-    else:
+    (source_dir, name) = get_defaults_file(iso_mount, grml_flavour, "default.cfg")
+    (source_dir, defaults_file) = get_defaults_file(iso_mount, grml_flavour, "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
 
         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 '*default.cfg', 'distri.cfg', \
-                    '*grml.cfg', 'grml.png', 'hd.cfg', 'isolinux.cfg', 'isolinux.bin', \
-                    'isoprompt.cfg', 'options.cfg', \
-                    'prompt.cfg', 'vesamenu.c32', 'vesamenu.cfg', 'grml.png':
-        files = glob.glob(iso_mount + source_dir + expr)
-        for path in files:
-            filename = os.path.basename(path)
-            exec_rsync(path, syslinux_target + filename)
+    for expr in name, 'distri.cfg', \
+        defaults_file, 'grml.png', 'hd.cfg', 'isolinux.cfg', 'isolinux.bin', \
+        'isoprompt.cfg', 'options.cfg', \
+        'prompt.cfg', 'vesamenu.cfg', 'grml.png', '*.c32':
+        glob_and_copy(iso_mount + source_dir + expr, syslinux_target)
+
+    for filename in glob.glob1(syslinux_target, "*.c32"):
+        copy_if_exist(os.path.join(SYSLINUX_LIBS, filename), syslinux_target)
+
 
     # copy the addons_*.cfg file to the new syslinux directory
 
     # 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)
+    glob_and_copy(iso_mount + source_dir + 'addon*.cfg', syslinux_target)
 
 
-    path = search_file('hidden.cfg', iso_mount + source_dir)
-    if path:
-        exec_rsync(path, syslinux_target + "new_" + 'hidden.cfg')
+    search_and_copy('hidden.cfg', iso_mount + source_dir, syslinux_target + "new_" + 'hidden.cfg')
 
 
     grub_target = target + '/boot/grub/'
 
 
     grub_target = target + '/boot/grub/'
@@ -1189,22 +1386,16 @@ def copy_bootloader_files(iso_mount, target):
         exec_rsync(GRML2USB_BASE + '/grub/splash.xpm.gz', grub_target + 'splash.xpm.gz')
 
     # grml splash in grub
         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"):
-        exec_rsync(GRML2USB_BASE + '/grub/grml.png', grub_target + 'grml.png')
+    copy_if_exist(GRML2USB_BASE + "/grub/grml.png", grub_target + 'grml.png')
 
     # font file for graphical bootsplash in grub
 
     # font file for graphical bootsplash in grub
-    if os.path.isfile("/usr/share/grub/ascii.pf2"):
-        exec_rsync('/usr/share/grub/ascii.pf2', grub_target + 'ascii.pf2')
+    copy_if_exist('/usr/share/grub/ascii.pf2', grub_target + 'ascii.pf2')
 
     # always copy grub content as it might be useful
 
     # 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)
+    glob_and_copy(iso_mount + '/boot/grub/*.mod', grub_target)
+    glob_and_copy(iso_mount + '/boot/grub/*.img', grub_target)
+    glob_and_copy(iso_mount + '/boot/grub/stage*', 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
@@ -1214,14 +1405,9 @@ def install_iso_files(grml_flavour, iso_mount, device, target):
     @device: device/partition where bootloader should be installed to
     @target: path where grml's main files should be copied to"""
 
     @device: device/partition where bootloader should be installed to
     @target: path where grml's main files should be copied to"""
 
-    # TODO => several improvements:
-    # * make sure grml_flavour, iso_mount, target are set when the function is called, otherwise raise exception
-    # * provide alternative search_file() if file information is stored in a config.ini file?
-    # * catch "install: .. No space left on device" & CO
-
+    global GRML_DEFAULT
+    GRML_DEFAULT = GRML_DEFAULT or grml_flavour
     if options.dryrun:
     if options.dryrun:
-        global GRML_DEFAULT
-        GRML_DEFAULT = grml_flavour
         return 0
     elif not options.bootloaderonly:
         logging.info("Copying files. This might take a while....")
         return 0
     elif not options.bootloaderonly:
         logging.info("Copying files. This might take a while....")
@@ -1239,7 +1425,7 @@ def install_iso_files(grml_flavour, iso_mount, device, target):
             copy_addons(iso_mount, target)
 
     if not options.copyonly:
             copy_addons(iso_mount, target)
 
     if not options.copyonly:
-        copy_bootloader_files(iso_mount, target)
+        copy_bootloader_files(iso_mount, target, grml_flavour)
 
         if not options.dryrun:
             handle_bootloader_config(grml_flavour, device, target)
 
         if not options.dryrun:
             handle_bootloader_config(grml_flavour, device, target)
@@ -1249,14 +1435,10 @@ def install_iso_files(grml_flavour, iso_mount, device, target):
     proc.wait()
 
 
     proc.wait()
 
 
-def uninstall_files(device):
-    """Get rid of all grml files on specified device
-
-    @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)
-
+def get_flavour(flavour_str):
+    """Returns the flavour of a grml version string
+    """
+    return re.match(r'[\w-]*', flavour_str).group()
 
 def identify_grml_flavour(mountpath):
     """Get name of grml flavour
 
 def identify_grml_flavour(mountpath):
     """Get name of grml flavour
@@ -1270,20 +1452,29 @@ 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
     except Exception, e:
         logging.critical("Unexpected error: %s", e)
         raise
         raise
     except Exception, e:
         logging.critical("Unexpected error: %s", e)
         raise
+    finally:
+        if tmpfile:
+            tmpfile.close()
 
 
-    return grml_flavour
+    return flavours
 
 
 def modify_grub_config(filename):
 
 
 def modify_grub_config(filename):
+    """Adjust bootoptions for a grub file
+
+    @filename: filename to modify
+    """
     if options.removeoption:
         regexe = []
         for regex in options.removeoption:
     if options.removeoption:
         regexe = []
         for regex in options.removeoption:
@@ -1358,7 +1549,7 @@ def handle_grub2_config(grml_flavour, grub_target, bootopt):
 
     # grub2 config
     grub2_cfg = grub_target + 'grub.cfg'
 
     # grub2 config
     grub2_cfg = grub_target + 'grub.cfg'
-    logging.debug("Creating grub2 configuration file (grub.lst)")
+    logging.debug("Creating grub2 configuration file (grub.cfg)")
 
     global GRML_DEFAULT
 
 
     global GRML_DEFAULT
 
@@ -1400,6 +1591,20 @@ def handle_grub2_config(grml_flavour, grub_target, bootopt):
     modify_grub_config(grub2_cfg)
 
 
     modify_grub_config(grub2_cfg)
 
 
+def get_bootoptions(grml_flavour):
+    """Returns bootoptions for specific flavour
+
+    @grml_flavour: name of the grml_flavour
+    """
+    # do NOT write "None" in kernel cmdline
+    if not options.bootoptions:
+        bootopt = ""
+    else:
+        bootopt = " ".join(options.bootoptions)
+    bootopt = bootopt.replace("%flavour", grml_flavour)
+    return bootopt
+
+
 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
 
@@ -1410,7 +1615,6 @@ def handle_grub_config(grml_flavour, device, target):
     logging.debug("Generating grub configuration")
 
     grub_target = target + '/boot/grub/'
     logging.debug("Generating grub configuration")
 
     grub_target = target + '/boot/grub/'
-    execute(mkdir, grub_target)
 
     if os.path.isdir(device):
         install_grub1_partition = None
 
     if os.path.isdir(device):
         install_grub1_partition = None
@@ -1420,11 +1624,8 @@ def handle_grub_config(grml_flavour, device, target):
         else:
             raise CriticalException("error validating partition schema (raw device?)")
 
         else:
             raise CriticalException("error validating partition schema (raw device?)")
 
-    # do NOT write "None" in kernel cmdline
-    if options.bootoptions is None:
-        bootopt = ""
-    else:
-        bootopt = options.bootoptions
+
+    bootopt = get_bootoptions(grml_flavour)
 
     # write menu.lst
     handle_grub1_config(grml_flavour, install_grub1_partition, grub_target, bootopt)
 
     # write menu.lst
     handle_grub1_config(grml_flavour, install_grub1_partition, grub_target, bootopt)
@@ -1443,7 +1644,7 @@ def initial_syslinux_config(target):
         return
     data = open(filename, "w")
     data.write(generate_main_syslinux_config())
         return
     data = open(filename, "w")
     data.write(generate_main_syslinux_config())
-    data.close
+    data.close()
 
     filename = target + "hiddens.cfg"
     data = open(filename, "w")
 
     filename = target + "hiddens.cfg"
     data = open(filename, "w")
@@ -1451,6 +1652,11 @@ def initial_syslinux_config(target):
     data.close()
 
 def add_entry_if_not_present(filename, entry):
     data.close()
 
 def add_entry_if_not_present(filename, entry):
+    """Write entry into filename if entry is not already in the file
+
+    @filanme: name of the file
+    @entry: data to write to the file
+    """
     data = open(filename, "a+")
     for line in data:
         if line == entry:
     data = open(filename, "a+")
     for line in data:
         if line == entry:
@@ -1460,19 +1666,29 @@ def add_entry_if_not_present(filename, entry):
 
     data.close()
 
 
     data.close()
 
+def get_flavour_filename(flavour):
+    """Generate a iso9960 save filename out of the specified flavour
 
 
+    @flavour: grml flavour
+    """
+    return flavour.replace('-', '_')
 
 def adjust_syslinux_bootoptions(src, flavour):
 
 def adjust_syslinux_bootoptions(src, flavour):
-    append_re = re.compile("^(\s*append.*)$", re.I)
+    """Adjust existing bootoptions of specified syslinux config to
+    grml2usb specific ones, e.g. change the location of the kernel...
+
+    @src: config file to alter
+    @flavour: grml 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)")
     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
+    bootopt = get_bootoptions(flavour)
 
     regexe = []
     option_re = None
 
     regexe = []
     option_re = None
@@ -1486,8 +1702,11 @@ def adjust_syslinux_bootoptions(src, flavour):
         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 = 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 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)
         if option_re and option_re.search(line):
             for regex in regexe:
                 line = regex.sub(' ', line)
@@ -1495,6 +1714,9 @@ def adjust_syslinux_bootoptions(src, flavour):
     fileinput.close()
 
 def adjust_labels(src, replacement):
     fileinput.close()
 
 def adjust_labels(src, replacement):
+    """Adjust the specified labels in the syslinux config file src with
+    specified 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)
     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)
@@ -1503,6 +1725,12 @@ def adjust_labels(src, replacement):
 
 
 def add_syslinux_entry(filename, grml_flavour):
 
 
 def add_syslinux_entry(filename, grml_flavour):
+    """Add includes for a specific grml_flavour to the specified filename
+
+    @filename: syslinux config file
+    @grml_flavour: grml flavour to add
+    """
+
     entry_filename = "option_%s.cfg" % grml_flavour
     entry = "include %s\n" % entry_filename
 
     entry_filename = "option_%s.cfg" % grml_flavour
     entry = "include %s\n" % entry_filename
 
@@ -1514,18 +1742,28 @@ def add_syslinux_entry(filename, grml_flavour):
     data.close()
 
 def modify_filenames(grml_flavour, target, filenames):
     data.close()
 
 def modify_filenames(grml_flavour, target, filenames):
+    """Replace the standarf filenames with the new ones
+
+    @grml_flavour: grml-flavour strin
+    @target: directory where the files are located
+    @filenames: list of filenames to alter
+    """
     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)
     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)
-        adjust_syslinux_bootoptions(new_filename, grml_flavour)
 
 
 def remove_default_entry(filename):
 
 
 def remove_default_entry(filename):
+    """Remove the default entry from specified syslinux file
+
+    @filename: syslinux config file
+    """
     default_re = re.compile("^(\s*menu\s*default\s*)$", re.I)
     for line in fileinput.input(filename, inplace=1):
     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
+        if default_re.match(line):
+            continue
         sys.stdout.write(line)
     fileinput.close()
 
         sys.stdout.write(line)
     fileinput.close()
 
@@ -1536,22 +1774,14 @@ def handle_syslinux_config(grml_flavour, target):
     @grml_flavour: name of grml flavour the configuration should be generated for
     @target: path of syslinux's configuration files"""
 
     @grml_flavour: name of grml flavour the configuration should be generated for
     @target: path of syslinux's configuration files"""
 
-    # do NOT write "None" in kernel cmdline
-    if options.bootoptions is None:
-        bootopt = ""
-    else:
-        bootopt = options.bootoptions
-
     logging.debug("Generating syslinux configuration")
     syslinux_target = target + '/boot/syslinux/'
     # should be present via  copy_bootloader_files(), but make sure it exits:
     execute(mkdir, syslinux_target)
     syslinux_cfg = syslinux_target + 'syslinux.cfg'
 
     logging.debug("Generating syslinux configuration")
     syslinux_target = target + '/boot/syslinux/'
     # should be present via  copy_bootloader_files(), but make sure it exits:
     execute(mkdir, syslinux_target)
     syslinux_cfg = syslinux_target + 'syslinux.cfg'
 
-    global GRML_DEFAULT
 
     # install main configuration only *once*, no matter how many ISOs we have:
 
     # install main configuration only *once*, no matter how many ISOs we have:
-    syslinux_flavour_is_default = False
     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 = open(syslinux_cfg, 'w')
     syslinux_config_file.write("TIMEOUT 300\n")
     syslinux_config_file.write("include vesamenu.cfg\n")
@@ -1562,25 +1792,25 @@ def handle_syslinux_config(grml_flavour, target):
     prompt_name.close()
 
     initial_syslinux_config(syslinux_target)
     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)
 
 
     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)
 
 
-    flavour_filename = grml_flavour.replace('-', '_')
     # 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:
     # 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:
-        new_hidden =  "%s_hidden.cfg" % (flavour_filename)
-        new_hidden_file =  "%s/%s" % (syslinux_target, new_hidden)
+        new_hidden_file =  "%s/%s_hidden.cfg" % (syslinux_target, flavour_filename)
         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)
         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
+        entry = 'include %s_hidden.cfg\n' % flavour_filename
         add_entry_if_not_present("%s/hiddens.cfg" % syslinux_target, entry)
 
 
         add_entry_if_not_present("%s/hiddens.cfg" % syslinux_target, entry)
 
 
@@ -1588,10 +1818,10 @@ def handle_syslinux_config(grml_flavour, target):
     new_default = "%s_default.cfg" % (flavour_filename)
     entry = 'include %s\n' % new_default
     defaults_file = '%s/defaults.cfg' % syslinux_target
     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):
 
     if os.path.isfile(defaults_file):
-        new_default_with_path = "%s/%s" % (syslinux_target, new_default)
-        new_grml_cfg = "%s/%s_grml.cfg" % ( syslinux_target, flavour_filename)
 
         # remove default menu entry in menu
         remove_default_entry(new_default_with_path)
 
         # remove default menu entry in menu
         remove_default_entry(new_default_with_path)
@@ -1600,6 +1830,9 @@ def handle_syslinux_config(grml_flavour, target):
         adjust_labels(new_default_with_path, r'\1 %s' % grml_flavour)
         adjust_labels(new_grml_cfg, r'\1 %s-\2' % grml_flavour)
 
         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_entry_if_not_present("%s/defaults.cfg" % syslinux_target, entry)
 
@@ -1613,6 +1846,8 @@ 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:
     if options.skipsyslinuxconfig:
         logging.info("Skipping generation of syslinux configuration as requested.")
     else:
@@ -1632,111 +1867,87 @@ def handle_bootloader_config(grml_flavour, device, target):
             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 install(image, device):
+    """Install a grml image to the specified device
 
 
-    logging.info("Using %s as install base", live_image)
-
-    if os.path.isdir(device):
-        logging.info("Specified target is a directory, therefore not mounting.")
-        device_mountpoint = device
-        remove_device_mountpoint = False
+    @image: directory or is file
+    @device: partition or directory to install the device
+    """
+    iso_mountpoint = image
+    remove_image_mountpoint = False
+    if os.path.isdir(image):
+        logging.info("Using %s as install base", image)
     else:
     else:
-        device_mountpoint = tempfile.mkdtemp(prefix="grml2usb")
-        register_tmpfile(device_mountpoint)
-        remove_device_mountpoint = True
+        logging.info("Using ISO %s", image)
+        iso_mountpoint = tempfile.mkdtemp(prefix="grml2usb")
+        register_tmpfile(iso_mountpoint)
+        remove_image_mountpoint = True
         try:
         try:
-            mount(device, device_mountpoint, "")
+            mount(image, iso_mountpoint, ["-o", "loop", "-t", "iso9660"])
         except CriticalException, error:
             logging.critical("Fatal: %s", error)
         except CriticalException, error:
             logging.critical("Fatal: %s", error)
-            cleanup()
             sys.exit(1)
 
     try:
             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)
-        except TypeError:
-            logging.critical("Fatal: a critical error happend during execution (not a grml ISO?), giving up")
-            sys.exit(1)
+        install_grml(iso_mountpoint, device)
     finally:
     finally:
-        if remove_device_mountpoint:
+        if remove_image_mountpoint:
             try:
             try:
-                unmount(device_mountpoint, "")
-                if os.path.isdir(device_mountpoint):
-                    os.rmdir(device_mountpoint)
-                    unregister_tmpfile(device_mountpoint)
+                remove_mountpoint(iso_mountpoint)
             except CriticalException, error:
                 logging.critical("Fatal: %s", error)
                 cleanup()
 
 
             except CriticalException, error:
                 logging.critical("Fatal: %s", error)
                 cleanup()
 
 
-def handle_iso(iso, device):
-    """Main logic for mounting ISOs and copying files.
-
-    @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)
 
 
-    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)
-        cleanup()
-        sys.exit(1)
+def install_grml(mountpoint, device):
+    """Main logic for copying files of the currently running grml system.
 
 
-    try:
-        mount(iso, iso_mountpoint, ["-o", "loop", "-t", "iso9660"])
-    except CriticalException, error:
-        logging.critical("Fatal: %s", error)
-        sys.exit(1)
+    @mountpoin: directory where currently running live system resides (usually /live/image)
+    @device: partition where the specified ISO should be installed to"""
 
 
+    device_mountpoint = device
     if os.path.isdir(device):
     if os.path.isdir(device):
-        logging.info("Specified target is a directory, therefore not mounting.")
-        device_mountpoint = device
+        logging.info("Specified device is not a directory, therefore not mounting.")
         remove_device_mountpoint = False
         remove_device_mountpoint = False
-        # skip_mbr = True
     else:
         device_mountpoint = tempfile.mkdtemp(prefix="grml2usb")
         register_tmpfile(device_mountpoint)
         remove_device_mountpoint = True
         try:
     else:
         device_mountpoint = tempfile.mkdtemp(prefix="grml2usb")
         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:
-        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)
-        except TypeError:
-            logging.critical("Fatal: a critical error happend during execution (not a grml ISO?), giving up")
-            sys.exit(1)
-    finally:
-        if os.path.isdir(iso_mountpoint) and remove_iso_mountpoint:
-            unmount(iso_mountpoint, "")
-            os.rmdir(iso_mountpoint)
-            unregister_tmpfile(iso_mountpoint)
-        if remove_device_mountpoint:
             try:
             try:
-                unmount(device_mountpoint, "")
-                if os.path.isdir(device_mountpoint):
-                    os.rmdir(device_mountpoint)
-                    unregister_tmpfile(device_mountpoint)
+                mount(device, device_mountpoint, "")
             except CriticalException, error:
                 logging.critical("Fatal: %s", error)
             except CriticalException, error:
                 logging.critical("Fatal: %s", error)
-                cleanup()
+                raise
+    try:
+        grml_flavours = identify_grml_flavour(mountpoint)
+        for flavour in set(grml_flavours):
+            if not flavour:
+                logging.warning("No valid flavour found, please check your iso")
+            logging.info("Identified grml flavour \"%s\".", flavour)
+            install_iso_files(flavour, mountpoint, device, device_mountpoint)
+            GRML_FLAVOURS.add(flavour)
+    finally:
+        if remove_device_mountpoint:
+            remove_mountpoint(device_mountpoint)
 
 
+def remove_mountpoint(mountpoint):
+    """remove a registred mountpoint
+    """
+
+    try:
+        unmount(mountpoint, "")
+        if os.path.isdir(mountpoint):
+            os.rmdir(mountpoint)
+            unregister_tmpfile(mountpoint)
+    except CriticalException, error:
+        logging.critical("Fatal: %s", error)
+        cleanup()
 
 def handle_mbr(device):
     """Main handler for installing master boot record (MBR)
 
 def handle_mbr(device):
     """Main handler for installing master boot record (MBR)
@@ -1787,35 +1998,30 @@ def handle_vfat(device):
             logging.critical('Please make sure to install dosfstools.')
             sys.exit(1)
 
             logging.critical('Please make sure to install dosfstools.')
             sys.exit(1)
 
-        exec_mkfs = False
         if options.force:
             print "Forcing mkfs.fat16 on %s as requested via option --force." % device
         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")
         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:
-                logging.critical("Execution failed: %s", error)
+            else:
                 sys.exit(1)
                 sys.exit(1)
-        else:
+        try:
+            mkfs_fat16(device)
+        except CriticalException, error:
+            logging.critical("Execution failed: %s", error)
             sys.exit(1)
 
     # check for vfat filesystem
             sys.exit(1)
 
     # check for vfat filesystem
-    if device is not None and not os.path.isdir(device):
+    if device is not None and not os.path.isdir(device) and options.syslinux:
         try:
             check_for_fat(device)
         except CriticalException, error:
             logging.critical("Execution failed: %s", error)
             sys.exit(1)
 
         try:
             check_for_fat(device)
         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 options.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":
@@ -1873,6 +2079,34 @@ def handle_bootloader(device):
         install_bootloader(device)
 
 
         install_bootloader(device)
 
 
+def check_options(opts):
+    """Check compability of provided user opts
+
+    @opts option dict from OptionParser
+    """
+    if opts.grubmbr and not opts.grub:
+        logging.critical("Error: --grub-mbr requires --grub option.")
+        sys.exit(1)
+
+
+def check_programs():
+    """check if all needed programs are installed"""
+    if options.grub:
+        if not which("grub-install"):
+            logging.critical("Fatal: grub-install not available (please install the "
+                             + "grub package or drop the --grub option)")
+            sys.exit(1)
+
+    if options.syslinux:
+        if not which("syslinux"):
+            logging.critical("Fatal: syslinux not available (please install the "
+                             + "syslinux package or use the --grub option)")
+            sys.exit(1)
+
+    if not which("rsync"):
+        logging.critical("Fatal: rsync not available, can not continue - sorry.")
+        sys.exit(1)
+
 def main():
     """Main function [make pylint happy :)]"""
 
 def main():
     """Main function [make pylint happy :)]"""
 
@@ -1889,14 +2123,14 @@ def main():
     # make sure we have the appropriate permissions
     check_uid_root()
 
     # make sure we have the appropriate permissions
     check_uid_root()
 
+    check_options(options)
+
     logging.info("Executing grml2usb version %s", PROG_VERSION)
 
     if options.dryrun:
         logging.info("Running in simulation mode as requested via option dry-run.")
 
     logging.info("Executing grml2usb version %s", PROG_VERSION)
 
     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)
+    check_programs()
 
     # specified arguments
     device = args[len(args) - 1]
 
     # specified arguments
     device = args[len(args) - 1]
@@ -1907,14 +2141,10 @@ def main():
             if int(device[-1:]) > 4 or device[-2:].isdigit():
                 logging.critical("Fatal: installation on partition number >4 not supported. (BIOS won't support it.)")
                 sys.exit(1)
             if int(device[-1:]) > 4 or device[-2:].isdigit():
                 logging.critical("Fatal: installation on partition number >4 not supported. (BIOS won't support it.)")
                 sys.exit(1)
-        else:
-            if os.path.exists(device):
-                logging.critical("Fatal: installation on raw device not supported. (BIOS won't support it.)")
-                sys.exit(1)
+        elif os.path.exists(device):
+            logging.critical("Fatal: installation on raw device not supported. (BIOS won't support it.)")
+            sys.exit(1)
 
 
-    if not which("rsync"):
-        logging.critical("Fatal: rsync not available, can not continue - sorry.")
-        sys.exit(1)
 
     # provide upgrade path
     handle_compat_warning(device)
 
     # provide upgrade path
     handle_compat_warning(device)
@@ -1924,15 +2154,11 @@ def main():
 
     # main operation (like installing files)
     for iso in isos:
 
     # main operation (like installing files)
     for iso in isos:
-        if os.path.isdir(iso):
-            handle_dir(iso, device)
-        else:
-            handle_iso(iso, device)
+        install(iso, device)
 
     # install mbr
 
     # install mbr
-    if not os.path.isdir(device):
-        if not options.skipmbr:
-            handle_mbr(device)
+    if not options.skipmbr and not os.path.isdir(device):
+        handle_mbr(device)
 
     handle_bootloader(device)
 
 
     handle_bootloader(device)