859 lines
30 KiB
Python
859 lines
30 KiB
Python
#
|
|
# images.py
|
|
#
|
|
# Copyright (C) 2009 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>
|
|
#
|
|
|
|
import sys
|
|
import os
|
|
import re
|
|
import shutil
|
|
import gzip
|
|
import commands
|
|
import tempfile
|
|
import math
|
|
import glob
|
|
import fnmatch
|
|
|
|
from base import BaseImageClass
|
|
from sysutils import *
|
|
|
|
|
|
class InitRD(BaseImageClass):
|
|
|
|
def __init__(self, installtree, modules, template_file, workdir="/tmp"):
|
|
BaseImageClass.__init__(self)
|
|
|
|
self.installtree = installtree
|
|
self.modules = modules
|
|
self.template_file = template_file
|
|
self.workdir = workdir
|
|
|
|
self.srctree = self.installtree.rootdir
|
|
self.dsttree = None
|
|
|
|
def create(self):
|
|
for kernel in self.installtree.kernels:
|
|
msg = ":: creating the initrd image for <b>{0}</b>"
|
|
msg = msg.format(kernel.filename)
|
|
self.pinfo(msg)
|
|
|
|
# prepare the working environment
|
|
self.pinfo("preparing the work environment")
|
|
self.prepare(kernel)
|
|
|
|
# get the kernel modules
|
|
self.pinfo("getting the kernel modules")
|
|
self.get_kernel_modules(kernel, self.modules)
|
|
|
|
# get keymaps
|
|
self.pinfo("creating keymaps")
|
|
ok = self.get_keymaps()
|
|
if not ok:
|
|
self.perror("could not create keymaps")
|
|
continue
|
|
|
|
# create locales
|
|
self.pinfo("creating locales")
|
|
ok = self.create_locales()
|
|
if not ok:
|
|
self.perror("could not create locales")
|
|
continue
|
|
|
|
# parse the template file
|
|
self.pinfo("parsing the template")
|
|
variables = {"buildarch": self.conf.buildarch,
|
|
"basearch": self.conf.basearch,
|
|
"libdir": self.conf.libdir}
|
|
self.parse_template(self.template_file, variables)
|
|
|
|
# create the initrd file
|
|
self.pinfo("compressing the initrd image file")
|
|
initrdfile = self.compress(kernel)
|
|
if not initrdfile:
|
|
self.perror("could not create the initrd image file")
|
|
continue
|
|
|
|
yield (kernel, initrdfile)
|
|
|
|
def prepare(self, kernel):
|
|
# create the initrd working directory
|
|
dir = os.path.join(self.workdir, "initrd-{0}".format(kernel.version))
|
|
if os.path.isdir(dir):
|
|
shutil.rmtree(dir)
|
|
os.mkdir(dir)
|
|
|
|
# set the destination tree
|
|
self.dsttree = dir
|
|
|
|
# copy the buildstamp
|
|
shutil.copy2(self.conf.buildstamp, self.dsttree)
|
|
|
|
# create the .profile
|
|
profile = os.path.join(self.dsttree, ".profile")
|
|
text = """PS1="[anaconda \u@\h \W]\\$ "
|
|
PATH=/bin:/usr/bin:/usr/sbin:/mnt/sysimage/sbin:/mnt/sysimage/usr/sbin:/mnt/sysimage/bin:/mnt/sysimage/usr/bin
|
|
export PS1 PATH
|
|
|
|
"""
|
|
|
|
with open(profile, "w") as f:
|
|
f.write(text)
|
|
|
|
# create the lib directories
|
|
os.mkdir(os.path.join(self.dsttree, self.conf.libdir))
|
|
os.makedirs(os.path.join(self.dsttree, "usr", self.conf.libdir))
|
|
|
|
# XXX
|
|
def get_kernel_modules(self, kernel, modset):
|
|
moddir = os.path.join(self.const.MODDIR, kernel.version)
|
|
src_moddir = os.path.join(self.srctree, moddir)
|
|
dst_moddir = os.path.join(self.dsttree, moddir)
|
|
|
|
# copy all modules to the initrd tree
|
|
os.makedirs(os.path.dirname(dst_moddir))
|
|
shutil.copytree(src_moddir, dst_moddir)
|
|
|
|
# expand modules
|
|
modules = set()
|
|
pattern = re.compile(r"\.ko$")
|
|
for name in modset:
|
|
if name.startswith("="):
|
|
group = name[1:]
|
|
if group in ("scsi", "ata"):
|
|
p = os.path.join(src_moddir, "modules.block")
|
|
elif group == "net":
|
|
p = os.path.join(src_moddir, "modules.networking")
|
|
else:
|
|
p = os.path.join(src_moddir, "modules.{0}".format(group))
|
|
|
|
if os.path.isfile(p):
|
|
with open(p, "r") as f:
|
|
for line in f:
|
|
module = pattern.sub("", line.strip())
|
|
modules.add(module)
|
|
else:
|
|
modules.add(name)
|
|
|
|
# resolve modules dependencies
|
|
moddep = os.path.join(src_moddir, self.const.MODDEPFILE)
|
|
with open(moddep, "r") as f:
|
|
lines = map(lambda line: line.strip(), f.readlines())
|
|
|
|
modpattern = re.compile(r"^.*/(?P<name>.*)\.ko:(?P<deps>.*)$")
|
|
deppattern = re.compile(r"^.*/(?P<name>.*)\.ko$")
|
|
unresolved = True
|
|
|
|
while unresolved:
|
|
unresolved = False
|
|
for line in lines:
|
|
m = modpattern.match(line)
|
|
modname = m.group("name")
|
|
if modname in modules:
|
|
# add the dependencies
|
|
for dep in m.group("deps").split():
|
|
m = deppattern.match(dep)
|
|
depname = m.group("name")
|
|
if depname not in modules:
|
|
unresolved = True
|
|
modules.add(depname)
|
|
|
|
# remove not needed modules
|
|
for root, dirs, files in os.walk(dst_moddir):
|
|
for file in files:
|
|
path = os.path.join(root, file)
|
|
name, ext = os.path.splitext(file)
|
|
|
|
if ext == ".ko":
|
|
if name not in modules:
|
|
os.unlink(path)
|
|
else:
|
|
# get the required firmware
|
|
cmd = "{0.MODINFO} -F firmware {1}"
|
|
cmd = cmd.format(self.cmd, path)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.perror(stdout)
|
|
continue
|
|
|
|
for fw in stdout.split():
|
|
fw = os.path.join(self.const.FWDIR, fw)
|
|
src = os.path.join(self.srctree, fw)
|
|
if not os.path.exists(src):
|
|
msg = "missing firmware {0}".format(fw)
|
|
self.pwarning(msg)
|
|
continue
|
|
|
|
# copy the firmware
|
|
dst = os.path.join(self.dsttree, fw)
|
|
dir = os.path.dirname(dst)
|
|
makedirs_(dir)
|
|
shutil.copy2(src, dst)
|
|
|
|
# copy additional firmware
|
|
fw = [("ipw2100", "ipw2100*"),
|
|
("ipw2200", "ipw2200*"),
|
|
("iwl3945", "iwlwifi-3945*"),
|
|
("iwl4965", "iwlwifi-4965*"),
|
|
("atmel", "atmel_*.bin"),
|
|
("zd1211rw", "zd1211"),
|
|
("qla2xxx", "ql*")]
|
|
|
|
for module, fname in fw:
|
|
if module in modules:
|
|
scopy_(src_root=self.srctree,
|
|
src_path=os.path.join(self.const.FWDIR, fname),
|
|
dst_root=self.dsttree,
|
|
dst_path=self.const.FWDIR)
|
|
|
|
# XXX
|
|
# remove empty directories
|
|
#empty_dirs = set()
|
|
#for root, dirs, files in os.walk(dst_moddir, topdown=False):
|
|
# if not dirs and not files:
|
|
# shutil.rmtree(root)
|
|
|
|
# get the modules paths
|
|
modpaths = {}
|
|
for root, dirs, files in os.walk(dst_moddir):
|
|
for file in files:
|
|
modpaths[file] = os.path.join(root, file)
|
|
|
|
# create the modules list
|
|
modlist = {}
|
|
for modtype, fname in {"scsi": "modules.block",
|
|
"eth": "modules.networking"}.items():
|
|
|
|
fname = os.path.join(dst_moddir, fname)
|
|
with open(fname, "r") as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
|
|
modname, ext = os.path.splitext(line)
|
|
if (line not in modpaths or
|
|
modname in ("floppy", "libiscsi", "scsi_mod")):
|
|
continue
|
|
|
|
cmd = "{0.MODINFO} -F description {1}"
|
|
cmd = cmd.format(self.cmd, modpaths[line])
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.pwarning(stdout)
|
|
desc = ""
|
|
else:
|
|
desc = stdout.split("\n")[0]
|
|
desc = desc.strip()[:65]
|
|
|
|
if not desc:
|
|
desc = "{0} driver".format(modname)
|
|
|
|
info = '{0}\n\t{1}\n\t"{2}"\n'
|
|
info = info.format(modname, modtype, desc)
|
|
modlist[modname] = info
|
|
|
|
# write the module-info
|
|
moduleinfo = os.path.join(os.path.dirname(dst_moddir),
|
|
self.const.MODULEINFO)
|
|
|
|
with open(moduleinfo, "w") as f:
|
|
f.write("Version 0\n")
|
|
for modname in sorted(modlist.keys()):
|
|
f.write(modlist[modname])
|
|
|
|
# compress modules
|
|
for root, dirs, files in os.walk(dst_moddir):
|
|
for file in filter(lambda f: f.endswith(".ko"), files):
|
|
path = os.path.join(root, file)
|
|
with open(path, "rb") as f:
|
|
data = f.read()
|
|
|
|
gzipped = gzip.open("{0}.gz".format(path), "wb")
|
|
gzipped.write(data)
|
|
gzipped.close()
|
|
os.unlink(path)
|
|
|
|
# run depmod
|
|
systemmap = os.path.join(self.srctree, self.const.BOOTDIR,
|
|
"System.map-{0}".format(kernel.version))
|
|
|
|
cmd = "{0.DEPMOD} -a -F {1} -b {2} {3}"
|
|
cmd = cmd.format(self.cmd, systemmap,
|
|
self.dsttree, kernel.version)
|
|
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.perror(stdout)
|
|
|
|
# remove *map files
|
|
remove_(os.path.join(dst_moddir, "*map"))
|
|
|
|
def get_keymaps(self):
|
|
override = "keymaps-override-{0}".format(self.conf.basearch)
|
|
override = os.path.join(self.srctree, self.const.ANACONDA_RUNTIME,
|
|
override)
|
|
|
|
getkeymaps = os.path.join(self.srctree, self.const.ANACONDA_RUNTIME,
|
|
"getkeymaps")
|
|
|
|
dst = os.path.join(self.dsttree, "etc/keymaps.gz")
|
|
dir = os.path.dirname(dst)
|
|
if not os.path.isdir(dir):
|
|
os.makedirs(dir)
|
|
|
|
if os.path.isfile(override):
|
|
self.pinfo("using keymaps override")
|
|
shutil.copy2(override, dst)
|
|
else:
|
|
cmd = "{0} {1} {2} {3}"
|
|
cmd = cmd.format(getkeymaps, self.conf.basearch, dst, self.srctree)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.perror(stdout)
|
|
return False
|
|
|
|
return True
|
|
|
|
def create_locales(self):
|
|
localedir = os.path.join(self.dsttree, self.const.LOCALEDIR)
|
|
os.makedirs(localedir)
|
|
|
|
cmd = "{0.LOCALEDEF} -c -i en_US -f UTF-8 --prefix {1} en_US"
|
|
cmd = cmd.format(self.cmd, self.dsttree)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.perror(stdout)
|
|
return False
|
|
|
|
return True
|
|
|
|
def compress(self, kernel):
|
|
filename = "initrd-{0}.img".format(kernel.version)
|
|
filepath = os.path.join(self.workdir, filename)
|
|
|
|
# create the cpio archive
|
|
cpioarchive = "{0}.cpio".format(filepath)
|
|
|
|
cwd = os.getcwd()
|
|
os.chdir(self.dsttree)
|
|
|
|
cmd = "find . | cpio --quiet -c -o > {0}".format(cpioarchive)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
|
|
os.chdir(cwd)
|
|
|
|
if err:
|
|
self.perror(stdout)
|
|
return None
|
|
|
|
# create the gzip archive
|
|
with open(cpioarchive, "rb") as f:
|
|
cpiodata = f.read()
|
|
|
|
gzipped = gzip.open(filepath, "wb")
|
|
gzipped.write(cpiodata)
|
|
gzipped.close()
|
|
|
|
# remove the cpio archive
|
|
os.unlink(cpioarchive)
|
|
|
|
# remove the initrd tree
|
|
#shutil.rmtree(self.dsttree)
|
|
|
|
return filepath
|
|
|
|
|
|
class EFI(BaseImageClass):
|
|
|
|
def __init__(self, installtree, kernel, initrd, product, version,
|
|
workdir="/tmp"):
|
|
|
|
BaseImageClass.__init__(self)
|
|
|
|
self.srctree = installtree.rootdir
|
|
self.dsttree = None
|
|
|
|
self.kernel = kernel
|
|
self.initrd = initrd
|
|
self.product = product
|
|
self.version = version
|
|
|
|
self.workdir = workdir
|
|
|
|
def create(self):
|
|
msg = ":: creating the efi images for <b>{0}</b>"
|
|
self.pinfo(msg.format(self.kernel.filename))
|
|
|
|
# create efiboot image with kernel
|
|
self.pinfo("creating efiboot image with kernel")
|
|
efiboot_kernel = self.create_efiboot(with_kernel=True)
|
|
if efiboot_kernel is None:
|
|
self.perror("unable to create the efiboot image")
|
|
return None, None
|
|
|
|
# create the efidisk image
|
|
self.pinfo("creating efidisk image")
|
|
efidisk = self.create_efidisk(efiboot_kernel)
|
|
if efidisk is None:
|
|
self.perror("unable to create the efidisk image")
|
|
return None, None
|
|
|
|
# remove the efiboot image with kernel
|
|
os.unlink(efiboot_kernel)
|
|
|
|
# create efiboot image without kernel
|
|
self.pinfo("creating efiboot image without kernel")
|
|
efiboot_nokernel = self.create_efiboot(with_kernel=False)
|
|
if efiboot_nokernel is None:
|
|
self.perror("unable to create the efiboot image")
|
|
return None, None
|
|
|
|
return efiboot_nokernel, efidisk
|
|
|
|
def create_efiboot(self, with_kernel=True):
|
|
# create the efi tree directory
|
|
efitree = tempfile.mkdtemp(prefix="efitree.", dir=self.workdir)
|
|
|
|
efikernelpath = "/images/pxeboot/vmlinuz"
|
|
efiinitrdpath = "/images/pxeboot/initrd.img"
|
|
efisplashpath = "/EFI/BOOT/splash.xpm.gz"
|
|
|
|
# copy kernel and initrd files to efi tree directory
|
|
if with_kernel:
|
|
kpath = self.kernel.path
|
|
shutil.copy2(kpath, os.path.join(efitree, "vmlinuz"))
|
|
shutil.copy2(self.initrd, os.path.join(efitree, "initrd.img"))
|
|
efikernelpath = "/EFI/BOOT/vmlinuz"
|
|
efiinitrdpath = "/EFI/BOOT/initrd.img"
|
|
|
|
# copy conf files to efi tree directory
|
|
srcdir = os.path.join(self.srctree, self.const.ANACONDA_BOOTDIR)
|
|
scopy_(src_root=srcdir, src_path="*.conf",
|
|
dst_root=efitree, dst_path="")
|
|
|
|
# edit the grub.conf file
|
|
grubconf = os.path.join(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.conf.efiarch == "IA32":
|
|
shutil.copy2(grubconf, os.path.join(efitree, "BOOT.conf"))
|
|
|
|
dst = os.path.join(efitree, "BOOT{0}.conf".format(self.conf.efiarch))
|
|
shutil.move(grubconf, dst)
|
|
|
|
# copy grub.efi
|
|
grubefi = os.path.join(self.srctree, self.const.EFIDIR, "grub.efi")
|
|
|
|
if self.conf.efiarch == "IA32":
|
|
shutil.copy2(grubefi, os.path.join(efitree, "BOOT.efi"))
|
|
|
|
dst = os.path.join(efitree, "BOOT{0}.efi".format(self.conf.efiarch))
|
|
shutil.copy2(grubefi, dst)
|
|
|
|
# copy splash.xpm.gz
|
|
splash = os.path.join(self.srctree, self.const.SPLASH)
|
|
shutil.copy2(splash, efitree)
|
|
|
|
efiboot = os.path.join(self.workdir, "efiboot.img")
|
|
if os.path.isfile(efiboot):
|
|
os.unlink(efiboot)
|
|
|
|
# calculate the size of the efi tree directory
|
|
fsoverhead = 100 * 1024
|
|
sizeinbytes = fsoverhead
|
|
for root, dirs, files in os.walk(efitree):
|
|
for file in files:
|
|
filepath = os.path.join(root, file)
|
|
sizeinbytes += os.path.getsize(filepath)
|
|
|
|
# mkdosfs needs the size in blocks of 1024 bytes
|
|
size = int(math.ceil(sizeinbytes / 1024.0))
|
|
|
|
cmd = "{0.MKDOSFS} -n ANACONDA -C {1} {2} > /dev/null"
|
|
cmd = cmd.format(self.cmd, efiboot, size)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.perror(stdout)
|
|
return None
|
|
|
|
# mount the efiboot image
|
|
efibootdir = tempfile.mkdtemp(prefix="efiboot.", dir=self.workdir)
|
|
|
|
cmd = "mount -o loop,shortname=winnt,umask=0777 -t vfat {0} {1}"
|
|
cmd = cmd.format(efiboot, efibootdir)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.perror(stdout)
|
|
return None
|
|
|
|
# copy the files to the efiboot image
|
|
dstdir = os.path.join(efibootdir, "EFI/BOOT")
|
|
os.makedirs(dstdir)
|
|
|
|
scopy_(src_root=efitree, src_path="*",
|
|
dst_root=dstdir, dst_path="")
|
|
|
|
# unmount the efiboot image
|
|
cmd = "umount {0}".format(efibootdir)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.pwarning(stdout)
|
|
|
|
# remove the working directories
|
|
shutil.rmtree(efibootdir)
|
|
#shutil.rmtree(efitree)
|
|
|
|
# XXX copy the conf files and splash.xpm.gz to the output directory
|
|
if not with_kernel:
|
|
scopy_(src_root=efitree, src_path="*.conf",
|
|
dst_root=self.conf.efidir, dst_path="")
|
|
shutil.copy2(splash, self.conf.efidir)
|
|
|
|
return efiboot
|
|
|
|
def create_efidisk(self, efiboot):
|
|
efidisk = os.path.join(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 the efidisk file
|
|
with open(efidisk, "wb") as f:
|
|
f.truncate(disksize)
|
|
|
|
# create the loop device
|
|
cmd = "{0.LOSETUP} -v -f {1} | {0.AWK} '{{print $4}}'"
|
|
cmd = cmd.format(self.cmd, efidisk)
|
|
err, loop = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.perror(loop)
|
|
os.unlink(efidisk)
|
|
return None
|
|
|
|
# create the dm device
|
|
dmdev = "efiboot"
|
|
cmd = '{0.DMSETUP} create {1} --table "0 {2} linear {3} 0"'
|
|
cmd = cmd.format(self.cmd, dmdev, disksize / 512, loop)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.perror(stdout)
|
|
self.remove_loop_dev(loop)
|
|
os.unlink(efidisk)
|
|
return None
|
|
|
|
cmd = ("{0.PARTED} --script /dev/mapper/{1} "
|
|
"mklabel gpt unit b mkpart '\"EFI System Partition\"' "
|
|
"fat32 17408 {2} set 1 boot on")
|
|
cmd = cmd.format(self.cmd, dmdev, partsize + 17408)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.perror(stdout)
|
|
self.remove_dm_dev(dmdev)
|
|
self.remove_loop_dev(loop)
|
|
os.unlink(efidisk)
|
|
return None
|
|
|
|
with open(efiboot, "rb") as f_from:
|
|
with open("/dev/mapper/{0}p1".format(dmdev), "wb") as f_to:
|
|
efidata = f_from.read(1024)
|
|
while efidata:
|
|
f_to.write(efidata)
|
|
efidata = f_from.read(1024)
|
|
|
|
self.remove_dm_dev("{0}p1".format(dmdev))
|
|
self.remove_dm_dev(dmdev)
|
|
self.remove_loop_dev(loop)
|
|
|
|
return efidisk
|
|
|
|
def remove_loop_dev(self, dev):
|
|
cmd = "{0.LOSETUP} -d {1}".format(self.cmd, dev)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.pwarning(stdout)
|
|
|
|
def remove_dm_dev(self, dev):
|
|
cmd = "{0.DMSETUP} remove /dev/mapper/{1}".format(self.cmd, dev)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.pwarning(stdout)
|
|
|
|
|
|
class Install(BaseImageClass):
|
|
|
|
def __init__(self, installtree, template_file, workdir="/tmp"):
|
|
BaseImageClass.__init__(self)
|
|
|
|
self.srctree = installtree.rootdir
|
|
self.dsttree = installtree.rootdir
|
|
self.template_file = template_file
|
|
self.workdir = workdir
|
|
|
|
def create(self, type="squashfs"):
|
|
self.pinfo(":: creating the install image")
|
|
|
|
# copy the .buildstamp
|
|
shutil.copy2(self.conf.buildstamp, self.srctree)
|
|
|
|
self.copy_stubs()
|
|
self.copy_bootloaders()
|
|
self.rename_repos()
|
|
self.move_anaconda_files()
|
|
self.create_modules_symlinks()
|
|
self.fix_man_pages()
|
|
self.remove_locales()
|
|
self.remove_unnecessary_files()
|
|
self.move_bins()
|
|
|
|
# parse the template file
|
|
self.pinfo("parsing the template")
|
|
variables = {"buildarch": self.conf.buildarch,
|
|
"basearch": self.conf.basearch,
|
|
"libdir": self.conf.libdir}
|
|
self.parse_template(self.template_file, variables)
|
|
|
|
installimg = os.path.join(self.workdir, "install.img")
|
|
if os.path.isfile(installimg):
|
|
os.unlink(installimg)
|
|
|
|
if type == "squashfs":
|
|
self.pinfo("using squash filesystem")
|
|
cmd = "{0.MKSQUASHFS} {1} {2} -all-root -no-fragments -no-progress"
|
|
cmd = cmd.format(self.cmd, self.srctree, installimg)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.perror(stdout)
|
|
return None
|
|
elif type == "cramfs":
|
|
# TODO
|
|
raise NotImplementedError
|
|
elif type == "ext2":
|
|
# TODO
|
|
raise NotImplementedError
|
|
|
|
return installimg
|
|
|
|
def copy_stubs(self):
|
|
stubs = ("raidstart", "raidstop", "losetup", "list-harddrives",
|
|
"loadkeys", "mknod", "syslogd")
|
|
|
|
for stub in map(lambda s: "{0}-stub".format(s), stubs):
|
|
src = os.path.join(self.srctree, "usr/lib/anaconda", stub)
|
|
dst = os.path.join(self.srctree, "usr/bin", stub)
|
|
if os.path.isfile(src):
|
|
shutil.copy2(src, dst)
|
|
|
|
def copy_bootloaders(self):
|
|
srcdir = os.path.join(self.srctree, self.const.BOOTDIR)
|
|
dstdir = os.path.join(self.srctree, self.const.ANACONDA_BOOTDIR)
|
|
|
|
if self.conf.buildarch in ("i386", "i586", "i686", "x86_64"):
|
|
for f in glob.iglob(os.path.join(srcdir, "memtest*")):
|
|
shutil.copy2(f, dstdir)
|
|
|
|
elif self.conf.buildarch in ("ppc", "ppc64"):
|
|
f = os.path.join(srcdir, "efika.forth")
|
|
shutil.copy2(f, dstdir)
|
|
|
|
elif self.conf.buildarch in ("sparc", "sparc64"):
|
|
for f in glob.iglob(os.path.join(srcdir, "*.b")):
|
|
shutil.copy2(f, dstdir)
|
|
|
|
elif self.conf.buildarch == "ia64":
|
|
srcdir = os.path.join(self.srctree, self.const.BOOTDIR_IA64)
|
|
for f in glob.iglob(os.path.join(srcdir, "*")):
|
|
shutil.copy2(dstdir)
|
|
|
|
def rename_repos(self):
|
|
src = os.path.join(self.srctree, "etc/yum.repos.d")
|
|
dst = os.path.join(self.srctree, "etc/anaconda.repos.d")
|
|
shutil.move(src, dst)
|
|
|
|
def move_anaconda_files(self):
|
|
# move anaconda executable
|
|
src = os.path.join(self.srctree, "usr/sbin/anaconda")
|
|
dst = os.path.join(self.srctree, "usr/bin/anaconda")
|
|
shutil.move(src, dst)
|
|
|
|
# move anaconda libraries
|
|
srcdir = os.path.join(self.srctree, self.const.ANACONDA_RUNTIME)
|
|
dstdir = os.path.join(self.srctree, "usr", self.conf.libdir)
|
|
for f in glob.iglob(os.path.join(srcdir, "lib*")):
|
|
shutil.move(f, dstdir)
|
|
|
|
def create_modules_symlinks(self):
|
|
remove_(os.path.join(self.srctree, self.const.MODDIR, "*"))
|
|
remove_(os.path.join(self.srctree, self.const.FWDIR, "*"))
|
|
os.symlink(os.path.join(self.srctree, self.const.MODDIR), "/modules")
|
|
os.symlink(os.path.join(self.srctree, self.const.FWDIR), "/firmware")
|
|
|
|
def fix_man_pages(self):
|
|
# fix up some links for man page related stuff
|
|
for file in ("nroff", "groff", "iconv", "geqn", "gtbl", "gpic",
|
|
"grefer"):
|
|
|
|
target = os.path.join("/mnt/sysimage/usr/bin", file)
|
|
name = os.path.join(self.srctree, "usr/bin", file)
|
|
if not os.path.isfile(name):
|
|
os.symlink(target, name)
|
|
|
|
# fix /etc/man.config to point into /mnt/sysimage
|
|
manconf = os.path.join(self.srctree, self.const.MANCONF)
|
|
replace_(manconf, r"^MANPATH\s+(\S+)", "MANPATH\t/mnt/sysimage\g<1>")
|
|
replace_(manconf, r"^MANPATH_MAP\s+(\S+)\s+(\S+)",
|
|
"MANPATH_MAP\t\g<1>\t/mnt/sysimage\g<2>")
|
|
|
|
def remove_locales(self):
|
|
langtable = os.path.join(self.srctree, self.const.LANGTABLE)
|
|
localepath = os.path.join(self.srctree, self.const.LOCALES)
|
|
|
|
if os.path.isfile(langtable):
|
|
keep = set()
|
|
|
|
with open(langtable, "r") as f:
|
|
lines = f.readlines()
|
|
|
|
for line in lines:
|
|
line = line.strip()
|
|
if not line or line.startswith("#"):
|
|
continue
|
|
|
|
fields = line.split("\t")
|
|
|
|
dir = os.path.join(localepath, fields[1])
|
|
if os.path.isdir(dir):
|
|
keep.add(fields[1])
|
|
|
|
locale = fields[3].split(".")[0]
|
|
dir = os.path.join(localepath, locale)
|
|
if os.path.isdir(dir):
|
|
keep.add(locale)
|
|
|
|
for locale in os.listdir(localepath):
|
|
if locale not in keep:
|
|
path = os.path.join(localepath, locale)
|
|
remove_(path)
|
|
|
|
def remove_unnecessary_files(self):
|
|
for root, dirs, files in os.walk(self.srctree):
|
|
for file in files:
|
|
path = os.path.join(root, file)
|
|
|
|
if (fnmatch.fnmatch(path, "*.a") and
|
|
not path.count("kernel-wrapper/wrapper.a")):
|
|
os.unlink(path)
|
|
|
|
if (fnmatch.fnmatch(path, "lib*.la") and
|
|
not path.count("gtk-2.0")):
|
|
os.unlink(path)
|
|
|
|
if fnmatch.fnmatch(path, "*.py"):
|
|
pyo, pyc = path + "o", path + "c"
|
|
if os.path.isfile(pyo):
|
|
os.unlink(pyo)
|
|
if os.path.isfile(pyc):
|
|
os.unlink(pyc)
|
|
|
|
os.symlink("/dev/null", pyc)
|
|
|
|
# remove libunicode-lite
|
|
remove_(os.path.join(self.srctree, "usr", self.conf.libdir,
|
|
"libunicode-lite*"))
|
|
|
|
def move_bins(self):
|
|
# move bin to usr/bin
|
|
scopy_(src_root=self.srctree, src_path="bin/*",
|
|
dst_root=self.srctree, dst_path="usr/bin")
|
|
remove_(os.path.join(self.srctree, "bin"))
|
|
|
|
# move sbin to /usr/sbin
|
|
scopy_(src_root=self.srctree, src_path="sbin/*",
|
|
dst_root=self.srctree, dst_path="usr/sbin")
|
|
remove_(os.path.join(self.srctree, "sbin"))
|
|
|
|
# fix broken links
|
|
brokenlinks = []
|
|
for dir in ("bin", "sbin"):
|
|
dir = os.path.join(self.srctree, "usr", dir)
|
|
for root, dnames, fnames in os.walk(dir):
|
|
for fname in fnames:
|
|
fname = os.path.join(root, fname)
|
|
if os.path.islink(fname) and not os.path.exists(fname):
|
|
brokenlinks.append(fname)
|
|
|
|
pattern = re.compile(r"^\.\./\.\./(bin|sbin)/(.*)$")
|
|
for link in brokenlinks:
|
|
target = os.readlink(link)
|
|
newtarget = pattern.sub(r"../\g<1>/\g<2>", target)
|
|
if newtarget != target:
|
|
os.unlink(link)
|
|
os.symlink(newtarget, link)
|
|
|
|
|
|
class Boot(BaseImageClass):
|
|
|
|
def __init__(self, product, workdir="/tmp"):
|
|
BaseImageClass.__init__(self)
|
|
self.product = product
|
|
self.workdir = workdir
|
|
|
|
self.efiboot = os.path.join(self.conf.imgdir, "efiboot.img")
|
|
|
|
def create(self):
|
|
self.pinfo(":: creating the boot iso image")
|
|
bootiso = os.path.join(self.workdir, "boot.iso")
|
|
if os.path.isfile(bootiso):
|
|
os.unlink(bootiso)
|
|
|
|
if os.path.isfile(self.efiboot):
|
|
self.pinfo("creating efi capable boot iso")
|
|
efiargs = "-eltorito-alt-boot -e images/efiboot.img -no-emul-boot"
|
|
efigraft = "EFI/BOOT={0}".format(self.conf.efidir)
|
|
else:
|
|
efiargs = ""
|
|
efigraft = ""
|
|
|
|
cmd = ("{0.MKISOFS} -U -A {1} -V {1} -volset {1} -J -joliet-long"
|
|
" -r -v -T -o {2} -b isolinux/isolinux.bin -c isolinux/boot.cat"
|
|
" -no-emul-boot -boot-load-size 4 -boot-info-table"
|
|
" {3} -graft-points isolinux={4} images={5} {6}")
|
|
cmd = cmd.format(self.cmd, self.product, bootiso, efiargs,
|
|
self.conf.isodir, self.conf.imgdir, efigraft)
|
|
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.perror(stdout)
|
|
return None
|
|
|
|
if os.path.isfile(self.cmd.ISOHYBRID):
|
|
self.pinfo("creating hybrid boot iso")
|
|
cmd = "{0.ISOHYBRID} {1}".format(self.cmd, bootiso)
|
|
err, stdout = commands.getstatusoutput(cmd)
|
|
if err:
|
|
self.pwarning(stdout)
|
|
|
|
return bootiso
|