751 lines
26 KiB
Python
751 lines
26 KiB
Python
#
|
|
# __init__.py
|
|
#
|
|
# Copyright (C) 2010 Red Hat, Inc.
|
|
#
|
|
# 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; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# 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 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 <http://www.gnu.org/licenses/>.
|
|
#
|
|
# Red Hat Author(s): Martin Gracik <mgracik@redhat.com>
|
|
# David Cantrell <dcantrell@redhat.com>
|
|
#
|
|
|
|
# set up logging
|
|
import logging
|
|
logger = logging.getLogger("pylorax")
|
|
|
|
sh = logging.StreamHandler()
|
|
sh.setLevel(logging.INFO)
|
|
logger.addHandler(sh)
|
|
|
|
|
|
import sys
|
|
import os
|
|
import ConfigParser
|
|
import tempfile
|
|
import shutil
|
|
import itertools
|
|
import glob
|
|
import math
|
|
import subprocess
|
|
|
|
from base import BaseLoraxClass, DataHolder
|
|
import output
|
|
|
|
import yum
|
|
import yumhelper
|
|
import ltmpl
|
|
|
|
import constants
|
|
from sysutils import *
|
|
|
|
from installtree import LoraxInstallTree
|
|
from outputtree import LoraxOutputTree
|
|
from buildstamp import BuildStamp
|
|
from treeinfo import TreeInfo
|
|
from discinfo import DiscInfo
|
|
import images
|
|
|
|
|
|
ARCHMAPS = {
|
|
"i386": {"base": "i386", "efi": "IA32", "is64": False},
|
|
"i586": {"base": "i386", "efi": "IA32", "is64": False},
|
|
"i686": {"base": "i386", "efi": "IA32", "is64": False},
|
|
"x86_64": {"base": "x86_64", "efi": "X64", "is64": True},
|
|
"ppc": {"base": "ppc", "efi": "", "is64": False},
|
|
"ppc64": {"base": "ppc", "efi": "", "is64": True},
|
|
"s390": {"base": "s390", "efi": "", "is64": False},
|
|
"s390x": {"base": "s390x", "efi": "", "is64": True},
|
|
"sparc": {"base": "sparc", "efi": "", "is64": False},
|
|
"sparcv9": {"base": "sparc", "efi": "", "is64": False},
|
|
"sparc64": {"base": "sparc", "efi": "", "is64": True},
|
|
"ia64": {"base": "ia64", "efi": "IA64", "is64": True}
|
|
}
|
|
|
|
LIB32 = "lib"
|
|
LIB64 = "lib64"
|
|
|
|
|
|
class Lorax(BaseLoraxClass):
|
|
|
|
def __init__(self):
|
|
BaseLoraxClass.__init__(self)
|
|
self._configured = False
|
|
|
|
def configure(self, conf_file="/etc/lorax/lorax.conf"):
|
|
self.conf = ConfigParser.SafeConfigParser()
|
|
|
|
# set defaults
|
|
self.conf.add_section("lorax")
|
|
self.conf.set("lorax", "debug", "1")
|
|
self.conf.set("lorax", "sharedir", "/usr/share/lorax")
|
|
|
|
self.conf.add_section("output")
|
|
self.conf.set("output", "colors", "1")
|
|
self.conf.set("output", "encoding", "utf-8")
|
|
self.conf.set("output", "ignorelist", "/usr/share/lorax/ignorelist")
|
|
|
|
self.conf.add_section("templates")
|
|
self.conf.set("templates", "ramdisk", "ramdisk.ltmpl")
|
|
|
|
# read the config file
|
|
if os.path.isfile(conf_file):
|
|
self.conf.read(conf_file)
|
|
|
|
# set up the output
|
|
debug = self.conf.getboolean("lorax", "debug")
|
|
output_level = output.DEBUG if debug else output.INFO
|
|
|
|
colors = self.conf.getboolean("output", "colors")
|
|
encoding = self.conf.get("output", "encoding")
|
|
|
|
self.output.basic_config(output_level=output_level,
|
|
colors=colors, encoding=encoding)
|
|
|
|
ignorelist = self.conf.get("output", "ignorelist")
|
|
if os.path.isfile(ignorelist):
|
|
with open(ignorelist, "r") as fobj:
|
|
for line in fobj:
|
|
line = line.strip()
|
|
if line and not line.startswith("#"):
|
|
self.output.ignore(line)
|
|
|
|
# cron does not have sbin in PATH,
|
|
# so we have to add it ourselves
|
|
os.environ["PATH"] = "{0}:/sbin:/usr/sbin".format(os.environ["PATH"])
|
|
|
|
self._configured = True
|
|
|
|
def init_file_logging(self, logdir, logname="pylorax.log"):
|
|
fh = logging.FileHandler(filename=joinpaths(logdir, logname), mode="w")
|
|
fh.setLevel(logging.DEBUG)
|
|
logger.addHandler(fh)
|
|
|
|
def run(self, ybo, product, version, release, variant="", bugurl="",
|
|
is_beta=False, workdir=None, outputdir=None):
|
|
|
|
assert self._configured
|
|
|
|
# set up work directory
|
|
self.workdir = workdir or tempfile.mkdtemp(prefix="pylorax.work.")
|
|
if not os.path.isdir(self.workdir):
|
|
os.makedirs(self.workdir)
|
|
|
|
# set up log directory
|
|
logdir = joinpaths(self.workdir, "log")
|
|
if not os.path.isdir(logdir):
|
|
os.makedirs(logdir)
|
|
|
|
self.init_file_logging(logdir)
|
|
logger.debug("using work directory {0.workdir}".format(self))
|
|
logger.debug("using log directory {0}".format(logdir))
|
|
|
|
# set up output directory
|
|
self.outputdir = outputdir or tempfile.mkdtemp(prefix="pylorax.out.")
|
|
if not os.path.isdir(self.outputdir):
|
|
os.makedirs(self.outputdir)
|
|
logger.debug("using output directory {0.outputdir}".format(self))
|
|
|
|
# do we have root privileges?
|
|
logger.info("checking for root privileges")
|
|
if not os.geteuid() == 0:
|
|
logger.critical("no root privileges")
|
|
sys.exit(1)
|
|
|
|
# do we have all lorax required commands?
|
|
self.lcmds = constants.LoraxRequiredCommands()
|
|
|
|
"""
|
|
missing = self.lcmds.get_missing()
|
|
if missing:
|
|
logger.critical("missing required command: {0}".format(missing))
|
|
sys.exit(1)
|
|
"""
|
|
|
|
# do we have a proper yum base object?
|
|
logger.info("checking yum base object")
|
|
if not isinstance(ybo, yum.YumBase):
|
|
logger.critical("no yum base object")
|
|
sys.exit(1)
|
|
|
|
# set up yum helper
|
|
logger.info("setting up yum helper")
|
|
self.yum = yumhelper.LoraxYumHelper(ybo)
|
|
logger.debug("using install root: {0}".format(self.yum.installroot))
|
|
|
|
# set up build architecture
|
|
logger.info("setting up build architecture")
|
|
|
|
self.buildarch = self.get_buildarch()
|
|
logger.debug("set buildarch = {0.buildarch}".format(self))
|
|
|
|
archmap = ARCHMAPS.get(self.buildarch)
|
|
assert archmap is not None
|
|
|
|
self.basearch = archmap.get("base")
|
|
self.efiarch = archmap.get("efi")
|
|
self.libdir = LIB64 if archmap.get("is64") else LIB32
|
|
logger.debug("set basearch = {0.basearch}".format(self))
|
|
logger.debug("set efiarch = {0.efiarch}".format(self))
|
|
logger.debug("set libdir = {0.libdir}".format(self))
|
|
|
|
# set up install tree
|
|
logger.info("setting up install tree")
|
|
self.installtree = LoraxInstallTree(self.yum, self.basearch,
|
|
self.libdir, self.workdir)
|
|
|
|
# set up required build parameters
|
|
logger.info("setting up build parameters")
|
|
self.product = product
|
|
self.version = version
|
|
self.release = release
|
|
logger.debug("set product = {0.product}".format(self))
|
|
logger.debug("set version = {0.version}".format(self))
|
|
logger.debug("set release = {0.release}".format(self))
|
|
|
|
# set up optional build parameters
|
|
self.variant = variant
|
|
self.bugurl = bugurl
|
|
self.is_beta = is_beta
|
|
logger.debug("set variant = {0.variant}".format(self))
|
|
logger.debug("set bugurl = {0.bugurl}".format(self))
|
|
logger.debug("set is_beta = {0.is_beta}".format(self))
|
|
|
|
# parse the template
|
|
logger.info("parsing the template")
|
|
tfile = joinpaths(self.conf.get("lorax", "sharedir"),
|
|
self.conf.get("templates", "ramdisk"))
|
|
|
|
tvars = { "basearch": self.basearch,
|
|
"buildarch": self.buildarch,
|
|
"libdir" : self.libdir,
|
|
"product": self.product.lower() }
|
|
|
|
template = ltmpl.LoraxTemplate()
|
|
template = template.parse(tfile, tvars)
|
|
|
|
# get required directories
|
|
logger.info("creating tree directories")
|
|
dirs = [f[1:] for f in template if f[0] == "mkdir"]
|
|
dirs = itertools.chain.from_iterable(dirs)
|
|
|
|
# create directories
|
|
for d in dirs:
|
|
os.makedirs(joinpaths(self.installtree.root, d))
|
|
|
|
# get list of required packages
|
|
logger.info("getting list of required packages")
|
|
required = [f[1:] for f in template if f[0] == "install"]
|
|
required = itertools.chain.from_iterable(required)
|
|
|
|
# install packages
|
|
for package in required:
|
|
self.installtree.yum.install(package)
|
|
self.installtree.yum.process_transaction()
|
|
|
|
# write .buildstamp
|
|
buildstamp = BuildStamp(self.workdir, self.product, self.version,
|
|
self.bugurl, self.is_beta, self.buildarch)
|
|
|
|
buildstamp.write()
|
|
shutil.copy2(buildstamp.path, self.installtree.root)
|
|
|
|
# DEBUG save list of installed packages
|
|
dname = joinpaths(self.workdir, "pkglists")
|
|
os.makedirs(dname)
|
|
for pkgname, pkgobj in self.installtree.yum.installed_packages.items():
|
|
with open(joinpaths(dname, pkgname), "w") as fobj:
|
|
for fname in pkgobj.filelist:
|
|
fobj.write("{0}\n".format(fname))
|
|
|
|
# remove locales
|
|
logger.info("removing locales")
|
|
self.installtree.remove_locales()
|
|
|
|
# create keymaps
|
|
logger.info("creating keymaps")
|
|
self.installtree.create_keymaps()
|
|
|
|
# create screenfont
|
|
logger.info("creating screenfont")
|
|
self.installtree.create_screenfont()
|
|
|
|
# move stubs
|
|
logger.info("moving stubs")
|
|
self.installtree.move_stubs()
|
|
|
|
# get the list of required modules
|
|
logger.info("getting list of required modules")
|
|
modules = [f[1:] for f in template if f[0] == "module"]
|
|
modules = list(itertools.chain.from_iterable(modules))
|
|
|
|
self.installtree.move_modules()
|
|
|
|
for kernel in self.installtree.kernels:
|
|
logger.info("cleaning up kernel modules")
|
|
self.installtree.cleanup_kernel_modules(modules, kernel)
|
|
|
|
logger.info("compressing modules")
|
|
self.installtree.compress_modules(kernel)
|
|
|
|
logger.info("running depmod")
|
|
self.installtree.run_depmod(kernel)
|
|
|
|
# move repos
|
|
logger.info("moving anaconda repos")
|
|
self.installtree.move_repos()
|
|
|
|
# create depmod conf
|
|
logger.info("creating depmod.conf")
|
|
self.installtree.create_depmod_conf()
|
|
|
|
# misc tree modifications
|
|
self.installtree.misc_tree_modifications()
|
|
|
|
# get config files
|
|
config_dir = joinpaths(self.conf.get("lorax", "sharedir"),
|
|
"config_files")
|
|
|
|
self.installtree.get_config_files(config_dir)
|
|
self.installtree.setup_sshd(config_dir)
|
|
|
|
# get anaconda portions
|
|
self.installtree.get_anaconda_portions()
|
|
|
|
# set up output tree
|
|
self.outputtree = LoraxOutputTree(self.outputdir, self.installtree,
|
|
self.product, self.version)
|
|
|
|
#self.outputtree.prepare()
|
|
#self.outputtree.get_isolinux()
|
|
#self.outputtree.get_memtest()
|
|
#self.outputtree.get_splash()
|
|
#self.outputtree.get_msg_files()
|
|
#self.outputtree.get_grub_conf()
|
|
|
|
# write .discinfo
|
|
discinfo = DiscInfo(self.workdir, self.release, self.basearch)
|
|
discinfo.write()
|
|
|
|
shutil.copy2(discinfo.path, self.outputtree.root)
|
|
|
|
# move grubefi to workdir
|
|
grubefi = joinpaths(self.installtree.root, "boot/efi/EFI/redhat",
|
|
"grub.efi")
|
|
|
|
if os.path.isfile(grubefi):
|
|
shutil.move(grubefi, self.workdir)
|
|
grubefi = joinpaths(self.workdir, os.path.basename(grubefi))
|
|
else:
|
|
grubefi = None
|
|
|
|
# move grub splash to workdir
|
|
splash = joinpaths(self.installtree.root, "boot/grub/",
|
|
"splash.xpm.gz")
|
|
|
|
if os.path.isfile(splash):
|
|
shutil.move(splash, self.workdir)
|
|
splash = joinpaths(self.workdir, os.path.basename(splash))
|
|
else:
|
|
splash = None
|
|
|
|
# copy kernels to output directory
|
|
self.outputtree.get_kernels(self.workdir)
|
|
|
|
# create .treeinfo
|
|
treeinfo = TreeInfo(self.workdir, self.product, self.version,
|
|
self.variant, self.basearch)
|
|
|
|
# get the image class
|
|
factory = images.Factory()
|
|
imgclass = factory.get_class(self.basearch)
|
|
|
|
i = imgclass(kernellist=self.outputtree.kernels,
|
|
installtree=self.installtree,
|
|
outputroot=self.outputtree.root,
|
|
product=self.product,
|
|
version=self.version,
|
|
treeinfo=treeinfo,
|
|
basearch=self.basearch)
|
|
|
|
# backup required files
|
|
i.backup_required(self.workdir)
|
|
|
|
# get list of not required packages
|
|
logger.info("getting list of not required packages")
|
|
remove = [f[1:] for f in template if f[0] == "remove"]
|
|
|
|
rdb = {}
|
|
order = []
|
|
for item in remove:
|
|
package = None
|
|
pattern = None
|
|
|
|
if item[0] == "--path":
|
|
# remove files
|
|
package = None
|
|
pattern = item[1]
|
|
else:
|
|
# remove package
|
|
package = item[0]
|
|
|
|
try:
|
|
pattern = item[1]
|
|
except IndexError:
|
|
pattern = None
|
|
|
|
if package not in rdb:
|
|
rdb[package] = [pattern]
|
|
order.append(package)
|
|
elif pattern not in rdb[package]:
|
|
rdb[package].append(pattern)
|
|
|
|
for package in order:
|
|
pattern_list = rdb[package]
|
|
logger.debug("{0}\t{1}".format(package, pattern_list))
|
|
self.installtree.yum.remove(package, pattern_list)
|
|
|
|
# cleanup python files
|
|
logger.info("cleaning up python files")
|
|
self.installtree.cleanup_python_files()
|
|
|
|
# compress install tree (create initrd)
|
|
logger.info("creating the initrd")
|
|
i.create_initrd(self.libdir)
|
|
|
|
#initrds = []
|
|
#for kernel in self.outputtree.kernels:
|
|
# suffix = ""
|
|
# if kernel.ktype == constants.K_PAE:
|
|
# suffix = "-PAE"
|
|
# elif kernel.ktype == constants.K_XEN:
|
|
# suffix = "-XEN"
|
|
#
|
|
# fname = "initrd{0}.img".format(suffix)
|
|
#
|
|
# initrd = DataHolder(fname=fname,
|
|
# fpath=joinpaths(self.workdir, fname),
|
|
# itype=kernel.ktype)
|
|
#
|
|
# logger.info("compressing install tree ({0})".format(kernel.version))
|
|
# success, elapsed = self.installtree.compress(initrd, kernel)
|
|
# if not success:
|
|
# logger.error("error while compressing install tree")
|
|
# else:
|
|
# logger.info("took {0:.2f} seconds".format(elapsed))
|
|
#
|
|
# initrds.append(initrd)
|
|
#
|
|
# # add kernel and initrd paths to .treeinfo
|
|
# section = "images-{0}".format("xen" if suffix else self.basearch)
|
|
# data = {"kernel": "images/pxeboot/{0}".format(kernel.fname)}
|
|
# treeinfo.add_section(section, data)
|
|
# data = {"initrd": "images/pxeboot/{0}".format(initrd.fname)}
|
|
# treeinfo.add_section(section, data)
|
|
#
|
|
## copy initrds to outputtree
|
|
#shutil.copy2(initrds[0].fpath, self.outputtree.isolinuxdir)
|
|
#
|
|
## create hard link
|
|
#source = joinpaths(self.outputtree.isolinuxdir, initrds[0].fname)
|
|
#link_name = joinpaths(self.outputtree.pxebootdir, initrds[0].fname)
|
|
#os.link(source, link_name)
|
|
#
|
|
#for initrd in initrds[1:]:
|
|
# shutil.copy2(initrd.fpath, self.outputtree.pxebootdir)
|
|
|
|
# create efi images
|
|
efiboot = None
|
|
if grubefi and self.efiarch not in ("IA32",):
|
|
# create efibootdir
|
|
self.outputtree.efibootdir = joinpaths(self.outputtree.root,
|
|
"EFI/BOOT")
|
|
os.makedirs(self.outputtree.efibootdir)
|
|
|
|
# set imgdir
|
|
self.outputtree.imgdir = joinpaths(self.outputtree.root,
|
|
"images")
|
|
|
|
kernel = i.kernels[0]
|
|
initrd = i.initrds[0]
|
|
|
|
# create efiboot image with kernel
|
|
logger.info("creating efiboot image with kernel")
|
|
efiboot = self.create_efiboot(kernel, initrd, grubefi, splash,
|
|
include_kernel=True)
|
|
|
|
if efiboot is None:
|
|
logger.critical("unable to create efiboot image")
|
|
sys.exit(1)
|
|
|
|
# create efidisk image
|
|
logger.info("creating efidisk image")
|
|
efidisk = self.create_efidisk(efiboot)
|
|
if efidisk is None:
|
|
logger.critical("unable to create efidisk image")
|
|
sys.exit(1)
|
|
|
|
# remove efiboot image with kernel
|
|
os.unlink(efiboot)
|
|
|
|
# create efiboot image without kernel
|
|
logger.info("creating efiboot image without kernel")
|
|
efiboot = self.create_efiboot(kernel, initrd, grubefi, splash,
|
|
include_kernel=False)
|
|
|
|
if efiboot is None:
|
|
logger.critical("unable to create efiboot image")
|
|
sys.exit(1)
|
|
|
|
# copy efiboot and efidisk to imgdir
|
|
shutil.copy2(efiboot, self.outputtree.imgdir)
|
|
shutil.copy2(efidisk, self.outputtree.imgdir)
|
|
|
|
# create boot iso
|
|
logger.info("creating boot iso")
|
|
i.create_boot(efiboot)
|
|
|
|
#bootiso = self.create_bootiso(self.outputtree, efiboot)
|
|
#if bootiso is None:
|
|
# logger.critical("unable to create boot iso")
|
|
# sys.exit(1)
|
|
#
|
|
#shutil.move(bootiso, self.outputtree.imgdir)
|
|
#
|
|
## add the boot.iso
|
|
#section = "images-{0}".format(self.basearch)
|
|
#data = {"boot.iso": "images/{0}".format(os.path.basename(bootiso))}
|
|
#treeinfo.add_section(section, data)
|
|
|
|
treeinfo.write()
|
|
|
|
shutil.copy2(treeinfo.path, self.outputtree.root)
|
|
|
|
def get_buildarch(self):
|
|
# get architecture of the available anaconda package
|
|
_, available = self.yum.search("anaconda")
|
|
|
|
if available:
|
|
anaconda = available.pop(0)
|
|
# src is not a real arch
|
|
if anaconda.arch == "src":
|
|
anaconda = available.pop(0)
|
|
buildarch = anaconda.arch
|
|
else:
|
|
# fallback to the system architecture
|
|
logger.warning("using system architecture")
|
|
buildarch = os.uname()[4]
|
|
|
|
return buildarch
|
|
|
|
def create_efiboot(self, kernel, initrd, grubefi, splash,
|
|
include_kernel=True):
|
|
|
|
# create the efi tree directory
|
|
efitree = tempfile.mkdtemp(prefix="efitree.", dir=self.workdir)
|
|
|
|
# copy kernel and initrd files to efi tree directory
|
|
if include_kernel:
|
|
shutil.copy2(kernel.fpath, efitree)
|
|
shutil.copy2(initrd.fpath, efitree)
|
|
efikernelpath = "/EFI/BOOT/{0}".format(kernel.fname)
|
|
efiinitrdpath = "/EFI/BOOT/{0}".format(initrd.fname)
|
|
else:
|
|
efikernelpath = "/images/pxeboot/{0}".format(kernel.fname)
|
|
efiinitrdpath = "/images/pxeboot/{0}".format(initrd.fname)
|
|
|
|
efisplashpath = "/EFI/BOOT/splash.xpm.gz"
|
|
|
|
# copy conf files to efi tree directory
|
|
src = joinpaths(self.installtree.root, "usr/share/anaconda/boot",
|
|
"*.conf")
|
|
|
|
for fname in glob.glob(src):
|
|
shutil.copy2(fname, efitree)
|
|
|
|
# edit the grub.conf file
|
|
grubconf = joinpaths(efitree, "grub.conf")
|
|
replace(grubconf, "@PRODUCT@", self.product)
|
|
replace(grubconf, "@VERSION@", self.version)
|
|
replace(grubconf, "@KERNELPATH@", efikernelpath)
|
|
replace(grubconf, "@INITRDPATH@", efiinitrdpath)
|
|
replace(grubconf, "@SPLASHPATH@", efisplashpath)
|
|
|
|
if self.efiarch == "IA32":
|
|
shutil.copy2(grubconf, joinpaths(efitree, "BOOT.conf"))
|
|
|
|
dst = joinpaths(efitree, "BOOT{0}.conf".format(self.efiarch))
|
|
shutil.move(grubconf, dst)
|
|
|
|
# copy grub.efi
|
|
if self.efiarch == "IA32":
|
|
shutil.copy2(grubefi, joinpaths(efitree, "BOOT.efi"))
|
|
|
|
dst = joinpaths(efitree, "BOOT{0}.efi".format(self.efiarch))
|
|
shutil.copy2(grubefi, dst)
|
|
|
|
# copy splash.xpm.gz
|
|
shutil.copy2(splash, efitree)
|
|
|
|
efiboot = joinpaths(self.workdir, "efiboot.img")
|
|
if os.path.isfile(efiboot):
|
|
os.unlink(efiboot)
|
|
|
|
# calculate the size of the efi tree directory
|
|
overhead = constants.FS_OVERHEAD * 1024
|
|
|
|
sizeinbytes = overhead
|
|
for root, _, fnames in os.walk(efitree):
|
|
for fname in fnames:
|
|
fpath = joinpaths(root, fname)
|
|
fsize = os.path.getsize(fpath)
|
|
|
|
# round to multiplications of 4096
|
|
fsize = math.ceil(fsize / 4096.0) * 4096
|
|
sizeinbytes += fsize
|
|
|
|
# mkdosfs needs the size in blocks of 1024 bytes
|
|
size = int(math.ceil(sizeinbytes / 1024.0))
|
|
|
|
cmd = [self.lcmds.MKDOSFS, "-n", "ANACONDA", "-C", efiboot, str(size)]
|
|
logger.debug(cmd)
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
|
proc.wait()
|
|
|
|
# mount the efiboot image
|
|
efibootdir = tempfile.mkdtemp(prefix="efiboot.", dir=self.workdir)
|
|
|
|
cmd = [self.lcmds.MOUNT, "-o", "loop,shortname=winnt,umask=0777",
|
|
"-t", "vfat", efiboot, efibootdir]
|
|
logger.debug(cmd)
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
|
proc.wait()
|
|
|
|
# copy the files to the efiboot image
|
|
dst = joinpaths(efibootdir, "EFI/BOOT")
|
|
os.makedirs(dst)
|
|
|
|
for fname in os.listdir(efitree):
|
|
fpath = joinpaths(efitree, fname)
|
|
shutil.copy2(fpath, dst)
|
|
|
|
if not include_kernel:
|
|
shutil.copy2(fpath, self.outputtree.efibootdir)
|
|
|
|
# unmount the efiboot image
|
|
cmd = [self.lcmds.UMOUNT, efibootdir]
|
|
logger.debug(cmd)
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
|
proc.wait()
|
|
|
|
# remove the work directories
|
|
shutil.rmtree(efibootdir)
|
|
#shutil.rmtree(efitree)
|
|
|
|
return efiboot
|
|
|
|
def create_efidisk(self, efiboot):
|
|
efidisk = joinpaths(self.workdir, "efidisk.img")
|
|
if os.path.isfile(efidisk):
|
|
os.unlink(efidisk)
|
|
|
|
partsize = os.path.getsize(efiboot)
|
|
disksize = 17408 + partsize + 17408
|
|
disksize = disksize + (disksize % 512)
|
|
|
|
# create efidisk file
|
|
with open(efidisk, "wb") as fobj:
|
|
fobj.truncate(disksize)
|
|
|
|
# create loop device
|
|
loopdev = create_loop_dev(efidisk)
|
|
|
|
if not loopdev:
|
|
os.unlink(efidisk)
|
|
return None
|
|
|
|
# create dm device
|
|
dmdev = create_dm_dev("efiboot", disksize / 512, loopdev)
|
|
|
|
if not dmdev:
|
|
remove_loop_dev(loopdev)
|
|
os.unlink(efidisk)
|
|
return None
|
|
|
|
# create partition on dm device
|
|
cmd = [self.lcmds.PARTED, "--script", dmdev, "mklabel", "gpt", "unit",
|
|
"b", "mkpart", '\"EFI System Partition\"', "fat32", "17408",
|
|
str(partsize + 17408), "set", "1", "boot", "on"]
|
|
logger.debug(cmd)
|
|
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
|
retcode = proc.wait()
|
|
|
|
if not retcode == 0:
|
|
remove_dm_dev(dmdev)
|
|
remove_loop_dev(loopdev)
|
|
os.unlink(efidisk)
|
|
return None
|
|
|
|
with open(efiboot, "rb") as f_from:
|
|
with open("{0}p1".format(dmdev), "wb") as f_to:
|
|
efidata = f_from.read(1024)
|
|
while efidata:
|
|
f_to.write(efidata)
|
|
efidata = f_from.read(1024)
|
|
|
|
remove_dm_dev("{0}p1".format(dmdev))
|
|
remove_dm_dev(dmdev)
|
|
remove_loop_dev(loopdev)
|
|
|
|
return efidisk
|
|
|
|
def create_bootiso(self, outputtree, efiboot=None):
|
|
bootiso = joinpaths(self.workdir, "boot.iso")
|
|
if os.path.isfile(bootiso):
|
|
os.unlink(bootiso)
|
|
|
|
if efiboot is not None:
|
|
efiargs = ["-eltorito-alt-boot", "-e", "images/efiboot.img",
|
|
"-no-emul-boot"]
|
|
efigraft = ["EFI/BOOT={0}".format(outputtree.efibootdir)]
|
|
else:
|
|
efiargs = []
|
|
efigraft = []
|
|
|
|
cmd = [self.lcmds.MKISOFS, "-o", bootiso,
|
|
"-b", "isolinux/isolinux.bin", "-c", "isolinux/boot.cat",
|
|
"-no-emul-boot", "-boot-load-size", "4",
|
|
"-boot-info-table"] + efiargs + ["-R", "-J", "-V", self.product,
|
|
"-T", "-graft-points",
|
|
"isolinux={0}".format(outputtree.isolinuxdir),
|
|
"images={0}".format(outputtree.imgdir)] + efigraft
|
|
logger.debug(cmd)
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
|
retcode = proc.wait()
|
|
|
|
if not retcode == 0:
|
|
return None
|
|
|
|
# create hybrid iso
|
|
cmd = [self.lcmds.ISOHYBRID, bootiso]
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
|
retcode = proc.wait()
|
|
|
|
# implant iso md5
|
|
cmd = [self.lcmds.IMPLANTISOMD5, bootiso]
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
|
retcode = proc.wait()
|
|
|
|
return bootiso
|