Support installation of the currently running grml live system
[grml2usb.git] / grml2usb
index b5338bd..f8a53c4 100755 (executable)
--- a/grml2usb
+++ b/grml2usb
@@ -18,7 +18,7 @@ from inspect import isroutine, isclass
 import datetime, logging, os, re, subprocess, sys, tempfile, time
 
 # global variables
-PROG_VERSION = "0.9.5"
+PROG_VERSION = "0.9.6"
 MOUNTED = set()  # register mountpoints
 TMPFILES = set() # register tmpfiles
 DATESTAMP = time.mktime(datetime.datetime.now().timetuple()) # unique identifier for syslinux.cfg
@@ -283,9 +283,9 @@ menuentry "FreeDOS" {
     initrd  /boot/addons/balder10.imz
 }
 
-menuentry "MirBSD" {
+menuentry "MirOS BSD" {
     set root=(hd0,%(install_partition)s)
-    linux   /boot/addons/bsd4grml/ldbsd.com
+    multiboot   /boot/addons/bsd4grml/ldbsd.com
 }
 
 menuentry "Boot OS of first partition on first disk" {
@@ -453,7 +453,7 @@ title FreeDOS
 kernel (hd0,%(install_partition)s)/boot/addons/memdisk
 initrd (hd0,%(install_partition)s)/boot/addons/balder10.imz
 
-title MirBSD
+title MirOS BSD
 kernel (hd0,%(install_partition)s)/boot/addons/bsd4grml/ldbsd.com
 
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp,
@@ -532,6 +532,11 @@ LABEL bsd
 MENU LABEL bsd
 KERNEL /boot/addons/bsd4grml/ldbsd.com
 
+# hardware detection tool
+MENU LABEL hdt
+KERNEL /boot/addons/hdt.c32
+APPEND pciids=/boot/addons/pci.ids
+
 ## end of global configuration
 """ % {'grml_flavour': grml_flavour, 'local_datestamp': local_datestamp, 'bootoptions': bootoptions} )
 
@@ -606,7 +611,10 @@ def install_grub(device):
                 "--root-directory=%s" % device_mountpoint, device], stdout=file(os.devnull, "r+"))
             proc.wait()
             if proc.returncode != 0:
-                raise Exception("error executing grub-install")
+                # raise Exception("error executing grub-install")
+                logging.critical("Fatal: error executing grub-install (please check the grml2usb FAQ)" % error)
+                cleanup()
+                sys.exit(1)
         except CriticalException, error:
             logging.critical("Fatal: %s" % error)
             cleanup()
@@ -951,6 +959,7 @@ def copy_system_files(grml_flavour, iso_mount, target):
     squashfs = search_file(grml_flavour + '.squashfs', iso_mount)
     if squashfs is None:
         logging.critical("Fatal: squashfs file not found")
+        raise CriticalException("error locating squashfs file")
     else:
         squashfs_target = target + '/live/' + grml_flavour + '/'
         execute(mkdir, squashfs_target)
@@ -1041,7 +1050,7 @@ def copy_addons(iso_mount, target):
     # 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")
+        logging.warn("Warning: allinone.img not found (that's fine if you don't need it)")
     else:
         logging.debug("cp %s %s" % (allinoneimg, addons + '/allinone.img'))
         proc = subprocess.Popen(["cp", allinoneimg, addons + 'allinone.img'])
@@ -1050,7 +1059,7 @@ def copy_addons(iso_mount, target):
     # 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")
+        logging.warn("Warning: bsd4grml not found (that's fine if you don't need it)")
     else:
         logging.debug("cp -a %s %s" % (bsdimg, addons + '/'))
         proc = subprocess.Popen(["cp", "-a", bsdimg, addons + '/'])
@@ -1059,16 +1068,32 @@ def copy_addons(iso_mount, target):
     # 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")
+        logging.warn("Warning: balder10.imz not found (that's fine if you don't need it)")
     else:
         logging.debug("cp %s %s" % (balderimg, addons + '/balder10.imz'))
         proc = subprocess.Popen(["cp", balderimg, addons + 'balder10.imz'])
         proc.wait()
 
+    # install hdt and pci.ids only when using syslinux (grub doesn't support it)
+    if options.syslinux:
+        # hdt (hardware detection tool) image
+        hdtimg = search_file('hdt.c32', iso_mount)
+        if hdtimg:
+            logging.debug("cp %s %s" % (hdtimg, addons + '/hdt.c32'))
+            proc = subprocess.Popen(["cp", hdtimg, addons + '/hdt.c32'])
+            proc.wait()
+    
+        # pci.ids file
+        picids = search_file('pci.ids', iso_mount)
+        if picids:
+            logging.debug("cp %s %s" % (picids, addons + '/pci.ids'))
+            proc = subprocess.Popen(["cp", picids, addons + '/pci.ids'])
+            proc.wait()
+
     # 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")
+        logging.warn("Warning: memdisk not found (that's fine if you don't need it)")
     else:
         logging.debug("cp %s %s" % (memdiskimg, addons + '/memdisk'))
         proc = subprocess.Popen(["cp", memdiskimg, addons + 'memdisk'])
@@ -1077,7 +1102,7 @@ def copy_addons(iso_mount, target):
     # 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")
+        logging.warn("Warning: memtest not found (that's fine if you don't need it)")
     else:
         logging.debug("cp %s %s" % (memtestimg, addons + '/memtest'))
         proc = subprocess.Popen(["cp", memtestimg, addons + 'memtest'])
@@ -1149,8 +1174,12 @@ def install_iso_files(grml_flavour, iso_mount, device, target):
         return 0
     elif not options.bootloaderonly:
         logging.info("Copying files. This might take a while....")
-        copy_system_files(grml_flavour, iso_mount, target)
-        copy_grml_files(iso_mount, target)
+        try:
+            copy_system_files(grml_flavour, iso_mount, target)
+            copy_grml_files(iso_mount, target)
+        except CriticalException, error:
+            logging.critical("Execution failed: %s", error)
+            sys.exit(1)
 
     if not options.skipaddons:
         if grml_flavour.endswith('-small'):
@@ -1396,6 +1425,47 @@ def handle_bootloader_config(grml_flavour, device, target):
             logging.critical("Fatal: %s" % error)
             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"""
+
+    logging.info("Using %s as install base" % live_image)
+
+    if os.path.isdir(device):
+        logging.info("Specified target is a directory, not mounting therefor.")
+        device_mountpoint = device
+        remove_device_mountpoint = False
+    else:
+        device_mountpoint = tempfile.mkdtemp(prefix="grml2usb")
+        register_tmpfile(device_mountpoint)
+        remove_device_mountpoint = True
+        try:
+            mount(device, device_mountpoint, "")
+        except CriticalException, error:
+            logging.critical("Fatal: %s" % error)
+            cleanup()
+            sys.exit(1)
+
+    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)
+    finally:
+        if remove_device_mountpoint:
+            try:
+                unmount(device_mountpoint, "")
+                if os.path.isdir(device_mountpoint):
+                    os.rmdir(device_mountpoint)
+                    unregister_tmpfile(device_mountpoint)
+            except CriticalException, error:
+                logging.critical("Fatal: %s" % error)
+                cleanup()
+
 
 def handle_iso(iso, device):
     """Main logic for mounting ISOs and copying files.
@@ -1405,10 +1475,6 @@ def handle_iso(iso, device):
 
     logging.info("Using ISO %s" % iso)
 
-    if os.path.isdir(iso):
-        logging.critical("TODO: /live/image handling not yet implemented - sorry")
-        sys.exit(1)
-
     iso_mountpoint = tempfile.mkdtemp(prefix="grml2usb")
     register_tmpfile(iso_mountpoint)
     remove_iso_mountpoint = True
@@ -1633,7 +1699,10 @@ def main():
 
     # main operation (like installing files)
     for iso in isos:
-        handle_iso(iso, device)
+        if os.path.isdir(iso):
+            handle_dir(iso, device)
+        else:
+            handle_iso(iso, device)
 
     # install mbr
     if not os.path.isdir(device):