Rewrote some parts of the source.

Added all functionality from upd-instroot and scrubtree.
Rewrote most of the old utils/ scripts.
This commit is contained in:
Martin Gracik 2009-04-22 15:01:28 +02:00
parent 0cb23d295a
commit d3fd188841
18 changed files with 971 additions and 1211 deletions

View File

@ -1,3 +0,0 @@
# FIXME: need to update mk-images to take the yumconf
echo "Making images..."
$MK_IMAGES $DEBUGSTR $NOGRSTR --imgdir $TREEDIR/install --arch $BUILDARCH --product "$PRODUCTSTR" --version $VERSION --bugurl "$BUGURL" --output $OUTPUT $yumconf

View File

@ -1,120 +0,0 @@
#!/bin/bash
# pulled right out of mkinitrd....
DSO_DEPS=""
LDSO=""
get_dso_deps() {
root="$1" ; shift
bin="$1" ; shift
DSO_DEPS=""
declare -a FILES
declare -a NAMES
# this is a hack, but the only better way requires binutils or elfutils
# be installed. i.e., we need readelf to find the interpretter.
if [ -z "$LDSO" ]; then
for ldso in $root/$LIBDIR/ld*.so* ; do
[ -L $ldso ] && continue
[ -x $ldso ] || continue
$ldso --verify $bin >/dev/null 2>&1 || continue
LDSO=$(echo $ldso |sed -e "s,$root,,")
done
fi
# I still hate shell.
declare -i n=0
while read NAME I0 FILE ADDR I1 ; do
[ "$FILE" == "not" ] && FILE="$FILE $ADDR"
NAMES[$n]="$NAME"
FILES[$n]="$FILE"
let n++
done << EOF
$(/usr/sbin/chroot $root env LD_TRACE_PRELINKING=1 LD_WARN= \
LD_TRACE_LOADED_OBJECTS=1 $LDSO $bin)
EOF
[ ${#FILES[*]} -eq 0 ] && return 1
# we don't want the name of the binary in the list
if [ "${FILES[0]}" == "$bin" ]; then
FILES[0]=""
NAMES[0]=""
[ ${#FILES[*]} -eq 1 ] && return 1
fi
declare -i n=0
while [ $n -lt ${#FILES[*]} ]; do
FILE="${FILES[$n]}"
if [ "$FILE" == "not found" ]; then
cat 1>&2 <<EOF
There are missing files on your system. The dynamic object $bin
requires ${NAMES[$n]} n order to properly function. mkinitrd cannot continue.
EOF
exit 1
fi
case "$FILE" in
/lib*)
TLIBDIR=`echo "$FILE" | sed 's,\(/lib[^/]*\)/.*$,\1,'`
BASE=`basename "$FILE"`
# Prefer nosegneg libs over direct segment accesses on i686.
if [ -f "$TLIBDIR/i686/nosegneg/$BASE" ]; then
FILE="$TLIBDIR/i686/nosegneg/$BASE"
# Otherwise, prefer base libraries rather than their optimized
# variants.
elif [ -f "$TLIBDIR/$BASE" ]; then
FILE="$TLIBDIR/$BASE"
fi
;;
esac
dynamic="yes"
let n++
done
DSO_DEPS="${FILES[@]}"
for l in $(/usr/sbin/chroot $root find /$LIBDIR -maxdepth 1 -type l -name ld*.so*); do
[ "$(/usr/sbin/chroot $root readlink -f $l)" == "$LDSO" ] && DSO_DEPS="$DSO_DEPS $l"
done
[ -n "$DEBUG" ] && echo "DSO_DEPS for $bin are $DSO_DEPS"
}
instFile() {
FILE=$1
DESTROOT=$2
[ -n "$DEBUG" ] && echo "Installing $FILE"
if [ -e $DESTROOT/$FILE -o -L $DESTROOT/$FILE ]; then
return
elif [ ! -d $DESTROOT/`dirname $FILE` ]; then
mkdir -p $DESTROOT/`dirname $FILE`
fi
if [ -L $FILE ]; then
cp -al $FILE $DESTROOT/`dirname $FILE`
instFile ./`dirname $FILE`/`readlink $FILE` $DESTROOT
return
else
cp -aL $FILE $DESTROOT/`dirname $FILE`
fi
file $FILE | egrep -q ": (setuid )?ELF" && {
get_dso_deps $(pwd) "$FILE"
local DEPS="$DSO_DEPS"
for x in $DEPS ; do
instFile ./$x $DESTROOT
done
}
}
instDir() {
DIR=$1
DESTROOT=$2
[ -n "$DEBUG" ] && echo "Installing $DIR"
if [ -d $DESTROOT/$DIR -o -h $DESTROOT/$DIR ]; then
return
fi
cp -a --parents $DIR $DESTROOT/
}

View File

@ -1,25 +0,0 @@
#!/bin/bash
#
# filtermoddeps
#
# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
#
# 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/>.
#
perl -e 'while (<>) { if (/\\\n/) { chop; s/\\$//; print;} else { print $_; } }' | grep ':.*ko' | sed -e '
s/\.ko//g
s,/[^: ]*/,,g
s/[ ][ ]*/ /g'

View File

@ -1,62 +0,0 @@
/*
* geninitrdsz.c
* Generate initrd.size file for zSeries platforms.
* Takes an integer argument and writes out the binary representation of
* that value to the initrd.size file.
* https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=197773
*
* Copyright (C) 2007 Red Hat, Inc. All rights reserved.
*
* 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/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(int argc,char **argv) {
unsigned int zero = 0;
int fd;
unsigned int size;
mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
if (argc != 3) {
printf("Usage: %s [integer size] [output file]\n", basename(argv[0]));
printf("Example: %s 12288475 initrd.size\n", basename(argv[0]));
return 0;
}
size = htonl(atoi(argv[1]));
fd = open(argv[2], O_CREAT | O_RDWR, mode);
if (write(fd, &zero, sizeof(int)) == -1) {
perror("writing initrd.size (zero)");
return errno;
}
if (write(fd, &size, sizeof(int)) == -1) {
perror("writing initrd.size (size)");
return errno;
}
close(fd);
return 0;
}

View File

@ -1,76 +0,0 @@
#!/usr/bin/python
#
# genmodinfo
#
# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
#
# 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/>.
#
import commands
import os
import string
import sys
uname = os.uname()[2]
if len(sys.argv) > 1:
path = sys.argv[1]
else:
path = '/lib/modules/%s' % (uname,)
mods = {}
for root, dirs, files in os.walk(path):
for file in files:
mods[file] = os.path.join(root,file)
modules = { 'scsi_hostadapter' : [ 'block' ], 'eth' : [ 'networking'] }
blacklist = ("floppy", "scsi_mod", "libiscsi")
list = {}
for modtype in modules.keys():
list[modtype] = {}
for file in modules[modtype]:
try:
f = open('%s/modules.%s' % (path,file),'r')
except:
continue
lines = f.readlines()
f.close()
for line in lines:
line = line.strip()
if mods.has_key(line):
desc = commands.getoutput("modinfo -F description %s" % (mods[line])).split("\n")[0]
desc = desc.strip()
modname = line[:-3]
if modname in blacklist:
continue
if desc and len(desc) > 65:
desc = desc[:65]
if not desc:
desc = "%s driver" % (modname,)
modinfo = """
%s
%s
"%s"
""" % (modname, modtype, desc)
list[modtype][modname] = modinfo
print "Version 0"
for type in list.keys():
modlist = list[type].keys()
modlist.sort()
for m in modlist:
print list[type][m]

View File

@ -18,154 +18,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
LANG=C
PATH=$PATH:/sbin:/usr/sbin
IMAGEUUID=$(date +%Y%m%d%H%M).$(uname -i)
TMPDIR=${TMPDIR:-/tmp}
usage () {
echo "usage: mk-images <pkgsrc> <toplevel> <template> <imgdir> <buildarch> <productname> <version> [<productpath>]"
exit 0
}
DEBUG=""
BUILDARCH=`uname -m`
BOOTISO="boot.iso"
while [ $# -gt 0 ]; do
case $1 in
--debug)
DEBUG="--debug"
shift
;;
--noiso)
BOOTISO=""
shift
;;
--arch)
BUILDARCH=$2
shift; shift
;;
--imgdir)
IMGPATH=$2
shift; shift
;;
--product)
PRODUCT=$2
shift; shift
;;
--version)
VERSION=$2
shift; shift
;;
--bugurl)
BUGURL=$2
shift; shift
;;
--output)
TOPDESTPATH=$2
shift; shift
;;
--nogr)
echo "*** DeprecationWarning: ignoring --nogr option." >&2
shift
;;
--mindir)
echo "*** DeprecationWarning: ignoring --mindir option." >&2
shift; shift
;;
--stg2dir)
echo "*** DeprecationWarning: please use --imgdir instead of --stg2dir." >&2
shift; shift
;;
*)
yumconf=$1
shift
;;
esac
done
if [ -z "$TOPDESTPATH" -o -z "$IMGPATH" -o -z "$PRODUCT" -o -z "$VERSION" ]; then usage; fi
TOPDIR=$(echo $0 | sed "s,/[^/]*$,,")
if [ $TOPDIR = $0 ]; then
$TOPDIR="."
fi
TOPDIR=$(cd $TOPDIR; pwd)
# modules that are needed. this is the generic "needed for every arch" stuff
COMMONMODS="fat vfat nfs sunrpc lockd floppy cramfs loop edd pcspkr squashfs ipv6 virtio_pci"
USBMODS="ohci-hcd uhci-hcd ehci-hcd hid mousedev usb-storage sd_mod sr_mod ub appletouch"
FIREWIREMODS="ohci1394 sbp2 fw-ohci fw-sbp2 firewire-sbp2 firewire-ohci"
IDEMODS="ide-cd ide-cd_mod"
SCSIMODS="sr_mod sg st sd_mod scsi_mod iscsi_tcp"
FSMODS="fat msdos vfat ext2 ext3 ext4dev reiserfs jfs xfs gfs2 lock_nolock cifs"
LVMMODS="dm-mod dm-zero dm-snapshot dm-mirror dm-multipath dm-round-robin dm-emc dm-crypt"
RAIDMODS="raid0 raid1 raid5 raid6 raid456 raid10 linear"
CRYPTOMODS="sha256_generic cbc xts lrw aes_generic crypto_blkcipher crc32c ecb arc4"
PCMCIASOCKMODS="yenta_socket i82365 tcic pcmcia"
DRMMODS="drm i810 i830 i915 mga nouveau r128 radeon savage sis tdfx via"
INITRDMODS="$USBMODS $FIREWIREMODS $IDEMODS $SCSIMODS $FSMODS $LVMMODS $RAIDMODS $CRYPTOMODS $COMMONMODS $PCMCIASOCKMODS $DRMMODS =scsi =net"
. $(dirname $0)/buildinstall.functions
# Set, verify, and create paths
IMAGEPATH=$TOPDESTPATH/images
FULLMODPATH=$TMPDIR/instimagemods.$$
FINALFULLMODPATH=$IMGPATH/modules
INSTIMGPATH=$TOPDESTPATH/images
KERNELBASE=$TMPDIR/updboot.kernel.$$
KERNELNAME=vmlinuz
if [ "$BUILDARCH" = "ia64" ]; then
KERNELDIR="/boot/efi/EFI/redhat"
else
KERNELDIR="/boot"
fi
if [ "$BUILDARCH" = "sparc64" ]; then
BASEARCH=sparc
else
BASEARCH=$BUILDARCH
fi
# explicit block size setting for some arches (FIXME: we compose
# ppc64-ish trees as ppc, so we have to set the "wrong" block size)
if [ "$BUILDARCH" = "sparc64" ]; then
CRAMBS="--blocksize 8192"
elif [ "$BUILDARCH" = "sparc" ]; then
CRAMBS="--blocksize 4096"
else
CRAMBS=""
fi
if [ $BUILDARCH = x86_64 -o $BUILDARCH = s390x ]; then
LIBDIR=lib64
else
LIBDIR=lib
fi
rm -rf $IMAGEPATH
rm -rf $FULLMODPATH
rm -rf $FINALFULLMODPATH
rm -rf $KERNELBASE
mkdir -p $IMAGEPATH
mkdir -p $FULLMODPATH
mkdir -p $FINALFULLMODPATH
mkdir -p $KERNELBASE
mkdir -p $INSTIMGPATH
# Stuff that we need
TRIMPCIIDS=$IMGPATH/usr/lib/anaconda-runtime/trimpciids

View File

@ -1,70 +0,0 @@
#!/bin/bash
DEBUG=""
if [ "$1" == "--debug" ]; then
DEBUG="--debug"
shift
fi
if [ -z "$1" ]; then
echo "Usage: $0 /path/to/tree"
exit 1
fi
p=$1
STRIP=strip
ARCH=`uname -m | sed -e 's/i.86/i386/'`
if [ $ARCH = ia64 ]; then
STRIP="strip --strip-debug"
fi
if [ $ARCH = x86_64 -o $ARCH = s390x ]; then
LIBDIR=lib64
else
LIBDIR=lib
fi
# Must create ld.so.conf, because ldconfig does not cache
# dirs specified on the command line.
touch $p/etc/ld.so.conf
mkdir $p/proc
mount -t proc proc $p/proc
[ -d $p/usr/X11R6/$LIBDIR ] && echo /usr/X11R6/$LIBDIR > $p/etc/ld.so.conf
echo /usr/kerberos/$LIBDIR > $p/etc/ld.so.conf
(cd $p; /usr/sbin/chroot $p usr/sbin/ldconfig )
if [ $ARCH != s390 -a $ARCH != s390x ]; then
rm -f $p/usr/sbin/ldconfig
fi
rm $p/etc/ld.so.conf
#
# make sure we have links for programs supplied by busybox
#
# HOWEVER dont clobber existing programs supplied by other packages if exist
#
mv $p/usr/sbin/busybox.anaconda $p/usr/bin/busybox
(cd $p/usr/bin;
set $(./busybox 2>&1| awk '/^\t([[:alnum:]_\[]+,)+/' | sed 's/,//g' | sed 's/ +//');
while [ -n "$1" ]; do
if [ $1 != "busybox" -a $1 != "sh" -a $1 != "shutdown" -a $1 != "poweroff" -a $1 != "reboot" ]; then
# if file doesnt already exist, link to busybox
if [ ! -f "$1" ]; then
ln -sf ./busybox $1
else
[ -n "$DEBUG" ] && echo "Overriding busybox version of $1"
fi
fi
shift
done
)
umount $p/proc
for l in `find $p -type f -perm +100 | grep -v "usr/X11R6/$LIBDIR/modules" | xargs file | sed -n 's/^\([^:]*\):.*ELF.*$/\1/p'`; do
$STRIP $l -R .comment -R .note `objdump -h $l | \
sed -n 's/^.*\(\.gnu\.warning\.[^ ]*\) .*$/-R \1/p'`
done

View File

@ -1,80 +0,0 @@
#!/usr/bin/python
#
# trimpciids
#
# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
#
# 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/>.
#
import sys
import os
import string
vendors = []
devices = []
f = open(sys.argv[1])
if f:
pcitable = f.readlines()
f.close()
for line in pcitable:
if not line.startswith("alias pci:"):
continue
vend = "0x%s" % (line[15:19],)
dev = "0x%s" % (line[24:28],)
vend = vend.upper()
dev = dev.upper()
if vend not in vendors:
vendors.append(vend)
if (vend, dev) not in devices:
devices.append( (vend, dev) )
for file in sys.argv[2:]:
if not os.path.exists(file):
sys.stderr.write("WARNING: non-existent file %s for trimpciids\n" %(file,))
continue
f = open(file)
if f:
pcitable = f.readlines()
f.close()
for line in pcitable:
if not line.startswith("alias pcivideo:"):
continue
vend = "0x%s" % (line[20:24],)
dev = "0x%s" % (line[29:33],)
vend = vend.upper()
dev = dev.upper()
if vend not in vendors:
vendors.append(vend)
if (vend, dev) not in devices:
devices.append( (vend, dev) )
pciids = sys.stdin.readlines()
current_vend = 0
for line in pciids:
if line.startswith("#") or line == "\n":
continue
if line.startswith("\t\t"):
continue
if not line.startswith("\t"):
current_vend = "0x%s" % line.split()[0]
current_vend = current_vend.upper()
if current_vend in vendors:
print line,
continue
dev = "0x%s" % line.split()[0]
dev = dev.upper()
if (current_vend, dev) in devices:
print line,

View File

@ -1,102 +0,0 @@
. $(dirname $0)/buildinstall.functions
# ..........this is the pylorax.instroot.installPackages() function in lorax
expandPackageSet() {
if [ -n "$UPDATES" ]; then
(cd $UPDATES; find) | (cd $UPDATES ; /bin/cpio --quiet -pmdu $YUMDIR)
fi
}
chown -R root:root $DEST
chmod -R a+rX-w $DEST
sed -i 's|\(installforallkernels\) = 0|\1 = 1|' $DEST/etc/yum/pluginconf.d/fedorakmod.conf
#
# Manual pages in rescue: We dont have man pages in the image, so we point everything (The pages
# and the man scripts to the /mnt/sysimage. We want the man command to depend only on the
# man.conf file, so we don't use the $MANPATH env variable. The executables stay unchanged as
# they will be soft links to /mnt/sysimage.
#
echo "Fixing up /etc/man.config to point into /mnt/sysimage"
#
# Lets avoid the lines with MANPATH_MAP for now
#
sed -i "s,^MANPATH[^_MAP][ \t]*,&/mnt/sysimage," $DEST/etc/man.config
#
# Lets change the lines with MANPATH_MAP. Don't know how much of a difference this will make.
#
sed -i "s,^MANPATH_MAP[ \t]*[a-zA-Z0-9/]*[ \t]*,&/mnt/sysimage," $DEST/etc/man.config
mv $DEST/usr/sbin/anaconda $DEST/usr/bin/anaconda
mv $DEST/usr/lib/anaconda-runtime/lib* $DEST/usr/$LIBDIR 2>/dev/null
mv $DEST/etc/yum.repos.d $DEST/etc/anaconda.repos.d
find $DEST -type d | xargs chmod 755
if [ -f $DEST/bin/bash ]; then
rm -f $DEST/bin/ash
ln -s bash $DEST/bin/sh
else
ln -sf busybox $DEST/bin/sh
fi
[ -d $DEST/bin ] || die "ERROR: directory missing: $DEST/bin"
[ -d $DEST/sbin ] || die "ERROR: directory missing: $DEST/sbin"
(cd $DEST/bin; find) | (cd $DEST/bin; /bin/cpio --quiet -pdmu $DEST/usr/bin)
(cd $DEST/sbin; find) | (cd $DEST/sbin; /bin/cpio --quiet -pdmu $DEST/usr/sbin)
rm -rf $DEST/bin
rm -rf $DEST/sbin
# Fix relative links like /usr/bin/udevinfo -> ../../sbin/udevadm
for brokenlink in $(find $DEST/usr/{bin,sbin} -follow -lname '*') ; do
target="$(readlink $brokenlink)"
for pathbit in bin sbin; do
# if it starts with "../../sbin/", remove that
newtarget="${target##../../$pathbit/}"
# if we removed something, replace it with the proper path
if [ "$newtarget" != "$target" ]; then
# make it ../sbin/ instead
ln -sf "../$pathbit/$newtarget" "$brokenlink"
fi
done
done
find $DEST -name "*.a" | grep -v kernel-wrapper/wrapper.a | xargs rm -rf
find $DEST -name "lib*.la" |grep -v "usr/$LIBDIR/gtk-2.0" | xargs rm -rf
# nuke some python stuff we don't need
for d in idle distutils bsddb lib-old hotshot doctest.py pydoc.py site-packages/japanese site-packages/japanese.pth ; do
rm -rf $DEST/$d
done
$DEST/usr/lib/anaconda-runtime/scrubtree $DEST
echo "Creating debug dir"
mkdir -p $DEST/usr/lib/debug
mkdir -p $DEST/usr/src/debug
find $DEST -name "*.py" | while read fn; do
rm -f ${fn}o
rm -f ${fn}c
ln -sf /dev/null ${fn}c
done
# some python stuff we don't need for install image
rm -rf $DEST/usr/$LIBDIR/python?.?/site-packages/distutils/
rm -rf $DEST/usr/$LIBDIR/python?.?/site-packages/lib-dynload/japanese
rm -rf $DEST/usr/$LIBDIR/python?.?/site-packages/encodings/
rm -rf $DEST/usr/$LIBDIR/python?.?/site-packages/compiler/
rm -rf $DEST/usr/$LIBDIR/python?.?/site-packages/email/test/
rm -rf $DEST/usr/$LIBDIR/python?.?/site-packages/curses/
rm -rf $DEST/usr/$LIBDIR/python?.?/site-packages/pydoc.py

View File

@ -1,4 +1,4 @@
scripts/buildinstall
DONE scripts/buildinstall
scripts/buildinstall.functions
DONE scripts/makestamp.py
DONE scripts/maketreeinfo.py
@ -9,12 +9,12 @@ DONE scripts/maketreeinfo.py
scripts/mk-images.ppc
scripts/mk-images.s390
scripts/mk-images.x86
scripts/scrubtree
scripts/upd-instroot
DONE scripts/scrubtree
DONE scripts/upd-instroot
utils/trimpciids
DONE utils/trimpciids
utils/mk-s390-cdboot.c
utils/filtermoddeps
utils/geninitrdsz.c
utils/genmodinfo
DONE utils/filtermoddeps
DONE utils/geninitrdsz.c
DONE utils/genmodinfo
utils/modlist

View File

@ -1,9 +1,9 @@
#!/usr/bin/python -tt
#!/usr/bin/env python
#
# lorax
# Install image and tree support data generation tool.
#
# Copyright (C) 2008 Red Hat, Inc.
# Copyright (C) 2008, 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
@ -19,113 +19,80 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Author(s): David Cantrell <dcantrell@redhat.com>
# Martin Gracik <mgracik@redhat.com>
#
import getopt
import os
import sys
import os
from optparse import OptionParser, OptionGroup
from pylorax import Lorax
import pylorax
def usage(prog):
print("Usage: %s -v VERSION -p PRODUCT -r RELEASE -o PATH REPO\n" % (prog,))
print("Required arguments:")
print(" -v, --version=STRING Version identifier.")
print(" -p, --product=STRING Product name.")
print(" -r, --release=STRING Release information or comment.\n")
print(" -o, --output=PATHSPEC Where to write output files.")
print("Optional arguments:")
print(" -d, --debug Enable debugging messages.")
print(" -t, --variant=STRING Variant name.")
print(" -b, --bugurl=URL Bug reporting URL for the product.")
print(" -u, --updates=PATHSPEC Path to find updated RPMS.")
print(" -m, --mirrorlist=REPO Mirror list repo, may be listed multiple times.")
print(" -c, --confdir=PATHSPEC Path to config files (default: /etc/lorax).")
print(" -C, --cleanup Cleanup on exit.\n")
print("A 'REPO' specification is a valid yum repository path.\n")
print("See the man page lorax(8) for more information.")
if __name__ == "__main__":
prog = os.path.basename(sys.argv[0])
opts, args, mirrorlist, extrarepos = [], [], [], []
confdir, version, product, release, output, repo = None, None, None, None, None, None
debug = False
cleanup = False
variant, updates = '', ''
bugurl = 'your distribution provided bug reporting tool.'
if __name__ == '__main__':
version = '%s 0.1' % (os.path.basename(sys.argv[0]),)
usage = '%prog -p PRODUCT -v VERSION -r RELEASE -o OUTPUT REPOSITORY'
try:
opts, args = getopt.getopt(sys.argv[1:], "v:p:r:o:dt:b:u:m:c:CV",
["version=", "product=", "release=",
"output=", "debug", "variant=",
"bugurl=", "updates=", "mirrorlist=",
"confdir=", "cleanup"])
except getopt.GetoptError:
usage(prog)
sys.exit(1)
parser = OptionParser(usage=usage)
for o, a in opts:
if o in ('-v', '--version'):
version = a
elif o in ('-p', '--product'):
product = a
elif o in ('-r', '--release'):
release = a
elif o in ('-o', '--output'):
output = a
elif o in ('-d', '--debug'):
debug = True
elif o in ('-t', '--variant'):
variant = a
elif o in ('-b', '--bugurl'):
bugurl = a
elif o in ('-u', '--updates'):
updates = a
elif o in ('-m', '--mirrorlist'):
mirrorlist.append(a)
elif o in ('-c', '--confdir'):
if os.path.isdir(a):
confdir = a
else:
sys.stderr.write("ERROR: %s is not a directory.\n" % (a,))
elif o in ('-C', '--cleanup'):
cleanup = True
elif o in ('-V'):
# XXX: need to fix this
#pylorax.show_version(prog)
sys.exit(0)
def check_dir(option, opt_str, value, parser):
if os.path.isdir(value):
setattr(parser.values, option.dest, value)
else:
parser.error('%s is not a directory' % (value,))
if version is None or product is None or release is None or output is None:
sys.stderr.write("ERROR: Missing a required argument.\n")
sys.exit(1)
# XXX "options" should not be required
# required
group = OptionGroup(parser, 'Required')
group.add_option('-p', '--product', help='Product name.',
metavar='STRING')
group.add_option('-v', '--version', help='Version identifier.',
metavar='STRING')
group.add_option('-r', '--release', help='Release information or comment.',
metavar='STRING')
group.add_option('-o', '--output', help='Destination directory.',
metavar='PATHSPEC')
parser.add_option_group(group)
if len(args) == 0:
sys.stderr.write("ERROR: Missing repo to use for image generation.\n")
sys.exit(1)
# XXX are all of these used?
# optional
group = OptionGroup(parser, 'Optional')
group.add_option('-d', '--debug', help='Enable debugging messages.',
action='store_true', default=False)
group.add_option('-t', '--variant', help='Variant name.',
metavar='STRING')
group.add_option('-b', '--bugurl', help='Bug reporting URL for the product.',
metavar='URL', default='your distribution provided bug reporting tool.')
group.add_option('-u', '--updates', help='Path to find updated RPMS.',
metavar='PATHSPEC')
group.add_option('-m', '--mirrorlist', help='Mirror list repository, may be listed multiple times.',
metavar='REPOSITORY', action='append', default=[])
group.add_option('-c', '--confdir', help='Path to config files (default: /etc/lorax).',
metavar='PATHSPEC', action='callback', callback=check_dir,
type='string', default='/etc/lorax')
group.add_option('-C', '--cleanup', help='Cleanup on exit.',
action='store_true', default=False)
group.add_option('-V', help='Print version and exit.',
action='store_true', default=False, dest='printver')
parser.add_option_group(group)
lorax = Lorax(repos=args, output=output, mirrorlist=mirrorlist)
# additional information
group = OptionGroup(parser, 'Additional information',
'A "REPOSITORY" specification is a valid yum repository path.\n'
'See the man page lorax(8) for more information.')
parser.add_option_group(group)
if confdir is not None:
lorax.conf['confdir'] = confdir
(opts, args) = parser.parse_args()
if opts.printver:
print(version)
sys.exit(0)
if not opts.product or not opts.version or not opts.release or not opts.output:
parser.error('Missing a required argument.')
if not args:
parser.error('Missing repository to use for image generation.')
lorax = pylorax.Lorax(repos=args, options=opts)
lorax.run()
if cleanup:
lorax.cleanup()
# print("\n+=======================================+")
# print("| Writing meta data to instroot tree... |")
# print("+=======================================+\n")
#
# # write .treeinfo file
# if not pylorax.treeinfo.write(family=product, variant=variant, version=version, arch=buildarch, outdir=output):
# sys.stderr.write("Error writing %s/.treeinfo file.\n" % (output,))
#
# # mk-images
# # XXX
#
# # write .discinfo file
# if not pylorax.discinfo.write(release=release, arch=buildarch, outdir=output):
# sys.stderr.write("Error writing %s/.discinfo file.\n" % (output,))

View File

@ -2,7 +2,7 @@
# pylorax
# Install image and tree support data generation tool -- Python module.
#
# Copyright (C) 2008 Red Hat, Inc.
# Copyright (C) 2008, 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
@ -18,120 +18,193 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Author(s): David Cantrell <dcantrell@redhat.com>
# Martin Gracik <mgracik@redhat.com>
#
version = (0, 1)
import sys
import os
import shutil
import tempfile
import time
import ConfigParser
import yum
import rpmUtils
import discinfo
import treeinfo
import instroot
import images
from instroot import InstRoot
class Lorax:
def __init__(self, repos=[], output=None, mirrorlist=[], updates=None):
self.conf = {}
self.conf['confdir'] = '/etc/lorax'
self.conf['tmpdir'] = tempfile.gettempdir()
self.conf['datadir'] = '/usr/share/lorax'
def __init__(self, repos, options):
self.repos = repos
self.output = output
self.mirrorlist = mirrorlist
self.updates = updates
# required
self.product = options.product
self.version = options.version
self.release = options.release
self.output = options.output
# optional
self.debug = options.debug
self.variant = options.variant
self.bugurl = options.bugurl
self.updates = options.updates
self.mirrorlist = options.mirrorlist
self.confdir = options.confdir
self.cleanup = options.cleanup
self.conf = {}
if not self.confdir:
self.confdir = '/etc/lorax'
self.conf['confdir'] = self.confdir
self.conf['datadir'] = '/usr/share/lorax'
self.conf['tmpdir'] = tempfile.gettempdir()
def run(self):
"""run()
Generate install images.
"""
print("\n+=======================================================+")
print("| Setting up work directories and configuration data... |")
print("+=======================================================+\n")
print('Collecting repos...')
self.repo, self.extrarepos = self.__collectRepos()
if repos != []:
self.repo, self.extrarepos = self.__collectRepos(repos)
else:
self.repo = None
self.extrarepos = []
if not self.repo:
sys.stderr.write('No valid repository.\n')
sys.exit(1)
print('Initializing directories...')
self.buildinstdir, self.treedir, self.cachedir = self.__initializeDirs()
print('Writing yum configuration...')
self.yumconf = self.__writeYumConf()
print("\n+================================================+")
print("| Creating instroot tree to build images from... |")
print("+================================================+\n")
print('Getting the build architecture...')
self.buildarch = self.__getBuildArch()
self.instroot = InstRoot(conf=self.conf,
yumconf=self.yumconf,
arch=self.getBuildArch(),
treedir=self.treedir,
updates=self.updates)
self.instroot.run()
print('Creating install root tree...')
self.makeInstRoot()
def showVersion(self, driver=None):
"""showVersion(driver)
print('Writing .treeinfo...')
self.__writeTreeInfo()
Display program name (driver) and version number. If prog is an empty
string or None, use the value 'pylorax'.
print('Writing .discinfo...')
self.__writeDiscInfo()
print('Creating images...')
self.makeImages()
if self.cleanup:
print('Cleaning up...')
self.cleanUp()
def __collectRepos(self):
"""_collectRepos()
Get the main repo (the first one) and then build a list of all remaining
repos in the list. Sanitize each repo URL for proper yum syntax.
"""
if prog is None or prog == '':
prog = 'pylorax'
repolist = []
for repospec in self.repos:
if repospec.startswith('/'):
repo = 'file://%s' % (repospec,)
print('Adding local repo:\n %s' % (repo,))
repolist.append(repo)
elif repospec.startswith('http://') or repospec.startswith('ftp://'):
print('Adding remote repo:\n %s' % (repospec,))
repolist.append(repospec)
print "%s version %d.%d" % (prog, version[0], version[1],)
if not repolist:
return None, []
else:
return repolist[0], repolist[1:]
def cleanup(self, trash=[]):
"""cleanup(trash)
Given a list of things to remove, cleanup() will remove them if it can.
Never fails, just tries to remove things and returns regardless of
failures removing things.
def __initializeDirs(self):
"""_initializeDirs()
Create directories used for image generation.
"""
if trash != []:
for item in trash:
if os.path.isdir(item):
shutil.rmtree(item, ignore_errors=True)
else:
os.unlink(item)
if not os.path.isdir(self.output):
os.makedirs(self.output, mode=0755)
if os.path.isdir(self.conf['tmpdir']):
shutil.rmtree(self.conf['tmpdir'], ignore_errors=True)
self.conf['tmpdir'] = tempfile.mkdtemp('XXXXXX', 'lorax.tmp.', self.conf['tmpdir'])
buildinstdir = tempfile.mkdtemp('XXXXXX', 'buildinstall.tree.', self.conf['tmpdir'])
treedir = tempfile.mkdtemp('XXXXXX', 'treedir.', self.conf['tmpdir'])
cachedir = tempfile.mkdtemp('XXXXXX', 'yumcache.', self.conf['tmpdir'])
def getBuildArch(self):
"""getBuildArch()
print('Working directories:')
print(' tmpdir = %s' % (self.conf['tmpdir'],))
print(' buildinstdir = %s' % (buildinstdir,))
print(' treedir = %s' % (treedir,))
print(' cachedir = %s' % (cachedir,))
return buildinstdir, treedir, cachedir
def __writeYumConf(self):
"""_writeYumConf()
Generate a temporary yum.conf file for image generation. Returns the path
to the temporary yum.conf file on success, None of failure.
"""
(fd, yumconf) = tempfile.mkstemp(prefix='yum.conf', dir=self.conf['tmpdir'])
f = os.fdopen(fd, 'w')
f.write('[main]\n')
f.write('cachedir=%s\n' % (self.cachedir,))
f.write('keepcache=0\n')
f.write('gpgcheck=0\n')
f.write('plugins=0\n')
f.write('reposdir=\n')
f.write('tsflags=nodocs\n\n')
f.write('[loraxrepo]\n')
f.write('name=lorax repo\n')
f.write('baseurl=%s\n' % (self.repo,))
f.write('enabled=1\n\n')
for n, extra in enumerate(self.extrarepos, start=1):
f.write('[lorax-extrarepo-%d]\n' % (n,))
f.write('name=lorax extra repo %d\n' % (n,))
f.write('baseurl=%s\n' % (extra,))
f.write('enabled=1\n')
for n, mirror in enumerate(self.mirrorlist, start=1):
f.write('[lorax-mirrorlistrepo-%d]\n' % (n,))
f.write('name=lorax mirrorlist repo %d\n' % (n,))
f.write('mirrorlist=%s\n' % (mirror,))
f.write('enabled=1\n')
f.close()
print('Wrote lorax yum configuration to %s' % (yumconf,))
return yumconf
def __getBuildArch(self):
"""_getBuildArch()
Query the configured yum repositories to determine our build architecture,
which is the architecture of the anaconda package in the repositories.
This function is based on a subset of what repoquery(1) does.
"""
uname_arch = os.uname()[4]
if self.yumconf == '' or self.yumconf is None or not os.path.isfile(self.yumconf):
print "RETURN HERE"
if not self.yumconf or not os.path.isfile(self.yumconf):
sys.stderr.write('ERROR: yum.conf does not exist, defaulting to %s\n' % (uname_arch,))
return uname_arch
repoq = yum.YumBase()
repoq.doConfigSetup()
repoq.doConfigSetup(self.yumconf)
try:
repoq.doRepoSetup()
except yum.Errors.RepoError, e:
sys.stderr.write("ERROR: could not query yum repository for build arch, defaulting to %s\n" % (uname_arch,))
except yum.Errors.RepoError:
sys.stderr.write('ERROR: cannot query yum repo, defaulting to %s\n' % (uname_arch,))
return uname_arch
repoq.doSackSetup(rpmUtils.arch.getArchList())
@ -144,109 +217,80 @@ class Lorax:
ret_arch = a
break
if ret_arch is None:
if not ret_arch:
ret_arch = uname_arch
print("Building images for %s" % (ret_arch,))
return ret_arch
def __collectRepos(self, repos):
"""_collectRepos(repos)
def __writeTreeInfo(self, discnum=1, totaldiscs=1, packagedir=''):
outfile = os.path.join(self.output, '.treeinfo')
Get the main repo (the first one) and then build a list of all remaining
repos in the list. Sanitize each repo URL for proper yum syntax.
data = { 'timestamp': time.time(),
'family': self.product,
'version': self.version,
'arch': self.buildarch,
'variant': self.variant,
'discnum': str(discnum),
'totaldiscs': str(totaldiscs),
'packagedir': packagedir }
c = ConfigParser.ConfigParser()
section = 'general'
c.add_section(section)
for key, value in data.items():
c.set(section, key, value)
try:
f = open(outfile, 'w')
except IOError:
return False
else:
c.write(f)
f.close()
return True
def __writeDiscInfo(self, discnum=0):
outfile = os.path.join(self.output, '.discinfo')
try:
f = open(outfile, 'w')
except IOError:
return False
else:
f.write('%f\n' % (time.time(),))
f.write('%s\n' % (self.release,))
f.write('%s\n' % (self.buildarch,))
f.write('%d\n' % (discnum,))
f.close()
return True
def makeInstRoot(self):
root = instroot.InstRoot(conf=self.conf,
yumconf=self.yumconf,
arch=self.buildarch,
treedir=self.treedir,
updates=self.updates)
root.run()
# TODO
def makeImages(self):
pass
def cleanUp(self, trash=[]):
"""cleanup([trash])
Given a list of things to remove, cleanUp() will remove them if it can.
Never fails, just tries to remove things and returns regardless of
failures removing things.
"""
if repos is None or repos == []:
return '', []
for item in trash:
if os.path.isdir(item):
shutil.rmtree(item, ignore_errors=True)
else:
os.unlink(item)
repolist = []
for repospec in repos:
if repospec.startswith('/'):
repo = "file://%s" % (repospec,)
print("Adding local repo:\n %s" % (repo,))
repolist.append(repo)
elif repospec.startswith('http://') or repospec.startswith('ftp://'):
print("Adding remote repo:\n %s" % (repospec,))
repolist.append(repospec)
if os.path.isdir(self.conf['tmpdir']):
shutil.rmtree(self.conf['tmpdir'], ignore_errors=True)
repo = repolist[0]
extrarepos = []
if len(repolist) > 1:
for extra in repolist[1:]:
print("Adding extra repo:\n %s" % (extra,))
extrarepos.append(extra)
return repo, extrarepos
def __initializeDirs(self):
"""_initializeDirs()
Create directories used for image generation.
"""
if not os.path.isdir(self.output):
os.makedirs(self.output, mode=0755)
self.conf['tmpdir'] = tempfile.mkdtemp('XXXXXX', 'lorax.tmp.', self.conf['tmpdir'])
buildinstdir = tempfile.mkdtemp('XXXXXX', 'buildinstall.tree.', self.conf['tmpdir'])
treedir = tempfile.mkdtemp('XXXXXX', 'treedir.', self.conf['tmpdir'])
cachedir = tempfile.mkdtemp('XXXXXX', 'yumcache.', self.conf['tmpdir'])
print("Working directories:")
print(" tmpdir = %s" % (self.conf['tmpdir'],))
print(" buildinstdir = %s" % (buildinstdir,))
print(" treedir = %s" % (treedir,))
print(" cachedir = %s" % (cachedir,))
return buildinstdir, treedir, cachedir
def __writeYumConf(self):
"""_writeYumConf()
Generate a temporary yum.conf file for image generation. Returns the path
to the temporary yum.conf file on success, None of failure.
"""
tmpdir = self.conf['tmpdir']
(fd, yumconf) = tempfile.mkstemp(prefix='yum.conf', dir=tmpdir)
f = os.fdopen(fd, 'w')
f.write("[main]\n")
f.write("cachedir=%s\n" % (self.cachedir,))
f.write("keepcache=0\n")
f.write("gpgcheck=0\n")
f.write("plugins=0\n")
f.write("reposdir=\n")
f.write("tsflags=nodocs\n\n")
f.write("[loraxrepo]\n")
f.write("name=lorax repo\n")
f.write("baseurl=%s\n" % (self.repo,))
f.write("enabled=1\n\n")
if self.extrarepos != []:
n = 1
for extra in self.extrarepos:
f.write("[lorax-extrarepo-%d]\n" % (n,))
f.write("name=lorax extra repo %d\n" % (n,))
f.write("baseurl=%s\n" % (extra,))
f.write("enabled=1\n")
n += 1
if self.mirrorlist != []:
n = 1
for mirror in self.mirrorlist:
f.write("[lorax-mirrorlistrepo-%d]\n" % (n,))
f.write("name=lorax mirrorlist repo %d\n" % (n,))
f.write("mirrorlist=%s\n" % (mirror,))
f.write("enabled=1\n")
n += 1
f.close()
print("Wrote lorax yum configuration to %s" % (yumconf,))
return yumconf

View File

@ -1,62 +0,0 @@
#
# pylorax discinfo module
# Install image and tree support data generation tool -- Python module.
#
# Copyright (C) 2008 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/>.
#
# Author(s): David Cantrell <dcantrell@redhat.com>
#
import os
import time
# Write out the .discinfo file
def write(release=None, arch=None, outdir=None, disc=None):
"""write(release=None, arch=None, outdir=None, [disc=None])
Write the .discinfo file to the specified directory (outdir).
The release string is specified as release and the architecture
is specified as arch. If disc is specified, it will be written
as the disc number, otherwise 0 is written for the disc number.
The release, arch, and outdir parameters are all required.
"""
if release is None or arch is None or outdir is None:
return False
if not os.path.isdir(outdir):
return False
outfile = "%s/.discinfo" % (outdir,)
try:
f = open(outfile, "w")
f.write("%s\n", time.time())
f.write("%s\n", release)
f.write("%s\n", arch)
if disc is not None:
f.write("%d\n", disc)
else:
f.write("0\n")
f.close()
except:
return False
return True

50
src/pylorax/fileutils.py Normal file
View File

@ -0,0 +1,50 @@
import os
import shutil
import glob
def cp(src, dst, verbose=False):
for name in glob.iglob(src):
__copy(name, dst, verbose=verbose)
def mv(src, dst, verbose=False):
for name in glob.iglob(src):
__copy(name, dst, verbose=verbose, remove=True)
def __copy(src, dst, verbose=False, remove=False):
if not os.path.exists(src):
print('cannot stat "%s": No such file or directory' % (src,))
return
if os.path.isdir(dst):
basename = os.path.basename(src)
dst = os.path.join(dst, basename)
if os.path.isdir(src):
if os.path.isfile(dst):
print('omitting directory "%s"' % (src,))
return
if not os.path.isdir(dst):
os.makedirs(dst)
names = map(lambda name: os.path.join(src, name), os.listdir(src))
for name in names:
__copy(name, dst, verbose=verbose, remove=remove)
else:
if os.path.isdir(dst):
print('cannot overwrite directory "%s" with non-directory' % (dst,))
return
try:
if verbose:
print('copying "%s" to "%s"' % (src, dst))
shutil.copy2(src, dst)
except shutil.Error, IOError:
print('cannot copy "%s" to "%s"' % (src, dst))
else:
if remove:
if verbose:
print('removing "%s"' % (src,))
os.unlink(src)

102
src/pylorax/images.py Normal file
View File

@ -0,0 +1,102 @@
#
# pylorax images module
# Install image and tree support data generation tool -- Python module
#
import datetime
class Images():
def __init__(self, conf, yumconf, arch, imgdir, product, version, bugurl, output, noiso=False):
self.conf = conf
self.yumconf = yumconf
self.arch = arch
self.imgdir = imgdir
self.product = product
self.version = version
self.bugurl = bugurl
self.output = output
self.noiso = noiso
now = datetime.datetime.now()
self.imageuuid = now.strftime('%Y%m%d%H%M') + '.' + os.uname()[4]
self.initrdmods = self.__getModulesList()
if self.arch == 'sparc64':
self.basearch = 'sparc'
else:
self.basearch = self.arch
self.libdir = 'lib'
if self.arch == 'x86_64' or self.arch =='s390x':
self.libdir = 'lib64'
# explicit block size setting for some arches
# FIXME we compose ppc64-ish trees as ppc, so we have to set the "wrong" block size
# XXX i don't get this :)
self.crambs = []
if self.arch == 'sparc64':
self.crambs = ['--blocksize', '8192']
elif self.arch == 'sparc':
self.crambs = ['--blocksize', '4096']
self.__setUpDirectories()
def __getModulesList(self):
modules = set()
modules_files = []
modules_files.append(os.path.join(self.conf['confdir'], 'modules'))
modules_files.append(os.path.join(self.conf['confdir'], self.arch, 'modules'))
for pfile in modules_files:
if os.path.isfile(pfile):
f = open(pfile, 'r')
for line in f.readlines():
line = line.strip()
if not line or line.startswith('#'):
continue
if line.startswith('-'):
modules.discard(line[1:])
else:
modules.add(line)
f.close()
modules = list(modules)
modules.sort()
return modules
def __setUpDirectories(self):
imagepath = os.path.join(self.output, 'images')
fullmodpath = tempfile.mkdtemp('XXXXXX', 'instimagemods.', self.conf['tmpdir'])
finalfullmodpath = os.path.join(self.output, 'modules')
kernelbase = tempfile.mkdtemp('XXXXXX', 'updboot.kernel.', self.conf['tmpdir'])
kernelname = 'vmlinuz'
kerneldir = '/boot'
if self.arch == 'ia64':
kerneldir = os.path.join(kerneldir, 'efi', 'EFI', 'redhat')
for dir in [imagepath, fullmodpath, finalfullmodpath, kernelbase]:
if os.path.isdir(dir):
shutil.rmtree(dir)
os.makedirs(dir)
self.imagepath = imagepath
self.fullmodpath = fullmodpath
self.finalfullmodpath = finalfullmodpath
self.kernelbase = kernelbase
self.kernelname = kernelname
self.kerneldir = kerneldir

View File

@ -2,7 +2,7 @@
# pylorax instroot module
# Install image and tree support data generation tool -- Python module.
#
# Copyright (C) 2008 Red Hat, Inc.
# Copyright (C) 2008, 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
@ -18,53 +18,57 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Author(s): David Cantrell <dcantrell@redhat.com>
# Martin Gracik <mgracik@redhat.com>
#
import glob
import os
import shutil
import sys
import os
import stat
import shutil
import glob
import fnmatch
import re
import fileinput
import subprocess
import pwd
import grp
from fileutils import cp, mv
sys.path.insert(0, '/usr/share/yum-cli')
import yummain
class InstRoot:
"""InstRoot(conf=None, yumconf=None, arch=None, treedir=None, [updates=None])
"""InstRoot(conf, yumconf, arch, treedir, [updates=None])
Create a instroot tree for the specified architecture. The list of
packages to install are specified in the /etc/lorax/packages and
/etc/lorax/ARCH/packages files.
yumconf is the path to the yum configuration create for this run of
yumconf is the path to the yum configuration file created for this run of
lorax. arch is the platform name we are building for, treedir is
the location where the instroot tree should go
(will be treedir + '/install'). updates is an optional path to a
directory of update RPM packages for the instroot.
directory of updated RPM packages for the instroot.
The yumconf, arch, and treedir parameters are all required.
The conf, yumconf, arch, and treedir parameters are all required.
On success, this function returns True. On failure, False is
returned or the program is aborted immediately.
"""
# Create inst root from which stage 1 and stage 2 images are built.
def __init__(self, conf=None, yumconf=None, arch=None, treedir=None, updates=None):
def __init__(self, conf, yumconf, arch, treedir, updates=None):
self.conf = conf
self.yumconf = yumconf
self.arch = arch
self.treedir = treedir
self.updates = updates
# XXX: these tests should raise exceptions
if yumconf is None or arch is None or treedir is None:
return False
self.libdir = 'lib'
# on 64-bit systems, make sure we use lib64 as the lib directory
if self.arch.endswith('64') or self.arch == 's390x':
self.libdir = 'lib64'
else:
self.libdir = 'lib'
# the directory where the instroot will be created
self.destdir = os.path.join(self.treedir, 'install')
@ -73,7 +77,6 @@ class InstRoot:
"""run()
Generate the instroot tree and prepare it for building images.
"""
if not os.path.isdir(self.destdir):
@ -101,14 +104,11 @@ class InstRoot:
for line in f.readlines():
line = line.strip()
if line.startswith('#') or line == '':
if not line or line.startswith('#'):
continue
if line.startswith('-'):
try:
packages.remove(line[1:])
except KeyError:
pass
packages.discard(line[1:])
else:
packages.add(line)
@ -119,64 +119,83 @@ class InstRoot:
return packages
# Call yummain to install the list of packages to destdir
def __installPackages(self):
# build the list of arguments to pass to yum
arglist = ['-c', self.yumconf]
arglist.append("--installroot=%s" % (self.destdir,))
arglist += ['install', '-y'] + self.packages
arglist.extend(['install', '-y'])
arglist.extend(self.packages)
# do some prep work on the destdir before calling yum
os.makedirs(os.path.join(self.destdir, 'boot'))
os.makedirs(os.path.join(self.destdir, 'usr', 'sbin'))
os.makedirs(os.path.join(self.destdir, 'usr', 'lib', 'debug'))
os.makedirs(os.path.join(self.destdir, 'usr', 'src', 'debug'))
os.makedirs(os.path.join(self.destdir, 'tmp'))
os.makedirs(os.path.join(self.destdir, 'var', 'log'))
os.makedirs(os.path.join(self.destdir, 'var', 'lib'))
os.makedirs(os.path.join(self.destdir, 'var', 'lib', 'yum'))
os.symlink(os.path.join(os.path.sep, 'tmp'), os.path.join(self.destdir, 'var', 'lib', 'xkb'))
# XXX: sort through yum errcodes and return False for actual bad things
# we care about
# XXX sort through yum errcodes and return False for actual bad things we care about
errcode = yummain.user_main(arglist, exit_code=False)
# Scrub the instroot tree (remove files we don't want, modify settings, etc)
def __scrubInstRoot(self):
print
# copy updates to destdir
if self.updates and os.path.isdir(self.updates):
cp(os.path.join(self.updates, '*'), self.destdir)
# drop custom configuration files in to the instroot
dogtailconf = os.path.join(self.conf['datadir'], 'dogtail-%conf.xml')
def __scrubInstRoot(self):
self.__createConfigFiles()
self.__removeGtkThemes()
self.__removeLocales()
self.__fixManPages()
self.__installStubs()
self.__copyBootloaders()
self.__moveYumRepos()
self.__configureKmod()
self.__moveAnacondaFiles()
self.__setShellLinks()
self.__moveBins()
self.__removeUnwanted()
self.__changeDestDirPermissions()
self.__createLDConfig()
self.__setBusyboxLinks()
self.__strip()
self.__fixBrokenLinks()
def __createConfigFiles(self):
# create %gconf.xml
dogtailconf = os.path.join(self.conf['datadir'], 'dogtail-%gconf.xml')
if os.path.isfile(dogtailconf):
os.makedirs(os.path.join(destdir, '.gconf', 'desktop', 'gnome', 'interface'))
f = open(os.path.join(destdir, '.gconf', 'desktop', '%gconf.xml'), 'w')
os.makedirs(os.path.join(self.destdir, '.gconf', 'desktop', 'gnome', 'interface'))
f = open(os.path.join(self.destdir, '.gconf', 'desktop', '%gconf.xml'), 'w')
f.close()
f = open(os.path.join(destdir, '.gconf', 'desktop', 'gnome', '%gconf.xml'), 'w')
f = open(os.path.join(self.destdir, '.gconf', 'desktop', 'gnome', '%gconf.xml'), 'w')
f.close()
dest = os.path.join(destdir, '.gconf', 'desktop', 'gnome', 'interface', '%gconf.xml')
print "Installing %s..." % (os.path.join(os.path.sep, '.gconf', 'desktop', 'gnome', 'interface', '%gconf.xml'),)
shutil.copy(dogtailconf, dest)
dst = os.path.join(self.destdir, '.gconf', 'desktop', 'gnome', 'interface', '%gconf.xml')
cp(dogtailconf, dst)
# create selinux config
if os.path.isfile(os.path.join(self.destdir, 'etc', 'selinux', 'targeted')):
src = os.path.join(self.conf['datadir'], 'selinux-config')
if os.path.isfile(src):
dest = os.path.join(self.destdir, 'etc', 'selinux', 'config')
print "Installing %s..." % (os.path.join(os.path.sep, 'etc', 'selinux', 'config'),)
shutil.copy(src, dest)
selinuxconf = os.path.join(self.conf['datadir'], 'selinux-config')
if os.path.isfile(selinuxconf):
dst = os.path.join(self.destdir, 'etc', 'selinux', 'config')
cp(selinuxconf, dst)
# create libuser.conf
src = os.path.join(self.conf['datadir'], 'libuser.conf')
dest = os.path.join(self.destdir, 'etc', 'libuser.conf')
if os.path.isfile(src):
print "Installing %s..." % (os.path.join(os.path.sep, 'etc', 'libuser.conf'),)
shutil.copy(src, dest)
libuserconf = os.path.join(self.conf['datadir'], 'libuser.conf')
if os.path.isfile(libuserconf):
dst = os.path.join(self.destdir, 'etc', 'libuser.conf')
cp(libuserconf, dst)
def __removeGtkThemes(self):
# figure out the gtk+ theme to keep
gtkrc = os.path.join(self.destdir, 'etc', 'gtk-2.0', 'gtkrc')
gtk_theme_name = None
gtk_icon_themes = []
gtk_engine = None
gtk_icon_themes = []
if os.path.isfile(gtkrc):
print "\nReading %s..." % (os.path.join(os.path.sep, 'etc', 'gtk-2.0', 'gtkrc'),)
f = open(gtkrc, 'r')
lines = f.readlines()
f.close()
@ -184,11 +203,12 @@ class InstRoot:
for line in lines:
line = line.strip()
if line.startswith('gtk-theme-name'):
gtk_theme_name = line[line.find('=') + 1:].replace('"', '').strip()
print " gtk-theme-name: %s" % (gtk_theme_name,)
gtk_theme_name = line[line.find('=') + 1:]
gtk_theme_name = gtk_theme_name.replace('"', '').strip()
# find the engine for this theme
gtkrc = os.path.join(self.destdir, 'usr', 'share', 'themes', gtk_theme_name, 'gtk-2.0', 'gtkrc')
gtkrc = os.path.join(self.destdir, 'usr', 'share', 'themes',
gtk_theme_name, 'gtk-2.0', 'gtkrc')
if os.path.isfile(gtkrc):
f = open(gtkrc, 'r')
engine_lines = f.readlines()
@ -196,19 +216,20 @@ class InstRoot:
for engine_line in engine_lines:
engine_line = engine_line.strip()
if engine_line.find('engine') != -1:
gtk_engine = engine_line[engine_line.find('"') + 1:].replace('"', '')
print " gtk-engine: %s" % (gtk_engine,)
gtk_engine = engine_line[engine_line.find('"') + 1:]
gtk_engine = gtk_engine.replace('"', '').strip()
break
elif line.startswith('gtk-icon-theme-name'):
icon_theme = line[line.find('=') + 1:].replace('"', '').strip()
print " gtk-icon-theme-name: %s" % (icon_theme,)
icon_theme = line[line.find('=') + 1:]
icon_theme = icon_theme.replace('"', '').strip()
gtk_icon_themes.append(icon_theme)
# bring in all inherited themes
while True:
icon_theme_index = os.path.join(self.destdir, 'usr', 'share', 'icons', icon_theme, 'index.theme')
icon_theme_index = os.path.join(self.destdir, 'usr', 'share', 'icons',
icon_theme, 'index.theme')
if os.path.isfile(icon_theme_index):
inherits = False
f = open(icon_theme_index, 'r')
@ -219,8 +240,8 @@ class InstRoot:
icon_line = icon_line.strip()
if icon_line.startswith('Inherits='):
inherits = True
icon_theme = icon_line[icon_line.find('=') + 1:].replace('"', '')
print " inherits gtk-icon-theme-name: %s" % (icon_theme,)
icon_theme = icon_line[icon_line.find('=') + 1:]
icon_theme = icon_theme.replace('"', '').strip()
gtk_icon_themes.append(icon_theme)
break
@ -229,34 +250,32 @@ class InstRoot:
else:
break
theme_path = os.path.join(self.estdir, 'usr', 'share', 'themes')
# remove themes we don't need
theme_path = os.path.join(self.destdir, 'usr', 'share', 'themes')
if os.path.isdir(theme_path):
for theme in os.listdir(theme_path):
if theme != gtk_theme_name:
theme = os.path.join(theme_path, theme)
shutil.rmtree(theme, ignore_errors=True)
for theme in filter(lambda theme: theme != gtk_theme_name, os.listdir(theme_path)):
theme = os.path.join(theme_path, theme)
shutil.rmtree(theme, ignore_errors=True)
# remove icons we don't need
icon_path = os.path.join(self.destdir, 'usr', 'share', 'icons')
if os.path.isdir(icon_path):
for icon in os.listdir(icon_path):
try:
if gtk_icon_themes.index(icon):
continue
except ValueError:
icon = os.path.join(icon_path, icon)
shutil.rmtree(icon, ignore_errors=True)
for icon in filter(lambda icon: icon not in gtk_icon_themes, os.listdir(icon_path)):
icon = os.path.join(icon_path, icon)
shutil.rmtree(icon, ignore_errors=True)
tmp_path = os.path.join(self.destdir, 'usr', libdir, 'gtk-2.0')
# remove engines we don't need
tmp_path = os.path.join(self.destdir, 'usr', self.libdir, 'gtk-2.0')
if os.path.isdir(tmp_path):
for subdir in os.listdir(tmp_path):
new_path = os.path.join(tmp_path, subdir, 'engines')
if os.path.isdir(new_path):
for engine in os.listdir(new_path):
if engine.find(gtk_engine) == -1:
tmp_engine = os.path.join(new_path, engine)
os.unlink(tmp_engine)
fnames = map(lambda fname: os.path.join(tmp_path, fname, 'engines'), os.listdir(tmp_path))
dnames = filter(lambda fname: os.path.isdir(fname), fnames)
for dir in dnames:
engines = filter(lambda engine: engine.find(gtk_engine) == -1, os.listdir(dir))
for engine in engines:
engine = os.path.join(dir, engine)
os.unlink(engine)
# clean out unused locales
def __removeLocales(self):
langtable = os.path.join(self.destdir, 'usr', 'lib', 'anaconda', 'lang-table')
localepath = os.path.join(self.destdir, 'usr', 'share', 'locale')
if os.path.isfile(langtable):
@ -267,11 +286,9 @@ class InstRoot:
lines = f.readlines()
f.close()
print "Keeping locales used during installation..."
for line in lines:
line = line.strip()
if line == '' or line.startswith('#'):
if not line or line.startswith('#'):
continue
fields = line.split('\t')
@ -283,23 +300,40 @@ class InstRoot:
if os.path.isdir(os.path.join(localepath, locale)):
locales.add(locale)
for locale in os.listdir(os.path.join(self.destdir, 'usr', 'share', 'locale')):
for locale in os.listdir(localepath):
all_locales.add(locale)
print "Removing unused locales..."
locales_to_remove = list(all_locales.difference(locales))
for locale in locales_to_remove:
rmpath = os.path.join(self.destdir, 'usr', 'share', 'locale', locale)
rmpath = os.path.join(localepath, locale)
shutil.rmtree(rmpath, ignore_errors=True)
# fix up some links for man page related stuff
def __fixManPages(self):
for file in ['nroff', 'groff', 'iconv', 'geqn', 'gtbl', 'gpic', 'grefer']:
src = os.path.join('mnt', 'sysimage', 'usr', 'bin', file)
dst = os.path.join(self.destdir, 'usr', 'bin', file)
if not os.path.isfile(dst):
os.symlink(src, dst)
# install anaconda stub programs as instroot programs
# fix /etc/man.config to point to /mnt/sysimage
manconfig = os.path.join(self.destdir, 'etc', 'man.config')
# XXX WHY?
# don't change MANPATH_MAP lines now
fin = fileinput.input(manconfig, inplace=1)
for line in fin:
line = re.sub(r'^MANPATH[^_MAP][ \t]*', r'&/mnt/sysimage', line)
sys.stdout.write(line)
fin.close()
# change MANPATH_MAP lines
fin = fileinput.input(manconfig, inplace=1)
for line in fin:
line = re.sub(r'^MANPATH_MAP[ \t]*[a-zA-Z0-9/]*[ \t]*', r'&/mnt/sysimage', line)
sys.stdout.write(line)
fin.close()
def __installStubs(self):
for subdir in ['lib', 'firmware']:
subdir = os.path.join(self.destdir, subdir)
if not os.path.isdir(subdir):
@ -311,56 +345,299 @@ class InstRoot:
shutil.rmtree(dst, ignore_errors=True)
os.symlink(src, dst)
for prog in ['raidstart', 'raidstop', 'losetup', 'list-harddrives', 'loadkeys', 'mknod', 'sysklogd']:
for prog in ['raidstart', 'raidstop', 'losetup', 'list-harddrives', 'loadkeys', 'mknod',
'syslogd']:
stub = "%s-stub" % (prog,)
src = os.path.join(self.destdir, 'usr', 'lib', 'anaconda', stub)
dst = os.path.join(self.destdir, 'usr', 'bin', prog)
if os.path.isfile(src) and not os.path.isfile(dst):
shutil.copy2(src, dst)
cp(src, dst)
# copy in boot loader files
def __copyBootloaders(self):
bootpath = os.path.join(self.destdir, 'usr', 'lib', 'anaconda-runtime', 'boot')
if not os.path.isdir(bootpath):
os.makedirs(bootpath)
if arch == 'i386' or arch == 'x86_64':
if self.arch == 'i386' or self.arch == 'x86_64':
for bootfile in os.listdir(os.path.join(self.destdir, 'boot')):
if bootfile.startswith('memtest'):
src = os.path.join(self.destdir, 'boot', bootfile)
dst = os.path.join(bootpath, bootfile)
shutil.copy2(src, dst)
elif arch.startswith('sparc'):
cp(src, dst)
elif self.arch.startswith('sparc'):
for bootfile in os.listdir(os.path.join(self.destdir, 'boot')):
if bootfile.endswith('.b'):
src = os.path.join(self.destdir, 'boot', bootfile)
dst = os.path.join(bootpath, bootfile)
shutil.copy2(src, dst)
elif arch.startswith('ppc'):
cp(src, dst)
elif self.arch.startswith('ppc'):
src = os.path.join(self.destdir, 'boot', 'efika.forth')
dst = os.path.join(bootpath, 'efika.forth')
shutil.copy2(src, dst)
elif arch == 'alpha':
cp(src, dst)
elif self.arch == 'alpha':
src = os.path.join(self.destdir, 'boot', 'bootlx')
dst = os.path.join(bootpath, 'bootlx')
shutil.copy2(src, dst)
elif arch == 'ia64':
cp(src, dst)
elif self.arch == 'ia64':
src = os.path.join(self.destdir, 'boot', 'efi', 'EFI', 'redhat')
shutil.rmtree(bootpath, ignore_errors=True)
shutil.copytree(src, bootpath)
cp(src, bootpath)
# move the yum repos configuration directory
def __moveYumRepos(self):
src = os.path.join(self.destdir, 'etc', 'yum.repos.d')
dst = os.path.join(self.destdir, 'etc', 'anaconda.repos.d')
if os.path.isdir(src):
shutil.rmtree(dst, ignore_errors=True)
shutil.move(src, dst)
mv(src, dst)
# remove things we do not want in the instroot
def __configureKmod(self):
fedorakmodconf = os.path.join(self.destdir, 'etc', 'yum', 'pluginconf.d', 'fedorakmod.conf')
# XXX this file does not exist, what package provides it?
if not os.path.exists(fedorakmodconf):
return
fin = fileinput.input(fedorakmodconf, inplace=1)
for line in fin:
line = re.sub(r'\(installforallkernels\) = 0', r'\1 = 1', line)
sys.stdout.write(line)
fin.close()
def __moveAnacondaFiles(self):
# move executable
src = os.path.join(self.destdir, 'usr', 'sbin', 'anaconda')
dst = os.path.join(self.destdir, 'usr', 'bin', 'anaconda')
mv(src, dst)
# move libraries
src = os.path.join(self.destdir, 'usr', 'lib', 'anaconda-runtime', 'lib')
dst = os.path.join(self.destdir, 'usr', self.libdir)
for fname in glob.glob(src + '*'):
mv(fname, dst)
def __setShellLinks(self):
bash = os.path.join(self.destdir, 'bin', 'bash')
ash = os.path.join(self.destdir, 'bin', 'ash')
sh = os.path.join(self.destdir, 'bin', 'sh')
busybox = os.path.join(self.destdir, 'bin', 'busybox')
if os.path.exists(bash):
# XXX is this needed? i don't have ash in the tree...
try:
os.unlink(ash)
except OSError:
pass
os.unlink(sh)
os.symlink(bash, sh)
else:
os.unlink(sh)
os.symlink(busybox, sh)
def __moveBins(self):
bin = os.path.join(self.destdir, 'bin')
sbin = os.path.join(self.destdir, 'sbin')
if not os.path.exists(bin) or not os.path.exists(sbin):
raise Error, 'bin or sbin directory missing'
dst = os.path.join(self.destdir, 'usr')
for src in (bin, sbin):
mv(src, dst)
def __removeUnwanted(self):
for subdir in ['boot', 'home', 'root', 'tmp']:
shutil.rmtree(os.path.join(self.destdir, subdir), ignore_errors=True)
for subdir in ['doc', 'info']:
shutil.rmtree(os.path.join(self.destdir, 'usr', 'share', subdir), ignore_errors=True)
for libname in glob.glob(os.path.join(self.destdir, 'usr', libdir), 'libunicode-lite*'):
for libname in glob.glob(os.path.join(self.destdir, 'usr', self.libdir, 'libunicode-lite*')):
shutil.rmtree(libname, ignore_errors=True)
to_remove = set()
for root, files, dirs in os.walk(self.destdir):
for file in files:
path = os.path.join(root, file)
if fnmatch.fnmatch(path, '*.a'):
if path.find('kernel-wrapper/wrapper.a') == -1:
to_remove.append(path)
elif fnmatch.fnmatch(path, 'lib*.la'):
if path.find('usr/' + self.libdir + '/gtk-2.0') == -1:
to_remove.append(path)
elif fnmatch.fnmatch(path, '*.py'):
to_remove.append(path + 'o')
to_remove.append(path + 'c')
os.symlink('/dev/null', path + 'c')
for file in to_remove:
if os.path.isdir(file):
shutil.rmtree(file)
else:
os.unlink(file)
# nuke some python stuff we don't need
for fname in ['idle', 'distutils', 'bsddb', 'lib-old', 'hotshot', 'doctest.py', 'pydoc.py',
'site-packages/japanese', 'site-packages/japanese.pth']:
path = os.path.join(self.destdir, fname)
if os.path.isdir(path):
shutil.rmtree(path)
else:
try:
os.unlink(path)
except OSError:
pass
for fname in ['distutils', 'lib-dynload/japanese', 'encodings', 'compiler', 'email/test',
'curses', 'pydoc.py']:
path = os.path.join(self.destdir, 'usr', self.libdir, 'python?.?', 'site-packages',
fname)
for item in glob.glob(path):
if os.path.isdir(item):
shutil.rmtree(item)
else:
os.unlink(item)
def __changeDestDirPermissions(self):
root_uid = pwd.getpwnam('root')[2]
root_gid = grp.getgrnam('root')[2]
for root, files, dirs in os.walk(self.destdir):
os.chown(root, root_uid, root_gid)
os.chmod(root, 0755)
for file in files:
path = os.path.join(root, file)
os.chown(path, root_uid, root_gid)
mode = os.stat(path).st_mode
if (mode & stat.S_IXUSR) or (mode & stat.S_IXGRP) or (mode & stat.S_IXOTH):
os.chmod(path, 0555)
else:
os.chmod(path, 0444)
def __createLDConfig(self):
ldsoconf = os.path.join(self.destdir, 'etc', 'ld.so.conf')
f = open(ldsoconf, 'w')
f.close()
proc_dir = os.path.join(self.destdir, 'proc')
if not os.path.isdir(proc_dir):
os.makedirs(proc_dir)
# XXX isn't there a better way?
os.system('mount -t proc proc %s' % (proc_dir,))
f = open(ldsoconf, 'w')
x11_libdir = os.path.join(self.destdir, 'usr', 'X11R6', self.libdir)
if os.path.exists(x11_libdir):
f.write('/usr/X11R6/%s\n' % (self.libdir,))
f.write('/usr/kerberos/%s\n' % (self.libdir,))
cwd = os.getcwd()
os.chdir(self.destdir)
# XXX can't exit from os.chroot() :(
os.system('/usr/sbin/chroot %s /usr/sbin/ldconfig' % (self.destdir,))
os.chdir(cwd)
if self.arch not in ('s390', 's390x'):
os.unlink(os.path.join(self.destdir, 'usr', 'sbin', 'ldconfig'))
os.unlink(os.path.join(self.destdir, 'etc', 'ld.so.conf'))
# XXX isn't there a better way?
os.system('umount %s' % (proc_dir,))
def __setBusyboxLinks(self):
src = os.path.join(self.destdir, 'usr', 'sbin', 'busybox.anaconda')
dst = os.path.join(self.destdir, 'usr', 'bin', 'busybox')
mv(src, dst)
cwd = os.getcwd()
os.chdir(os.path.join(self.destdir, 'usr', 'bin'))
busybox_process = subprocess.Popen(['./busybox'], stdout=subprocess.PIPE)
busybox_process.wait()
if busybox_process.returncode:
raise LoraxError, 'cannot run busybox'
busybox_output = busybox_process.stdout.readlines()
busybox_output = map(lambda line: line.strip(), busybox_output)
busybox_output = busybox_output[busybox_output.index('Currently defined functions:') + 1:]
commands = []
for line in busybox_output:
commands.extend(map(lambda c: c.strip(), line.split(',')))
# remove empty strings
commands = filter(lambda c: c, commands)
for command in commands:
# XXX why do we skip these commands? can "busybox" be there at all?
if command not in ['buxybox', 'sh', 'shutdown', 'poweroff', 'reboot']:
if not os.path.exists(command):
os.symlink('busybox', command)
os.chdir(cwd)
def __strip(self):
# XXX is this thing really needed? it's ugly
fnames = map(lambda fname: os.path.join(self.destdir, fname), os.listdir(self.destdir))
fnames = filter(lambda fname: os.path.isfile(fname), fnames)
executables = []
xmodules = os.path.join('usr', 'X11R6', self.libdir, 'modules')
for fname in fnames:
if not fname.find(xmodules) == -1:
continue
mode = os.stat(fname).st_mode
if (mode & stat.S_IXUSR):
executables.append(fname)
elfs = []
for exe in executables:
p = subprocess.Popen(['file', exe], stdout=subprocess.PIPE)
p.wait()
output = p.stdout.readlines()
output = ''.join(output)
if re.match(r'^[^:]*:.*ELF.*$', output):
elfs.append(exe)
for elf in elfs:
p = subprocess.Popen(['objdump', '-h', elf], stdout=subprocess.PIPE)
p.wait()
cmd = ['strip']
if self.arch == 'ia64':
cmd.append('--strip-debug')
arglist = [elf, '-R', '.comment', '-R', '.note']
for line in p.stdout.readlines():
m = re.match(r'^.*(?P<warning>\.gnu\.warning\.[^ ]*) .*$', line)
if m:
arglist.extend(['-R', m.group('warning')])
p = subprocess.Popen(cmd + arglist)
p.wait()
def __fixBrokenLinks(self):
for dir in ['bin', 'sbin']:
dir = os.path.join(self.destdir, 'usr', dir)
brokenlinks = []
for root, fnames, dnames in os.walk(dir):
for fname in fnames:
fname = os.path.join(root, fname)
if os.path.islink(fname) and not os.path.lexists(fname):
brokenlinks.append(fname)
for link in brokenlinks:
target = os.readlink(link)
for dir in ['bin', 'sbin']:
newtarget = re.sub(r'^\.\./\.\./%s/\(.*\)' % dir, r'\.\./%s/\1' % dir, target)
if newtarget != target:
os.symlink(newtarget, link)

View File

@ -0,0 +1,161 @@
import sys
import os
import commands
import re
import socket
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('pylorax')
def genmodinfo(path=None):
if not path:
release = os.uname()[2]
path = os.path.join('/lib/modules', release)
mods = {}
for root, dirs, files in os.walk(path):
for file in files:
mods[file] = os.path.join(root, file)
modules = { 'scsi_hostadapter': ['block'], 'eth': ['networking'] }
blacklist = ('floppy', 'scsi_mod', 'libiscsi')
list = {}
for modtype in modules:
list[modtype] = {}
for file in modules[modtype]:
try:
filename = os.path.join(path, 'modules.%s' % file)
f = open(filename, 'r')
except IOError:
logger.error('cannot open file %s', filename)
continue
else:
lines = f.readlines()
f.close()
for line in lines:
line = line.strip()
if line in mods:
modname, ext = os.path.splitext(line)
if modname in blacklist:
logger.info('skipping %s', modname)
continue
outtext = commands.getoutput('modinfo -F description %s' % mods[line])
desc = outtext.split('\n')[0]
desc = desc.strip()
# XXX why we need to do this?
desc = desc[:65]
if not desc:
desc = '%s driver' % modname
modinfo = '%s\n\t%s\n\t"%s"\n' % (modname, modtype, desc)
list[modtype][modname] = modinfo
# XXX i don't think we want to print it out now
print 'Version 0'
for type in list:
modlist = list[type].keys()
modlist.sort()
for m in modlist:
print list[type][m]
# XXX is the input a path to a file?
def filtermoddeps(input):
try:
f = open(input, 'r')
except IOError:
logger.error('cannot open file %s', input)
return
# concatenate lines ending with \
lines = []
for line in f.readlines():
if line.endswith('\\\n'):
line = line[:-2]
lines.append(line)
f.close()
lines = ''.join(lines).split('\n')
# XXX what's the purpose of these gentlemen?
lines = filter(lambda line: re.search(':.*ko', line), lines)
lines = map(lambda line: re.sub('\.ko', '', line), lines)
lines = map(lambda line: re.sub('/[^: ]*/', '', line), lines)
lines = map(lambda line: re.sub('\t+', ' ', line), lines)
return lines
# XXX what are the inputs for this thing?
def trimpciids(pciids, *paths):
vendors = []
devices = []
for file in paths:
try:
f = open(file, 'r')
except IOError:
logger.error('cannot open file %s', file)
continue
else:
pcitable = f.readlines()
f.close()
for line in pcitable:
if line.startswith('alias pci:'):
vend = '0x%s' % line[15:19]
dev = '0x%s' % line[24:28]
elif line.startswith('alias pcivideo:'):
vend = '0x%s' % line[20:24]
dev = '0x%s' % line[29:33]
else:
continue
vend = vend.upper()
dev = dev.upper()
if vend not in vendors:
vendors.append(vend)
if (vend, dev) not in devices:
devices.append((vend, dev))
current_vend = 0
for line in pciids:
if line.startswith('#') or line.startswith('\t\t') or line == '\n':
continue
# XXX print or return?
if not line.startswith('\t'):
current_vend = '0x%s' % line.split()[0]
current_vend = current_vend.upper()
if current_vend in vendors:
print line,
continue
# XXX print or return?
dev = '0x%s' % line.split()[0]
dev = dev.upper()
if (current_vend, dev) in devices:
print line,
# XXX what is this whole thing for?
def geninitrdsz(size, filename):
size = socket.htonl(size)
try:
f = open(filename, 'w')
except IOError:
logger.error('cannot open file %s', filename)
else:
f.write(str(size))
f.close()
# XXX is this needed? default mode is 0664
os.chmod(filename, 0644)

View File

@ -1,93 +0,0 @@
#
# pylorax treeinfo module
# Install image and tree support data generation tool -- Python module.
#
# Copyright (C) 2007, 2008 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/>.
#
# Author(s): David Cantrell <dcantrell@redhat.com>
# Will Woods <wwoods@redhat.com>
#
import os
import time
import ConfigParser
# Write out the .treeinfo file
def write(family=None, version=None, arch=None, outdir=None, variant='',
discnum=None, totaldiscs=None, packagedir='', allDiscs=True):
"""write(family=None, version=None, arch=None, outdir=None,
[variant='', discnum=None, totaldiscs=None, packagedir=''])
Write the .treeinfo file to the specified directory (outdir).
Required parameters:
family String specifying the family.
version String specifying the version number.
arch String specifying the architecture.
outdir Directory to write .treeinfo to (must exist).
Optional parameters may be specified:
variant Defaults to an empty string, but can be any string.
discnum Defaults to '1', but you can specify an integer.
totaldiscs Defaults to '1', but you can specify an integer.
packagedir Directory where packages are located.
allDiscs Boolean stating all discs are in one tree (default: True)
Returns True on success, False on failure.
"""
if family is None or arch is None or outdir is None:
return False
if not os.path.isdir(outdir):
return False
data = { "timestamp": float(time.time()),
"family": family,
"variant": variant,
"version": version,
"arch": arch,
"discnum": "1",
"totaldiscs": "1",
"packagedir": packagedir,
"outfile": None }
outfile = "%s/.treeinfo" % (outdir,)
section = 'general'
c = ConfigParser.ConfigParser()
c.add_section(section)
if not allDiscs:
if discnum is not None:
data["discnum"] = str(discnum)
if totaldiscs is not None:
data["totaldiscs"] = str(totaldiscs)
try:
f = open(outfile, "w")
for key, value in data.items():
c.set(section, key, value)
c.write(f)
f.close()
except:
return False
return True