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/>. # 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 # Stuff that we need
TRIMPCIIDS=$IMGPATH/usr/lib/anaconda-runtime/trimpciids 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 scripts/buildinstall.functions
DONE scripts/makestamp.py DONE scripts/makestamp.py
DONE scripts/maketreeinfo.py DONE scripts/maketreeinfo.py
@ -9,12 +9,12 @@ DONE scripts/maketreeinfo.py
scripts/mk-images.ppc scripts/mk-images.ppc
scripts/mk-images.s390 scripts/mk-images.s390
scripts/mk-images.x86 scripts/mk-images.x86
scripts/scrubtree DONE scripts/scrubtree
scripts/upd-instroot DONE scripts/upd-instroot
utils/trimpciids DONE utils/trimpciids
utils/mk-s390-cdboot.c utils/mk-s390-cdboot.c
utils/filtermoddeps DONE utils/filtermoddeps
utils/geninitrdsz.c DONE utils/geninitrdsz.c
utils/genmodinfo DONE utils/genmodinfo
utils/modlist utils/modlist

View File

@ -1,9 +1,9 @@
#!/usr/bin/python -tt #!/usr/bin/env python
# #
# lorax # lorax
# Install image and tree support data generation tool. # 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 # 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 # 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
# Author(s): David Cantrell <dcantrell@redhat.com> # Author(s): David Cantrell <dcantrell@redhat.com>
# Martin Gracik <mgracik@redhat.com>
# #
import getopt
import os
import sys 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__": if __name__ == '__main__':
prog = os.path.basename(sys.argv[0]) version = '%s 0.1' % (os.path.basename(sys.argv[0]),)
opts, args, mirrorlist, extrarepos = [], [], [], [] usage = '%prog -p PRODUCT -v VERSION -r RELEASE -o OUTPUT REPOSITORY'
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.'
try: parser = OptionParser(usage=usage)
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)
for o, a in opts: def check_dir(option, opt_str, value, parser):
if o in ('-v', '--version'): if os.path.isdir(value):
version = a setattr(parser.values, option.dest, value)
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: else:
sys.stderr.write("ERROR: %s is not a directory.\n" % (a,)) parser.error('%s is not a directory' % (value,))
elif o in ('-C', '--cleanup'):
cleanup = True # XXX "options" should not be required
elif o in ('-V'): # required
# XXX: need to fix this group = OptionGroup(parser, 'Required')
#pylorax.show_version(prog) 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)
# 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)
# 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)
(opts, args) = parser.parse_args()
if opts.printver:
print(version)
sys.exit(0) sys.exit(0)
if version is None or product is None or release is None or output is None: if not opts.product or not opts.version or not opts.release or not opts.output:
sys.stderr.write("ERROR: Missing a required argument.\n") parser.error('Missing a required argument.')
sys.exit(1)
if len(args) == 0: if not args:
sys.stderr.write("ERROR: Missing repo to use for image generation.\n") parser.error('Missing repository to use for image generation.')
sys.exit(1)
lorax = Lorax(repos=args, output=output, mirrorlist=mirrorlist)
if confdir is not None:
lorax.conf['confdir'] = confdir
lorax = pylorax.Lorax(repos=args, options=opts)
lorax.run() 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 # pylorax
# Install image and tree support data generation tool -- Python 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 # 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 # 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
# Author(s): David Cantrell <dcantrell@redhat.com> # Author(s): David Cantrell <dcantrell@redhat.com>
# Martin Gracik <mgracik@redhat.com>
# #
version = (0, 1) import sys
import os import os
import shutil import shutil
import tempfile import tempfile
import time
import ConfigParser
import yum import yum
import rpmUtils import rpmUtils
import discinfo import instroot
import treeinfo import images
from instroot import InstRoot
class Lorax: class Lorax:
def __init__(self, repos=[], output=None, mirrorlist=[], updates=None): def __init__(self, repos, options):
self.conf = {}
self.conf['confdir'] = '/etc/lorax'
self.conf['tmpdir'] = tempfile.gettempdir()
self.conf['datadir'] = '/usr/share/lorax'
self.repos = repos self.repos = repos
self.output = output
self.mirrorlist = mirrorlist # required
self.updates = updates 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): def run(self):
"""run() """run()
Generate install images. Generate install images.
""" """
print("\n+=======================================================+") print('Collecting repos...')
print("| Setting up work directories and configuration data... |") self.repo, self.extrarepos = self.__collectRepos()
print("+=======================================================+\n")
if repos != []: if not self.repo:
self.repo, self.extrarepos = self.__collectRepos(repos) sys.stderr.write('No valid repository.\n')
else: sys.exit(1)
self.repo = None
self.extrarepos = []
print('Initializing directories...')
self.buildinstdir, self.treedir, self.cachedir = self.__initializeDirs() self.buildinstdir, self.treedir, self.cachedir = self.__initializeDirs()
print('Writing yum configuration...')
self.yumconf = self.__writeYumConf() self.yumconf = self.__writeYumConf()
print("\n+================================================+") print('Getting the build architecture...')
print("| Creating instroot tree to build images from... |") self.buildarch = self.__getBuildArch()
print("+================================================+\n")
self.instroot = InstRoot(conf=self.conf, print('Creating install root tree...')
yumconf=self.yumconf, self.makeInstRoot()
arch=self.getBuildArch(),
treedir=self.treedir,
updates=self.updates)
self.instroot.run()
def showVersion(self, driver=None): print('Writing .treeinfo...')
"""showVersion(driver) self.__writeTreeInfo()
Display program name (driver) and version number. If prog is an empty print('Writing .discinfo...')
string or None, use the value 'pylorax'. 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 == '': repolist = []
prog = 'pylorax' 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, []
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 trash != []:
for item in trash:
if os.path.isdir(item):
shutil.rmtree(item, ignore_errors=True)
else: else:
os.unlink(item) return repolist[0], repolist[1:]
if os.path.isdir(self.conf['tmpdir']): def __initializeDirs(self):
shutil.rmtree(self.conf['tmpdir'], ignore_errors=True) """_initializeDirs()
def getBuildArch(self): Create directories used for image generation.
"""getBuildArch() """
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.
"""
(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, Query the configured yum repositories to determine our build architecture,
which is the architecture of the anaconda package in the repositories. which is the architecture of the anaconda package in the repositories.
This function is based on a subset of what repoquery(1) does. This function is based on a subset of what repoquery(1) does.
""" """
uname_arch = os.uname()[4] uname_arch = os.uname()[4]
if self.yumconf == '' or self.yumconf is None or not os.path.isfile(self.yumconf): if not self.yumconf or not os.path.isfile(self.yumconf):
print "RETURN HERE" sys.stderr.write('ERROR: yum.conf does not exist, defaulting to %s\n' % (uname_arch,))
return uname_arch return uname_arch
repoq = yum.YumBase() repoq = yum.YumBase()
repoq.doConfigSetup() repoq.doConfigSetup(self.yumconf)
try: try:
repoq.doRepoSetup() repoq.doRepoSetup()
except yum.Errors.RepoError, e: except yum.Errors.RepoError:
sys.stderr.write("ERROR: could not query yum repository for build arch, defaulting to %s\n" % (uname_arch,)) sys.stderr.write('ERROR: cannot query yum repo, defaulting to %s\n' % (uname_arch,))
return uname_arch return uname_arch
repoq.doSackSetup(rpmUtils.arch.getArchList()) repoq.doSackSetup(rpmUtils.arch.getArchList())
@ -144,109 +217,80 @@ class Lorax:
ret_arch = a ret_arch = a
break break
if ret_arch is None: if not ret_arch:
ret_arch = uname_arch ret_arch = uname_arch
print("Building images for %s" % (ret_arch,))
return ret_arch return ret_arch
def __collectRepos(self, repos): def __writeTreeInfo(self, discnum=1, totaldiscs=1, packagedir=''):
"""_collectRepos(repos) outfile = os.path.join(self.output, '.treeinfo')
Get the main repo (the first one) and then build a list of all remaining data = { 'timestamp': time.time(),
repos in the list. Sanitize each repo URL for proper yum syntax. 'family': self.product,
'version': self.version,
'arch': self.buildarch,
'variant': self.variant,
'discnum': str(discnum),
'totaldiscs': str(totaldiscs),
'packagedir': packagedir }
""" c = ConfigParser.ConfigParser()
if repos is None or repos == []: section = 'general'
return '', [] c.add_section(section)
for key, value in data.items():
repolist = [] c.set(section, key, value)
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)
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
try:
f = open(outfile, 'w')
except IOError:
return False
else:
c.write(f)
f.close() f.close()
print("Wrote lorax yum configuration to %s" % (yumconf,)) 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.
"""
for item in trash:
if os.path.isdir(item):
shutil.rmtree(item, ignore_errors=True)
else:
os.unlink(item)
if os.path.isdir(self.conf['tmpdir']):
shutil.rmtree(self.conf['tmpdir'], ignore_errors=True)
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 # pylorax instroot module
# Install image and tree support data generation tool -- Python 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 # 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 # 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
# Author(s): David Cantrell <dcantrell@redhat.com> # Author(s): David Cantrell <dcantrell@redhat.com>
# Martin Gracik <mgracik@redhat.com>
# #
import glob
import os
import shutil
import sys 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') sys.path.insert(0, '/usr/share/yum-cli')
import yummain import yummain
class InstRoot: 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 Create a instroot tree for the specified architecture. The list of
packages to install are specified in the /etc/lorax/packages and packages to install are specified in the /etc/lorax/packages and
/etc/lorax/ARCH/packages files. /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 lorax. arch is the platform name we are building for, treedir is
the location where the instroot tree should go the location where the instroot tree should go
(will be treedir + '/install'). updates is an optional path to a (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 On success, this function returns True. On failure, False is
returned or the program is aborted immediately. returned or the program is aborted immediately.
""" """
# Create inst root from which stage 1 and stage 2 images are built. def __init__(self, conf, yumconf, arch, treedir, updates=None):
def __init__(self, conf=None, yumconf=None, arch=None, treedir=None, updates=None):
self.conf = conf self.conf = conf
self.yumconf = yumconf self.yumconf = yumconf
self.arch = arch self.arch = arch
self.treedir = treedir self.treedir = treedir
self.updates = updates self.updates = updates
# XXX: these tests should raise exceptions self.libdir = 'lib'
if yumconf is None or arch is None or treedir is None:
return False
# on 64-bit systems, make sure we use lib64 as the lib directory # on 64-bit systems, make sure we use lib64 as the lib directory
if self.arch.endswith('64') or self.arch == 's390x': if self.arch.endswith('64') or self.arch == 's390x':
self.libdir = 'lib64' self.libdir = 'lib64'
else:
self.libdir = 'lib'
# the directory where the instroot will be created # the directory where the instroot will be created
self.destdir = os.path.join(self.treedir, 'install') self.destdir = os.path.join(self.treedir, 'install')
@ -73,7 +77,6 @@ class InstRoot:
"""run() """run()
Generate the instroot tree and prepare it for building images. Generate the instroot tree and prepare it for building images.
""" """
if not os.path.isdir(self.destdir): if not os.path.isdir(self.destdir):
@ -101,14 +104,11 @@ class InstRoot:
for line in f.readlines(): for line in f.readlines():
line = line.strip() line = line.strip()
if line.startswith('#') or line == '': if not line or line.startswith('#'):
continue continue
if line.startswith('-'): if line.startswith('-'):
try: packages.discard(line[1:])
packages.remove(line[1:])
except KeyError:
pass
else: else:
packages.add(line) packages.add(line)
@ -119,64 +119,83 @@ class InstRoot:
return packages return packages
# Call yummain to install the list of packages to destdir
def __installPackages(self): def __installPackages(self):
# build the list of arguments to pass to yum # build the list of arguments to pass to yum
arglist = ['-c', self.yumconf] arglist = ['-c', self.yumconf]
arglist.append("--installroot=%s" % (self.destdir,)) 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 # 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', 'lib', 'debug'))
os.makedirs(os.path.join(self.destdir, 'usr', 'src', '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, 'tmp'))
os.makedirs(os.path.join(self.destdir, 'var', 'log')) 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'))
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')) 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 # XXX sort through yum errcodes and return False for actual bad things we care about
# we care about
errcode = yummain.user_main(arglist, exit_code=False) errcode = yummain.user_main(arglist, exit_code=False)
# Scrub the instroot tree (remove files we don't want, modify settings, etc) # copy updates to destdir
def __scrubInstRoot(self): if self.updates and os.path.isdir(self.updates):
print cp(os.path.join(self.updates, '*'), self.destdir)
# drop custom configuration files in to the instroot def __scrubInstRoot(self):
dogtailconf = os.path.join(self.conf['datadir'], 'dogtail-%conf.xml') 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): if os.path.isfile(dogtailconf):
os.makedirs(os.path.join(destdir, '.gconf', 'desktop', 'gnome', 'interface')) os.makedirs(os.path.join(self.destdir, '.gconf', 'desktop', 'gnome', 'interface'))
f = open(os.path.join(destdir, '.gconf', 'desktop', '%gconf.xml'), 'w') f = open(os.path.join(self.destdir, '.gconf', 'desktop', '%gconf.xml'), 'w')
f.close() 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() f.close()
dest = os.path.join(destdir, '.gconf', 'desktop', 'gnome', 'interface', '%gconf.xml') dst = os.path.join(self.destdir, '.gconf', 'desktop', 'gnome', 'interface', '%gconf.xml')
print "Installing %s..." % (os.path.join(os.path.sep, '.gconf', 'desktop', 'gnome', 'interface', '%gconf.xml'),) cp(dogtailconf, dst)
shutil.copy(dogtailconf, dest)
# create selinux config # create selinux config
if os.path.isfile(os.path.join(self.destdir, 'etc', 'selinux', 'targeted')): if os.path.isfile(os.path.join(self.destdir, 'etc', 'selinux', 'targeted')):
src = os.path.join(self.conf['datadir'], 'selinux-config') selinuxconf = os.path.join(self.conf['datadir'], 'selinux-config')
if os.path.isfile(src): if os.path.isfile(selinuxconf):
dest = os.path.join(self.destdir, 'etc', 'selinux', 'config') dst = os.path.join(self.destdir, 'etc', 'selinux', 'config')
print "Installing %s..." % (os.path.join(os.path.sep, 'etc', 'selinux', 'config'),) cp(selinuxconf, dst)
shutil.copy(src, dest)
# create libuser.conf # create libuser.conf
src = os.path.join(self.conf['datadir'], 'libuser.conf') libuserconf = os.path.join(self.conf['datadir'], 'libuser.conf')
dest = os.path.join(self.destdir, 'etc', 'libuser.conf') if os.path.isfile(libuserconf):
if os.path.isfile(src): dst = os.path.join(self.destdir, 'etc', 'libuser.conf')
print "Installing %s..." % (os.path.join(os.path.sep, 'etc', 'libuser.conf'),) cp(libuserconf, dst)
shutil.copy(src, dest)
def __removeGtkThemes(self):
# figure out the gtk+ theme to keep # figure out the gtk+ theme to keep
gtkrc = os.path.join(self.destdir, 'etc', 'gtk-2.0', 'gtkrc') gtkrc = os.path.join(self.destdir, 'etc', 'gtk-2.0', 'gtkrc')
gtk_theme_name = None gtk_theme_name = None
gtk_icon_themes = []
gtk_engine = None gtk_engine = None
gtk_icon_themes = []
if os.path.isfile(gtkrc): if os.path.isfile(gtkrc):
print "\nReading %s..." % (os.path.join(os.path.sep, 'etc', 'gtk-2.0', 'gtkrc'),)
f = open(gtkrc, 'r') f = open(gtkrc, 'r')
lines = f.readlines() lines = f.readlines()
f.close() f.close()
@ -184,11 +203,12 @@ class InstRoot:
for line in lines: for line in lines:
line = line.strip() line = line.strip()
if line.startswith('gtk-theme-name'): if line.startswith('gtk-theme-name'):
gtk_theme_name = line[line.find('=') + 1:].replace('"', '').strip() gtk_theme_name = line[line.find('=') + 1:]
print " gtk-theme-name: %s" % (gtk_theme_name,) gtk_theme_name = gtk_theme_name.replace('"', '').strip()
# find the engine for this theme # 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): if os.path.isfile(gtkrc):
f = open(gtkrc, 'r') f = open(gtkrc, 'r')
engine_lines = f.readlines() engine_lines = f.readlines()
@ -196,19 +216,20 @@ class InstRoot:
for engine_line in engine_lines: for engine_line in engine_lines:
engine_line = engine_line.strip() engine_line = engine_line.strip()
if engine_line.find('engine') != -1: if engine_line.find('engine') != -1:
gtk_engine = engine_line[engine_line.find('"') + 1:].replace('"', '') gtk_engine = engine_line[engine_line.find('"') + 1:]
print " gtk-engine: %s" % (gtk_engine,) gtk_engine = gtk_engine.replace('"', '').strip()
break break
elif line.startswith('gtk-icon-theme-name'): elif line.startswith('gtk-icon-theme-name'):
icon_theme = line[line.find('=') + 1:].replace('"', '').strip() icon_theme = line[line.find('=') + 1:]
print " gtk-icon-theme-name: %s" % (icon_theme,) icon_theme = icon_theme.replace('"', '').strip()
gtk_icon_themes.append(icon_theme) gtk_icon_themes.append(icon_theme)
# bring in all inherited themes # bring in all inherited themes
while True: 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): if os.path.isfile(icon_theme_index):
inherits = False inherits = False
f = open(icon_theme_index, 'r') f = open(icon_theme_index, 'r')
@ -219,8 +240,8 @@ class InstRoot:
icon_line = icon_line.strip() icon_line = icon_line.strip()
if icon_line.startswith('Inherits='): if icon_line.startswith('Inherits='):
inherits = True inherits = True
icon_theme = icon_line[icon_line.find('=') + 1:].replace('"', '') icon_theme = icon_line[icon_line.find('=') + 1:]
print " inherits gtk-icon-theme-name: %s" % (icon_theme,) icon_theme = icon_theme.replace('"', '').strip()
gtk_icon_themes.append(icon_theme) gtk_icon_themes.append(icon_theme)
break break
@ -229,34 +250,32 @@ class InstRoot:
else: else:
break 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): if os.path.isdir(theme_path):
for theme in os.listdir(theme_path): for theme in filter(lambda theme: theme != gtk_theme_name, os.listdir(theme_path)):
if theme != gtk_theme_name:
theme = os.path.join(theme_path, theme) theme = os.path.join(theme_path, theme)
shutil.rmtree(theme, ignore_errors=True) shutil.rmtree(theme, ignore_errors=True)
# remove icons we don't need
icon_path = os.path.join(self.destdir, 'usr', 'share', 'icons') icon_path = os.path.join(self.destdir, 'usr', 'share', 'icons')
if os.path.isdir(icon_path): if os.path.isdir(icon_path):
for icon in os.listdir(icon_path): for icon in filter(lambda icon: icon not in gtk_icon_themes, os.listdir(icon_path)):
try:
if gtk_icon_themes.index(icon):
continue
except ValueError:
icon = os.path.join(icon_path, icon) icon = os.path.join(icon_path, icon)
shutil.rmtree(icon, ignore_errors=True) 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): if os.path.isdir(tmp_path):
for subdir in os.listdir(tmp_path): fnames = map(lambda fname: os.path.join(tmp_path, fname, 'engines'), os.listdir(tmp_path))
new_path = os.path.join(tmp_path, subdir, 'engines') dnames = filter(lambda fname: os.path.isdir(fname), fnames)
if os.path.isdir(new_path): for dir in dnames:
for engine in os.listdir(new_path): engines = filter(lambda engine: engine.find(gtk_engine) == -1, os.listdir(dir))
if engine.find(gtk_engine) == -1: for engine in engines:
tmp_engine = os.path.join(new_path, engine) engine = os.path.join(dir, engine)
os.unlink(tmp_engine) os.unlink(engine)
# clean out unused locales def __removeLocales(self):
langtable = os.path.join(self.destdir, 'usr', 'lib', 'anaconda', 'lang-table') langtable = os.path.join(self.destdir, 'usr', 'lib', 'anaconda', 'lang-table')
localepath = os.path.join(self.destdir, 'usr', 'share', 'locale') localepath = os.path.join(self.destdir, 'usr', 'share', 'locale')
if os.path.isfile(langtable): if os.path.isfile(langtable):
@ -267,11 +286,9 @@ class InstRoot:
lines = f.readlines() lines = f.readlines()
f.close() f.close()
print "Keeping locales used during installation..."
for line in lines: for line in lines:
line = line.strip() line = line.strip()
if not line or line.startswith('#'):
if line == '' or line.startswith('#'):
continue continue
fields = line.split('\t') fields = line.split('\t')
@ -283,23 +300,40 @@ class InstRoot:
if os.path.isdir(os.path.join(localepath, locale)): if os.path.isdir(os.path.join(localepath, locale)):
locales.add(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) all_locales.add(locale)
print "Removing unused locales..."
locales_to_remove = list(all_locales.difference(locales)) locales_to_remove = list(all_locales.difference(locales))
for locale in locales_to_remove: 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) 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']: for file in ['nroff', 'groff', 'iconv', 'geqn', 'gtbl', 'gpic', 'grefer']:
src = os.path.join('mnt', 'sysimage', 'usr', 'bin', file) src = os.path.join('mnt', 'sysimage', 'usr', 'bin', file)
dst = os.path.join(self.destdir, 'usr', 'bin', file) dst = os.path.join(self.destdir, 'usr', 'bin', file)
if not os.path.isfile(dst): if not os.path.isfile(dst):
os.symlink(src, 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']: for subdir in ['lib', 'firmware']:
subdir = os.path.join(self.destdir, subdir) subdir = os.path.join(self.destdir, subdir)
if not os.path.isdir(subdir): if not os.path.isdir(subdir):
@ -311,56 +345,299 @@ class InstRoot:
shutil.rmtree(dst, ignore_errors=True) shutil.rmtree(dst, ignore_errors=True)
os.symlink(src, dst) 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,) stub = "%s-stub" % (prog,)
src = os.path.join(self.destdir, 'usr', 'lib', 'anaconda', stub) src = os.path.join(self.destdir, 'usr', 'lib', 'anaconda', stub)
dst = os.path.join(self.destdir, 'usr', 'bin', prog) dst = os.path.join(self.destdir, 'usr', 'bin', prog)
if os.path.isfile(src) and not os.path.isfile(dst): 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') bootpath = os.path.join(self.destdir, 'usr', 'lib', 'anaconda-runtime', 'boot')
if not os.path.isdir(bootpath): if not os.path.isdir(bootpath):
os.makedirs(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')): for bootfile in os.listdir(os.path.join(self.destdir, 'boot')):
if bootfile.startswith('memtest'): if bootfile.startswith('memtest'):
src = os.path.join(self.destdir, 'boot', bootfile) src = os.path.join(self.destdir, 'boot', bootfile)
dst = os.path.join(bootpath, bootfile) dst = os.path.join(bootpath, bootfile)
shutil.copy2(src, dst) cp(src, dst)
elif arch.startswith('sparc'): elif self.arch.startswith('sparc'):
for bootfile in os.listdir(os.path.join(self.destdir, 'boot')): for bootfile in os.listdir(os.path.join(self.destdir, 'boot')):
if bootfile.endswith('.b'): if bootfile.endswith('.b'):
src = os.path.join(self.destdir, 'boot', bootfile) src = os.path.join(self.destdir, 'boot', bootfile)
dst = os.path.join(bootpath, bootfile) dst = os.path.join(bootpath, bootfile)
shutil.copy2(src, dst) cp(src, dst)
elif arch.startswith('ppc'): elif self.arch.startswith('ppc'):
src = os.path.join(self.destdir, 'boot', 'efika.forth') src = os.path.join(self.destdir, 'boot', 'efika.forth')
dst = os.path.join(bootpath, 'efika.forth') dst = os.path.join(bootpath, 'efika.forth')
shutil.copy2(src, dst) cp(src, dst)
elif arch == 'alpha': elif self.arch == 'alpha':
src = os.path.join(self.destdir, 'boot', 'bootlx') src = os.path.join(self.destdir, 'boot', 'bootlx')
dst = os.path.join(bootpath, 'bootlx') dst = os.path.join(bootpath, 'bootlx')
shutil.copy2(src, dst) cp(src, dst)
elif arch == 'ia64': elif self.arch == 'ia64':
src = os.path.join(self.destdir, 'boot', 'efi', 'EFI', 'redhat') src = os.path.join(self.destdir, 'boot', 'efi', 'EFI', 'redhat')
shutil.rmtree(bootpath, ignore_errors=True) 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') src = os.path.join(self.destdir, 'etc', 'yum.repos.d')
dst = os.path.join(self.destdir, 'etc', 'anaconda.repos.d') dst = os.path.join(self.destdir, 'etc', 'anaconda.repos.d')
if os.path.isdir(src): if os.path.isdir(src):
shutil.rmtree(dst, ignore_errors=True) 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']: for subdir in ['boot', 'home', 'root', 'tmp']:
shutil.rmtree(os.path.join(self.destdir, subdir), ignore_errors=True) shutil.rmtree(os.path.join(self.destdir, subdir), ignore_errors=True)
for subdir in ['doc', 'info']: for subdir in ['doc', 'info']:
shutil.rmtree(os.path.join(self.destdir, 'usr', 'share', subdir), ignore_errors=True) 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) 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