Fixes/Enhancements on loopback.cfg generation.

* Be more consistent about location of 'loopback.cfg'. (Use the first
one found in the iso image.)
* Fixed failure to pick the last menu item defined in syslinux config file.
* Pick 'initrd=...' parameter in 'append ...' line and generate 'initrd
...' line.
* Keep the previous content when updating.updating
* Removed redundant open/close in write_to_file().
* Fixed error message in write_to_file()
* Reduced the number of open/close in iso2grub2().
* Avoid adding a menu item withe a given name more than once.
* Keep, within the generated file, record of the source files from which menu items were picked up.
pull/291/head
Shinji Suzuki 6 years ago
parent 9f28a1d756
commit 8ea5932bdc

@ -21,15 +21,24 @@ def mbusb_update_grub_cfg():
:return:
"""
# Lets convert syslinux config file to grub2 accepted file format.
_iso_dir = os.path.join(config.usb_mount, 'multibootusb', iso.iso_basename(config.image_path))
install_dir = os.path.join(config.usb_mount, 'multibootusb',
iso.iso_basename(config.image_path))
# First write custom loopback.cfg file so as to be detected by iso2grub2 function later.
write_custom_gurb_cfg()
# There may be more than one loopback.cfg but we just need to fix
# one and that is goingn to be referenced in mbusb's grub.cfg.
loopback_cfg_path = iso.iso_file_path(config.image_path, 'loopback.cfg')
if not loopback_cfg_path:
loopback_cfg_path = 'loopback.cfg'
wrote_custom_cfg = write_custom_grub_cfg(install_dir, loopback_cfg_path)
# Try to generate loopback entry file from syslinux config files
try:
gen.log('Trying to create loopback.cfg')
iso2_grub2_cfg = iso2grub2(_iso_dir)
iso2_grub2_cfg = iso2grub2(install_dir, loopback_cfg_path,
wrote_custom_cfg)
except Exception as e:
print(e)
gen.log(e)
@ -39,7 +48,6 @@ def mbusb_update_grub_cfg():
grub_cfg_path = None
syslinux_menu = None
# sys_cfg_path = None
loopback_cfg_path = None
mbus_grub_cfg_path = os.path.join(config.usb_mount, 'multibootusb', 'grub', 'grub.cfg')
# iso_grub_cfg = iso.iso_file_path(config.image_path, 'grub.cfg')
if iso.isolinux_bin_dir(config.image_path) is not False:
@ -55,7 +63,6 @@ def mbusb_update_grub_cfg():
efi_grub_cfg = get_grub_cfg(config.image_path)
boot_grub_cfg = get_grub_cfg(config.image_path, efi=False)
loopback_cfg_path = iso.iso_file_path(config.image_path, 'loopback.cfg')
if loopback_cfg_path is not False:
grub_cfg_path = loopback_cfg_path.replace('\\', '/')
@ -109,12 +116,13 @@ def mbusb_update_grub_cfg():
gen.log('Unable to update entry in grub.cfg...')
def write_custom_gurb_cfg():
def write_custom_grub_cfg(install_dir, loopback_cfg_path):
"""
Create custom grub loopback.cfg file for known distros. Custom menu entries are stored on munus.py module
:return:
"""
loopback_cfg_path = os.path.join(config.usb_mount, 'multibootusb', iso.iso_basename(config.image_path), 'loopback.cfg')
loopback_cfg_path = os.path.join(
install_dir, loopback_cfg_path.lstrip(r'\/'))
menu = False
if config.distro == 'pc-tool':
menu = menus.pc_tool_config(syslinux=False, grub=True)
@ -124,6 +132,9 @@ def write_custom_gurb_cfg():
if menu is not False:
gen.log('Writing custom loopback.cfg file...')
write_to_file(loopback_cfg_path, menu)
return True
else:
return False
def get_grub_cfg(iso_link, efi=True):
@ -194,13 +205,10 @@ def grub_raw_iso(mbus_grub_cfg_path):
def write_to_file(file_path, _strings):
try:
if not os.path.exists(file_path):
open(file_path, 'a').close()
with open(file_path, 'a') as f:
f.write(_strings + '\n')
except:
gen.log('Error writing to loopback.cfg file..')
gen.log('Error writing to %s...' % file_path)
def extract_kernel_line(search_text, match_line, isolinux_dir):
@ -247,20 +255,60 @@ def extract_kernel_line(search_text, match_line, isolinux_dir):
return kernel_line.replace('\\', '/').replace('//', '/')
def iso2grub2(iso_dir):
def extract_initrd_param(value, isolinux_dir):
kernel_search_path = [
'',
os.path.join('multibootusb',
iso.iso_basename(config.image_path), isolinux_dir),
os.path.join('multibootusb', # A dire attemp to find.
iso.iso_basename(config.image_path)),
]
initrd_line, others = '', []
for paramdef in value.split(' '):
if not paramdef.lower().startswith('initrd='):
others.append(paramdef)
continue
paths = []
for path in paramdef[len('initrd='):].split(','):
# try to find the specified kernel
for d in kernel_search_path:
if os.path.exists(os.path.join(config.usb_mount, d, path)):
paths.append(os.path.join(d, path))
break
else:
# Give up and use the specified kernel as is.
paths.append(path)
initrd_line = 'initrd ' + ' '.join(paths)
return initrd_line, ' '.join(others)
def iso2grub2(install_dir, loopback_cfg_path, wrote_custom_cfg):
"""
Function to convert syslinux configuration to grub2 accepted configuration format. Features implemented are similar
to that of grub2 'loopback.cfg'. This 'loopback.cfg' file can be later on caled directly from grub2. The main
advantage of this function is to generate the 'loopback.cfg' file automatically without manual involvement.
:param iso_dir: Path to distro install directory for looping through '.cfg' files.
:param install_dir: Path to distro install directory for looping through '.cfg' files.
:param loopback_cfg_path: Path to 'loopback.cfg' to be updated
:param file_out: Path to 'loopback.cfg' file. By default it is set to root of distro install directory.
:return:
"""
grub_file_path = os.path.join(config.usb_mount, 'multibootusb', iso.iso_basename(config.image_path), 'loopback.cfg')
gen.log('loopback.cfg file is set to ' + grub_file_path)
loopback_cfg_path = os.path.join(
install_dir, loopback_cfg_path.lstrip(r'\/'))
gen.log('loopback.cfg file is set to ' + loopback_cfg_path)
# Comment-out the previous content if write_custom_grub_cfg() did nothing.
if os.path.exists(loopback_cfg_path) and not wrote_custom_cfg:
with open(loopback_cfg_path, 'r') as f:
lines = f.readlines()
with open(loopback_cfg_path, 'w') as f:
f.write('##### Previous content is kept from here.\n')
f.write( ''.join('#'+s for s in lines))
f.write('##### to here.\n\n')
iso_bin_dir = iso.isolinux_bin_dir(config.image_path)
seen_menu_lines = []
# Loop though the distro installed directory for finding config files
for dirpath, dirnames, filenames in os.walk(iso_dir):
for dirpath, dirnames, filenames in os.walk(install_dir):
for f in filenames:
# We will strict to only files ending with '.cfg' extension. This is the file extension isolinux or syslinux
# recommends for writing configurations
@ -274,85 +322,93 @@ def iso2grub2(iso_dir):
with open(cfg_file_path, "r", errors='ignore') as f:
data = f.read()
# Make sure that lines with menu label, kernel and append are available for processing
ext_text = re.finditer('^(menu label|label)(.*?)(?=^(menu label|label))', data, re.I|re.DOTALL|re.MULTILINE)
if not ext_text:
matching_blocks = re.finditer(
'^(menu label|label)(.*?)(?=^(menu label|label|$))',
data, re.I|re.DOTALL|re.MULTILINE)
# materialize the list.
matching_blocks = [s for s in matching_blocks]
if not matching_blocks:
continue
for m in ext_text:
menuentry = ''
# kernel = ''
kernel_line = ''
boot_options = ''
initrd_line = ''
# initrd = ''
# Extract line containing 'menu label' and convert to menu entry of grub2
matched = m.group().lower()
if 'menu label' in matched:
menu_line = re.search('menu label(.*)\s', m.group(), re.I).group()
menuentry = 'menuentry ' + gen.quote(re.sub(r'menu label', '', menu_line, re.I, ).strip())
# Ensure that we do not have caps menu label in the menuentry
menuentry = menuentry.replace('MENU LABEL', '')
elif 'label ' in matched:
# Probably config does not use 'menu label' line. Just line containing 'label'
# and convert to menu entry of grub2
menu_line = re.search('^label(.*)\s', m.group(), re.I).group()
menuentry = 'menuentry ' + gen.quote(re.sub(r'label', '', menu_line, re.I, ).strip())
# Ensure that we do not have caps label in the menuentry
menuentry = menuentry.replace('LABEL', '')
# Extract kernel line and change to linux line of grub2
if 'kernel' in matched or 'linux' in matched:
kernel_text = re.findall('((kernel|linux)[= ].*?[ \s])', m.group(), re.I)
match_count = len(re.findall('((kernel|linux)[= ].*?[ \s])', m.group(), re.I))
if match_count is 1:
kernel_line = extract_kernel_line(kernel_text[0][1], kernel_text[0][0], iso_bin_dir)
elif match_count > 2:
for _lines in kernel_text:
kernel_line = extract_kernel_line(_lines[1], _lines[0],
iso_bin_dir)
if kernel_line == '':
continue
else:
break
if 'initrd' in matched:
initrd_text = re.findall('((initrd)[= ].*?[ \s])', m.group(), re.I)
match_count = len(re.findall('((initrd)[= ].*?[ \s])', m.group(), re.I))
if match_count is 1:
initrd_line = extract_kernel_line(initrd_text[0][1], initrd_text[0][0], iso_bin_dir)
elif match_count > 2:
for _lines in initrd_text:
initrd_line = extract_kernel_line(_lines[1], _lines[0],
iso_bin_dir)
if initrd_line == '':
continue
else:
break
if 'append' in matched:
append_line = re.search('append (.*)\s', m.group(), re.I).group()
boot_options = re.sub(r'((initrd[= ])(.*?)[ ])', '', append_line, re.I, flags=re.DOTALL)
boot_options = re.sub(r'append', '', boot_options, re.I).strip()
boot_options = boot_options.replace('APPEND', '')
if kernel_line.strip():
linux = kernel_line.strip() + ' ' + boot_options.strip().strip()
gen.log("Probing '%s'" % cfg_file_path)
out_lines = []
for match in matching_blocks:
matched_block = match.group()
# Extract 'menu label or 'label' line.
matches = re.findall(
r'^\s*(menu label|label)\s+(.*)$',
matched_block, re.I|re.MULTILINE)
if 0 == len(matches):
gen.log('Warning: found a block without menu-entry.')
menu_line = 'menuentry "Anonymous"'
menu_label = 'Unlabeled'
else:
if 2 <= len(matches):
gen.log('Warning: found a block with more than one '
'menu entries.')
keyword, value = matches[0]
menu_line = 'menuentry ' + gen.quote(value)
menu_label = value
# Extract lines containing 'kernel','linux','initrd'
# or 'append' to convert them into grub2 compatible ones.
linux_line = initrd_line = None
appends = []
for keyword, value in re.findall(
r'^\s*(kernel|linux|initrd|append)[= ](.*)$',
matched_block, re.I|re.MULTILINE):
# Ensure that we do not have caps label in the menuentry.
value = value.replace(keyword.upper(), '') # Essencial?
kw = keyword.lower()
if kw in ['kernel', 'linux']:
if linux_line:
gen.log("Warning: found more than one "
"'kernel/linux' lines in block '%s'."
% menu_label)
continue
linux_line = extract_kernel_line(
keyword, '%s %s' % (keyword, value), iso_bin_dir)
elif kw == 'initrd':
if initrd_line:
gen.log("Warning: found more than one "
"'initrd' specifications in block '%s'."
% menu_label)
continue
initrd_line = extract_kernel_line(
keyword, '%s %s' % (keyword, value), iso_bin_dir)
elif kw== 'append':
if initrd_line:
gen.log("Warning: found both 'append initrd=...' "
"and 'initrd ...' line")
new_initrd_line, new_value = extract_initrd_param(
value, iso_bin_dir)
if new_initrd_line:
initrd_line = new_initrd_line
appends.append(new_value)
if menu_line in seen_menu_lines:
out_lines.append( "# '%s' is superceded by the previous "
"definition." % menu_label)
else:
linux = ''
if menuentry.strip() and linux.strip() and initrd_line.strip():
write_to_file(grub_file_path, menuentry + '{')
write_to_file(grub_file_path, ' ' + linux)
write_to_file(grub_file_path, ' ' + initrd_line)
write_to_file(grub_file_path, '}\n')
elif menuentry.strip() and linux.strip():
write_to_file(grub_file_path, menuentry + '{')
write_to_file(grub_file_path, ' ' + linux)
write_to_file(grub_file_path, '}\n')
if os.path.exists(grub_file_path):
if linux_line or initrd_line:
seen_menu_lines.append(menu_line)
out_lines.append(menu_line + ' {')
for l, a in [
(linux_line, ' ' + ' '.join(appends)),
(initrd_line, '')]:
if l:
out_lines.append(' ' + l + a)
out_lines.append( '}' )
else:
out_lines.append("# Avoided emitting an empty "
"menu item '%s'." % menu_label)
with open(loopback_cfg_path, 'a') as f:
f.write('# Extracted from %s\n' % cfg_file_path)
f.write('\n'.join(out_lines) + '\n')
f.write('\n')
if os.path.exists(loopback_cfg_path):
gen.log(
'loopback.cfg file is successfully created.\nYou must send this file for debugging if something goes wrong.')
return 'loopback.cfg'

Loading…
Cancel
Save