pungi/pungi_utils/patch_iso.py
Lubomír Sedlář 4b90822115 Add a script for modifying ISO images
With this script it's possible to add additional files into an ISO file.
If the file happens to be ks.cfg, the boot configs are tweaked so that
the kickstart is actually used.

Resolves: #503
Signed-off-by: Lubomír Sedlář <lsedlar@redhat.com>
2017-03-21 07:55:19 +01:00

134 lines
4.8 KiB
Python

# -*- coding: utf-8 -*-
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <https://gnu.org/licenses/>.
from kobo import shortcuts
import os
import productmd
import tempfile
try:
from shlex import quote
except ImportError:
from pipes import quote
from pungi import util
from pungi.phases.buildinstall import tweak_configs
from pungi.wrappers import iso
def sh(log, cmd, *args, **kwargs):
log.info('Running: %s', ' '.join(quote(x) for x in cmd))
ret, out = shortcuts.run(cmd, *args, **kwargs)
if out:
log.debug('%s', out)
return ret, out
def get_lorax_dir(default='/usr/share/lorax'):
try:
_, out = shortcuts.run(['python3', '-c' 'import pylorax; print(pylorax.find_templates())'])
return out.strip()
except Exception:
return default
def as_bool(arg):
if arg == 'true':
return True
elif arg == 'false':
return False
else:
return arg
def get_arch(log, iso_dir):
di_path = os.path.join(iso_dir, '.discinfo')
if os.path.exists(di_path):
di = productmd.discinfo.DiscInfo()
di.load(di_path)
log.info('Detected bootable ISO for %s (based on .discinfo)', di.arch)
return di.arch
ti_path = os.path.join(iso_dir, '.treeinfo')
if os.path.exists(ti_path):
ti = productmd.treeinfo.TreeInfo()
ti.load(ti_path)
log.info('Detected bootable ISO for %s (based on .treeinfo)', ti.tree.arch)
return ti.tree.arch
# There is no way to tell the architecture of an ISO file without guessing.
# Let's print a warning and continue with assuming unbootable ISO.
log.warning('Failed to detect arch for ISO, assuming unbootable one.')
log.warning('If this is incorrect, use the --force-arch option.')
return None
def run(log, opts):
# mount source iso
log.info('Mounting %s', opts.source)
target = os.path.abspath(opts.target)
with util.temp_dir(prefix='patch-iso-') as work_dir:
with iso.mount(opts.source) as source_iso_dir:
util.copy_all(source_iso_dir, work_dir)
# Make everything writable
for root, dirs, files in os.walk(work_dir):
for name in files:
os.chmod(os.path.join(root, name), 0o640)
for name in dirs:
os.chmod(os.path.join(root, name), 0o755)
# volume id is copied from source iso unless --label is specified
volume_id = opts.volume_id or iso.get_volume_id(opts.source)
# create graft points from mounted source iso + overlay dir
graft_points = iso.get_graft_points([work_dir, opts.dir])
# if ks.cfg is detected, patch syslinux + grub to use it
if 'ks.cfg' in graft_points:
log.info('Adding ks.cfg to boot configs')
tweak_configs(work_dir, volume_id, graft_points['ks.cfg'])
arch = opts.force_arch or get_arch(log, work_dir)
with tempfile.NamedTemporaryFile(prefix='graft-points-') as graft_file:
iso.write_graft_points(graft_file.name, graft_points,
exclude=["*/TRANS.TBL", "*/boot.cat"])
# make the target iso bootable if source iso is bootable
boot_args = input_charset = None
if arch:
boot_args = iso.get_boot_options(
arch, os.path.join(get_lorax_dir(), 'config_files/ppc'))
input_charset = 'utf-8' if 'ppc' not in arch else None
# Create the target ISO
mkisofs_cmd = iso.get_mkisofs_cmd(target, None,
volid=volume_id,
exclude=["./lost+found"],
graft_points=graft_file.name,
input_charset=input_charset,
boot_args=boot_args)
sh(log, mkisofs_cmd, workdir=work_dir)
# isohybrid support
if arch in ["x86_64", "i386"]:
isohybrid_cmd = iso.get_isohybrid_cmd(target, arch)
sh(log, isohybrid_cmd)
supported = as_bool(opts.supported or iso.get_checkisomd5_data(opts.source)['Supported ISO'])
# implantmd5 + supported bit (use the same as on source iso, unless
# overriden by --supported option)
isomd5sum_cmd = iso.get_implantisomd5_cmd(target, supported)
sh(log, isomd5sum_cmd)