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
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? :)
"""
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
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):
# * what about systems using grub2 without having grub1 available?
# * support grub2?
- grml_name = grml_flavour
-
return("""\
# misc options:
timeout 30
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())
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
# * 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())
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):
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()
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( )
"""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
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
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)
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.')
# * 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)
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