Initial working version
authorMichael Prokop <mika@grml.org>
Wed, 4 Feb 2009 13:17:33 +0000 (14:17 +0100)
committerMichael Prokop <mika@grml.org>
Wed, 4 Feb 2009 13:17:33 +0000 (14:17 +0100)
What works so far:

* /grml/git/grml2usb/grml2usb.py --mbr /path/to/grml.iso /dev/sdc1
* copying files
* installing MBR
* installing syslinux

grml2usb.8.txt
grml2usb.py

index b49bce9..4962126 100644 (file)
@@ -19,7 +19,7 @@ Options
 The ISO[s] might be the path to one or multiple grml-ISOs as well as the path to
 the currently running live-system (being /live/image).
 
-The device either might be a device name like /dev/usb-sda1 or a directory. When
+The device either might be a device name like /dev/sda1 or a directory. When
 specifying a device name the device is mounted automatically. When specifying a
 directory it won't be touched but instead grml2usb is assuming that you did set
 up a bootloader on your own and a bootloader won't be installed automatically.
@@ -124,9 +124,8 @@ Directory layout on usb device
     |   |-- menu.lst
     |   |-- splash.xpm.gz
     |   `-- stage2_eltorito
-    `-- isolinux/
+    `-- syslinux/
         |-- boot.msg
-        |-- boot-beep.msg
         |-- f1
         |-- f2
         |-- f3
@@ -138,8 +137,6 @@ Directory layout on usb device
         |-- f9
         |-- f10
         |-- logo.16
-        |-- isolinux-main.cfg
-        |-- isolinux.cfg
         `-- syslinux.cfg
 
   grml/
@@ -175,41 +172,41 @@ Directory layout on usb device
 Usage examples
 --------------
 
-  # grml2usb /home/grml/grml_2008.11.iso /dev/usb-sdb1
+  # grml2usb /home/grml/grml_2008.11.iso /dev/sdb1
 
-Install specified ISOs on device /dev/usb-sdb1.
+Install specified ISOs on device /dev/sdb1.
 
-  # grml2usb /home/grml/grml_2008.11.iso /home/grml/grml_small_2008.11.iso /dev/usb-sdb1
+  # grml2usb /home/grml/grml_2008.11.iso /home/grml/grml_small_2008.11.iso /dev/sdb1
 
-Install specified ISOs on device /dev/usb-sdb1 for multibooting ISOs.
+Install specified ISOs on device /dev/sdb1 for multibooting ISOs.
 Note: boot "grml" as usual, for booting grml-small use "grml-small on the
 bootprompt, for grml64 use "grml64" and so on...
 
-  # grml2usb --fat16 --mbr /home/grml/grml_2008.11.iso /dev/usb-sdb1
+  # grml2usb --fat16 --mbr /home/grml/grml_2008.11.iso /dev/sdb1
 
-Install specified ISO on device /dev/usb-sdb1, install MBR on /dev/usb-sdb and
-format partition /dev/usb-sdb1 with FAT16 filesystem.
+Install specified ISO on device /dev/sdb1, install MBR on /dev/sdb and
+format partition /dev/sdb1 with FAT16 filesystem.
 
-  # grml2usb --grub /home/grml/grml_2008.11.iso /dev/usb-sdb1
+  # grml2usb --grub /home/grml/grml_2008.11.iso /dev/sdb1
 
-Install specified ISO on device /dev/usb-sdb1 and use Grub as bootloader
+Install specified ISO on device /dev/sdb1 and use Grub as bootloader
 (instead of syslinux being the default).
 
   # grml2usb --kernel=/boot/vmlinuz-2.6.28-grml --initrd=/boot/initrd.img-2.6.28-grml \
-             /home/grml/grml_2008.11.iso /dev/usb-sdb1
+             /home/grml/grml_2008.11.iso /dev/sdb1
 
-Install specified ISO on device /dev/usb-sdb1 but use given kernel and initrd
+Install specified ISO on device /dev/sdb1 but use given kernel and initrd
 instead of the ones provided by the ISO.
 
   # grml2usb --squashfs=/grml/grml-live/grml_cd/live/grml.squashfs \
-             /home/grml/grml_2008.11.iso /dev/usb-sdb1
+             /home/grml/grml_2008.11.iso /dev/sdb1
 
-Install specified ISO on device /dev/usb-sdb1 but use given squashfs
+Install specified ISO on device /dev/sdb1 but use given squashfs
 file instead of the one provided by the ISO.
 
-  # grml2usb --bootoptions="lang=de ssh=mysecret" grml_2008.11.iso /dev/usb-sdb1
+  # grml2usb --bootoptions="lang=de ssh=mysecret" grml_2008.11.iso /dev/sdb1
 
-Install specified ISO on device /dev/usb-sdb1 and use "lang=de ssh=mysecret" as
+Install specified ISO on device /dev/sdb1 and use "lang=de ssh=mysecret" as
 default bootoptions.
 
 Bugs
index becbd02..f4e45e9 100755 (executable)
@@ -4,7 +4,7 @@
 grml2usb
 ~~~~~~~~
 
-This script installs a grml system (running system / ISO(s) to a USB device
+This script installs a grml system (running system / ISO[s]) to a USB device
 
 :copyright: (c) 2009 by Michael Prokop <mika@grml.org>
 :license: GPL v2 or any later version
@@ -13,18 +13,14 @@ This script installs a grml system (running system / ISO(s) to a USB device
 TODO
 ----
 
-* detect old grml2usb usage and inform user about it and exit then
-  -> rename grml2usb.py to grml2usb then
-* handling of bootloader configuration for multiple ISOs
-* verify that the specified device is really USB (/dev/usb-sd* -> /sys/devices/*/removable_)
-* validate partition schema? bootable flag
+* verify that the specified device is really an USB device (/sys/devices/*/removable_)
+* validate partition schema/layout:
+  -> bootable flag?
+  -> fat16 partition if using syslinux
 * implement missing options (--kernel, --initrd, --uninstall,...)
 * improve error handling :)
-* get rid of "if not dry_run" inside code/functions
-* implement mount handling
 * implement logic for storing information about copied files
   -> register every single file?
-* trap handling (like unmount devices when interrupting?)
 * get rid of all TODOs in code :)
 * graphical version? :)
 """
@@ -91,6 +87,7 @@ def get_function_name(obj):
         obj = type(obj)
     return obj.__module__ + '.' + obj.__name__
 
+
 def execute(f, *args):
     """Wrapper for executing a command. Either really executes
     the command (default) or when using --dry-run commandline option
@@ -151,9 +148,14 @@ def check_uid_root():
 def install_syslinux(device, dry_run=False):
     # TODO
     """Install syslinux on specified device."""
-    logging.critical("debug: syslinux %s [TODO]" % device)
 
-    # syslinux -d boot/isolinux /dev/usb-sdb1
+    # syslinux -d boot/isolinux /dev/sdb1
+    logging.info("Installing syslinux")
+    logging.debug("syslinux -d boot/syslinux %s" % device)
+    proc = subprocess.Popen(["syslinux", "-d", "boot/syslinux", device])
+    proc.wait()
+    if proc.returncode != 0:
+        raise Exception, "error executing syslinux"
 
 
 def generate_grub_config(grml_flavour):
@@ -165,8 +167,6 @@ def generate_grub_config(grml_flavour):
     # * what about systems using grub2 without having grub1 available?
     # * support grub2?
 
-    grml_name = grml_flavour
-
     return("""\
 # misc options:
 timeout 30
@@ -176,9 +176,9 @@ foreground  = 000000
 background  = FFCC33
 
 # define entries:
-title %(grml_name)s  - Default boot (using 1024x768 framebuffer)
-kernel /boot/release/%(grml_name)s/linux26 apm=power-off lang=us vga=791 quiet boot=live nomce module=%(grml_name)s
-initrd /boot/release/%(grml_name)s/initrd.gz
+title %(grml_flavour)s  - Default boot (using 1024x768 framebuffer)
+kernel /boot/release/%(grml_flavour)s/linux26 apm=power-off lang=us vga=791 quiet boot=live nomce module=%(grml_flavour)s
+initrd /boot/release/%(grml_flavour)s/initrd.gz
 
 # TODO: extend configuration :)
 """ % locals())
@@ -193,14 +193,14 @@ def generate_isolinux_splash(grml_flavour):
     grml_name = grml_flavour
 
     return("""\
-\ f17\f\18/boot/isolinux/logo.16
+\ f17\f\18/boot/syslinux/logo.16
 
 Some information and boot options available via keys F2 - F10. http://grml.org/
 %(grml_name)s
 """ % locals())
 
-def generate_syslinux_config(grml_flavour):
-    """Generate configuration for use in syslinux.cfg"""
+def generate_main_syslinux_config(grml_flavour, grml_bootoptions):
+    """Generate main configuration for use in syslinux.cfg"""
 
     # TODO
     # * install main part of configuration just *once* and append
@@ -208,31 +208,42 @@ def generate_syslinux_config(grml_flavour):
     # * unify isolinux and syslinux setup ("INCLUDE /boot/...")
     #   as far as possible
 
-    grml_name = grml_flavour
-
     return("""\
+## main syslinux configuration - generated by grml2usb
 # use this to control the bootup via a serial port
 # SERIAL 0 9600
 DEFAULT grml
 TIMEOUT 300
 PROMPT 1
-DISPLAY /boot/isolinux/boot.msg
-F1 /boot/isolinux/boot.msg
-F2 /boot/isolinux/f2
-F3 /boot/isolinux/f3
-F4 /boot/isolinux/f4
-F5 /boot/isolinux/f5
-F6 /boot/isolinux/f6
-F7 /boot/isolinux/f7
-F8 /boot/isolinux/f8
-F9 /boot/isolinux/f9
-F10 /boot/isolinux/f10
-
-LABEL grml
-KERNEL /boot/release/%(grml_name)s/linux26
-APPEND initrd=/boot/release/%(grml_name)s/initrd.gz apm=power-off lang=us boot=live nomce module=%(grml_name)s
+DISPLAY /boot/syslinux/boot.msg
+F1 /boot/syslinux/boot.msg
+F2 /boot/syslinux/f2
+F3 /boot/syslinux/f3
+F4 /boot/syslinux/f4
+F5 /boot/syslinux/f5
+F6 /boot/syslinux/f6
+F7 /boot/syslinux/f7
+F8 /boot/syslinux/f8
+F9 /boot/syslinux/f9
+F10 /boot/syslinux/f10
+## end of main configuration
+
+# flavour specific configuration for grml
+LABEL  grml
+KERNEL /boot/release/%(grml_flavour)s/linux26
+APPEND initrd=/boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce quiet module=%(grml_flavour)s %(grml_bootoptions)s
 
-# TODO: extend configuration :)
+""" % locals())
+
+def generate_flavour_specific_syslinux_config(grml_flavour, bootoptions):
+    """Generate flavour specific configuration for use in syslinux.cfg"""
+
+    return("""\
+
+# flavour specific configuration for %(grml_flavour)s
+LABEL  %(grml_flavour)s
+KERNEL /boot/release/%(grml_flavour)s/linux26
+APPEND initrd=/boot/release/%(grml_flavour)s/initrd.gz apm=power-off boot=live nomce quiet module=%(grml_flavour)s %(bootoptions)s
 """ % locals())
 
 
@@ -243,17 +254,18 @@ def install_grub(device, dry_run=False):
 
 def install_bootloader(partition, dry_run=False):
     """Install bootloader on device."""
+
     # Install bootloader on the device (/dev/sda),
-    # not on the partition itself (/dev/sda1)
-    if partition[-1:].isdigit():
-        device = re.match(r'(.*?)\d*$', partition).group(1)
-    else:
-        device = partition
+    # not on the partition itself (/dev/sda1)?
+#    if partition[-1:].isdigit():
+#        device = re.match(r'(.*?)\d*$', partition).group(1)
+#    else:
+#        device = partition
 
     if options.grub:
-        install_grub(device, dry_run)
+        install_grub(partition, dry_run)
     else:
-        install_syslinux(device, dry_run)
+        install_syslinux(partition, dry_run)
 
 
 def is_writeable(device):
@@ -276,12 +288,13 @@ def install_mbr(device, dry_run=False):
     if not is_writeable(device):
         raise IOError, "device not writeable for user"
 
-    lilo = './lilo/lilo.static' # FIXME
+    lilo = '/grml/git/grml2usb/lilo/lilo.static' # FIXME
 
     if not is_exe(lilo):
         raise Exception, "lilo executable not available."
 
     # to support -A for extended partitions:
+    logging.info("Installing MBR")
     logging.debug("%s -S /dev/null -M %s ext" % (lilo, device))
     proc = subprocess.Popen([lilo, "-S", "/dev/null", "-M", device, "ext"])
     proc.wait()
@@ -408,51 +421,70 @@ def copy_grml_files(grml_flavour, iso_mount, target, dry_run=False):
     proc.wait()
 
     if not options.copyonly:
-        isolinux_target = target + '/boot/isolinux/'
-        execute(mkdir, isolinux_target)
+        syslinux_target = target + '/boot/syslinux/'
+        execute(mkdir, syslinux_target)
 
-        # FIXME - Fatal: could not identify grml flavour, sorry.
         logo = search_file('logo.16', iso_mount)
-        logging.debug("cp %s %s" % logo, isolinux_target + 'logo.16')
-        proc = execute(subprocess.Popen, ["install", "--mode=664", logo, isolinux_target + 'logo.16'])
+        logging.debug("cp %s %s" % (logo, syslinux_target + 'logo.16'))
+        proc = execute(subprocess.Popen, ["install", "--mode=664", logo, syslinux_target + 'logo.16'])
         proc.wait()
 
         for ffile in 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10':
             bootsplash = search_file(ffile, iso_mount)
-            logging.debug("cp %s %s" % (bootsplash, isolinux_target + ffile))
-            proc = execute(subprocess.Popen, ["install", "--mode=664", bootsplash, isolinux_target + ffile])
+            logging.debug("cp %s %s" % (bootsplash, syslinux_target + ffile))
+            proc = execute(subprocess.Popen, ["install", "--mode=664", bootsplash, syslinux_target + ffile])
             proc.wait()
 
         grub_target = target + '/boot/grub/'
         execute(mkdir, grub_target)
 
-        logging.debug("cp grub/splash.xpm.gz %s" % grub_target + 'splash.xpm.gz')
-        proc = execute(subprocess.Popen, ["install", "--mode=664", 'grub/splash.xpm.gz', grub_target + 'splash.xpm.gz'])
+        logging.debug("cp /grml/git/grml2usb/grub/splash.xpm.gz %s" % grub_target + 'splash.xpm.gz') # FIXME - path of grub
+        proc = execute(subprocess.Popen, ["install", "--mode=664", '/grml/git/grml2usb/grub/splash.xpm.gz', grub_target + 'splash.xpm.gz']) # FIXME
         proc.wait()
 
-        logging.debug("cp grub/stage2_eltorito to %s" % grub_target + 'stage2_eltorito')
-        proc = execute(subprocess.Popen, ["install", "--mode=664", 'grub/stage2_eltorito', grub_target + 'stage2_eltorito'])
+        logging.debug("cp /grml/git/grml2usb/grub/stage2_eltorito to %s" % grub_target + 'stage2_eltorito') # FIXME - path of grub
+        proc = execute(subprocess.Popen, ["install", "--mode=664", '/grml/git/grml2usb/grub/stage2_eltorito', grub_target + 'stage2_eltorito']) # FIXME
         proc.wait()
 
-        logging.debug("Generating grub configuration %s" % grub_target + 'menu.lst')
         if not dry_run:
+            logging.debug("Generating grub configuration") # % grub_target + 'menu.lst')
             #with open("...", "w") as f:
             #f.write("bla bla bal")
             grub_config_file = open(grub_target + 'menu.lst', 'w')
             grub_config_file.write(generate_grub_config(grml_flavour))
-            grub_config_file.close( )
-
-        syslinux_target = target + '/boot/isolinux/'
-        execute(mkdir, syslinux_target)
-
-        logging.debug("Generating syslinux configuration %s" % syslinux_target + 'syslinux.cfg')
-        if not dry_run:
-            syslinux_config_file = open(syslinux_target + 'syslinux.cfg', 'w')
-            syslinux_config_file.write(generate_syslinux_config(grml_flavour))
-            syslinux_config_file.close( )
-
-        logging.debug("Generating isolinux/syslinux splash %s" % syslinux_target + 'boot.msg')
-        if not dry_run:
+            grub_config_file.close()
+
+            logging.info("Generating syslinux configuration") # % syslinux_target + 'syslinux.cfg')
+            syslinux_cfg = syslinux_target + 'syslinux.cfg'
+
+            # install main configuration only *once*, no matter how many ISOs we have:
+            if os.path.isfile(syslinux_cfg):
+                string = open(syslinux_cfg).readline()
+                if not re.match("## main syslinux configuration", string):
+                    syslinux_config_file = open(syslinux_cfg, 'w')
+                    syslinux_config_file.write(generate_main_syslinux_config(grml_flavour, "")) # FIXME - bootoptions
+                    syslinux_config_file.close()
+            else:
+                    syslinux_config_file = open(syslinux_cfg, 'w')
+                    syslinux_config_file.write(generate_main_syslinux_config(grml_flavour, "")) # FIXME - bootoptions
+                    syslinux_config_file.close()
+
+            # install flavour specific configuration only *once* as well
+            # ugly - I'm pretty sure this could be smoother...
+            flavour_config = True
+            if os.path.isfile(syslinux_cfg):
+                string = open(syslinux_cfg).readlines()
+                flavour = re.compile("^# flavour specific configuration for %s"  % re.escape(grml_flavour))
+                for line in string:
+                    if flavour.match(line):
+                        flavour_config = False
+
+            if flavour_config:
+                syslinux_config_file = open(syslinux_cfg, 'a')
+                syslinux_config_file.write(generate_flavour_specific_syslinux_config(grml_flavour, "")) # FIXME - bootoptions
+                syslinux_config_file.close( )
+
+            logging.debug("Generating isolinux/syslinux splash %s" % syslinux_target + 'boot.msg')
             isolinux_splash = open(syslinux_target + 'boot.msg', 'w')
             isolinux_splash.write(generate_isolinux_splash(grml_flavour))
             isolinux_splash.close( )
@@ -497,7 +529,7 @@ def handle_iso(iso, device):
     """TODO
     """
 
-    logging.info("iso = %s" % iso)
+    logging.info("Using ISO %s" % iso)
 
     if os.path.isdir(iso):
         logging.critical("TODO: /live/image handling not yet implemented") # TODO
@@ -507,7 +539,7 @@ def handle_iso(iso, device):
         mount(iso, iso_mountpoint, ["-o", "loop", "-t", "iso9660"])
 
         if os.path.isdir(device):
-            logging.debug("Specified target is a directory, not mounting therefore.")
+            logging.info("Specified target is a directory, not mounting therefore.")
             device_mountpoint = device
             remove_device_mountpoint = False
             skip_mbr = True
@@ -522,15 +554,18 @@ def handle_iso(iso, device):
             logging.info("Identified grml flavour \"%s\"." % grml_flavour)
             copy_grml_files(grml_flavour, iso_mountpoint, device_mountpoint, dry_run=options.dryrun)
         except TypeError:
-            logging.critical("Fatal: could not identify grml flavour, sorry.")
+            logging.critical("Fatal: something happend - TODO")
             sys.exit(1)
         finally:
             if os.path.isdir(iso_mountpoint) and remove_iso_mountpoint:
                 unmount(iso_mountpoint)
                 os.rmdir(iso_mountpoint)
-            if os.path.isdir(device_mountpoint) and remove_device_mountpoint:
+
+            if remove_device_mountpoint:
                 unmount(device_mountpoint)
-                os.rmdir(device_mountpoint)
+
+                if os.path.isdir(device_mountpoint):
+                    os.rmdir(device_mountpoint)
 
         # grml_flavour_short = grml_flavour.replace('-','')
         # logging.debug("grml_flavour_short = %s" % grml_flavour_short)
@@ -564,6 +599,18 @@ def main():
     device = args[len(args) - 1]
     isos = args[0:len(args) - 1]
 
+    # make sure we can replace old grml2usb script and warn user when using old way of life:
+    if device.startswith("/mnt/external") or device.startswith("/mnt/usb"):
+        print "Warning: the semantics of grml2usb has changed."
+        print "Instead of using grml2usb /path/to/iso %s you might" % device
+        print "want to use grml2usb /path/to/iso /dev/... instead."
+        print "Please check out the grml2usb manpage for details."
+        f = raw_input("Do you really want to continue? y/N ")
+        if f == "y" or f == "Y":
+           pass
+        else:
+            sys.exit(1)
+
     if not which("syslinux"):
         logging.critical('Sorry, syslinux not available. Exiting.')
         logging.critical('Please install syslinux or consider using the --grub option.')
@@ -573,18 +620,18 @@ def main():
     # * check for valid blockdevice, vfat and mount functions
     # if device is not None:
         # check_for_vat(device)
-        # mount_target(partition)
 
     for iso in isos:
         handle_iso(iso, device)
 
     if options.mbr and not skip_mbr:
+
         # make sure we install MBR on /dev/sdX and not /dev/sdX#
         if device[-1:].isdigit():
-            device = re.match(r'(.*?)\d*$', device).group(1)
+            mbr_device = re.match(r'(.*?)\d*$', device).group(1)
 
         try:
-            install_mbr(device, dry_run=options.dryrun)
+            install_mbr(mbr_device, dry_run=options.dryrun)
         except IOError, error:
             logging.critical("Execution failed:", error)
             sys.exit(1)
@@ -603,7 +650,7 @@ if __name__ == "__main__":
     try:
         main()
     except KeyboardInterrupt:
-        print "TODO: handle me! :)"
+        print "TODO / FIXME: handle me! :)"
 
 ## END OF FILE #################################################################
 # vim:foldmethod=marker expandtab ai ft=python tw=120 fileencoding=utf-8