UUID = None
SYSLINUX_LIBS = "/usr/lib/syslinux/"
+RE_PARTITION = re.compile(r'([a-z/]*?)(\d+)$')
+RE_P_PARTITION = re.compile(r'(.*?\d+)p(\d+)$')
+RE_LOOP_DEVICE = re.compile(r'/dev/loop\d+$')
def syslinux_warning(option, opt, value, opt_parser):
"""A helper function for printing a warning about deprecated option
setattr(opt_parser.values, 'syslinux', False)
# cmdline parsing
-USAGE = "Usage: %prog [options] <[ISO[s] | /live/image]> </dev/sdX#>\n\
+USAGE = "Usage: %prog [options] <[ISO[s] | /lib/live/mount/medium]> </dev/sdX#>\n\
\n\
-%prog installs grml ISO[s] to an USB device to be able to boot from it.\n\
-Make sure you have at least one grml ISO or a running grml system (/live/image),\n\
+%prog installs Grml ISO[s] to an USB device to be able to boot from it.\n\
+Make sure you have at least one Grml ISO or a running Grml system (/lib/live/mount/medium),\n\
grub or syslinux and root access.\n\
\n\
Run %prog --help for usage hints, further information via: man grml2usb"
@Exception: message"""
pass
+class VerifyException(Exception):
+ """Throw critical exception if there is an fatal error when verifying something.
+
+ @Exception: message"""
+ pass
+
# The following two functions help to operate on strings as
# array (list) of bytes (octets). In Python 3000, the bytes
os.unlink(tmpfile)
# ignore: RuntimeError: Set changed size during iteration
except RuntimeError:
- logging.debug('caught expection RuntimeError, ignoring')
+ logging.debug('caught exception RuntimeError, ignoring')
def register_tmpfile(path):
def check_uid_root():
"""Check for root permissions"""
if not os.geteuid() == 0:
- sys.exit("Error: please run this script with uid 0 (root).")
+ raise CriticalException("please run this script with uid 0 (root).")
+
+
+def check_boot_flag(device):
+ boot_dev, x = get_device_from_partition(device)
+
+ with open(boot_dev, 'r') as image:
+ data = image.read(520)
+ bootcode = data[440:]
+ gpt_header = "\x55\xaa\x45\x46\x49\x20\x50\x41\x52\x54" # original GPT header
+ gpt_data = bootcode[70:80]
+
+ if gpt_data == gpt_header:
+ logging.info("GPT detected, skipping bootflag check")
+ elif bootcode[6] == '\x80':
+ logging.debug("bootflag is enabled")
+ else:
+ logging.debug("bootflag is NOT enabled")
+ raise VerifyException("Device %s does not have the bootflag set. "
+ "Please enable it to be able to boot." % boot_dev)
def mkfs_fat16(device):
# If using --grub-mbr then make sure we install grub in MBR instead of PBR
if options.grubmbr:
logging.debug("Using option --grub-mbr ...")
- if device[-1:].isdigit():
- grub_device = re.match(r'(.*?)\d*$', device).group(1)
- else:
- grub_device = device
+ grub_device, x = get_device_from_partition(device)
else:
grub_device = device
logging.info("Installing default MBR")
if not os.path.isfile(mbrtemplate):
- logging.critical("Error: %s can not be read.", mbrtemplate)
- raise CriticalException("Error installing MBR (either try --syslinux-mbr or install missing file \"%s\"?)" % mbrtemplate)
+ logging.error('Error installing MBR (either try --syslinux-mbr or '
+ 'install missing file "%s"?)', mbrtemplate)
+ raise CriticalException("%s can not be read." % mbrtemplate)
if partition is not None and ((partition < 0) or (partition > 3)):
- logging.warn("Cannot activate partition %d" % partition)
+ logging.warn("Cannot activate partition %d", partition)
partition = None
if ismirbsdmbr:
squashfs = search_file(grml_flavour + '.squashfs', iso_mount)
if squashfs is None:
- logging.critical("Fatal: squashfs file not found"
- ", please check that your iso is not corrupt")
- raise CriticalException("error locating squashfs file")
+ logging.error("error locating squashfs file")
+ raise CriticalException("squashfs file not found"
+ ", please check that your iso is not corrupt")
else:
squashfs_target = target + '/live/' + grml_flavour + '/'
execute(mkdir, squashfs_target)
if filesystem_module:
break
if filesystem_module is None:
- logging.critical("Fatal: filesystem.module not found")
- raise CriticalException("error locating filesystem.module file")
+ logging.error("error locating filesystem.module file")
+ raise CriticalException("filesystem.module not found")
else:
exec_rsync(filesystem_module, squashfs_target + 'filesystem.module')
kernel = search_file('linux26', iso_mount)
if kernel is None:
- logging.critical("Fatal: kernel not found")
- raise CriticalException("error locating kernel file")
+ logging.error("error locating kernel file")
+ raise CriticalException("Kernel not found")
source = os.path.dirname(kernel) + '/'
dest = target + '/' + os.path.dirname(kernel).replace(iso_mount, '') + '/'
(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.")
- raise
+ raise CriticalException(
+ "file default.cfg could not be found.\n"
+ "Note: this grml2usb version requires an ISO generated by grml-live >=0.9.24 ...\n"
+ " ... either use grml releases >=2009.10 or switch to an older grml2usb version.")
if not os.path.exists(iso_mount + '/boot/grub/footer.cfg'):
logging.warning("Warning: Grml releases older than 2011.12 support only one flavour in grub.")
proc.wait()
+def get_device_from_partition(partition):
+ device = partition
+ partition_number = None
+ if partition[-1].isdigit() and not RE_LOOP_DEVICE.match(partition):
+ m = RE_P_PARTITION.match(partition)
+ if not m:
+ m = RE_PARTITION.match(partition)
+ if m:
+ device = m.group(1)
+ partition_number = int(m.group(2)) - 1
+ return (device, partition_number)
+
+
def get_flavour(flavour_str):
"""Returns the flavour of a grml version string
"""
version_files = search_file('grml-version', mountpath, lst_return=True)
if not version_files:
- logging.critical("Error: could not find grml-version file.")
- raise
+ if mountpath.startswith("/lib/live/mount/medium"):
+ logging.critical("Error: could not find grml-version file.")
+ logging.critical("Looks like your system is running from RAM but required files are not available.")
+ logging.critical("Please either boot without toram=... or use boot option toram instead of toram=...")
+ cleanup()
+ sys.exit(1)
+ else:
+ logging.critical("Error: could not find grml-version file.")
+ cleanup()
+ sys.exit(1)
flavours = []
logging.debug("version_files = %s", version_files)
except TypeError, e:
raise
except Exception, e:
- logging.critical("Unexpected error: %s", e)
raise
finally:
if tmpfile:
logging.info("Using %s as install base", image)
else:
logging.info("Using ISO %s", image)
- iso_mountpoint = tempfile.mkdtemp(prefix="grml2usb", dir=options.tmpdir)
+ iso_mountpoint = tempfile.mkdtemp(prefix="grml2usb", dir=os.path.abspath(options.tmpdir))
register_tmpfile(iso_mountpoint)
remove_image_mountpoint = True
try:
try:
remove_mountpoint(iso_mountpoint)
except CriticalException, error:
- logging.critical("Fatal: %s", error)
cleanup()
+ raise
def install_grml(mountpoint, device):
"""Main logic for copying files of the currently running grml system.
- @mountpoin: directory where currently running live system resides (usually /live/image)
+ @mountpoint: directory where currently running live system resides (usually /lib/live/mount/medium)
@device: partition where the specified ISO should be installed to"""
device_mountpoint = device
if os.path.isdir(device):
- logging.info("Specified device is not a directory, therefore not mounting.")
+ logging.info("Specified device is a directory, therefore not mounting.")
remove_device_mountpoint = False
else:
device_mountpoint = tempfile.mkdtemp(prefix="grml2usb")
remove_device_mountpoint = True
try:
check_for_fat(device)
+ check_boot_flag(device)
mount(device, device_mountpoint, ['-o', 'utf8,iocharset=iso8859-1'])
+ except VerifyException, error:
+ raise
except CriticalException, error:
- try:
- mount(device, device_mountpoint, "")
- except CriticalException, error:
- logging.critical("Fatal: %s", error)
- raise
+ mount(device, device_mountpoint, "")
try:
grml_flavours = identify_grml_flavour(mountpoint)
for flavour in set(grml_flavours):
def remove_mountpoint(mountpoint):
- """remove a registred mountpoint
+ """remove a registered mountpoint
"""
try:
os.rmdir(mountpoint)
unregister_tmpfile(mountpoint)
except CriticalException, error:
- logging.critical("Fatal: %s", error)
cleanup()
+ raise
def handle_mbr(device):
logging.info("Would install MBR")
return 0
- if device[-1:].isdigit():
- mbr_device = re.match(r'(.*?)\d*$', device).group(1)
- partition_number = int(device[-1:]) - 1
- else:
+ mbr_device, partition_number = get_device_from_partition(device)
+ if partition_number is None:
logging.warn("Could not detect partition number, not activating partition")
- partition_number = None
# if we get e.g. /dev/loop1 as device we don't want to put the MBR
# into /dev/loop of course, therefore use /dev/loop1 as mbr_device
if options.verbose and options.quiet:
parser.error("please use either verbose (--verbose) or quiet (--quiet) option")
+ FORMAT = "%(message)s"
if options.verbose:
- FORMAT = "Debug: %(asctime)-15s %(message)s"
+ FORMAT = "%(asctime)-15s %(message)s"
logging.basicConfig(level=logging.DEBUG, format=FORMAT)
elif options.quiet:
- FORMAT = "Critical: %(message)s"
logging.basicConfig(level=logging.CRITICAL, format=FORMAT)
else:
- FORMAT = "%(message)s"
logging.basicConfig(level=logging.INFO, format=FORMAT)
@opts option dict from OptionParser
"""
if opts.grubmbr and not opts.grub:
- logging.critical("Error: --grub-mbr requires --grub option.")
- sys.exit(1)
+ raise CriticalException("--grub-mbr requires --grub option.")
def check_programs():
def load_loop():
"""Runs modprobe loop and throws away it's output"""
+ if not which("modprobe"):
+ logging.critical("Fatal: modprobe not available, can not continue - sorry.")
+ logging.critical("Hint: is /sbin missing in PATH?")
+ sys.exit(1)
+
proc = subprocess.Popen(["modprobe", "loop"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
proc.wait()
def main():
"""Main function [make pylint happy :)]"""
- if options.version:
- print os.path.basename(sys.argv[0]) + " " + PROG_VERSION
- sys.exit(0)
+ try:
+ if options.version:
+ print os.path.basename(sys.argv[0]) + " " + PROG_VERSION
+ sys.exit(0)
- if len(args) < 2:
- parser.error("invalid usage")
+ if len(args) < 2:
+ parser.error("invalid usage")
- # log handling
- handle_logging()
+ # log handling
+ handle_logging()
- # make sure we have the appropriate permissions
- check_uid_root()
+ # make sure we have the appropriate permissions
+ check_uid_root()
- check_options(options)
+ check_options(options)
- load_loop()
+ load_loop()
- logging.info("Executing grml2usb version %s", PROG_VERSION)
+ 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.dryrun:
+ logging.info("Running in simulation mode as requested via option dry-run.")
- check_programs()
+ check_programs()
- # specified arguments
- device = os.path.realpath(args[len(args) - 1])
- isos = args[0:len(args) - 1]
+ # specified arguments
+ device = os.path.realpath(args[len(args) - 1])
+ isos = args[0:len(args) - 1]
- if not os.path.isdir(device):
- if device[-1:].isdigit():
- 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 not os.path.isdir(device):
+ if device[-1:].isdigit():
+ 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)
+
+ # provide upgrade path
+ handle_compat_warning(device)
- # provide upgrade path
- handle_compat_warning(device)
+ # check for vfat partition
+ handle_vfat(device)
- # check for vfat partition
- handle_vfat(device)
+ # main operation (like installing files)
+ for iso in isos:
+ install(iso, device)
- # main operation (like installing files)
- for iso in isos:
- install(iso, device)
+ # install mbr
+ is_superfloppy = not device[-1:].isdigit()
+ if is_superfloppy:
+ logging.info("Detected superfloppy format - not installing MBR")
- # install mbr
- is_superfloppy = not device[-1:].isdigit()
- if is_superfloppy:
- logging.info("Detected superfloppy format - not installing MBR")
+ if not options.skipmbr and not os.path.isdir(device) and not is_superfloppy:
+ handle_mbr(device)
- if not options.skipmbr and not os.path.isdir(device) and not is_superfloppy:
- handle_mbr(device)
+ handle_bootloader(device)
- handle_bootloader(device)
+ logging.info("Note: grml flavour %s was installed as the default booting system.", GRML_DEFAULT)
- logging.info("Note: grml flavour %s was installed as the default booting system.", GRML_DEFAULT)
+ for flavour in GRML_FLAVOURS:
+ logging.info("Note: you can boot flavour %s using '%s' on the commandline.", flavour, flavour)
- for flavour in GRML_FLAVOURS:
- logging.info("Note: you can boot flavour %s using '%s' on the commandline.", flavour, flavour)
+ # finally be politely :)
+ logging.info("Finished execution of grml2usb (%s). Have fun with your grml system.", PROG_VERSION)
- # finally be politely :)
- logging.info("Finished execution of grml2usb (%s). Have fun with your grml system.", PROG_VERSION)
+ except Exception, error:
+ logging.critical("Fatal: %s", str(error))
+ sys.exit(1)
if __name__ == "__main__":