From b672d9936eb68b9c78f3781547db0b909ee04e1b Mon Sep 17 00:00:00 2001 From: Martin Gracik Date: Tue, 15 Dec 2009 15:26:01 +0100 Subject: [PATCH] New version Added support for Mako templates. Changed the Lorax class to require an yumbase object as a parameter. Changed a lot of unnecessary system calls to native python code. Moved most of the file paths into a separate object. The output and config objects are now singletons. Also done a lot of code cleanup. --- etc/initrd/includes/initrd.common | 222 ---- etc/initrd/initrd.alpha | 1 - etc/initrd/initrd.i386 | 12 - etc/initrd/initrd.ia64 | 1 - etc/initrd/initrd.ppc | 1 - etc/initrd/initrd.ppc64 | 1 - etc/initrd/initrd.s390 | 54 - etc/initrd/initrd.s390x | 1 - etc/initrd/initrd.sparc | 1 - etc/initrd/initrd.x86_64 | 1 - etc/lorax/config.i386 | 8 + etc/lorax/config.i586 | 1 + etc/lorax/config.noarch | 23 + etc/lorax/config.s390 | 11 + etc/lorax/config.s390x | 1 + etc/lorax/config.x86_64 | 1 + etc/lorax/templates/initrd/includes/initrd | 242 +++++ etc/lorax/templates/initrd/initrd.i386 | 11 + etc/lorax/templates/initrd/initrd.s390 | 51 + etc/lorax/templates/scrubs/scrubs.i386 | 103 ++ .../templates/scrubs}/scrubs.s390 | 0 etc/modules/modules.all | 84 -- etc/modules/modules.alpha | 2 - etc/modules/modules.s390 | 15 - etc/modules/modules.s390x | 1 - etc/packages/packages.all | 43 - etc/packages/packages.alpha | 1 - etc/packages/packages.i386 | 7 - etc/packages/packages.i586 | 1 - etc/packages/packages.ia64 | 3 - etc/packages/packages.ppc | 6 - etc/packages/packages.ppc64 | 1 - etc/packages/packages.s390 | 19 - etc/packages/packages.s390x | 1 - etc/packages/packages.sparc | 2 - etc/packages/packages.x86_64 | 1 - etc/tree/scrubs.alpha | 1 - etc/tree/scrubs.i386 | 103 -- etc/tree/scrubs.ia64 | 1 - etc/tree/scrubs.ppc | 1 - etc/tree/scrubs.ppc64 | 1 - etc/tree/scrubs.s390x | 1 - etc/tree/scrubs.sparc | 1 - etc/tree/scrubs.x86_64 | 1 - src/bin/lorax | 112 +- src/pylorax/__init__.py | 988 +++++++++--------- src/pylorax/_rewrite/scrubs.py | 126 --- src/pylorax/actions/__init__.py | 58 - src/pylorax/actions/base.py | 404 ------- src/pylorax/config.py | 239 +++-- src/pylorax/efi.py | 213 ++++ src/pylorax/images.py | 867 --------------- src/pylorax/install.py | 479 +++++++++ src/pylorax/insttree.py | 551 ---------- src/pylorax/launcher.py | 205 ++++ src/pylorax/lcs/__init__.py | 58 + src/pylorax/lcs/actions/__init__.py | 31 + src/pylorax/lcs/actions/base.py | 37 + src/pylorax/lcs/actions/file.py | 282 +++++ src/pylorax/lcs/actions/ssh.py | 39 + src/pylorax/misc.py | 41 - src/pylorax/output.py | 138 +-- src/pylorax/ramdisk.py | 435 ++++++++ src/pylorax/singleton.py | 14 + src/pylorax/template.py | 113 -- src/pylorax/utils.py | 405 +++++++ src/pylorax/utils/fileutils.py | 306 ------ src/pylorax/utils/ldd.py | 88 -- src/pylorax/utils/yumwrapper.py | 129 --- .../share/lorax/initrd/s390/etc}/pam.d/login | 0 usr/share/lorax/initrd/s390/etc/pam.d/remote | 9 + usr/share/lorax/initrd/s390/etc/pam.d/sshd | 9 + .../lorax/initrd/s390/etc/ssh}/sshd_config | 0 usr/share/lorax/initrd/s390x | 1 + .../noarch/.gconf/desktop/%gconf.xml | 0 .../noarch/.gconf/desktop/gnome/%gconf.xml | 0 .../desktop/gnome/interface}/%gconf.xml | 0 .../installtree/noarch/etc}/libuser.conf | 0 .../installtree/noarch/etc}/selinux/config | 0 .../share/lorax/outputdir}/images/README | 0 .../lorax/outputdir}/images/pxeboot/README | 0 81 files changed, 3371 insertions(+), 4050 deletions(-) delete mode 100644 etc/initrd/includes/initrd.common delete mode 120000 etc/initrd/initrd.alpha delete mode 100644 etc/initrd/initrd.i386 delete mode 120000 etc/initrd/initrd.ia64 delete mode 120000 etc/initrd/initrd.ppc delete mode 120000 etc/initrd/initrd.ppc64 delete mode 100644 etc/initrd/initrd.s390 delete mode 120000 etc/initrd/initrd.s390x delete mode 120000 etc/initrd/initrd.sparc delete mode 120000 etc/initrd/initrd.x86_64 create mode 100644 etc/lorax/config.i386 create mode 120000 etc/lorax/config.i586 create mode 100644 etc/lorax/config.noarch create mode 100644 etc/lorax/config.s390 create mode 120000 etc/lorax/config.s390x create mode 120000 etc/lorax/config.x86_64 create mode 100644 etc/lorax/templates/initrd/includes/initrd create mode 100644 etc/lorax/templates/initrd/initrd.i386 create mode 100644 etc/lorax/templates/initrd/initrd.s390 create mode 100644 etc/lorax/templates/scrubs/scrubs.i386 rename etc/{tree => lorax/templates/scrubs}/scrubs.s390 (100%) delete mode 100644 etc/modules/modules.all delete mode 100644 etc/modules/modules.alpha delete mode 100644 etc/modules/modules.s390 delete mode 120000 etc/modules/modules.s390x delete mode 100644 etc/packages/packages.all delete mode 100644 etc/packages/packages.alpha delete mode 100644 etc/packages/packages.i386 delete mode 120000 etc/packages/packages.i586 delete mode 100644 etc/packages/packages.ia64 delete mode 100644 etc/packages/packages.ppc delete mode 120000 etc/packages/packages.ppc64 delete mode 100644 etc/packages/packages.s390 delete mode 120000 etc/packages/packages.s390x delete mode 100644 etc/packages/packages.sparc delete mode 120000 etc/packages/packages.x86_64 delete mode 120000 etc/tree/scrubs.alpha delete mode 100644 etc/tree/scrubs.i386 delete mode 120000 etc/tree/scrubs.ia64 delete mode 120000 etc/tree/scrubs.ppc delete mode 120000 etc/tree/scrubs.ppc64 delete mode 120000 etc/tree/scrubs.s390x delete mode 120000 etc/tree/scrubs.sparc delete mode 120000 etc/tree/scrubs.x86_64 delete mode 100644 src/pylorax/_rewrite/scrubs.py delete mode 100644 src/pylorax/actions/__init__.py delete mode 100644 src/pylorax/actions/base.py create mode 100644 src/pylorax/efi.py delete mode 100644 src/pylorax/images.py create mode 100644 src/pylorax/install.py delete mode 100644 src/pylorax/insttree.py create mode 100644 src/pylorax/launcher.py create mode 100644 src/pylorax/lcs/__init__.py create mode 100644 src/pylorax/lcs/actions/__init__.py create mode 100644 src/pylorax/lcs/actions/base.py create mode 100644 src/pylorax/lcs/actions/file.py create mode 100644 src/pylorax/lcs/actions/ssh.py delete mode 100644 src/pylorax/misc.py create mode 100644 src/pylorax/ramdisk.py create mode 100644 src/pylorax/singleton.py delete mode 100644 src/pylorax/template.py create mode 100644 src/pylorax/utils.py delete mode 100644 src/pylorax/utils/fileutils.py delete mode 100644 src/pylorax/utils/ldd.py delete mode 100644 src/pylorax/utils/yumwrapper.py rename {share => usr/share/lorax/initrd/s390/etc}/pam.d/login (100%) create mode 100644 usr/share/lorax/initrd/s390/etc/pam.d/remote create mode 100644 usr/share/lorax/initrd/s390/etc/pam.d/sshd rename {share/sshd => usr/share/lorax/initrd/s390/etc/ssh}/sshd_config (100%) create mode 120000 usr/share/lorax/initrd/s390x rename src/pylorax/utils/__init__.py => usr/share/lorax/installtree/noarch/.gconf/desktop/%gconf.xml (100%) create mode 100644 usr/share/lorax/installtree/noarch/.gconf/desktop/gnome/%gconf.xml rename {share/dogtail => usr/share/lorax/installtree/noarch/.gconf/desktop/gnome/interface}/%gconf.xml (100%) rename {share/libuser => usr/share/lorax/installtree/noarch/etc}/libuser.conf (100%) rename {share => usr/share/lorax/installtree/noarch/etc}/selinux/config (100%) rename {share => usr/share/lorax/outputdir}/images/README (100%) rename {share => usr/share/lorax/outputdir}/images/pxeboot/README (100%) diff --git a/etc/initrd/includes/initrd.common b/etc/initrd/includes/initrd.common deleted file mode 100644 index c0a74a38..00000000 --- a/etc/initrd/includes/initrd.common +++ /dev/null @@ -1,222 +0,0 @@ -# initrd template - -# create required directories -makedir @initrd@/lib -makedir @initrd@/modules -makedir @initrd@/firmware -link @initrd@/lib/modules to ../modules -link @initrd@/lib/firmware to ../firmware -makedir @initrd@/sbin -makedir @initrd@/dev -makedir @initrd@/etc -makedir @initrd@/etc/udev/rules.d -makedir @initrd@/lib/udev/rules.d -makedir @initrd@/proc -makedir @initrd@/selinux -makedir @initrd@/sys -makedir @initrd@/etc/terminfo/a -makedir @initrd@/etc/terminfo/d -makedir @initrd@/etc/terminfo/l -makedir @initrd@/etc/terminfo/s -makedir @initrd@/etc/terminfo/v -makedir @initrd@/etc/terminfo/x -makedir @initrd@/etc/terminfo/g -makedir @initrd@/tmp -makedir @initrd@/usr/libexec -makedir @initrd@/usr/@libdir@/NetworkManager -makedir @initrd@/usr/share/dbus-1/system-services -makedir @initrd@/var/cache/hald -makedir @initrd@/var/lib/dbus -makedir @initrd@/var/lib/dhclient -makedir @initrd@/var/lock/rpm -makedir @initrd@/var/run -makedir @initrd@/var/run/dbus -makedir @initrd@/var/run/hald -makedir @initrd@/var/run/NetworkManager -makedir @initrd@/etc/dbus-1/system.d -makedir @initrd@/etc/modprobe.d -makedir @initrd@/etc/NetworkManager/dispatcher.d -makedir @initrd@/@libdir@/dbus-1 -makedir @initrd@/etc/sysconfig/network-scripts -makedir @initrd@/usr/share/PolicyKit/policy -makedir @initrd@/etc/PolicyKit -makedir @initrd@/var/lib/misc -makedir @initrd@/etc/hal/fdi -makedir @initrd@/usr/share/hal/fdi -makedir @initrd@/usr/share/hwdata -makedir @initrd@/etc/rc.d/init.d -makedir @initrd@/usr/sbin -makedir @initrd@/var/run/wpa_supplicant - -# set the buildarch -edit @initrd@/etc/arch text "@buildarch@" - -# copy etc stuff -copy @instroot@ etc/passwd to @initrd@ etc -chmod @initrd@/etc/passwd mode 0644 - -copy @instroot@ etc/group to @initrd@ etc -chmod @initrd@/etc/group mode 0644 - -copy @instroot@ etc/nsswitch.conf to @initrd@ etc -chmod @initrd@/etc/nsswitch.conf mode 0644 - -copy @instroot@ etc/hosts to @initrd@ etc -chmod @initrd@/etc/hosts mode 0644 - -# copy mount/umount -copy @instroot@ bin/mount to @initrd@ sbin -copy @instroot@ bin/umount to @initrd@ sbin -copy @instroot@ sbin/mount.* to @initrd@ sbin -copy @instroot@ sbin/umount.* to @initrd@ sbin - -# copy udev -copy @instroot@ sbin/udevd to @initrd@ sbin -copy @instroot@ sbin/udevadm to @initrd@ sbin -link @initrd@/sbin/udevinfo to udevadm -link @initrd@/sbin/udevsettle to udevadm - -# udev rules -copy @instroot@ etc/udev/udev.conf to @initrd@ etc/udev -chmod @initrd@/etc/udev/udev.conf mode 0644 - -copy @instroot@ lib/udev/* to @initrd@ lib/udev -#chmod @initrd@/lib/udev/* mode 0644 - -remove @initrd@/lib/udev/rules.d/*persistent* -remove @initrd@/lib/udev/rules.d/*generator* - -copy @instroot@ etc/udev/rules.d/*.rules to @initrd@ etc/udev/rules.d -chmod @initrd@/etc/udev/rules.d/*.rules mode 0644 - -# copy bash -copy @instroot@ bin/bash to @initrd@ sbin -link @initrd@/sbin/sh to bash - -copy @instroot@ sbin/consoletype to @initrd@ sbin -copy @instroot@ usr/bin/logger to @initrd@ sbin - -copy @instroot@ etc/rc.d/init.d/functions to @initrd@ etc/rc.d/init.d -copy @instroot@ etc/sysconfig/network-scripts/network-functions* to @initrd@ etc/sysconfig/network-scripts - -link @initrd@/etc/init.d to /etc/rc.d/init.d - -# dhcp and dhcpv6 client daemons and support programs -copy @instroot@ sbin/dhclient to @initrd@ sbin -copy @instroot@ sbin/dhclient-script to @initrd@ sbin -copy @instroot@ sbin/dhcp6c to @initrd@ sbin -copy @instroot@ sbin/arping to @initrd@ sbin -copy @instroot@ sbin/ifconfig to @initrd@ sbin -copy @instroot@ sbin/ip to @initrd@ sbin -copy @instroot@ bin/ipcalc to @initrd@ sbin -copy @instroot@ bin/hostname to @initrd@ sbin -copy @instroot@ sbin/ethtool to @initrd@ sbin -copy @instroot@ sbin/route to @initrd@ sbin -touch @initrd@/etc/resolv.conf - -# hwdata -copy @instroot@ usr/share/hwdata/pci.ids to @initrd@ usr/share/hwdata -copy @instroot@ usr/share/hwdata/usb.ids to @initrd@ usr/share/hwdata - -# hal -copy @instroot@ usr/sbin/hald to @initrd@ sbin -copy @instroot@ usr/libexec/hald-runner to @initrd@ usr/libexec -copy @instroot@ usr/libexec/hald-generate-fdi-cache to @initrd@ usr/libexec -copy @instroot@ usr/libexec/hal*storage* to @initrd@ usr/libexec -touch @initrd@/var/run/hald.acl-list -copy @instroot@ usr/share/hal/fdi/* to @initrd@ usr/share/hal/fdi -copy @instroot@ etc/hal/fdi/* to @initrd@ etc/hal/fdi -copy @instroot@ etc/dbus-1/system.d/hal.conf to @initrd@ etc/dbus-1/system.d - -# policykit -copy @instroot@ etc/PolicyKit/PolicyKit.conf to @initrd@ etc/PolicyKit -copy @instroot@ usr/share/dbus-1/system-services/org.freedesktop.PolicyKit.service to @initrd@ usr/share/dbus-1/system-services -copy @instroot@ usr/share/PolicyKit/policy/org.freedesktop.policykit.policy to @initrd@ usr/share/PolicyKit/policy -copy @instroot@ var/lib/misc/PolicyKit.reload to @initrd@ var/lib/misc - -# dbus -copy @instroot@ bin/dbus-uuidgen to @initrd@ sbin -copy @instroot@ bin/dbus-daemon to @initrd@ sbin -copy @instroot@ etc/dbus-1/system.conf to @initrd@ etc/dbus-1 -copy @instroot@ @libdir@/dbus-1/dbus-daemon-launch-helper to @initrd@ @libdir@/dbus-1 -chown @initrd@/@libdir@/dbus-1/dbus-daemon-launch-helper user root group dbus -chmod @initrd@/@libdir@/dbus-1/dbus-daemon-launch-helper mode 04750 - -# wpa_supplicant -copy @instroot@ usr/sbin/wpa_passphrase to @initrd@ usr/sbin -copy @instroot@ usr/sbin/wpa_supplicant to @initrd@ usr/sbin -copy @instroot@ etc/dbus-1/system.d/wpa_supplicant.conf to @initrd@ etc/dbus-1/system.d -copy @instroot@ etc/wpa_supplicant/wpa_supplicant.conf to @initrd@ etc/wpa_supplicant -copy @instroot@ usr/share/dbus-1/system-services/fi.epitest.hostap.WPASupplicant.service to @initrd@ usr/share/dbus-1/system-services - -# networkmanager -copy @instroot@ usr/sbin/NetworkManager to @initrd@ usr/sbin -copy @instroot@ usr/sbin/nm-system-settings to @initrd@ usr/sbin -copy @instroot@ etc/dbus-1/system.d/nm-*.conf to @initrd@ etc/dbus-1/system.d -copy @instroot@ etc/dbus-1/system.d/NetworkManager.conf to @initrd@ etc/dbus-1/system.d -copy @instroot@ etc/NetworkManager/nm-system-settings.conf to @initrd@ etc/NetworkManager -copy @instroot@ usr/@libdir@/NetworkManager/libnm-settings-plugin-ifcfg-fedora.so to @initrd@ usr/@libdir@/NetworkManager -copy @instroot@ usr/libexec/nm-* to @initrd@ usr/libexec -copy @instroot@ usr/share/dbus-1/system-services/org.freedesktop.NetworkManagerSystemSettings.service to @initrd@ usr/share/dbus-1/system-services -copy @instroot@ usr/share/dbus-1/system-services/org.freedesktop.nm_dispatcher.service to @initrd@ usr/share/dbus-1/system-services - -# modprobe -copy @instroot@ sbin/modprobe to @initrd@ sbin -copy @instroot@ sbin/insmod to @initrd@ sbin -copy @instroot@ sbin/rmmod to @initrd@ sbin - -# profile -edit @initrd@/.profile text "PATH=/bin:/usr/bin:/usr/sbin:/mnt/sysimage/sbin:/mnt/sysimage/usr/sbin:/mnt/sysimage/bin:/mnt/sysimage/usr/bin\nexport PATH" - -# terminfos -copy @instroot@ usr/share/terminfo/a/ansi to @initrd@ etc/terminfo/a nolinks -copy @instroot@ usr/share/terminfo/d/dumb to @initrd@ etc/terminfo/d nolinks -copy @instroot@ usr/share/terminfo/l/linux to @initrd@ etc/terminfo/l nolinks -copy @instroot@ usr/share/terminfo/s/screen to @initrd@ etc/terminfo/s nolinks -copy @instroot@ usr/share/terminfo/v/vt100 to @initrd@ etc/terminfo/v nolinks -copy @instroot@ usr/share/terminfo/v/vt100-nav to @initrd@ etc/terminfo/v nolinks -copy @instroot@ usr/share/terminfo/v/vt102 to @initrd@ etc/terminfo/v nolinks -copy @instroot@ usr/share/terminfo/x/xterm to @initrd@ etc/terminfo/x nolinks -copy @instroot@ usr/share/terminfo/x/xterm-color to @initrd@ etc/terminfo/x nolinks -copy @instroot@ usr/share/terminfo/g/gnome to @initrd@ etc/terminfo/g nolinks -chmod @initrd@/etc/terminfo/*/* mode 0644 - -# misc -copy @instroot@ bin/awk to @initrd@ sbin -copy @instroot@ bin/gawk to @initrd@ sbin -copy @instroot@ bin/egrep to @initrd@ sbin -copy @instroot@ bin/fgrep to @initrd@ sbin -copy @instroot@ bin/grep to @initrd@ sbin -copy @instroot@ bin/kill to @initrd@ sbin -copy @instroot@ bin/ln to @initrd@ sbin -copy @instroot@ bin/readlink to @initrd@ sbin -copy @instroot@ bin/rm to @initrd@ sbin -copy @instroot@ bin/rmdir to @initrd@ sbin -copy @instroot@ bin/sed to @initrd@ sbin -copy @instroot@ bin/sleep to @initrd@ sbin -copy @instroot@ bin/touch to @initrd@ sbin - -link @initrd@/init to /sbin/init -link @initrd@/etc/mtab to /proc/mounts -link @initrd@/bin to sbin -link @initrd@/var/lib/xkb to ../../tmp - -# loader -copy @instroot@ usr/lib/anaconda-runtime/loader/loader to @initrd@ sbin -copy @instroot@ usr/lib/anaconda-runtime/loader/loader.tr to @initrd@ etc -chmod @initrd/etc/loader.tr mode 0644 - -# indirect dependencies -copy @instroot@ @libdir@/ld-linux.so.2 to @initrd@ @libdir@ -#copy @instroot@ @libdir@/libcom_err.so.2 to @initrd@ @libdir@ -#copy @instroot@ @libdir@/libdbus-glib-1.so.2 to @initrd@ @libdir@ -#copy @instroot@ @libdir@/libfreebl3.so to @initrd@ @libdir@ -copy @instroot@ @libdir@/libgcc_s.so.1 to @initrd@ @libdir@ -copy @instroot@ @libdir@/libnss_dns.so.2 to @initrd@ @libdir@ -copy @instroot@ @libdir@/libnss_files.so.2 to @initrd@ @libdir@ -copy @instroot@ @libdir@/libsoftokn3.so to @initrd@ @libdir@ - -copy @instroot@ usr/@libdir@/libsqlite3.so.0 to @initrd@ usr/@libdir@ - -# langtable -copy @instroot@ usr/lib/anaconda/lang-table to @initrd@ etc diff --git a/etc/initrd/initrd.alpha b/etc/initrd/initrd.alpha deleted file mode 120000 index 7f5d6354..00000000 --- a/etc/initrd/initrd.alpha +++ /dev/null @@ -1 +0,0 @@ -initrd.i386 \ No newline at end of file diff --git a/etc/initrd/initrd.i386 b/etc/initrd/initrd.i386 deleted file mode 100644 index b6c71784..00000000 --- a/etc/initrd/initrd.i386 +++ /dev/null @@ -1,12 +0,0 @@ -# initrd template - -#include includes/initrd.common - -# loader -copy @instroot@ usr/lib/anaconda-runtime/loader/init to @initrd@ sbin/init -link @initrd@/sbin/reboot to init -link @initrd@/sbin/halt to init -link @initrd@/sbin/poweroff to init - -# screenfont -copy @instroot@ usr/lib/anaconda-runtime/screenfont-@buildarch@.gz to @initrd@ etc/screenfont.gz diff --git a/etc/initrd/initrd.ia64 b/etc/initrd/initrd.ia64 deleted file mode 120000 index 7f5d6354..00000000 --- a/etc/initrd/initrd.ia64 +++ /dev/null @@ -1 +0,0 @@ -initrd.i386 \ No newline at end of file diff --git a/etc/initrd/initrd.ppc b/etc/initrd/initrd.ppc deleted file mode 120000 index 7f5d6354..00000000 --- a/etc/initrd/initrd.ppc +++ /dev/null @@ -1 +0,0 @@ -initrd.i386 \ No newline at end of file diff --git a/etc/initrd/initrd.ppc64 b/etc/initrd/initrd.ppc64 deleted file mode 120000 index 24600f3b..00000000 --- a/etc/initrd/initrd.ppc64 +++ /dev/null @@ -1 +0,0 @@ -initrd.ppc \ No newline at end of file diff --git a/etc/initrd/initrd.s390 b/etc/initrd/initrd.s390 deleted file mode 100644 index cf079699..00000000 --- a/etc/initrd/initrd.s390 +++ /dev/null @@ -1,54 +0,0 @@ -# initrd template - -#include includes/initrd.common - -# create required directories -makedir @initrd@/var/empty/sshd mode 0111 -makedir @initrd@/etc/pam.d -makedir @initrd@/etc/security -makedir @initrd@/@libdir@/security - -# copy some files -copy @instroot@ usr/bin/xauth to @initrd@ sbin -copy @instroot@ usr/sbin/cmsfs* to @initrd@ sbin - -copy @instroot@ @libdir@/libpam_misc.so.0.* to @initrd@ @libdir@/libpam_misc.so.0 -copy @instroot@ @libdir@/libwrap*.so* to @initrd@ @libdir@ - -link @initrd@/var/state/xkb to /tmp - -# loader -copy @instroot@ usr/lib/anaconda-runtime/loader/shutdown to @initrd@ sbin -copy @instroot@ usr/lib/anaconda-runtime/loader/linuxrc.s390 to @initrd@ sbin/init -copy @instroot@ usr/lib/anaconda-runtime/loader/lsznet.raw to @initrd@ sbin/lsznet -copy @instroot@ usr/lib/anaconda-runtime/loader/controlunits.sh @initrd@ sbin/controlunits -copy @instroot@ usr/sbin/dasdfmt to @initrd@ sbin - -# setup shell environment -edit @initrd@/etc/protocols text "tcp\t6\tTCP\n" - -copy @instroot@ @libdir@/security/pam_limits.so to @initrd@ @libdir@/security -copy @instroot@ @libdir@/security/pam_env.so to @initrd@ @libdir@/security -copy @instroot@ @libdir@/security/pam_unix.so to @initrd@ @libdir@/security -copy @instroot@ @libdir@/security/pam_deny.so to @initrd@ @libdir@/security - -copy @instroot@ etc/pam.d/other to @initrd@ etc/pam.d -copy @datadir@ pam.d/login to @initrd@ etc/pam.d/login -copy @datadir@ pam.d/login to @initrd@ etc/pam.d/sshd -copy @datadir@ pam.d/login to @initrd@ etc/pam.d/remote - -copy @instroot@ etc/security/limits.conf to @initrd@ etc/security -copy @Instroot@ etc/security/pam_env.conf to @initrd@ etc/security - -# generate keys -makedir @initrd@/etc/ssh mode 0700 -genkey @initrd@/etc/ssh/ssh_host_key type rsa1 -genkey @initrd@/etc/ssh/ssh_host_rsa_key type rsa -genkey @initrd@/etc/ssh/ssh_host_dsa_key type dsa - -copy @datadir@ sshd/sshd_config to @initrd@ etc/ssh/sshd_config -chmod @initrd@/etc/ssh/sshd_config mode 0600 - -# copy in the binaries -copy @instroot@ bin/login to @initrd@ sbin/login -copy @instroot@ usr/sbin/sshd to @initrd@ sbin/sshd diff --git a/etc/initrd/initrd.s390x b/etc/initrd/initrd.s390x deleted file mode 120000 index 07ba502b..00000000 --- a/etc/initrd/initrd.s390x +++ /dev/null @@ -1 +0,0 @@ -initrd.s390 \ No newline at end of file diff --git a/etc/initrd/initrd.sparc b/etc/initrd/initrd.sparc deleted file mode 120000 index 7f5d6354..00000000 --- a/etc/initrd/initrd.sparc +++ /dev/null @@ -1 +0,0 @@ -initrd.i386 \ No newline at end of file diff --git a/etc/initrd/initrd.x86_64 b/etc/initrd/initrd.x86_64 deleted file mode 120000 index 7f5d6354..00000000 --- a/etc/initrd/initrd.x86_64 +++ /dev/null @@ -1 +0,0 @@ -initrd.i386 \ No newline at end of file diff --git a/etc/lorax/config.i386 b/etc/lorax/config.i386 new file mode 100644 index 00000000..3783aada --- /dev/null +++ b/etc/lorax/config.i386 @@ -0,0 +1,8 @@ +[lorax] + +packages: + grub gpart syslinux memtest86+ efibootmgr dmidecode pcmciautils + kernel-PAE + +initrd_template=templates/initrd/initrd.i386 +scrubs_template=templates/scrubs/scrubs.i386 diff --git a/etc/lorax/config.i586 b/etc/lorax/config.i586 new file mode 120000 index 00000000..744d7dfd --- /dev/null +++ b/etc/lorax/config.i586 @@ -0,0 +1 @@ +config.i386 \ No newline at end of file diff --git a/etc/lorax/config.noarch b/etc/lorax/config.noarch new file mode 100644 index 00000000..aa95e3bf --- /dev/null +++ b/etc/lorax/config.noarch @@ -0,0 +1,23 @@ +[lorax] + +packages: + anaconda kernel *firmware* joe gnome-icon-theme fedora-icon-theme + xorg-x11-server-Xorg firstaidkit bzip2 busybox selinux-policy-targeted + python-imaging hal specspo xorg-x11-fonts-misc xorg-x11-drivers rhpxl + ntfs-3g ntfsprogs xfsprogs xfsdump reiserfs-utils gfs2-utils jfsutils + nfs-utils btrfs-progs mesa-dri-drivers dogtail rsh rsync prelink + smartmontools iscsi-initiator-utils samba-client mtr gtk-nodoka-engine + ftp openssh-clients gtk+ gdk-pixbuf madan-fonts lklug-fonts + xorg-x11-fonts-ethiopic un-core-fonts-dotum man yum-fedorakmod + /etc/gtk-2.0/gtkrc + +modules: + sunrpc lockd floppy cramfs loop edd pcspkr squashfs + ipv6 virtio_pci ohci-hcd uhci-hcd ehci-hcd usbhid mousedev usb-storage + sd_mod sr_mod ub appletouch ohci1394 sbp2 fw-ohci fw-sbp2 firewire-sbp2 + firewire-ohci mmc-block sdhci sdhci-pci ide-cd ide-cd_mod sr_mod sg st + sd_mod scsi_mod iscsi_tcp iscsi_ibft fat msdos vfat ext2 ext3 ext4 reiserfs + jfs xfs gfs2 cifs nfs fuse btrfs dm-mod dm-zero dm-snapshot dm-mirror + dm-multipath dm-round-robin dm-crypt raid0 raid1 raid5 raid6 raid456 raid10 + linear sha256_generic cbc xts lrw aes_generic crypto_blkcipher crc32c ecb + arc4 yenta_socket i82365 tcic pcmcia =scsi =net =drm diff --git a/etc/lorax/config.s390 b/etc/lorax/config.s390 new file mode 100644 index 00000000..5593f498 --- /dev/null +++ b/etc/lorax/config.s390 @@ -0,0 +1,11 @@ +[lorax] + +packages: s390utils binutils libgcc tcp_wrappers sed net-tools openssh + openssh-server coreutils login initscripts portmap pam mount modutils + s390utils-cmsfs strace xorg-x11-xauth xorg-x11-libs + +modules: zfcp tape390 dasd_diag_mod dasd_eckd_mod dasd_fba_mod dasd_mod + ctc netiucv smsgiucv lcs qdio qeth ccwgroup crypto_api xfrm_nalgo + +initrd_template=templates/initrd/initrd.s390 +scrubs_template=templates/scrubs/scrubs.s390 diff --git a/etc/lorax/config.s390x b/etc/lorax/config.s390x new file mode 120000 index 00000000..5c0bf0e5 --- /dev/null +++ b/etc/lorax/config.s390x @@ -0,0 +1 @@ +config.s390 \ No newline at end of file diff --git a/etc/lorax/config.x86_64 b/etc/lorax/config.x86_64 new file mode 120000 index 00000000..744d7dfd --- /dev/null +++ b/etc/lorax/config.x86_64 @@ -0,0 +1 @@ +config.i386 \ No newline at end of file diff --git a/etc/lorax/templates/initrd/includes/initrd b/etc/lorax/templates/initrd/includes/initrd new file mode 100644 index 00000000..b2fc47b9 --- /dev/null +++ b/etc/lorax/templates/initrd/includes/initrd @@ -0,0 +1,242 @@ +## create required directories +makedirs ${initrd}/lib +makedirs ${initrd}/modules +makedirs ${initrd}/firmware +symlink name ${initrd}/lib/modules target ../modules +symlink name ${initrd}/lib/firmware target ../firmware + +makedirs ${initrd}/sbin +makedirs ${initrd}/dev +makedirs ${initrd}/etc +makedirs ${initrd}/etc/udev/rules.d +makedirs ${initrd}/lib/udev/rules.d +makedirs ${initrd}/proc +makedirs ${initrd}/selinux +makedirs ${initrd}/sys +makedirs ${initrd}/etc/terminfo/{a,d,l,s,v,x,g} +makedirs ${initrd}/tmp +makedirs ${initrd}/usr/libexec +makedirs ${initrd}/usr/${libdir}/NetworkManager +makedirs ${initrd}/usr/share/dbus-1/system-services +makedirs ${initrd}/var/cache/hald +makedirs ${initrd}/var/lib/dbus +makedirs ${initrd}/var/lib/dhclient +makedirs ${initrd}/var/lock/rpm +makedirs ${initrd}/var/run +makedirs ${initrd}/var/run/dbus +makedirs ${initrd}/var/run/hald +makedirs ${initrd}/var/run/NetworkManager +makedirs ${initrd}/etc/dbus-1/system.d +makedirs ${initrd}/etc/modprobe.d +makedirs ${initrd}/etc/NetworkManager/dispatcher.d +makedirs ${initrd}/${libdir}/dbus-1 +makedirs ${initrd}/etc/sysconfig/network-scripts +makedirs ${initrd}/usr/share/PolicyKit/policy +makedirs ${initrd}/etc/PolicyKit +makedirs ${initrd}/var/lib/misc +makedirs ${initrd}/etc/hal/fdi +makedirs ${initrd}/usr/share/hal/fdi +makedirs ${initrd}/usr/share/hwdata +makedirs ${initrd}/etc/rc.d/init.d +makedirs ${initrd}/usr/sbin +makedirs ${initrd}/var/run/wpa_supplicant + +## set the buildarch +edit ${initrd}/etc/arch text "${arch}" + +## copy etc stuff +copy ${instroot} etc/passwd to ${initrd} etc +chmod ${initrd}/etc/passwd mode 0644 + +copy ${instroot} etc/group to ${initrd} etc +chmod ${initrd}/etc/group mode 0644 + +copy ${instroot} etc/nsswitch.conf to ${initrd} etc +chmod ${initrd}/etc/nsswitch.conf mode 0644 + +copy ${instroot} etc/hosts to ${initrd} etc +chmod ${initrd}/etc/hosts mode 0644 + +## copy mount/umount +copy ${instroot} bin/mount to ${initrd} sbin +copy ${instroot} bin/umount to ${initrd} sbin +copy ${instroot} sbin/mount.* to ${initrd} sbin +copy ${instroot} sbin/umount.* to ${initrd} sbin + +## copy udev +copy ${instroot} sbin/udevd to ${initrd} sbin +copy ${instroot} sbin/udevadm to ${initrd} sbin +symlink name ${initrd}/sbin/udevinfo target udevadm +symlink name ${initrd}/sbin/udevsettle target udevadm + +## udev rules +copy ${instroot} etc/udev/udev.conf to ${initrd} etc/udev +chmod ${initrd}/etc/udev/udev.conf mode 0644 + +copy ${instroot} lib/udev/* to ${initrd} lib/udev +##chmod ${initrd}/lib/udev/* mode 0644 + +remove ${initrd}/lib/udev/rules.d/*persistent* +remove ${initrd}/lib/udev/rules.d/*generator* + +copy ${instroot} etc/udev/rules.d/*.rules to ${initrd} etc/udev/rules.d +chmod ${initrd}/etc/udev/rules.d/*.rules mode 0644 + +## copy bash +copy ${instroot} bin/bash to ${initrd} sbin +symlink name ${initrd}/sbin/sh target bash + +copy ${instroot} sbin/consoletype to ${initrd} sbin +copy ${instroot} usr/bin/logger to ${initrd} sbin + +copy ${instroot} etc/rc.d/init.d/functions to ${initrd} etc/rc.d/init.d +copy ${instroot} etc/sysconfig/network-scripts/network-functions* to \ + ${initrd} etc/sysconfig/network-scripts + +symlink name ${initrd}/etc/init.d target /etc/rc.d/init.d + +## dhcp and dhcpv6 client daemons and support programs +copy ${instroot} sbin/dhclient to ${initrd} sbin +copy ${instroot} sbin/dhclient-script to ${initrd} sbin +copy ${instroot} sbin/dhcp6c to ${initrd} sbin +copy ${instroot} sbin/arping to ${initrd} sbin +copy ${instroot} sbin/ifconfig to ${initrd} sbin +copy ${instroot} sbin/ip to ${initrd} sbin +copy ${instroot} bin/ipcalc to ${initrd} sbin +copy ${instroot} bin/hostname to ${initrd} sbin +copy ${instroot} sbin/ethtool to ${initrd} sbin +copy ${instroot} sbin/route to ${initrd} sbin +touch ${initrd}/etc/resolv.conf + +## hwdata +copy ${instroot} usr/share/hwdata/pci.ids to ${initrd} usr/share/hwdata +copy ${instroot} usr/share/hwdata/usb.ids to ${initrd} usr/share/hwdata + +## hal +copy ${instroot} usr/sbin/hald to ${initrd} sbin +copy ${instroot} usr/libexec/hald-runner to ${initrd} usr/libexec +copy ${instroot} usr/libexec/hald-generate-fdi-cache to ${initrd} usr/libexec +copy ${instroot} usr/libexec/hal*storage* to ${initrd} usr/libexec +touch ${initrd}/var/run/hald.acl-list +copy ${instroot} usr/share/hal/fdi/* to ${initrd} usr/share/hal/fdi +copy ${instroot} etc/hal/fdi/* to ${initrd} etc/hal/fdi +copy ${instroot} etc/dbus-1/system.d/hal.conf to ${initrd} etc/dbus-1/system.d + +## policykit +copy ${instroot} etc/PolicyKit/PolicyKit.conf to ${initrd} etc/PolicyKit +copy ${instroot} \ + usr/share/dbus-1/system-services/org.freedesktop.PolicyKit.service to \ + ${initrd} usr/share/dbus-1/system-services + +copy ${instroot} usr/share/PolicyKit/policy/org.freedesktop.policykit.policy \ + to ${initrd} usr/share/PolicyKit/policy + +copy ${instroot} var/lib/misc/PolicyKit.reload to ${initrd} var/lib/misc + +## dbus +copy ${instroot} bin/dbus-uuidgen to ${initrd} sbin +copy ${instroot} bin/dbus-daemon to ${initrd} sbin +copy ${instroot} etc/dbus-1/system.conf to ${initrd} etc/dbus-1 +copy ${instroot} ${libdir}/dbus-1/dbus-daemon-launch-helper to \ + ${initrd} ${libdir}/dbus-1 + +chown ${initrd}/${libdir}/dbus-1/dbus-daemon-launch-helper user root group dbus +chmod ${initrd}/${libdir}/dbus-1/dbus-daemon-launch-helper mode 04750 + +## wpa_supplicant +copy ${instroot} usr/sbin/wpa_passphrase to ${initrd} usr/sbin +copy ${instroot} usr/sbin/wpa_supplicant to ${initrd} usr/sbin +copy ${instroot} etc/dbus-1/system.d/wpa_supplicant.conf to \ + ${initrd} etc/dbus-1/system.d + +copy ${instroot} etc/wpa_supplicant/wpa_supplicant.conf to \ + ${initrd} etc/wpa_supplicant + +copy ${instroot} \ + usr/share/dbus-1/system-services/fi.epitest.hostap.WPASupplicant.service \ + to ${initrd} usr/share/dbus-1/system-services + +## networkmanager +copy ${instroot} usr/sbin/NetworkManager to ${initrd} usr/sbin +copy ${instroot} usr/sbin/nm-system-settings to ${initrd} usr/sbin +copy ${instroot} etc/dbus-1/system.d/nm-*.conf to ${initrd} etc/dbus-1/system.d +copy ${instroot} etc/dbus-1/system.d/NetworkManager.conf to \ + ${initrd} etc/dbus-1/system.d +copy ${instroot} etc/NetworkManager/nm-system-settings.conf to \ + ${initrd} etc/NetworkManager +copy ${instroot} \ + usr/${libdir}/NetworkManager/libnm-settings-plugin-ifcfg-fedora.so to \ + ${initrd} usr/${libdir}/NetworkManager +copy ${instroot} usr/libexec/nm-* to ${initrd} usr/libexec +copy ${instroot} usr/share/dbus-1/system-services/org.freedesktop.NetworkManagerSystemSettings.service to ${initrd} usr/share/dbus-1/system-services +copy ${instroot} usr/share/dbus-1/system-services/org.freedesktop.nm_dispatcher.service to ${initrd} usr/share/dbus-1/system-services + +## modprobe +copy ${instroot} sbin/modprobe to ${initrd} sbin +copy ${instroot} sbin/insmod to ${initrd} sbin +copy ${instroot} sbin/rmmod to ${initrd} sbin + +## profile +edit ${initrd}/.profile text "PATH=/bin:/usr/bin:/usr/sbin:/mnt/sysimage/sbin:/mnt/sysimage/usr/sbin:/mnt/sysimage/bin:/mnt/sysimage/usr/bin\nexport PATH" + +## terminfos +copy ${instroot} usr/share/terminfo/a/ansi to ${initrd} etc/terminfo/a \ + nosymlinks +copy ${instroot} usr/share/terminfo/d/dumb to ${initrd} etc/terminfo/d \ + nosymlinks +copy ${instroot} usr/share/terminfo/l/linux to ${initrd} etc/terminfo/l \ + nosymlinks +copy ${instroot} usr/share/terminfo/s/screen to ${initrd} etc/terminfo/s \ + nosymlinks +copy ${instroot} usr/share/terminfo/v/vt100 to ${initrd} etc/terminfo/v \ + nosymlinks +copy ${instroot} usr/share/terminfo/v/vt100-nav to ${initrd} etc/terminfo/v \ + nosymlinks +copy ${instroot} usr/share/terminfo/v/vt102 to ${initrd} etc/terminfo/v \ + nosymlinks +copy ${instroot} usr/share/terminfo/x/xterm to ${initrd} etc/terminfo/x \ + nosymlinks +copy ${instroot} usr/share/terminfo/x/xterm-color to ${initrd} etc/terminfo/x \ + nosymlinks +copy ${instroot} usr/share/terminfo/g/gnome to ${initrd} etc/terminfo/g \ + nosymlinks +chmod ${initrd}/etc/terminfo/*/* mode 0644 + +## misc +copy ${instroot} bin/awk to ${initrd} sbin +copy ${instroot} bin/gawk to ${initrd} sbin +copy ${instroot} bin/egrep to ${initrd} sbin +copy ${instroot} bin/fgrep to ${initrd} sbin +copy ${instroot} bin/grep to ${initrd} sbin +copy ${instroot} bin/kill to ${initrd} sbin +copy ${instroot} bin/ln to ${initrd} sbin +copy ${instroot} bin/readlink to ${initrd} sbin +copy ${instroot} bin/rm to ${initrd} sbin +copy ${instroot} bin/rmdir to ${initrd} sbin +copy ${instroot} bin/sed to ${initrd} sbin +copy ${instroot} bin/sleep to ${initrd} sbin +copy ${instroot} bin/touch to ${initrd} sbin + +symlink name ${initrd}/init target /sbin/init +symlink name ${initrd}/etc/mtab target /proc/mounts +symlink name ${initrd}/bin target sbin +symlink name ${initrd}/var/lib/xkb target ../../tmp + +## loader +copy ${instroot} usr/lib/anaconda-runtime/loader/loader to ${initrd} sbin +copy ${instroot} usr/lib/anaconda-runtime/loader/loader.tr to ${initrd} etc +chmod ${initrd}/etc/loader.tr mode 0644 + +## indirect dependencies +##copy ${instroot} ${libdir}/ld-linux.so.2 to ${initrd} ${libdir} +copy ${instroot} ${libdir}/libcom_err.so.2 to ${initrd} ${libdir} +copy ${instroot} ${libdir}/libdbus-glib-1.so.2 to ${initrd} ${libdir} +copy ${instroot} ${libdir}/libfreebl3.so to ${initrd} ${libdir} +copy ${instroot} ${libdir}/libgcc_s.so.1 to ${initrd} ${libdir} +copy ${instroot} ${libdir}/libnss_dns.so.2 to ${initrd} ${libdir} +copy ${instroot} ${libdir}/libnss_files.so.2 to ${initrd} ${libdir} +copy ${instroot} ${libdir}/libsoftokn3.so to ${initrd} ${libdir} +copy ${instroot} usr/${libdir}/libsqlite3.so.0 to ${initrd} usr/${libdir} + +## langtable +copy ${instroot} usr/lib/anaconda/lang-table to ${initrd} etc diff --git a/etc/lorax/templates/initrd/initrd.i386 b/etc/lorax/templates/initrd/initrd.i386 new file mode 100644 index 00000000..7e148591 --- /dev/null +++ b/etc/lorax/templates/initrd/initrd.i386 @@ -0,0 +1,11 @@ +<%include file="includes/initrd" /> + +## loader +copy ${instroot} usr/lib/anaconda-runtime/loader/init to ${initrd} sbin/init +symlink name ${initrd}/sbin/reboot target init +symlink name ${initrd}/sbin/halt target init +symlink name ${initrd}/sbin/poweroff target init + +## screenfont +copy ${instroot} usr/lib/anaconda-runtime/screenfont-${arch}.gz to \ + ${initrd} etc/screenfont.gz diff --git a/etc/lorax/templates/initrd/initrd.s390 b/etc/lorax/templates/initrd/initrd.s390 new file mode 100644 index 00000000..1093bec8 --- /dev/null +++ b/etc/lorax/templates/initrd/initrd.s390 @@ -0,0 +1,51 @@ +<%include file="includes/initrd" /> + +## create required directories +makedirs ${initrd}/var/empty/sshd mode 0111 +makedirs ${initrd}/etc/security +makedirs ${initrd}/${libdir}/security + +## copy some files +copy ${instroot} usr/bin/xauth to ${initrd} sbin +copy ${instroot} usr/sbin/cmsfs* to ${initrd} sbin + +copy ${instroot} ${libdir}/libpam_misc.so.0.* to ${initrd} ${libdir}/libpam_misc.so.0 +copy ${instroot} ${libdir}/libwrap*.so* to ${initrd} ${libdir} + +symlink name ${initrd}/var/state/xkb target /tmp + +## loader +copy ${instroot} usr/lib/anaconda-runtime/loader/shutdown to ${initrd} sbin +copy ${instroot} usr/lib/anaconda-runtime/loader/linuxrc.s390 to \ + ${initrd} sbin/init +copy ${instroot} usr/lib/anaconda-runtime/loader/lsznet.raw to \ + ${initrd} sbin/lsznet +copy ${instroot} usr/lib/anaconda-runtime/loader/controlunits.sh to \ + ${initrd} sbin/controlunits +copy ${instroot} usr/sbin/dasdfmt to ${initrd} sbin + +## setup shell environment +edit ${initrd}/etc/protocols text "tcp\t6\tTCP\n" + +copy ${instroot} ${libdir}/security/pam_limits.so to \ + ${initrd} ${libdir}/security +copy ${instroot} ${libdir}/security/pam_env.so to ${initrd} ${libdir}/security +copy ${instroot} ${libdir}/security/pam_unix.so to ${initrd} ${libdir}/security +copy ${instroot} ${libdir}/security/pam_deny.so to ${initrd} ${libdir}/security + +copy ${instroot} etc/pam.d/other to ${initrd} etc/pam.d + +copy ${instroot} etc/security/limits.conf to ${initrd} etc/security +copy ${instroot} etc/security/pam_env.conf to ${initrd} etc/security + +## generate ssh keys +makedirs ${initrd}/etc/ssh mode 0700 +gensshkey ${initrd}/etc/ssh/ssh_host_key type rsa1 +gensshkey ${initrd}/etc/ssh/ssh_host_rsa_key type rsa +gensshkey ${initrd}/etc/ssh/ssh_host_dsa_key type dsa + +chmod ${initrd}/etc/ssh/sshd_config mode 0600 + +## copy in the binaries +copy ${instroot} bin/login to ${initrd} sbin/login +copy ${instroot} usr/sbin/sshd to ${initrd} sbin/sshd diff --git a/etc/lorax/templates/scrubs/scrubs.i386 b/etc/lorax/templates/scrubs/scrubs.i386 new file mode 100644 index 00000000..a35c0ee1 --- /dev/null +++ b/etc/lorax/templates/scrubs/scrubs.i386 @@ -0,0 +1,103 @@ +## remove unnecessary directories from / +remove ${instroot}/boot +remove ${instroot}/dev +remove ${instroot}/home +remove ${instroot}/media +remove ${instroot}/mnt +remove ${instroot}/opt +remove ${instroot}/root +remove ${instroot}/selinux +remove ${instroot}/srv +remove ${instroot}/sys +remove ${instroot}/tmp + +## remove directories from /usr +remove ${instroot}/usr/etc +remove ${instroot}/usr/games +remove ${instroot}/usr/include +remove ${instroot}/usr/kerberos +remove ${instroot}/usr/local +remove ${instroot}/usr/tmp + +## remove modules and firmware directories +remove ${instroot}/lib/modules +remove ${instroot}/lib/firmware + +## remove directories from /var +remove ${instroot}/var/db +remove ${instroot}/var/empty +remove ${instroot}/var/games +remove ${instroot}/var/local +remove ${instroot}/var/lock +remove ${instroot}/var/log +remove ${instroot}/var/mail +remove ${instroot}/var/nis +remove ${instroot}/var/opt +remove ${instroot}/var/preserve +remove ${instroot}/var/spool +remove ${instroot}/var/tmp +remove ${instroot}/var/yp + +## remove directories from /lib +remove ${instroot}/lib/i686 +remove ${instroot}/lib/kbd +remove ${instroot}/lib/rtkaio +remove ${instroot}/lib/security +remove ${instroot}/lib/tls +remove ${instroot}/lib/xtables + +## remove directories from /etc +remove ${instroot}/etc/ConsoleKit +remove ${instroot}/etc/X11 +remove ${instroot}/etc/alternatives +remove ${instroot}/etc/asterisk +remove ${instroot}/etc/avahi +remove ${instroot}/etc/blkid +remove ${instroot}/etc/bonobo* +remove ${instroot}/etc/chkconfig* +remove ${instroot}/etc/cron.* +remove ${instroot}/etc/default +remove ${instroot}/etc/depmod.d +remove ${instroot}/etc/dirmngr +remove ${instroot}/etc/dnsmasq.d +remove ${instroot}/etc/event.d +remove ${instroot}/etc/firmware +remove ${instroot}/etc/firstaidkit +remove ${instroot}/etc/gconf +remove ${instroot}/etc/gcrypt +remove ${instroot}/etc/gnome-vfs* +remove ${instroot}/etc/gnupg +remove ${instroot}/etc/gtk +remove ${instroot}/etc/hotplug +remove ${instroot}/etc/init.d +remove ${instroot}/etc/iproute2 +remove ${instroot}/etc/iscsi +remove ${instroot}/etc/kernel +remove ${instroot}/etc/ld.so.conf.d +remove ${instroot}/etc/logrotate.d +remove ${instroot}/etc/lvm +remove ${instroot}/etc/makedev.d +remove ${instroot}/etc/modprobe.d +remove ${instroot}/etc/netplug* +remove ${instroot}/etc/ntp +remove ${instroot}/etc/openldap +remove ${instroot}/etc/opt +remove ${instroot}/etc/pam.d +remove ${instroot}/etc/pki +remove ${instroot}/etc/pm +remove ${instroot}/etc/popt.d +remove ${instroot}/etc/ppp +remove ${instroot}/etc/prelink.conf.d +remove ${instroot}/etc/profile.d +remove ${instroot}/etc/rc?.d +remove ${instroot}/etc/rwtab.d +remove ${instroot}/etc/samba +remove ${instroot}/etc/sasl2 +remove ${instroot}/etc/security +remove ${instroot}/etc/setuptool.d +remove ${instroot}/etc/skel +remove ${instroot}/etc/ssh +remove ${instroot}/etc/statetab.d +remove ${instroot}/etc/terminfo +remove ${instroot}/etc/xdg +remove ${instroot}/etc/xinetd.d diff --git a/etc/tree/scrubs.s390 b/etc/lorax/templates/scrubs/scrubs.s390 similarity index 100% rename from etc/tree/scrubs.s390 rename to etc/lorax/templates/scrubs/scrubs.s390 diff --git a/etc/modules/modules.all b/etc/modules/modules.all deleted file mode 100644 index b173cbf7..00000000 --- a/etc/modules/modules.all +++ /dev/null @@ -1,84 +0,0 @@ -fat -vfat -nfs -sunrpc -lockd -floppy -cramfs -loop -edd -pcspkr -squashfs -ipv6 -virtio_pci -ohci-hcd -uhci-hcd -ehci-hcd -usbhid -mousedev -usb-storage -sd_mod -sr_mod -ub -appletouch -ohci1394 -sbp2 -fw-ohci -fw-sbp2 -firewire-sbp2 -firewire-ohci -mmc-block -sdhci -sdhci-pci -ide-cd -ide-cd_mod -sr_mod -sg -st -sd_mod -scsi_mod -iscsi_tcp -iscsi_ibft -fat -msdos -vfat -ext2 -ext3 -ext4 -reiserfs -jfs -xfs -gfs2 -cifs -fuse -btrfs -dm-mod -dm-zero -dm-snapshot -dm-mirror -dm-multipath -dm-round-robin -dm-crypt -raid0 -raid1 -raid5 -raid6 -raid456 -raid10 -linear -sha256_generic -cbc -xts -lrw -aes_generic -crypto_blkcipher -crc32c -ecb -arc4 -yenta_socket -i82365 -tcic -pcmcia -=scsi -=net -=drm diff --git a/etc/modules/modules.alpha b/etc/modules/modules.alpha deleted file mode 100644 index dff84cf7..00000000 --- a/etc/modules/modules.alpha +++ /dev/null @@ -1,2 +0,0 @@ -tgafb -crc32 diff --git a/etc/modules/modules.s390 b/etc/modules/modules.s390 deleted file mode 100644 index 02177798..00000000 --- a/etc/modules/modules.s390 +++ /dev/null @@ -1,15 +0,0 @@ -zfcp -tape390 -dasd_diag_mod -dasd_eckd_mod -dasd_fba_mod -dasd_mod -ctc -netiucv -smsgiucv -lcs -qdio -qeth -ccwgroup -crypto_api -xfrm_nalgo diff --git a/etc/modules/modules.s390x b/etc/modules/modules.s390x deleted file mode 120000 index a125a962..00000000 --- a/etc/modules/modules.s390x +++ /dev/null @@ -1 +0,0 @@ -modules.s390 \ No newline at end of file diff --git a/etc/packages/packages.all b/etc/packages/packages.all deleted file mode 100644 index df07843e..00000000 --- a/etc/packages/packages.all +++ /dev/null @@ -1,43 +0,0 @@ -joe -gnome-icon-theme -fedora-icon-theme -xorg-x11-server-Xorg -firstaidkit -bzip2 -busybox -selinux-policy-targeted -python-imaging -hal -specspo -xorg-x11-fonts-misc -xorg-x11-drivers -rhpxl -ntfs-3g -ntfsprogs -xfsprogs -xfsdump -reiserfs-utils -gfs2-utils -jfsutils -nfs-utils -btrfs-progs -mesa-dri-drivers -dogtail -rsh -rsync -prelink -smartmontools -iscsi-initiator-utils -samba-client -mtr -gtk-nodoka-engine -ftp -openssh-clients -gtk+ -gdk-pixbuf -madan-fonts -lklug-fonts -xorg-x11-fonts-ethiopic -un-core-fonts-dotum -man -yum-fedorakmod \ No newline at end of file diff --git a/etc/packages/packages.alpha b/etc/packages/packages.alpha deleted file mode 100644 index 066c6d60..00000000 --- a/etc/packages/packages.alpha +++ /dev/null @@ -1 +0,0 @@ -aboot diff --git a/etc/packages/packages.i386 b/etc/packages/packages.i386 deleted file mode 100644 index c1aa3a2f..00000000 --- a/etc/packages/packages.i386 +++ /dev/null @@ -1,7 +0,0 @@ -pcmciautils -grub -dmidecode -efibootmgr -gpart -syslinux -memtest86+ \ No newline at end of file diff --git a/etc/packages/packages.i586 b/etc/packages/packages.i586 deleted file mode 120000 index cd9dd23d..00000000 --- a/etc/packages/packages.i586 +++ /dev/null @@ -1 +0,0 @@ -packages.i386 \ No newline at end of file diff --git a/etc/packages/packages.ia64 b/etc/packages/packages.ia64 deleted file mode 100644 index 1e565c1e..00000000 --- a/etc/packages/packages.ia64 +++ /dev/null @@ -1,3 +0,0 @@ -dmidecode -efibootmgr -elilo diff --git a/etc/packages/packages.ppc b/etc/packages/packages.ppc deleted file mode 100644 index 1bdc4e13..00000000 --- a/etc/packages/packages.ppc +++ /dev/null @@ -1,6 +0,0 @@ -pcmciautils -pdisk -yaboot -hfsutils -fbset -ppc64-utils diff --git a/etc/packages/packages.ppc64 b/etc/packages/packages.ppc64 deleted file mode 120000 index 602b9e1e..00000000 --- a/etc/packages/packages.ppc64 +++ /dev/null @@ -1 +0,0 @@ -packages.ppc \ No newline at end of file diff --git a/etc/packages/packages.s390 b/etc/packages/packages.s390 deleted file mode 100644 index 96c92436..00000000 --- a/etc/packages/packages.s390 +++ /dev/null @@ -1,19 +0,0 @@ -s390utils -binutils -libgcc -tcp_wrappers -sed -net-tools -openssh -openssh-server -coreutils -login -initscripts -portmap -pam -mount -modutils -s390utils-cmsfs -strace -xorg-x11-xauth -xorg-x11-libs diff --git a/etc/packages/packages.s390x b/etc/packages/packages.s390x deleted file mode 120000 index 2ec6ed77..00000000 --- a/etc/packages/packages.s390x +++ /dev/null @@ -1 +0,0 @@ -packages.s390 \ No newline at end of file diff --git a/etc/packages/packages.sparc b/etc/packages/packages.sparc deleted file mode 100644 index a78741ac..00000000 --- a/etc/packages/packages.sparc +++ /dev/null @@ -1,2 +0,0 @@ -tilo -silo diff --git a/etc/packages/packages.x86_64 b/etc/packages/packages.x86_64 deleted file mode 120000 index cd9dd23d..00000000 --- a/etc/packages/packages.x86_64 +++ /dev/null @@ -1 +0,0 @@ -packages.i386 \ No newline at end of file diff --git a/etc/tree/scrubs.alpha b/etc/tree/scrubs.alpha deleted file mode 120000 index 782e69b5..00000000 --- a/etc/tree/scrubs.alpha +++ /dev/null @@ -1 +0,0 @@ -scrubs.i386 \ No newline at end of file diff --git a/etc/tree/scrubs.i386 b/etc/tree/scrubs.i386 deleted file mode 100644 index e0205a90..00000000 --- a/etc/tree/scrubs.i386 +++ /dev/null @@ -1,103 +0,0 @@ -# remove unnecessary directories from / -remove @instroot@/boot -remove @instroot@/dev -remove @instroot@/home -remove @instroot@/media -remove @instroot@/mnt -remove @instroot@/opt -remove @instroot@/root -remove @instroot@/selinux -remove @instroot@/srv -remove @instroot@/sys -remove @instroot@/tmp - -# remove directories from /usr -remove @instroot@/usr/etc -remove @instroot@/usr/games -remove @instroot@/usr/include -remove @instroot@/usr/kerberos -remove @instroot@/usr/local -remove @instroot@/usr/tmp - -# remove modules and firmware directories -remove @instroot@/lib/modules -remove @instroot@/lib/firmware - -# remove directories from /var -remove @instroot@/var/db -remove @instroot@/var/empty -remove @instroot@/var/games -remove @instroot@/var/local -remove @instroot@/var/lock -remove @instroot@/var/log -remove @instroot@/var/mail -remove @instroot@/var/nis -remove @instroot@/var/opt -remove @instroot@/var/preserve -remove @instroot@/var/spool -remove @instroot@/var/tmp -remove @instroot@/var/yp - -# remove directories from /lib -remove @instroot@/lib/i686 -remove @instroot@/lib/kbd -remove @instroot@/lib/rtkaio -remove @instroot@/lib/security -remove @instroot@/lib/tls -remove @instroot@/lib/xtables - -# remove directories from /etc -remove @instroot@/etc/ConsoleKit -remove @instroot@/etc/X11 -remove @instroot@/etc/alternatives -remove @instroot@/etc/asterisk -remove @instroot@/etc/avahi -remove @instroot@/etc/blkid -remove @instroot@/etc/bonobo* -remove @instroot@/etc/chkconfig* -remove @instroot@/etc/cron.* -remove @instroot@/etc/default -remove @instroot@/etc/depmod.d -remove @instroot@/etc/dirmngr -remove @instroot@/etc/dnsmasq.d -remove @instroot@/etc/event.d -remove @instroot@/etc/firmware -remove @instroot@/etc/firstaidkit -remove @instroot@/etc/gconf -remove @instroot@/etc/gcrypt -remove @instroot@/etc/gnome-vfs* -remove @instroot@/etc/gnupg -remove @instroot@/etc/gtk -remove @instroot@/etc/hotplug -remove @instroot@/etc/init.d -remove @instroot@/etc/iproute2 -remove @instroot@/etc/iscsi -remove @instroot@/etc/kernel -remove @instroot@/etc/ld.so.conf.d -remove @instroot@/etc/logrotate.d -remove @instroot@/etc/lvm -remove @instroot@/etc/makedev.d -remove @instroot@/etc/modprobe.d -remove @instroot@/etc/netplug* -remove @instroot@/etc/ntp -remove @instroot@/etc/openldap -remove @instroot@/etc/opt -remove @instroot@/etc/pam.d -remove @instroot@/etc/pki -remove @instroot@/etc/pm -remove @instroot@/etc/popt.d -remove @instroot@/etc/ppp -remove @instroot@/etc/prelink.conf.d -remove @instroot@/etc/profile.d -remove @instroot@/etc/rc?.d -remove @instroot@/etc/rwtab.d -remove @instroot@/etc/samba -remove @instroot@/etc/sasl2 -remove @instroot@/etc/security -remove @instroot@/etc/setuptool.d -remove @instroot@/etc/skel -remove @instroot@/etc/ssh -remove @instroot@/etc/statetab.d -remove @instroot@/etc/terminfo -remove @instroot@/etc/xdg -remove @instroot@/etc/xinetd.d diff --git a/etc/tree/scrubs.ia64 b/etc/tree/scrubs.ia64 deleted file mode 120000 index 782e69b5..00000000 --- a/etc/tree/scrubs.ia64 +++ /dev/null @@ -1 +0,0 @@ -scrubs.i386 \ No newline at end of file diff --git a/etc/tree/scrubs.ppc b/etc/tree/scrubs.ppc deleted file mode 120000 index 782e69b5..00000000 --- a/etc/tree/scrubs.ppc +++ /dev/null @@ -1 +0,0 @@ -scrubs.i386 \ No newline at end of file diff --git a/etc/tree/scrubs.ppc64 b/etc/tree/scrubs.ppc64 deleted file mode 120000 index 66cc7aa3..00000000 --- a/etc/tree/scrubs.ppc64 +++ /dev/null @@ -1 +0,0 @@ -scrubs.ppc \ No newline at end of file diff --git a/etc/tree/scrubs.s390x b/etc/tree/scrubs.s390x deleted file mode 120000 index 580b924c..00000000 --- a/etc/tree/scrubs.s390x +++ /dev/null @@ -1 +0,0 @@ -scrubs.s390 \ No newline at end of file diff --git a/etc/tree/scrubs.sparc b/etc/tree/scrubs.sparc deleted file mode 120000 index 782e69b5..00000000 --- a/etc/tree/scrubs.sparc +++ /dev/null @@ -1 +0,0 @@ -scrubs.i386 \ No newline at end of file diff --git a/etc/tree/scrubs.x86_64 b/etc/tree/scrubs.x86_64 deleted file mode 120000 index 782e69b5..00000000 --- a/etc/tree/scrubs.x86_64 +++ /dev/null @@ -1 +0,0 @@ -scrubs.i386 \ No newline at end of file diff --git a/src/bin/lorax b/src/bin/lorax index 94fc3d0c..b98c1477 100755 --- a/src/bin/lorax +++ b/src/bin/lorax @@ -2,119 +2,11 @@ # # lorax -# lorax executable script -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): David Cantrell -# Martin Gracik # import sys -import os -from optparse import OptionParser, OptionGroup - -import pylorax +import pylorax.launcher if __name__ == "__main__": - version = "%s 0.1" % (os.path.basename(sys.argv[0]),) - usage = "%prog -p PRODUCT -v VERSION -r RELEASE -o OUTPUTDIR REPOSITORY" - - parser = OptionParser(usage=usage) - - 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,)) - - - # required - # XXX "options" should not be 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) - - # optional - # XXX are all of these used? - 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="Directory containing updates", - 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="Clean up 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) - - if not opts.product or not opts.version or not opts.release or not opts.output: - parser.error("Missing required argument") - - if not args: - parser.error("Missing repository") - - config = pylorax.Config() - config.set(confdir=opts.confdir, - debug=opts.debug, - cleanup=opts.cleanup) - - # required - config.set(product=opts.product, - version=opts.version, - release=opts.release, - outdir=opts.output, - repos=args) - - # optional - config.set(variant=opts.variant, - bugurl=opts.bugurl, - updates=opts.updates, - mirrorlist=opts.mirrorlist) - - lorax = pylorax.Lorax(config=config) - lorax.run() + pylorax.launcher.main(sys.argv) diff --git a/src/pylorax/__init__.py b/src/pylorax/__init__.py index d4c9b22e..6f71126d 100644 --- a/src/pylorax/__init__.py +++ b/src/pylorax/__init__.py @@ -1,639 +1,595 @@ # # __init__.py -# lorax main class -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): Martin Gracik -# David Cantrell # +__VERSION__ = "0.1" + import sys import os -import tempfile -import re -import shutil import ConfigParser +import re +import glob import time import datetime +import shutil import commands -from config import Container -from utils.yumwrapper import Yum -from utils.fileutils import copy, edit, replace +import yum +import yum.callbacks +import yum.rpmtrans +import config import output -import insttree -import images +import ramdisk +import efi +import install +import lcs -class Config(Container): +ARCHS64 = ( "x86_64", + "s390x", + "sparc64" ) - def __init__(self): - config = ("confdir", "datadir", "tempdir", "debug", "cleanup") +BASEARCH_MAP = { "i386" : "i386", + "i586" : "i386", + "sparc64" : "sparc" } - # options - required = ("product", "version", "release", "outdir", "repos") - optional = ("variant", "bugurl", "updates", "mirrorlist") +EFIARCH_MAP = { "i386" : "IA32", + "x86_64" : "X64", + "ia64" : "IA64" } - Container.__init__(self, config + required + optional) - - # set defaults - self.set(confdir="/etc/lorax", - datadir="/usr/share/lorax", - tempdir=tempfile.mkdtemp(prefix="lorax.tmp.", - dir=tempfile.gettempdir()), - debug=False, - cleanup=False) - - self.set(product="", - version="", - release="", - outdir="", - repos=[]) - - self.set(variant="", - bugurl="", - updates="", - mirrorlist=[]) +LIB32 = "lib" +LIB64 = "lib64" class LoraxError(Exception): pass + class Lorax(object): - def __init__(self, config): - assert isinstance(config, Config) == True - self.conf = config + SETTINGS = ( "colors", + "encoding", + "debug", + "cleanup" ) - # check if we have all required options - if not self.conf.repos: - raise LoraxError, "missing required parameter 'repos'" - if not self.conf.outdir: - raise LoraxError, "missing required parameter 'outdir'" - if not self.conf.product: - raise LoraxError, "missing required parameter 'product'" - if not self.conf.version: - raise LoraxError, "missing required parameter 'version'" - if not self.conf.release: - raise LoraxError, "missing required parameter 'release'" + REQ_PARAMS = ( "product", + "version", + "release", + "outputdir", + "tempdir", + "installtree" ) - self.yum = None + OPT_PARAMS = ( "variant", + "bugurl", + "updates" ) - # initialize the output objects - self.so, self.se = output.initialize(verbose=self.conf.debug) + def __init__(self, yb, *args, **kwargs): + # check if we have root privileges + if not os.geteuid() == 0: + raise LoraxError("no root privileges") - def collect_repositories(self): - repolist = [] + # check the yumbase object + if not isinstance(yb, yum.YumBase): + raise LoraxError("not an yumbase object") - for repospec in self.conf.repos: - if repospec.startswith("/"): - repo = "file://%s" % (repospec,) - self.so.info("Adding local repo: %s" % (repo,)) - repolist.append(repo) - elif repospec.startswith("http://") or repospec.startswith("ftp://"): - self.so.info("Adding remote repo: %s" % (repospec,)) - repolist.append(repospec) - else: - self.se.warning("Invalid repo path: %s" % (repospec,)) + # create the yum object + self.yum = YumHelper(yb) - if not repolist: - return False - else: - mainrepo, extrarepos = repolist[0], repolist[1:] + # get the config object + self.conf = config.LoraxConfig.get() - self.conf.addAttr(["mainrepo", "extrarepos"]) - self.conf.set(mainrepo=mainrepo, extrarepos=extrarepos) - - # remove not needed attributes from config - self.conf.delAttr("repos") + # get the settings first + for key in self.SETTINGS: + value = kwargs.get(key, None) + if value is not None: + setattr(self.conf, key, value) - return True + # set up the output + self.output = output.Terminal.get() - def initialize_directories(self): - # create the temporary directories - treedir = os.path.join(self.conf.tempdir, "treedir", "install") - os.makedirs(treedir) + output_level = output.INFO + if self.conf.debug: + output_level = output.DEBUG - self.so.info("Working directories:") - - self.so.indent() - self.so.info("tempdir = %s" % (self.conf.tempdir,)) - self.so.info("treedir = %s" % (treedir,)) - self.so.unindent() + self.output.basic_config(colors=self.conf.colors, + encoding=self.conf.encoding, + level=output_level) - self.conf.addAttr("treedir") - self.conf.set(treedir=treedir) + # check and set up the required parameters + for key in self.REQ_PARAMS: + value = kwargs.get(key, None) - # create the destination directories - if not os.path.isdir(self.conf.outdir): - os.makedirs(self.conf.outdir, mode=0755) + if value is None: + raise LoraxError("missing required parameter '%s'" % key) - imagesdir = os.path.join(self.conf.outdir, "images") - if not os.path.isdir(imagesdir): - os.makedirs(imagesdir) + setattr(self.conf, key, value) - pxebootdir = os.path.join(imagesdir, "pxeboot") - if not os.path.isdir(pxebootdir): - os.makedirs(pxebootdir) + # set up the optional parameters + for key in self.OPT_PARAMS: + setattr(self.conf, key, kwargs.get(key, "")) - efibootdir = os.path.join(self.conf.outdir, "EFI", "BOOT") - if not os.path.isdir(efibootdir): - os.makedirs(efibootdir) + # check if the required directories exist + if os.path.isdir(self.conf.outputdir): + raise LoraxError("output directory '%s' already exist" % \ + self.conf.outputdir) - # create the isolinux directory - isolinuxdir = os.path.join(self.conf.outdir, "isolinux") - if not os.path.isdir(isolinuxdir): - os.makedirs(isolinuxdir) + if not os.path.isdir(self.conf.tempdir): + raise LoraxError("temporary directory '%s' does not exist" % \ + self.conf.tempdir) - self.so.info("Destination directories:") + if not os.path.isdir(self.conf.installtree): + raise LoraxError("install tree directory '%s' does not exist" % \ + self.conf.installtree) - self.so.indent() - self.so.info("outdir = %s" % (self.conf.outdir,)) - self.so.info("imagesdir = %s" % (imagesdir,)) - self.so.info("pxebootdir = %s" % (pxebootdir,)) - self.so.info("efibootdir = %s" % (efibootdir,)) - self.so.info("isolinuxdir = %s" % (isolinuxdir,)) - self.so.unindent() + # get the paths + self.paths = config.LoraxPaths.get() - self.conf.addAttr(["imagesdir", "pxebootdir", - "efibootdir", "isolinuxdir"]) - self.conf.set(imagesdir=imagesdir, pxebootdir=pxebootdir, - efibootdir=efibootdir, isolinuxdir=isolinuxdir) - - def initialize_yum(self): - yumconf = os.path.join(self.conf.tempdir, "yum.conf") - - # create the yum cache directory - cachedir = os.path.join(self.conf.tempdir, "yumcache") - os.makedirs(cachedir) - - c = ConfigParser.ConfigParser() - - # main section - section = "main" - data = { "cachedir": cachedir, - "keepcache": 0, - "gpgcheck": 0, - "plugins": 0, - "reposdir": "", - "tsflags": "nodocs" } - c.add_section(section) - [c.set(section, key, value) for key, value in data.items()] - - # main repo - section = "lorax-repo" - data = { "name": "lorax repo", - "baseurl": self.conf.mainrepo, - "enabled": 1 } - c.add_section(section) - [c.set(section, key, value) for key, value in data.items()] - - # extra repos - for n, extra in enumerate(self.conf.extrarepos, start=1): - section = "lorax-extrarepo-%d" % (n,) - data = { "name": "lorax extra repo %d" % (n,), - "baseurl": extra, - "enabled": 1 } - c.add_section(section) - [c.set(section, key, value) for key, value in data.items()] - - # mirrorlist repos - for n, mirror in enumerate(self.conf.mirrorlist, start=1): - section = "lorax-mirrorlistrepo-%d" % (n,) - data = { "name": "lorax mirrorlist repo %d" % (n,), - "mirrorlist": mirror, - "enabled": 1 } - c.add_section(section) - [c.set(section, key, value) for key, value in data.items()] - - try: - f = open(yumconf, "w") - except IOError as why: - self.se.error("Unable to write yum.conf file: %s" % (why,)) - return False - else: - c.write(f) - f.close() - - self.conf.addAttr("yumconf") - self.conf.set(yumconf=yumconf) - - # remove not needed attributes from config - self.conf.delAttr(["mainrepo", "extrarepos", "mirrorlist"]) - - # create the Yum object - self.yum = Yum(yumconf=self.conf.yumconf, installroot=self.conf.treedir, - errfile=os.path.join(self.conf.tempdir, "yum.errors")) - - return True - - def set_architecture(self): - # get the system architecture - unamearch = os.uname()[4] - - self.conf.addAttr("buildarch") - self.conf.set(buildarch=unamearch) - - # get the anaconda package architecture - installed, available = self.yum.find("anaconda") - try: - self.conf.set(buildarch=available[0].arch) - except: - pass - - # set basearch - self.conf.addAttr("basearch") - self.conf.set(basearch=self.conf.buildarch) - - if re.match(r"i.86", self.conf.basearch): - self.conf.set(basearch="i386") - elif self.conf.basearch == "sparc64": - self.conf.set(basearch="sparc") + def run(self): + # set the target architecture + self.output.info(":: setting the build architecture") + self.conf.arch = self.get_arch() + self.conf.basearch = BASEARCH_MAP.get(self.conf.arch, self.conf.arch) + self.conf.efiarch = EFIARCH_MAP.get(self.conf.arch, "") # set the libdir - self.conf.addAttr("libdir") - self.conf.set(libdir="lib") + self.conf.libdir = LIB32 + if self.conf.arch in ARCHS64: + self.conf.libdir = LIB64 - # on 64-bit systems, make sure we use lib64 as the lib directory - if self.conf.buildarch.endswith("64") or self.conf.buildarch == "s390x": - self.conf.set(libdir="lib64") + # read the config files + self.output.info(":: reading the configuration files") + packages, modules, initrd_template, scrubs_template = self.get_config() - # set efiarch - self.conf.addAttr("efiarch") - self.conf.set(efiarch="") + # add the branding + packages.add("%s-logos" % self.conf.product.lower()) + packages.add("%s-release" % self.conf.product.lower()) - if self.conf.buildarch == "i386": - self.conf.set(efiarch="ia32") - elif self.conf.buildarch == "x86_64": - self.conf.set(efiarch="x64") - elif self.conf.buildarch == "ia64": - self.conf.set(efiarch="ia64") + self.conf.packages = packages + self.conf.modules = modules + self.conf.initrd_template = initrd_template + self.conf.scrubs_template = scrubs_template + + # install packages into the install tree + self.output.info(":: installing required packages") + for name in packages: + if not self.yum.install(name): + self.output.warning("no package %s found" % \ + self.output.format(name, type=output.BOLD)) + + self.yum.process_transaction() + + # copy the updates + if self.conf.updates and os.path.isdir(self.conf.updates): + self.output.info(":: copying updates") + utils.scopy(src_root=self.conf.updates, src_path="*", + dst_root=self.conf.installtree, dst_path="") + + # get the anaconda runtime directory + if os.path.isdir(self.paths.ANACONDA_RUNTIME): + self.conf.anaconda_runtime = self.paths.ANACONDA_RUNTIME + self.conf.anaconda_boot = self.paths.ANACONDA_BOOT + else: + self.output.critical("no anaconda runtime directory found") + sys.exit(1) + + # get list of the installed kernel files + kerneldir = self.paths.BOOTDIR + if self.conf.arch == "ia64": + kerneldir = self.paths.BOOTDIR_IA64 + + kernelfiles = glob.glob(os.path.join(kerneldir, "vmlinuz-*")) + + if not kernelfiles: + self.output.critical("no kernel image found") + sys.exit(1) + + # create treeinfo, discinfo, and buildstamp + self.conf.treeinfo = self.write_treeinfo() + self.conf.discinfo = self.write_discinfo() + self.conf.buildstamp = self.write_buildstamp() + + # prepare the output directory + self.output.info(":: preparing the output directory") + ok = self.prepare_output_directory() + + if not ok: + self.output.critical("unable to prepare the output directory") + sys.exit(1) + + for kernelfile in kernelfiles: + kfilename = os.path.basename(kernelfile) + m = re.match(r"vmlinuz-(?P.*)", kfilename) + if m: + self.conf.kernelfile = kernelfile + self.conf.kernelver = m.group("ver") + else: + continue + + self.output.info(":: creating initrd for '%s'" % kfilename) + + # create a temporary directory for the ramdisk tree + self.conf.ramdisktree = os.path.join(self.conf.tempdir, + "ramdisk-%s" % \ + self.conf.kernelver) + + utils.makedirs(self.conf.ramdisktree) + + initrd = ramdisk.Ramdisk() + kernel_path, initrd_path = initrd.create() + + # copy the kernel and initrd images to the pxeboot directory + shutil.copy2(kernel_path, self.conf.pxebootdir) + shutil.copy2(initrd_path, self.conf.pxebootdir) + + # if this is a PAE kernel, skip the EFI part + if kernel_path.endswith("PAE"): + continue + + # copy the kernel and initrd images to the isolinux directory + shutil.copy2(kernel_path, self.conf.isolinuxdir) + shutil.copy2(initrd_path, self.conf.isolinuxdir) + + # create the efi images + self.output.info(":: creating efi images for '%s'" % kfilename) + + efiimages = efi.EFI() + eb, ed = efiimages.create(kernel=kernel_path, + initrd=initrd_path, + kernelpath="/images/pxeboot/vmlinuz", + initrdpath="/images/pxeboot/initrd.img") + + self.conf.efiboot = eb + self.conf.efidisk = ed + + # copy the efi images to the images directory + shutil.copy2(self.conf.efiboot, self.conf.imagesdir) + shutil.copy2(self.conf.efidisk, self.conf.imagesdir) + + # create the install image + self.output.info(":: creating the install image") + i = install.InstallImage() + installimg = i.create() + + if installimg is None: + self.output.critical("unable to create install image") + sys.exit(1) + + shutil.copy2(installimg, self.conf.imagesdir) + + # create the boot iso + self.output.info(":: creating the boot iso") + bootiso = self.create_boot_iso() + + if bootiso is None: + self.output.critical("unable to create boot iso") + sys.exit(1) + + shutil.copy2(bootiso, self.conf.imagesdir) + + # copy the treeinfo and discinfo to the output directory + shutil.copy2(self.conf.treeinfo, self.conf.outputdir) + shutil.copy2(self.conf.discinfo, self.conf.outputdir) + + # cleanup + self.cleanup() + + def get_arch(self): + # get the architecture of the anaconda package + installed, available = self.yum.search(self.paths.ANACONDA_PACKAGE) + try: + arch = available[0].arch + except: + # fallback to the system architecture + arch = os.uname()[4] + + return arch + + def get_config(self): + generic = os.path.join(self.conf.confdir, "config.noarch") + specific = os.path.join(self.conf.confdir, + "config.%s" % self.conf.arch) + + packages, modules = set(), set() + initrd_template, scrubs_template = None, None + + for f in (generic, specific): + if not os.path.isfile(f): + continue + + c = ConfigParser.ConfigParser() + c.read(f) + + if c.has_option("lorax", "packages"): + list = c.get("lorax", "packages").split() + for name in list: + if name.startswith("-"): + packages.discard(name) + else: + packages.add(name) + + if c.has_option("lorax", "modules"): + list = c.get("lorax", "modules").split() + for name in list: + if name.startswith("-"): + modules.discard(name) + else: + modules.add(name) + + if c.has_option("lorax", "initrd_template"): + initrd_template = c.get("lorax", "initrd_template") + initrd_template = os.path.join(self.conf.confdir, + initrd_template) + + if c.has_option("lorax", "scrubs_template"): + scrubs_template = c.get("lorax", "scrubs_template") + scrubs_template = os.path.join(self.conf.confdir, + scrubs_template) + + return packages, modules, initrd_template, scrubs_template def write_treeinfo(self, discnum=1, totaldiscs=1, packagedir=""): - outfile = os.path.join(self.conf.outdir, ".treeinfo") + outfile = os.path.join(self.conf.tempdir, ".treeinfo") + + variant = self.conf.variant + if variant is None: + variant = "" - # don't print anything instead of None, if variant is not specified - variant = "" - if self.conf.variant is not None: - variant = self.conf.variant - c = ConfigParser.ConfigParser() - # general section section = "general" - data = { "timestamp": time.time(), - "family": self.conf.product, - "version": self.conf.version, - "arch": self.conf.basearch, - "variant": variant, - "discnum": discnum, - "totaldiscs": totaldiscs, - "packagedir": packagedir } - c.add_section(section) - [c.set(section, key, value) for key, value in data.items()] + data = { "timestamp" : time.time(), + "family" : self.conf.product, + "version" : self.conf.version, + "arch" : self.conf.basearch, + "variant" : variant, + "discnum" : discnum, + "totaldiscs" : totaldiscs, + "packagedir" : packagedir } - # images section - section = "images-%s" % (self.conf.basearch,) - data = { "kernel": "images/pxeboot/vmlinuz", - "initrd": "images/pxeboot/initrd.img", - "boot.iso": "images/boot.iso" } c.add_section(section) - [c.set(section, key, value) for key, value in data.items()] + map(lambda (key, value): c.set(section, key, value), data.items()) - try: - f = open(outfile, "w") - except IOError as why: - self.se.error("Unable to write .treeinfo file: %s" % (why,)) - return False - else: + section = "images-%s" % self.conf.basearch + data = { "kernel" : "images/pxeboot/vmlinuz", + "initrd" : "images/pxeboot/initrd.img", + "boot.iso" : "images/boot.iso" } + + c.add_section(section) + map(lambda (key, value): c.set(section, key, value), data.items()) + + with open(outfile, "w") as f: c.write(f) - f.close() - - return True + + return outfile def write_discinfo(self, discnum="ALL"): - outfile = os.path.join(self.conf.outdir, ".discinfo") + outfile = os.path.join(self.conf.tempdir, ".discinfo") - try: - f = open(outfile, "w") - except IOError as why: - self.se.error("Unable to write .discinfo file: %s" % (why,)) - return False - else: - f.write("%f\n" % (time.time(),)) - f.write("%s\n" % (self.conf.release,)) - f.write("%s\n" % (self.conf.basearch,)) - f.write("%s\n" % (discnum,)) - f.close() - - return True + with open(outfile, "w") as f: + f.write("%f\n" % time.time()) + f.write("%s\n" % self.conf.release) + f.write("%s\n" % self.conf.basearch) + f.write("%s\n" % discnum) + + return outfile def write_buildstamp(self): - outfile = os.path.join(self.conf.treedir, ".buildstamp") + outfile = os.path.join(self.conf.tempdir, ".buildstamp") - # make image uuid now = datetime.datetime.now() - uuid = "%s.%s" % (now.strftime("%Y%m%d%H%M"), self.conf.buildarch) + uuid = "%s.%s" % (now.strftime("%Y%m%d%H%M"), self.conf.arch) - try: - f = open(outfile, "w") - except IOError as why: - self.se.error("Unable to write .buildstamp file: %s" % (why,)) - return False - else: - f.write("%s\n" % (uuid,)) - f.write("%s\n" % (self.conf.product,)) - f.write("%s\n" % (self.conf.version,)) - f.write("%s\n" % (self.conf.bugurl,)) - f.close() + with open(outfile, "w") as f: + f.write("%s\n" % uuid) + f.write("%s\n" % self.conf.product) + f.write("%s\n" % self.conf.version) + f.write("%s\n" % self.conf.bugurl) - self.conf.addAttr("buildstamp") - self.conf.set(buildstamp=outfile) - - return True + return outfile def prepare_output_directory(self): - # write the images/README - src = os.path.join(self.conf.datadir, "images", "README") - dst = os.path.join(self.conf.imagesdir, "README") + # create the output directory + os.mkdir(self.conf.outputdir) + + # create the images directory + imagesdir = os.path.join(self.conf.outputdir, "images") + utils.mkdir(imagesdir) + self.conf.imagesdir = imagesdir + + # write the images/README file + src = os.path.join(self.paths.OUTPUTDIR_DATADIR, "images", "README") + dst = os.path.join(imagesdir, "README") shutil.copy2(src, dst) - replace(dst, r"@PRODUCT@", self.conf.product) + utils.replace(dst, r"@PRODUCT@", self.conf.product) - # write the images/pxeboot/README - src = os.path.join(self.conf.datadir, "images", "pxeboot", "README") - dst = os.path.join(self.conf.pxebootdir, "README") + # create the pxeboot directory + pxebootdir = os.path.join(imagesdir, "pxeboot") + utils.mkdir(pxebootdir) + self.conf.pxebootdir = pxebootdir + + # write the images/pxeboot/README file + src = os.path.join(self.paths.OUTPUTDIR_DATADIR, "images", "pxeboot", + "README") + dst = os.path.join(pxebootdir, "README") shutil.copy2(src, dst) - replace(dst, r"@PRODUCT@", self.conf.product) + utils.replace(dst, r"@PRODUCT@", self.conf.product) - # set up some dir variables for further use - anacondadir = os.path.join(self.conf.treedir, - "usr", "lib", "anaconda-runtime") - - bootdiskdir = os.path.join(anacondadir, "boot") - self.conf.addAttr("bootdiskdir") - self.conf.set(bootdiskdir=bootdiskdir) + # create the efiboot directory + efibootdir = os.path.join(self.conf.outputdir, "EFI", "BOOT") + utils.makedirs(efibootdir) + self.conf.efibootdir = efibootdir - syslinuxdir = os.path.join(self.conf.treedir, "usr", "lib", "syslinux") - isolinuxbin = os.path.join(syslinuxdir, "isolinux.bin") + # create the isolinux directory + isolinuxdir = os.path.join(self.conf.outputdir, "isolinux") + utils.mkdir(isolinuxdir) + self.conf.isolinuxdir = isolinuxdir - if os.path.isfile(isolinuxbin): - # copy the isolinux.bin - shutil.copy2(isolinuxbin, self.conf.isolinuxdir) + syslinuxdir = self.paths.SYSLINUXDIR + isolinuxbin = self.paths.ISOLINUXBIN - # copy the syslinux.cfg to isolinux/isolinux.cfg - isolinuxcfg = os.path.join(self.conf.isolinuxdir, "isolinux.cfg") - shutil.copy2(os.path.join(bootdiskdir, "syslinux.cfg"), isolinuxcfg) + if not os.path.isfile(isolinuxbin): + self.output.error("no isolinux binary found") + return False - # set the product and version in isolinux.cfg - replace(isolinuxcfg, r"@PRODUCT@", self.conf.product) - replace(isolinuxcfg, r"@VERSION@", self.conf.version) + # copy the isolinux.bin + shutil.copy2(isolinuxbin, isolinuxdir) - # set up the label for finding stage2 with a hybrid iso - replace(isolinuxcfg, r"initrd=initrd.img", - 'initrd=initrd.img stage2=hd:LABEL="%s"' % (self.conf.product,)) + # copy the syslinux.cfg to isolinux/isolinux.cfg + isolinuxcfg = os.path.join(isolinuxdir, "isolinux.cfg") + shutil.copy2(self.paths.SYSLINUXCFG, isolinuxcfg) - # copy the grub.conf - shutil.copy2(os.path.join(bootdiskdir, "grub.conf"), - self.conf.isolinuxdir) + # set the product and version in isolinux.cfg + utils.replace(isolinuxcfg, r"@PRODUCT@", self.conf.product) + utils.replace(isolinuxcfg, r"@VERSION@", self.conf.version) - # copy the splash files - vesasplash = os.path.join(anacondadir, "syslinux-vesa-splash.jpg") - if os.path.isfile(vesasplash): - shutil.copy2(vesasplash, - os.path.join(self.conf.isolinuxdir, "splash.jpg")) + # set up the label for finding stage2 with a hybrid iso + utils.replace(isolinuxcfg, r"initrd=initrd.img", + 'initrd=initrd.img stage2=hd:LABEL="%s"' % \ + self.conf.product) - vesamenu = os.path.join(syslinuxdir, "vesamenu.c32") - shutil.copy2(vesamenu, self.conf.isolinuxdir) + # copy the grub.conf + dst = os.path.join(isolinuxdir, "grub.conf") + shutil.copy2(self.paths.GRUBCONF, dst) - replace(isolinuxcfg, r"default linux", r"default vesamenu.c32") - replace(isolinuxcfg, r"prompt 1", r"#prompt 1") - else: - splashtools = os.path.join(anacondadir, "splashtools.sh") - splashlss = os.path.join(bootdiskdir, "splash.lss") + utils.replace(dst, "@PRODUCT@", self.conf.product) + utils.replace(dst, "@VERSION@", self.conf.version) - if os.path.isfile(splashtools): - cmd = "%s %s %s" % (splashtools, - os.path.join(bootdiskdir, "syslinux-splash.jpg"), - splashlss) - out = commands.getoutput(cmd) + # copy the splash files + if os.path.isfile(self.paths.VESASPLASH): + shutil.copy2(self.paths.VESASPLASH, + os.path.join(isolinuxdir, "splash.jpg")) - if os.path.isfile(splashlss): - shutil.copy2(splashlss, self.conf.isolinuxdir) + shutil.copy2(self.paths.VESAMENU, isolinuxdir) - # copy the .msg files - for file in os.listdir(bootdiskdir): - if file.endswith(".msg"): - shutil.copy2(os.path.join(bootdiskdir, file), - self.conf.isolinuxdir) - replace(os.path.join(self.conf.isolinuxdir, file), - r"@VERSION@", self.conf.version) + utils.replace(isolinuxcfg, r"default linux", "default vesamenu.c32") + utils.replace(isolinuxcfg, r"prompt 1", "#prompt 1") - # if present, copy the memtest - for fname in os.listdir(os.path.join(self.conf.treedir, "boot")): - if fname.startswith("memtest"): - src = os.path.join(self.conf.treedir, "boot", fname) - dst = os.path.join(self.conf.isolinuxdir, "memtest") - shutil.copy2(src, dst) - - text = "label memtest86\n" - text = text + " menu label ^Memory test\n" - text = text + " kernel memtest\n" - text = text + " append -\n" - edit(isolinuxcfg, text, append=True) else: - return False - - return True + if os.path.isfile(self.paths.SPLASHTOOLS): + cmd = "%s %s %s" % (self.paths.SPLASHTOOLS, + self.paths.SYSLINUXSPLASH, + self.paths.SPLASHLSS) + err, output = commands.getstatusoutput(cmd) + if err: + self.output.warning(output) - def create_install_image(self, type="squashfs"): - installimg = os.path.join(self.conf.imagesdir, "install.img") + if os.path.isfile(self.paths.SPLASHLSS): + shutil.copy2(self.paths.SPLASHLSS, isolinuxdir) - if os.path.exists(installimg): - os.unlink(installimg) + # copy the .msg files + msgfiles = os.path.join(self.conf.anaconda_boot, "*.msg") + for fname in glob.glob(msgfiles): + shutil.copy2(fname, isolinuxdir) + utils.replace(os.path.join(isolinuxdir, os.path.basename(fname)), + r"@VERSION@", self.conf.version) - if type == "squashfs": - cmd = "mksquashfs %s %s -all-root -no-fragments -no-progress" \ - % (self.conf.treedir, installimg) - self.so.debug(cmd) - err, output = commands.getstatusoutput(cmd) - if err: - self.se.info(output) - return False + # copy the memtest + memtest = os.path.join(self.paths.BOOTDIR, "memtest*") + for fname in glob.glob(memtest): + shutil.copy2(fname, os.path.join(isolinuxdir, "memtest")) - elif type == "cramfs": - if self.conf.buildarch == "sparc64": - crambs = "--blocksize 8192" - elif self.conf.buildarch == "sparc": - crambs = "--blocksize 4096" - else: - crambs = "" + text = """label memtest86 + menu label ^Memory test + kernel memtest + append - - cmd = "mkfs.cramfs %s %s %s" % (crambs, self.conf.treedir, - installimg) - self.so.debug(cmd) - err, output = commands.getstatusoutput(cmd) - if err: - self.se.info(output) - return False +""" - elif type == "ext2": - # TODO - return False - - # append stage2 to .treeinfo file - text = "\n[stage2]\n" - text += "mainimage = %s\n" % (installimg,) - edit(os.path.join(self.conf.outdir, ".treeinfo"), append=True, text=text) + utils.edit(isolinuxcfg, append=True, text=text) + break return True def create_boot_iso(self): - bootiso = os.path.join(self.conf.imagesdir, "boot.iso") + bootiso = os.path.join(self.conf.tempdir, "boot.iso") if os.path.exists(bootiso): os.unlink(bootiso) - efiboot = os.path.join(self.conf.imagesdir, "efiboot.img") - - if os.path.exists(efiboot): - self.so.info("Found efiboot.img, making an EFI-capable boot.iso") + if os.path.exists(self.conf.efiboot): + self.output.info(":: creating efi capable boot iso") efiargs = "-eltorito-alt-boot -e images/efiboot.img -no-emul-boot" - efigraft = "EFI/BOOT=%s" % (os.path.join(self.conf.outdir, - "EFI", "BOOT"),) + efigraft = "EFI/BOOT=%s" % self.conf.efibootdir else: - self.so.info("No efiboot.img found, making BIOS-only boot.iso") efiargs = "" efigraft = "" biosargs = "-b isolinux/isolinux.bin -c isolinux/boot.cat" \ - " -no-emul-boot -boot-load-size 4 -boot-info-table" - mkisocmd = "mkisofs -v -o %s %s %s -R -J -V %s -T -graft-points" \ - " isolinux=%s images=%s %s" % (bootiso, biosargs, efiargs, - self.conf.product, self.conf.isolinuxdir, self.conf.imagesdir, - efigraft) - self.so.debug(mkisocmd) - err, out = commands.getstatusoutput(mkisocmd) - if err: - self.se.info(out) - return False + " -no-emul-boot -boot-load-size 4 -boot-info-table" - hybrid = os.path.join("/", "usr", "bin", "isohybrid") - if os.path.exists(hybrid): - cmd = "%s %s" % (hybrid, os.path.join(self.conf.imagesdir, "boot.iso")) - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) + cmd = "%s -v -o %s %s %s -R -J -V %s -T -graft-points" \ + " isolinux=%s images=%s %s" % (self.paths.MKISOFS, bootiso, + biosargs, efiargs, + self.conf.product, + self.conf.isolinuxdir, + self.conf.imagesdir, efigraft) + + err, output = commands.getstatusoutput(cmd) + if err: + self.output.error(output) + return None + + if os.path.isfile(self.paths.ISOHYBRID): + cmd = "%s %s" % (self.paths.ISOHYBRID, bootiso) + err, output = commands.getstatusoutput(cmd) if err: - self.se.info(out) - # XXX is this a problem? - # should we return false, or just go on? + self.output.warning(output) + + return bootiso + + def cleanup(self): + if self.conf.cleanup: + shutil.rmtree(self.conf.tempdir) + + +class YumHelper(object): + + def __init__(self, yb): + self.yb = yb + + def install(self, pattern): + try: + self.yb.install(name=pattern) + except yum.Errors.InstallError: + try: + self.yb.install(pattern=pattern) + except yum.Errors.InstallError: + return False return True - def clean_up(self): - if os.path.isdir(self.conf.tempdir): - shutil.rmtree(self.conf.tempdir, ignore_errors=True) + def process_transaction(self): + self.yb.resolveDeps() + self.yb.buildTransaction() - def run(self): - self.so.header(":: Collecting repositories") - ok = self.collect_repositories() - if not ok: - # we have no valid repository to work with - self.se.error("No valid repository") - sys.exit(1) + cb = yum.callbacks.ProcessTransBaseCallback() + rpmcb = RpmCallback() - self.so.header(":: Initializing directories") - self.initialize_directories() + self.yb.processTransaction(callback=cb, rpmDisplay=rpmcb) - self.so.header(":: Initializing yum") - ok = self.initialize_yum() - if not ok: - # the yum object could not be initialized - self.se.error("Unable to initialize the yum object") - sys.exit(1) + self.yb.closeRpmDB() + self.yb.close() - self.so.header(":: Setting the architecture") - self.set_architecture() + def search(self, pattern): + pl = self.yb.doPackageLists(patterns=[pattern]) + return pl.installed, pl.available - self.so.header(":: Writing the .treeinfo file") - ok = self.write_treeinfo() - if not ok: - # XXX is this a problem? - pass - self.so.header(":: Writing the .discinfo file") - ok = self.write_discinfo() - if not ok: - # XXX is this a problem? - pass +class RpmCallback(yum.rpmtrans.SimpleCliCallBack): - self.so.header(":: Writing the .buildstamp file") - ok = self.write_buildstamp() - if not ok: - # XXX is this a problem? - pass + def __init__(self): + yum.rpmtrans.SimpleCliCallBack.__init__(self) + self.output = output.Terminal.get() - self.so.header(":: Preparing the install tree") - tree = insttree.InstallTree(self.conf, self.yum, (self.so, self.se)) - kernelfiles = tree.run() + def event(self, package, action, te_current, te_total, + ts_current, ts_total): - if not kernelfiles: - self.se.error("No kernel image found") - sys.exit(1) + msg = "(%3d/%3d) [%3d%%] %s %s\r" % (ts_current, ts_total, + float(te_current) / float(te_total) * 100, + self.action[action], + self.output.format("%s" % package, type=output.BOLD)) - self.so.header(":: Preparing the output directory") - ok = self.prepare_output_directory() - if not ok: - # XXX there's no isolinux.bin, i guess this is a problem... - self.se.error("Unable to prepare the output directory") - sys.exit(1) - - self.conf.addAttr(["kernelfile", "kernelver"]) - for kernelfile in kernelfiles: - # get the kernel version - m = re.match(r".*vmlinuz-(.*)", kernelfile) - if m: - kernelver = m.group(1) - self.conf.set(kernelfile=kernelfile, kernelver=kernelver) - else: - self.se.warning("Invalid kernel filename '%s'" % (kernelfile,)) - continue - - self.so.header(":: Creating the initrd image for kernel '%s'" \ - % (os.path.basename(kernelfile),)) - initrd = images.InitRD(self.conf, self.yum, (self.so, self.se)) - initrd.run() - - self.so.header(":: Creating the install image") - - self.so.info("Scrubbing the install tree") - tree.scrub() - - ok = self.create_install_image() - if not ok: - self.se.error("Unable to create the install image") - sys.exit(1) - - self.so.header(":: Creating the boot iso") - ok = self.create_boot_iso() - if not ok: - self.se.error("Unable to create the boot iso") - sys.exit(1) - - if self.conf.cleanup: - self.so.header(":: Cleaning up") - self.clean_up() + self.output.write(msg) + if te_current == te_total: + self.output.write("\n") diff --git a/src/pylorax/_rewrite/scrubs.py b/src/pylorax/_rewrite/scrubs.py deleted file mode 100644 index af4d9f04..00000000 --- a/src/pylorax/_rewrite/scrubs.py +++ /dev/null @@ -1,126 +0,0 @@ -import stat -import commands -import pwd -import grp - -class Install(object): - - def scrub(self): - # change tree permissions - root_uid = pwd.getpwnam('root')[2] - root_gid = grp.getgrnam('root')[2] - - for root, files, dirs in os.walk(self.conf.treedir): - 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) - - # create ld.so.conf - ldsoconf = os.path.join(self.conf.treedir, 'etc', 'ld.so.conf') - touch(ldsoconf) - - procdir = os.path.join(self.conf.treedir, 'proc') - if not os.path.isdir(procdir): - os.makedirs(procdir) - os.system('mount -t proc proc %s' % procdir) - - f = open(ldsoconf, 'w') - f.write('/usr/kerberos/%s\n' % self.conf.libdir) - f.close() - - cwd = os.getcwd() - os.chdir(self.conf.treedir) - os.system('/usr/sbin/chroot %s /sbin/ldconfig' % self.conf.treedir) - os.chdir(cwd) - - if self.conf.buildarch not in ('s390', 's390x'): - # XXX this is not in usr - rm(os.path.join(self.conf.treedir, 'usr', 'sbin', 'ldconfig')) - - # XXX why are we removing this? - #rm(os.path.join(self.conf.treedir, 'etc', 'ld.so.conf')) - os.system('umount %s' % procdir) - - # make bash link - # XXX already exists - #if os.path.isfile(os.path.join(self.conf.treedir, 'bin', 'bash')): - # rm(os.path.join(self.conf.treedir, 'bin', 'ash')) - # os.symlink('bash', os.path.join(self.conf.treedir, 'bin', 'sh')) - - # make awk link - # XXX already exists - #if os.path.isfile(os.path.join(self.conf.treedir, 'bin', 'gawk')): - # os.symlink('awk', os.path.join(self.conf.treedir, 'bin', 'gawk')) - - # remove dirs from usr/lib - dirs = ('ConsoleKit', 'X11', 'alsa-lib', 'asterisk', 'avahi', 'booty', 'db4.5*', 'enchant', 'games', 'gio', 'gnome-keyring', 'gnome-vfs-2.0', - 'krb5', 'libglade', 'libxslt-plugins', 'lua', 'notification-daemon*', 'nss', 'openssl', 'orbit-2.0', 'perl5', 'pkgconfig', 'plymouth', - 'pm-utils', 'pppd', 'pygtk', 'rsyslog', 'samba', 'sasl2', 'sse2', 'syslinux', 'tc', 'tls', 'udev', 'window-manager-settings') - for dir in dirs: - rm(os.path.join(self.conf.treedir, 'usr', 'lib', dir)) - - # remove dirs from usr/share - dirs = ('GConf', 'NetworkManager', 'aclocal', 'alsa', 'application-registry', 'applications', 'asterisk', 'augeas', 'authconfig', 'avahi', - 'awk', 'createrepo', 'desktop-directories', 'dict', 'doc', 'dogtail', 'emacs', 'empty', 'enchant', 'file', 'firmware', 'firmware-tools', - 'firstboot', 'games', 'gnome*', 'gnupg', 'groff', 'gtk-*', 'help', 'i18n', 'info', 'kde*', 'librarian', 'libthai', 'lua', - 'makebootfat', 'man', 'metacity', 'mime*', 'misc', 'myspell', 'octave', 'omf', 'pkgconfig', 'plymouth', 'pygtk', 'selinux', - 'setuptool', 'sgml', 'system-config-firewall', 'system-config-network', 'system-config-users', 'tabset', 'tc', 'usermode', 'xml', - 'xsessions', 'yum-cli', 'magic') - for dir in dirs: - rm(os.path.join(self.conf.treedir, 'usr', 'share', dir)) - - # remove dirs from usr/share/themes - dirs = ('AgingGorilla', 'Atlanta', 'Bright', 'Clearlooks', 'ClearlooksClassic', 'Crux', 'Default', 'Emacs', 'Esco', 'Glider', 'Glossy', - 'HighContrast*', 'Industrial', 'Inverted', 'LargePrint', 'LowContrast*', 'Metabox', 'Mist', 'Raleigh', 'Simple', 'ThinIce') - for dir in dirs: - rm(os.path.join(self.conf.treedir, 'usr', 'share', 'themes', dir)) - - # remove dirs from usr/libexec - dirs = ('awk', 'gcc', 'getconf', 'openssh', 'plymouth') - for dir in dirs: - rm(os.path.join(self.conf.treedir, 'usr', 'libexec', dir)) - - # remove dirs from usr/share/locale - dirs = ('af_ZA', 'ca_ES', 'cs_CZ', 'de_DE', 'el_GR', 'en', 'en_US', 'es_ES', 'et_EE', 'fa_IR', 'fr_FR', 'he_IL', 'hr_HR', 'it_IT', 'ja_JP', - 'ko_KR', 'nb_NO', 'nl_NL', 'nso', 'pl_PL', 'pt_PT', 'ru_RU', 'sr', 'sv_SE', 'uk_UA') - for dir in dirs: - rm(os.path.join(self.conf.treedir, 'usr', 'share', 'locale')) - - # remove dirs from var/cache - dirs = ('dirmngr', 'fontconfig', 'man', 'yum') - map(lambda dir: rm(os.path.join(self.conf.treedir, 'var', 'cache', dir)), dirs) - - # remove dirs from var/lib - dirs = ('alternatives', 'asterisk', 'authconfig', 'dhclient', 'dhcpv6', 'dirmngr', 'dnsmasq', 'games', 'iscsi', 'nfs', 'ntp', 'plymouth', - 'rpcbind', 'rpm', 'samba', 'selinux', 'sepolgen', 'stateless', 'udev', 'yum', 'logrotate.status') - map(lambda dir: rm(os.path.join(self.conf.treedir, 'var', 'lib', dir)), dirs) - - # remove dirs from var/run - dirs = ('ConsoleKit', 'NetworkManager', 'asterisk', 'avahi-daemon', 'console', 'dirmngr', 'hald', 'mdadm', 'netreport', 'plymouth', - 'pm-utils', 'ppp', 'sepermit', 'setrans', 'winbindd', 'wpa_supplicant', 'utmp') - map(lambda dir: rm(os.path.join(self.conf.treedir, 'var', 'run', dir)), dirs) - - # remove dirs from usr/share/terminfo - dirs = ('A', 'E', 'a', 'c', 'd', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'r', 's', 't', 'w') - map(lambda dir: rm(os.path.join(self.conf.treedir, 'usr', 'share', 'terminfo', dir)), dirs) - - # remove dirs from usr/share/pixmaps - dirs = ('redhat', 'splash') - map(lambda dir: rm(os.path.join(self.conf.treedir, 'usr', 'share', 'pixmaps', dir)), dirs) - - # remove dirs form usr/share/X11/fonts - dirs = ('OTF', 'encodings', 'util') - map(lambda dir: rm(os.path.join(self.conf.treedir, 'usr', 'share', 'X11', 'fonts', dir)), dirs) - - # remove dirs from usr/lib/python2.5/site-packages - dirs = ('firmware_addon_dell', 'firmwaretools') - map(lambda dir: rm(os.path.join(self.conf.treedir, 'usr', 'lib', 'python2.5', 'site-packages', dir)), dirs) diff --git a/src/pylorax/actions/__init__.py b/src/pylorax/actions/__init__.py deleted file mode 100644 index 59d52e29..00000000 --- a/src/pylorax/actions/__init__.py +++ /dev/null @@ -1,58 +0,0 @@ -# -# __init__.py -# actions parser -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): Martin Gracik -# - -import sys -import os - - -def getActions(verbose=False): - actions = {} - root, actions_dir = os.path.split(os.path.dirname(__file__)) - - sys.path.insert(0, root) - - modules = set() - for filename in os.listdir(os.path.join(root, actions_dir)): - if filename.endswith(".py") and filename != "__init__.py": - basename, extension = os.path.splitext(filename) - modules.add(os.path.join(actions_dir, basename).replace("/", ".")) - - for module in modules: - if verbose: - print("Loading actions from module '%s'" % (module,)) - imported = __import__(module, globals(), locals(), [module], -1) - - try: - commands = getattr(imported, "COMMANDS") - except AttributeError: - if verbose: - print("No actions found") - continue - else: - for command, classname in commands.items(): - if verbose: - print("Loaded: %s" % classname) - actions[command] = getattr(imported, classname) - - sys.path.pop(0) - - return actions diff --git a/src/pylorax/actions/base.py b/src/pylorax/actions/base.py deleted file mode 100644 index 245a40ed..00000000 --- a/src/pylorax/actions/base.py +++ /dev/null @@ -1,404 +0,0 @@ -# -# base.py -# base actions -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): Martin Gracik -# - -import os -import re -import pwd -import grp -import glob - -from pylorax.utils.fileutils import copy, move, remove, touch, edit, replace, chmod - - -# command:action mapping -# maps a template command to an action class -# if you want your new action to be supported, you have to include it in this mapping -COMMANDS = { 'copy': 'Copy', - 'move': 'Move', - 'remove': 'Remove', - 'link': 'Link', - 'touch': 'Touch', - 'edit': 'Edit', - 'replace': 'Replace', - 'makedir': 'MakeDir', - 'chmod': 'Chmod', - 'chown': 'Chown', - 'genkey': 'GenerateSSHKey' } - - -class LoraxAction(object): - """Actions base class. - - To create your own custom action, subclass this class and override the methods you need. - - A valid action has to have a REGEX class variable, which specifies the format of the action - command line, so the needed parameters can be properly extracted from it. - All the work should be done in the execute method, which will be called from Lorax. - At the end, set the success to False, or True depending on the success or failure of your action. - - If you need to install some package prior to executing the action, return an install pattern - with the "install" property. Lorax will get this first, and will try to install the needed - package. - - Don't forget to include a command:action map for your new action in the COMMANDS dictionary. - Action classes which are not in the COMMANDS dictionary will not be loaded. - - You can take a look at some of the builtin actions to get an idea of how to create your - own actions.""" - - - REGEX = r'' # regular expression for extracting the parameters from the command line - - def __init__(self): - if self.__class__ is LoraxAction: - raise TypeError, 'LoraxAction is an abstract class, cannot be used this way' - - self._attrs = {} - self._attrs['success'] = None # success is None, if the action wasn't executed yet - - def __str__(self): - return '%s: %s' % (self.__class__.__name__, self._attrs) - - def execute(self, verbose=False): - """This method is the main body of the action. Put all the "work" stuff in here.""" - raise NotImplementedError, 'execute method not implemented for LoraxAction class' - - @property - def success(self): - """Returns if the action's execution was successful or not.""" - return self._attrs['success'] - - @property - def install(self): - """Returns a pattern that needs to be installed, prior to calling the execute method.""" - return None - - @property - def getDeps(self): - return None - - -##### builtin actions - -class Copy(LoraxAction): - - REGEX = r'^(?P.*?)\s(?P.*?)\sto\s(?P.*?)\s(?P.*?)(\s(?Pinstall))?(\s(?Pnolinks))?$' - - def __init__(self, **kwargs): - LoraxAction.__init__(self) - self._attrs['src_root'] = kwargs.get('src_root') - self._attrs['src_path'] = kwargs.get('src_path') - self._attrs['dst_root'] = kwargs.get('dst_root') - self._attrs['dst_path'] = kwargs.get('dst_path') - - install = kwargs.get('install', False) - if install: - self._attrs['install'] = True - else: - self._attrs['install'] = False - - nolinks = kwargs.get('nolinks', False) - if nolinks: - self._attrs['nolinks'] = True - else: - self._attrs['nolinks'] = False - - def execute(self, verbose=False): - copy(src_root=self.src_root, src_path=self.src_path, - dst_root=self.dst_root, dst_path=self.dst_path, - nolinks=self.nolinks, ignore_errors=False, verbose=verbose) - self._attrs['success'] = True - - @property - def src(self): - path = os.path.join(self._attrs['src_root'], self._attrs['src_path']) - return os.path.normpath(path) - - @property - def src_root(self): - return self._attrs['src_root'] - - @property - def src_path(self): - return self._attrs['src_path'] - - @property - def dst(self): - path = os.path.join(self._attrs['dst_root'], self._attrs['dst_path']) - return os.path.normpath(path) - - @property - def dst_root(self): - return self._attrs['dst_root'] - - @property - def dst_path(self): - return self._attrs['dst_path'] - - @property - def mode(self): - return self._attrs['mode'] - - @property - def install(self): - if self._attrs['install']: - return self._attrs['src'] - else: - return None - - @property - def getDeps(self): - return self.src - - @property - def nolinks(self): - return self._attrs['nolinks'] - - -class Move(Copy): - def execute(self, verbose=False): - move(src_root=self.src_root, src_path=self.src_path, - dst_root=self.dst_root, dst_path=self.dst_path, - nolinks=self.nolinks, ignore_errors=False, verbose=verbose) - self._attrs['success'] = True - - -class Remove(LoraxAction): - - REGEX = r'^(?P.*?)$' - - def __init__(self, **kwargs): - LoraxAction.__init__(self) - self._attrs['filename'] = kwargs.get('filename') - - def execute(self, verbose=False): - remove(self.filename, verbose=verbose) - self._attrs['success'] = True - - @property - def filename(self): - return self._attrs['filename'] - - -class Link(LoraxAction): - - REGEX = r'^(?P.*?)\sto\s(?P.*?)$' - - def __init__(self, **kwargs): - LoraxAction.__init__(self) - self._attrs['name'] = kwargs.get('name') - self._attrs['target'] = kwargs.get('target') - - def execute(self, verbose=False): - os.symlink(self.target, self.name) - self._attrs['success'] = True - - @property - def name(self): - return self._attrs['name'] - - @property - def target(self): - return self._attrs['target'] - - @property - def install(self): - return self._attrs['target'] - - -class Touch(LoraxAction): - - REGEX = r'^(?P.*?)$' - - def __init__(self, **kwargs): - LoraxAction.__init__(self) - self._attrs['filename'] = kwargs.get('filename') - - def execute(self, verbose=False): - touch(filename=self.filename, verbose=verbose) - self._attrs['success'] = True - - @property - def filename(self): - return self._attrs['filename'] - - -class Edit(Touch): - - REGEX = r'^(?P.*?)\stext\s"(?P.*?)"(\s(?Pappend))?$' - - def __init__(self, **kwargs): - Touch.__init__(self, **kwargs) - self._attrs['text'] = kwargs.get('text') - - append = kwargs.get('append', False) - if append: - self._attrs['append'] = True - else: - self._attrs['append'] = False - - def execute(self, verbose=False): - edit(filename=self.filename, text=self.text, append=self.append, verbose=verbose) - self._attrs['success'] = True - - @property - def text(self): - return self._attrs['text'] - - @property - def append(self): - return self._attrs['append'] - - @property - def install(self): - return self._attrs['filename'] - - -class Replace(Touch): - - REGEX = r'^(?P.*?)\sfind\s"(?P.*?)"\sreplace\s"(?P.*?)"$' - - def __init__(self, **kwargs): - Touch.__init__(self, **kwargs) - self._attrs['find'] = kwargs.get('find') - self._attrs['replace'] = kwargs.get('replace') - - def execute(self, verbose=False): - replace(filename=self.filename, find=self.find, replace=self.replace, verbose=verbose) - self._attrs['success'] = True - - @property - def find(self): - return self._attrs['find'] - - @property - def replace(self): - return self._attrs['replace'] - - @property - def install(self): - return self._attrs['filename'] - - -class MakeDir(LoraxAction): - - REGEX = r'^(?P.*?)(\smode\s(?P.*?))?$' - - def __init__(self, **kwargs): - LoraxAction.__init__(self) - self._attrs['dir'] = kwargs.get('dir') - self._attrs['mode'] = kwargs.get('mode') - - def execute(self, verbose=False): - if not os.path.isdir(self.dir): - if self.mode: - os.makedirs(self.dir, mode=int(self.mode)) - else: - os.makedirs(self.dir) - self._attrs['success'] = True - - @property - def dir(self): - return self._attrs['dir'] - - @property - def mode(self): - return self._attrs['mode'] - - -class Chmod(LoraxAction): - - REGEX = r'^(?P.*?)\smode\s(?P[0-9]*?)$' - - def __init__(self, **kwargs): - LoraxAction.__init__(self) - self._attrs['filename'] = kwargs.get('filename') - self._attrs['mode'] = kwargs.get('mode') - - def execute(self, verbose=False): - chmod(self.filename, self.mode) - self._attrs['success'] = True - - @property - def filename(self): - return self._attrs['filename'] - - @property - def mode(self): - return self._attrs['mode'] - - -class Chown(LoraxAction): - - REGEX = r'^(?P.*?)\suser\s(?P.*?)\sgroup\s(?P.*?)$' - - def __init__(self, **kwargs): - LoraxAction.__init__(self) - self._attrs['filename'] = kwargs.get('filename') - self._attrs['user'] = kwargs.get('user') - self._attrs['group'] = kwargs.get('group') - - def execute(self, verbose=False): - uid = pwd.getpwnam(self.user)[2] - gid = grp.getgrnam(self.group)[2] - os.chown(self.filename, uid, gid) - self._attrs['success'] = True - - @property - def filename(self): - return self._attrs['filename'] - - @property - def user(self): - return self._attrs['user'] - - @property - def group(self): - return self._attrs['group'] - - -class GenerateSSHKey(LoraxAction): - - REGEX = r'^(?P.*?)\stype\s(?P.*?)$' - - def __init__(self, **kwargs): - LoraxAction.__init__(self) - self._attrs['file'] = kwargs.get('file') - self._attrs['type'] = kwargs.get('type') - - def execute(self, verbose=False): - cmd = "/usr/bin/ssh-keygen -q -t %s -f %s -C '' -N ''" % (self.type, self.file) - err, output = commands.getstatusoutput(cmd) - - if not err: - os.chmod(self.file, 0600) - os.chmod(self.file + '.pub', 0644) - - self._attrs['success'] = True - - @property - def file(self): - return self._attrs['file'] - - @property - def type(self): - return self._attrs['type'] diff --git a/src/pylorax/config.py b/src/pylorax/config.py index aee19a1f..e7ee5a27 100644 --- a/src/pylorax/config.py +++ b/src/pylorax/config.py @@ -1,90 +1,191 @@ # # config.py -# lorax configuration -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): Martin Gracik # -from misc import seq +import os + +import singleton +import output -class Container(object): +class LoraxConfig(singleton.Singleton): - def __init__(self, attrs=None): - self.__dict__["__internal"] = {} - self.__dict__["__internal"]["attrs"] = set() + def __init__(self): + self.confdir = "/etc/lorax" + self.datadir = "/usr/share/lorax" - if attrs: - self.addAttr(attrs) - - def __str__(self): - return str(self.__makeDict()) - - def __iter__(self): - return iter(self.__makeDict()) - - def __getitem__(self, attr): - self.__checkInternal(attr) - - if attr not in self.__dict__: - raise AttributeError, "object has no attribute '%s'" % attr - - return self.__dict__[attr] + self.colors = True + self.encoding = "utf-8" + self.debug = False + self.cleanup = False def __setattr__(self, attr, value): - raise AttributeError, "you can't do that, use addAttr() and/or set() instead" + output.Terminal.get().debug("[%s = %s]" % (attr, value)) + singleton.Singleton.__setattr__(self, attr, value) - def __delattr__(self, attr): - raise AttributeError, "you can't do that, use delAttr() instead" - def addAttr(self, attrs): - for attr in filter(lambda attr: attr not in self.__dict__, seq(attrs)): - self.__checkInternal(attr) +class LoraxPaths(singleton.Singleton): - self.__dict__[attr] = None - self.__dict__["__internal"]["attrs"].add(attr) + def __init__(self): + self.datadir = LoraxConfig.get().datadir + self.installtree = LoraxConfig.get().installtree - def delAttr(self, attrs): - for attr in filter(lambda attr: attr in self.__dict__, seq(attrs)): - self.__checkInternal(attr) + @property + def ANACONDA_PACKAGE(self): return "anaconda" - del self.__dict__[attr] - self.__dict__["__internal"]["attrs"].discard(attr) + @property + def INITRD_DATADIR(self): + return os.path.join(self.datadir, "initrd") - def set(self, **kwargs): - unknown = set() - for attr, value in kwargs.items(): - self.__checkInternal(attr) + @property + def INSTALLTREE_DATADIR(self): + return os.path.join(self.datadir, "installtree") - if attr in self.__dict__: - self.__dict__[attr] = value - else: - unknown.add(attr) + @property + def OUTPUTDIR_DATADIR(self): + return os.path.join(self.datadir, "outputdir") - return unknown + @property + def BOOTDIR(self): + return os.path.join(self.installtree, "boot") - def __makeDict(self): - d = {} - for attr in self.__dict__["__internal"]["attrs"]: - d[attr] = self.__dict__[attr] + @property + def BOOTDIR_IA64(self): + return os.path.join(self.BOOTDIR, "efi", "EFI", "redhat") - return d + @property + def ANACONDA_RUNTIME(self): + return os.path.join(self.installtree, "usr", "lib", "anaconda-runtime") - def __checkInternal(self, attr): - if attr.startswith("__"): - raise AttributeError, "do not mess with internal objects" + @property + def ANACONDA_BOOT(self): + return os.path.join(self.ANACONDA_RUNTIME, "boot") + + @property + def SYSLINUXDIR(self): + return os.path.join(self.installtree, "usr", "lib", "syslinux") + + @property + def ISOLINUXBIN(self): + return os.path.join(self.SYSLINUXDIR, "isolinux.bin") + + @property + def SYSLINUXCFG(self): + return os.path.join(self.ANACONDA_BOOT, "syslinux.cfg") + + @property + def GRUBCONF(self): + return os.path.join(self.ANACONDA_BOOT, "grub.conf") + + @property + def GRUBEFI(self): + return os.path.join(self.BOOTDIR, "efi", "EFI", "redhat", "grub.efi") + + @property + def VESASPLASH(self): + return os.path.join(self.ANACONDA_RUNTIME, "syslinux-vesa-splash.jpg") + + @property + def VESAMENU(self): + return os.path.join(self.SYSLINUXDIR, "vesamenu.c32") + + @property + def SPLASHTOOLS(self): + return os.path.join(self.ANACONDA_RUNTIME, "splashtools.sh") + + @property + def SPLASHLSS(self): + return os.path.join(self.ANACONDA_BOOT, "splash.lss") + + @property + def SYSLINUXSPLASH(self): + return os.path.join(self.ANACONDA_BOOT, "syslinux-splash.jpg") + + @property + def SPLASHXPM(self): + return os.path.join(self.BOOTDIR, "grub", "splash.xpm.gz") + + @property + def MODULES_DIR(self): + return os.path.join(self.installtree, "lib", "modules", + LoraxConfig.get().kernelver) + + @property + def MODULES_DEP(self): + return os.path.join(self.MODULES_DIR, "modules.dep") + + @property + def MODINFO(self): return "/sbin/modinfo" + + @property + def MODLIST(self): + return os.path.join(self.ANACONDA_RUNTIME, "modlist") + + @property + def DEPMOD(self): return "/sbin/depmod" + + @property + def GETKEYMAPS(self): + return os.path.join(self.ANACONDA_RUNTIME, "getkeymaps") + + @property + def LOCALEDEF(self): return "/usr/bin/localedef" + + @property + def GENINITRDSZ(self): + return os.path.join(self.ANACONDA_RUNTIME, "geninitrdsz") + + @property + def REDHAT_EXEC(self): + return os.path.join(self.ANACONDA_BOOT, "redhat.exec") + + @property + def GENERIC_PRM(self): + return os.path.join(self.ANACONDA_BOOT, "generic.prm") + + @property + def MKS390CD(self): + return os.path.join(self.ANACONDA_RUNTIME, "mk-s390-cdboot") + + @property + def MKSQUASHFS(self): return "/sbin/mksquashfs" + + @property + def MKCRAMFS(self): return "/sbin/mkfs.cramfs" + + @property + def MKISOFS(self): return "/usr/bin/mkisofs" + + @property + def MKDOSFS(self): return "/sbin/mkdosfs" + + @property + def ISOHYBRID(self): return "/usr/bin/isohybrid" + + @property + def SYSTEM_MAP(self): + return os.path.join(self.BOOTDIR, + "System.map-%s" % LoraxConfig.get().kernelver) + + @property + def KEYMAPS_OVERRIDE(self): + return os.path.join(self.ANACONDA_RUNTIME, + "keymaps-override-%s" % LoraxConfig.get().arch) + + @property + def LANGTABLE(self): + return os.path.join(self.installtree, "usr", "lib", "anaconda", + "lang-table") + + @property + def LOCALEPATH(self): + return os.path.join(self.installtree, "usr", "share", "locale") + + @property + def MANCONFIG(self): + return os.path.join(self.installtree, "etc", "man.config") + + @property + def FEDORAKMODCONF(self): + return os.path.join(self.installtree, "etc", "yum", "pluginconf.d", + "fedorakmod.conf") diff --git a/src/pylorax/efi.py b/src/pylorax/efi.py new file mode 100644 index 00000000..ef892c90 --- /dev/null +++ b/src/pylorax/efi.py @@ -0,0 +1,213 @@ +# +# efi.py +# + +import sys +import os +import shutil +import tempfile +import commands + +import config +import output +import utils + + +class EFI(object): + + def __init__(self): + self.conf = config.LoraxConfig.get() + self.paths = config.LoraxPaths.get() + self.output = output.Terminal.get() + + def create_efiboot(self, kernel=None, initrd=None, + kernelpath=None, initrdpath=None): + + # create the temporary efi tree directory + efitreedir = tempfile.mkdtemp(prefix="efitree.", dir=self.conf.tempdir) + + # copy kernel and initrd files to efi tree directory + if kernel and initrd: + shutil.copy2(kernel, os.path.join(efitreedir, "vmlinuz")) + shutil.copy2(initrd, os.path.join(efitreedir, "initrd.img")) + efikernelpath = "/EFI/BOOT/vmlinuz" + efiinitrdpath = "/EFI/BOOT/initrd.img" + else: + efikernelpath = kernelpath + efiinitrdpath = initrdpath + + # copy conf files to efi tree directory + utils.scopy(src_root=self.conf.anaconda_boot, src_path="*.conf", + dst_root=efitreedir, dst_path="") + + # edit the grub.conf file + grubconf = os.path.join(efitreedir, "grub.conf") + utils.replace(grubconf, "@PRODUCT@", self.conf.product) + utils.replace(grubconf, "@VERSION@", self.conf.version) + utils.replace(grubconf, "@KERNELPATH@", efikernelpath) + utils.replace(grubconf, "@INITRDPATH@", efiinitrdpath) + utils.replace(grubconf, "@SPLASHPATH@", "/EFI/BOOT/splash.xpm.gz") + + # copy grub.efi + shutil.copy2(self.paths.GRUBEFI, efitreedir) + + # the first generation mactel machines get the bootloader name wrong + if self.conf.efiarch == "IA32": + src = os.path.join(efitreedir, "grub.efi") + dst = os.path.join(efitreedir, "BOOT.efi") + shutil.copy2(src, dst) + + src = os.path.join(efitreedir, "grub.conf") + dst = os.path.join(efitreedir, "BOOT.conf") + shutil.copy2(src, dst) + + src = os.path.join(efitreedir, "grub.efi") + dst = os.path.join(efitreedir, "BOOT%s.efi" % self.conf.efiarch) + shutil.move(src, dst) + + src = os.path.join(efitreedir, "grub.conf") + dst = os.path.join(efitreedir, "BOOT%s.conf" % self.conf.efiarch) + shutil.move(src, dst) + + # copy splash.xpm.gz + shutil.copy2(self.paths.SPLASHXPM, efitreedir) + + efiboot = os.path.join(self.conf.tempdir, "efiboot.img") + if os.path.isfile(efiboot): + os.unlink(efiboot) + + # calculate the size of the efitree directory + sizeinbytes = 0 + for root, dirs, files in os.walk(efitreedir): + for file in files: + filepath = os.path.join(root, file) + sizeinbytes += os.path.getsize(filepath) + + # mkdosfs needs the size in blocks of 1024 bytes + size = int(round(sizeinbytes / 1024.0)) + + # add 100 blocks for the filesystem overhead + size += 100 + + cmd = "%s -n ANACONDA -C %s %s > /dev/null" % (self.paths.MKDOSFS, + efiboot, size) + err, output = commands.getstatusoutput(cmd) + if err: + self.output.error(output) + return None + + # mount the efiboot image + efibootdir = tempfile.mkdtemp(prefix="efiboot.", dir=self.conf.tempdir) + + cmd = "mount -o loop,shortname=winnt,umask=0777 -t vfat %s %s" % \ + (efiboot, efibootdir) + err, output = commands.getstatusoutput(cmd) + if err: + self.output.error(output) + return None + + # copy the files to the efiboot image + utils.scopy(src_root=efitreedir, src_path="*", + dst_root=efibootdir, dst_path="") + + # unmount the efiboot image + cmd = "umount %s" % efibootdir + err, output = commands.getstatusoutput(cmd) + if err: + self.output.warning(output) + pass + + # copy the conf files to the output directory + if not kernel and not initrd: + utils.scopy(src_root=efitreedir, src_path="*.conf", + dst_root=self.conf.efibootdir, dst_path="") + + return efiboot + + def create_efidisk(self, efiboot): + efidisk = os.path.join(self.conf.tempdir, "efidisk.img") + if os.path.isfile(efidisk): + os.unlink(efidisk) + + partsize = os.path.getsize(efiboot) + disksize = 17408 + partsize + 17408 + disksize = disksize + (disksize % 512) + + with open(efidisk, "wb") as f: + f.truncate(disksize) + + cmd = "losetup -v -f %s | awk '{print $4}'" % efidisk + err, loop = commands.getstatusoutput(cmd) + if err: + self.output.error(loop) + os.unlink(efidisk) + return None + + cmd = 'dmsetup create efiboot --table "0 %s linear %s 0"' % \ + (disksize / 512, loop) + err, output = commands.getstatusoutput(cmd) + if err: + self.output.error(output) + self.remove_loop_dev(loop) + os.unlink(efidisk) + return None + + cmd = "parted --script /dev/mapper/efiboot " \ + "mklabel gpt unit b mkpart '\"EFI System Partition\"' " \ + "fat32 17408 %s set 1 boot on" % (partsize + 17408) + err, output = commands.getstatusoutput(cmd) + if err: + self.output.error(output) + self.remove_dm_dev("efiboot") + self.remove_loop_dev(loop) + os.unlink(efidisk) + return None + + with open(efiboot, "rb") as f_from: + with open("/dev/mapper/efibootp1", "wb") as f_to: + efidata = f_from.read(1024) + while efidata: + f_to.write(efidata) + efidata = f_from.read(1024) + + self.remove_dm_dev("efibootp1") + self.remove_dm_dev("efiboot") + self.remove_loop_dev(loop) + + return efidisk + + def remove_loop_dev(self, dev): + cmd = "losetup -d %s" % dev + err, output = commands.getstatusoutput(cmd) + if err: + self.output.warning(output) + + def remove_dm_dev(self, dev): + cmd = "dmsetup remove /dev/mapper/%s" % dev + err, output = commands.getstatusoutput(cmd) + if err: + self.output.warning(output) + + def create(self, kernel=None, initrd=None, + kernelpath=None, initrdpath=None): + + # create the efiboot image + efiboot = self.create_efiboot(kernel, initrd) + if efiboot is None: + self.output.critical("unable to create the efiboot image") + sys.exit(1) + + # create the efidisk image + efidisk = self.create_efidisk(efiboot) + if efidisk is None: + self.output.critical("unable to create the efidisk image") + sys.exit(1) + + # create the efiboot image again + efiboot = self.create_efiboot(kernelpath=kernelpath, + initrdpath=initrdpath) + if efiboot is None: + self.output.critical("unable to create the efiboot image") + sys.exit(1) + + return efiboot, efidisk diff --git a/src/pylorax/images.py b/src/pylorax/images.py deleted file mode 100644 index 34f31eb2..00000000 --- a/src/pylorax/images.py +++ /dev/null @@ -1,867 +0,0 @@ -# -# images.py -# lorax images manipulation -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): Martin Gracik -# - -import sys -import os -import glob -import shutil -import commands -import re - -import actions -import actions.base - -from template import Template - -from utils.fileutils import copy, remove, touch, edit, replace -from utils.ldd import LDD - - -class InitRD(object): - - def __init__(self, config, yum, output): - self.conf = config - self.yum = yum - - self.so, self.se = output - - def read_template(self): - # get supported actions - supported_actions = actions.getActions(verbose=self.conf.debug) - - # variables supported in templates - vars = { "instroot": self.conf.treedir, - "initrd": self.conf.initrddir, - "libdir": self.conf.libdir, - "buildarch": self.conf.buildarch, - "basearch": self.conf.basearch, - "confdir" : self.conf.confdir, - "datadir": self.conf.datadir } - - # parse the template file - initrd_template = os.path.join(self.conf.confdir, "initrd", - "initrd.%s" % self.conf.buildarch) - - self.template = Template() - self.template.preparse(initrd_template) - self.template.parse(supported_actions, vars) - - def install_required_packages(self): - packages = set() - for action in filter(lambda action: action.install, self.template.actions): - m = re.match(r"%s(.*)" % (self.conf.treedir,), action.install) - if m: - packages.add(m.group(1)) - - for package in packages: - ok = self.yum.add_package(package) - if not ok: - self.se.error("No package '%s' found" % (package,)) - - self.yum.install() - - def get_file_dependencies(self): - libroots = [] - libroots.append(os.path.join(self.conf.treedir, self.conf.libdir)) - libroots.append(os.path.join(self.conf.treedir, "usr", self.conf.libdir)) - - # on 64 bit systems, add also normal lib directories - if self.conf.libdir.endswith("64"): - libdir = self.conf.libdir[:-2] - libroots.append(os.path.join(self.conf.treedir, libdir)) - libroots.append(os.path.join(self.conf.treedir, "usr", libdir)) - - ldd = LDD(libroots) - - for action in self.template.actions: - if action.getDeps: - [ldd.getDeps(fname) for fname in glob.glob(action.getDeps)] - - if ldd.errors: - # XXX ldd didn't get all the dependencies, what now? - for filename, error in ldd.errors: - self.se.error(filename) - self.se.error(error) - - # additional actions that need to be processed - self._actions = [] - - # add dependencies to actions, so they are copied too - for dep in ldd.deps: - kwargs = {} - kwargs["src_root"] = self.conf.treedir - kwargs["src_path"] = dep.replace(self.conf.treedir + "/", "", 1) - kwargs["dst_root"] = self.conf.initrddir - kwargs["dst_path"] = os.path.dirname(kwargs["src_path"]) - - if kwargs["dst_path"].startswith("/"): - kwargs["dst_path"] = kwargs["dst_path"][1:] - - new_action = actions.base.Copy(**kwargs) - self._actions.append(new_action) - - def process_actions(self): - for action in self.template.actions: - action.execute() - - # process dependencies - for action in self._actions: - action.execute() - - def create_modinfo(self, moddir, target): - # XXX why do we need this thing? - mods = {} - for root, dirs, files in os.walk(moddir): - 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(moddir, "modules.%s" % file) - f = open(filename, "r") - except IOError as why: - self.se.error("Unable to 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: - continue - - cmd = "modinfo -F description %s" % (mods[line],) - outtext = commands.getoutput(cmd) - - desc = outtext.split("\n")[0] - desc = desc.strip() - 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 - - f = open(target, "a") - f.write("Version 0\n") - for type in list: - modlist = list[type].keys() - modlist.sort() - for m in modlist: - f.write("%s\n" % (list[type][m],)) - f.close() - - def get_kernel_modules(self): - kernelver = self.conf.kernelver - - modfiles = [] - modfiles.append(os.path.join(self.conf.confdir, "modules", - "modules.all")) - modfiles.append(os.path.join(self.conf.confdir, "modules", - "modules.%s" % (self.conf.buildarch,))) - - src_moddir = os.path.join(self.conf.treedir, "lib", "modules", kernelver) - dst_moddir = os.path.join(self.conf.initrddir, "lib", "modules", kernelver) - - # get the modules from configuration files - modules = set() - for file in modfiles: - if os.path.isfile(file): - f = open(file, "r") - lines = f.readlines() - f.close() - - for line in lines: - line, sep, comment = line.partition("#") - line = line.strip() - - if not line: - continue - - if line.startswith("-"): - modules.discard(line[1:]) - elif line.startswith("="): - # expand modules - group = line[1:] - - if group in ("scsi", "ata"): - path = os.path.join(src_moddir, "modules.block") - elif group == "net": - path = os.path.join(src_moddir, "modules.networking") - else: - path = os.path.join(src_moddir, "modules.%s" % (group,)) - - if os.path.isfile(path): - f = open(path, "r") - for module in f.readlines(): - module = module.strip() - module = module.replace(".ko", "") - modules.add(module) - f.close() - else: - modules.add(line) - - # resolve modules dependencies - depfile = os.path.join(src_moddir, "modules.dep") - f = open(depfile, "r") - lines = f.readlines() - f.close() - - changed = True - while changed: - for line in lines: - changed = False - line = line.strip() - - m = re.match(r"^.*/(?P.*)\.ko:(?P.*)$", line) - modname = m.group("name") - - if modname in modules: - for dep in m.group("deps").split(): - m = re.match(r"^.*/(?P.*)\.ko$", dep) - depname = m.group("name") - - if depname not in modules: - changed = True - modules.add(depname) - - # copy the modules directory - copy(src_root=self.conf.treedir, - src_path=os.path.join("lib", "modules", kernelver), - dst_root=self.conf.initrddir, - dst_path=os.path.join("lib", "modules")) - - # remove not needed modules - for root, dirs, files in os.walk(dst_moddir): - for file in files: - full_path = os.path.join(root, file) - name, ext = os.path.splitext(file) - - if ext == ".ko": - if name not in modules: - remove(full_path) - else: - # copy the required firmware - cmd = "modinfo -F firmware %s" % (full_path,) - err, output = commands.getstatusoutput(cmd) - - for fw in output.split(): - dst = os.path.join(self.conf.initrddir, - "lib", "firmware", fw) - - dir = os.path.dirname(dst) - if not os.path.exists(dir): - os.makedirs(dir) - - copy(src_root = self.conf.treedir, - src_path = os.path.join("lib", "firmware", fw), - dst_root = self.conf.initrddir, - dst_path = os.path.join("lib", "firmware", fw)) - - # copy additional firmware - srcdir = os.path.join(self.conf.treedir, "lib", "firmware") - dstdir = os.path.join(self.conf.initrddir, "lib", "firmware") - - fw = ( ("ipw2100", "ipw2100*"), - ("ipw2200", "ipw2200*"), - ("iwl3945", "iwlwifi-3945*"), - ("iwl4965", "iwlwifi-4965*"), - ("atmel", "atmel_*.bin"), - ("zd1211rw", "zd1211"), - ("qla2xxx", "ql*") ) - - for module, file in fw: - if module in modules: - copy(src_root=self.conf.treedir, - src_path=os.path.join("lib", "firmware", file), - dst_root=self.conf.initrddir, - dst_path=os.path.join("lib", "firmware")) - - # compress modules - cmd = "find -H %s -type f -name *.ko -exec gzip -9 {} \\;" % (dst_moddir,) - err, output = commands.getstatusoutput(cmd) - if err: - self.se.debug(output) - - # create modinfo - modinfo = os.path.join(self.conf.tempdir, "modinfo") - self.create_modinfo(src_moddir, modinfo) - - modlist = os.path.join(self.conf.treedir, - "usr", "lib", "anaconda-runtime", "modlist") - - target = os.path.join(self.conf.initrddir, "lib", "modules", "module-info") - cmd = "%s --modinfo-file %s --ignore-missing --modinfo %s > %s" % \ - (modlist, modinfo, " ".join(list(modules)), target) - err, output = commands.getstatusoutput(cmd) - if err: - self.se.debug(output) - - # run depmod - systemmap = os.path.join(self.conf.treedir, "boot", "System.map-%s" \ - % (kernelver,)) - cmd = "/sbin/depmod -a -F %s -b %s %s" % (systemmap, - self.conf.initrddir, kernelver) - err, output = commands.getstatusoutput(cmd) - if err: - self.se.debug(output) - - # remove leftovers - remove(os.path.join(dst_moddir, "modules.*map")) - - def trim_pci_ids(self): - # FIXME remove this function, just copy the original pci.ids file - - kernelver = self.conf.kernelver - - vendors = set() - devices = set() - - modulesalias = os.path.join(self.conf.treedir, - "lib", "modules", kernelver, "modules.alias") - f = open(modulesalias) - pcitable = f.readlines() - f.close() - - for line in pcitable: - if not line.startswith("alias pci:"): - continue - - vend = "0x%s" % (line[15:19],) - vend = vend.upper() - dev = "0x%s" % (line[24:28],) - dev = dev.upper() - - vendors.add(vend) - devices.add((vend, dev)) - - videoaliases = os.path.join(self.conf.treedir, - "usr", "share", "hwdata", "videoaliases", "*") - for file in glob.iglob(videoaliases): - f = open(file) - pcitable = f.readlines() - f.close() - - for line in pcitable: - if not line.startswith("alias pcivideo:"): - continue - - vend = "0x%s" % (line[20:24],) - vend = vend.upper() - dev = "0x%s" % (line[29:33],) - dev = dev.upper() - - vendors.add(vend) - devices.add((vend, dev)) - - # create the pci.ids file - src = os.path.join(self.conf.treedir, "usr", "share", "hwdata", "pci.ids") - dst = os.path.join(self.conf.initrddir, "usr", "share", "hwdata", "pci.ids") - - input = open(src, "r") - pcitable = input.readlines() - input.close() - - output = open(dst, "w") - - current_vend = 0 - for line in pcitable: - # skip lines that start with 2 tabs or # - if line.startswith("\t\t") or line.startswith("#"): - continue - - # skip empty lines - if line == "\n": - continue - - # end of file - if line == "ffff Illegal Vendor ID": - break - - if not line.startswith("\t"): - current_vend = "0x%s" % (line.split()[0],) - current_vend = current_vend.upper() - if current_vend in vendors: - output.write(line) - continue - - dev = "0x%s" % (line.split()[0],) - dev = dev.upper() - if (current_vend, dev) in devices: - output.write(line) - - output.close() - - def get_keymaps(self): - anadir = os.path.join(self.conf.treedir, "usr", "lib", "anaconda-runtime") - override = os.path.join(anadir, - "keymaps-override-%s" % (self.conf.buildarch,)) - - if os.path.isfile(override): - self.so.debug("Found keymap override, using it") - shutil.copy2(override, - os.path.join(self.conf.initrddir, "etc", "keymaps.gz")) - else: - cmd = "%s %s %s %s" % (os.path.join(anadir, "getkeymaps"), - self.conf.buildarch, - os.path.join(self.conf.initrddir, "etc", "keymaps.gz"), - self.conf.treedir) - - err, output = commands.getstatusoutput(cmd) - if err: - return False - - return True - - def create_locales(self): - os.makedirs(os.path.join(self.conf.initrddir, "usr", "lib", "locale")) - err, output = commands.getstatusoutput("localedef -c -i en_US -f UTF-8" - " --prefix %s en_US" % (self.conf.initrddir,)) - - def create(self, target): - # copy the .buildstamp file - shutil.copy2(self.conf.buildstamp, self.conf.initrddir) - - cwd = os.getcwd() - os.chdir(self.conf.initrddir) - - cmd = "find . | cpio --quiet -c -o | gzip -9 > %s" % (target,) - output = commands.getoutput(cmd) - - os.chdir(cwd) - - def run(self): - # create the temporary directory for initrd - initrddir = os.path.join(self.conf.tempdir, "initrddir", - self.conf.kernelver) - self.so.info("Creating the temporary initrd directory") - os.makedirs(initrddir) - self.conf.addAttr("initrddir") - self.conf.set(initrddir=initrddir) - - self.so.info("Reading the initrd template file") - self.read_template() - - self.so.info("Installing additional packages") - self.install_required_packages() - - self.so.info("Getting required dependencies") - self.get_file_dependencies() - - self.so.info("Copying required files to initrd directory") - self.process_actions() - - self.so.info("Getting required kernel modules") - self.get_kernel_modules() - - self.so.info("Getting the pci.ids file") - self.trim_pci_ids() - - ok = self.get_keymaps() - if not ok: - self.se.error("Unable to create the keymaps") - sys.exit(1) - - self.so.info("Creating locales") - self.create_locales() - - f = getattr(self, "run_%s" % (self.conf.buildarch,), None) - if f: - f() - - def run_i386(self): - initrd_filename = "initrd.img" - kernel_filename = "vmlinuz" - - if self.conf.kernelfile.endswith("PAE"): - initrd_filename = "initrd-PAE.img" - kernel_filename = "vmlinuz-PAE" - - text = "[images-xen]\n" - text += "kernel = images/pxeboot/vmlinuz-PAE\n" - text += "initrd = images/pxeboot/initrd-PAE.img\n" - edit(os.path.join(self.conf.outdir, ".treeinfo"), - append=True, text=text) - - self.so.info("Compressing the image file '%s'" % (initrd_filename,)) - self.create(os.path.join(self.conf.pxebootdir, initrd_filename)) - - self.so.info("Copying the kernel file") - shutil.copy2(self.conf.kernelfile, - os.path.join(self.conf.pxebootdir, kernel_filename)) - - if not self.conf.kernelfile.endswith("PAE"): - # copy the kernel and initrd to the isolinux directory - shutil.copy2(self.conf.kernelfile, - os.path.join(self.conf.isolinuxdir, kernel_filename)) - shutil.copy2(os.path.join(self.conf.pxebootdir, initrd_filename), - os.path.join(self.conf.isolinuxdir, initrd_filename)) - - # create the efi images - efi = EFI(self.conf, (self.so, self.se)) - efi.run(kernelfile=self.conf.kernelfile, - initrd=os.path.join(self.conf.pxebootdir, initrd_filename), - kernelpath="/images/pxeboot/vmlinuz", - initrdpath="/images/pxeboot/initrd.img") - - def run_x86_64(self): - self.run_i386() - - def run_s390(self): - initrd_filename = "initrd.img" - kernel_filename = "kernel.img" - - self.so.info("Compressing the image file '%s'" % (initrd_filename,)) - self.create(os.path.join(self.conf.imagesdir, initrd_filename)) - - cmd = "ls -l %s | awk '{print $5}'" % \ - (os.path.join(self.conf.imagesdir, initrd_filename),) - self.so.debug(cmd) - err, size = commands.getstatusoutput(cmd) - if err: - self.se.debug(size) - - geninitrdsz = os.path.join(self.conf.treedir, "usr", "lib", - "anaconda-runtime", "geninitrdsz") - - cmd = "%s %s %s" % (geninitrdsz, size, - os.path.join(self.conf.imagesdir, "initrd.size")) - self.so.debug(cmd) - err, output = commands.getstatusoutput(cmd) - if err: - self.se.debug(output) - - # copy the kernel file - shutil.copy2(self.conf.kernelfile, - os.path.join(self.conf.imagesdir, kernel_filename)) - - for filename in ("redhat.exec", "generic.prm"): - shutil.copy2(os.path.join(self.conf.bootdiskdir, filename), - self.conf.imagesdir) - shutil.copy2(os.path.join(self.conf.bootdiskdir, filename), - self.conf.outdir) - - mks390cdboot = os.path.join(self.conf.treedir, "usr", "lib", - "anaconda-runtime", "mk-s390-cdboot") - - cmd = "%s -i %s -r %s -p %s -o %s" % (mks390cdboot, - os.path.join(self.conf.imagesdir, kernel_filename), - os.path.join(self.conf.imagesdir, initrd_filename), - os.path.join(self.conf.imagesdir, "generic.prm"), - os.path.join(self.conf.imagesdir, "cdboot.img")) - err, output = commands.getstatusoutput(cmd) - if err: - self.se.debug(output) - - text = "[images-%s" % (self.conf.buildarch,) - text += "kernel = images/kernel.img" - text += "initrd = images/initrd.img" - text += "initrd.size = images/initrd.size" - text += "generic.prm = images/generic.prm" - text += "generic.ins = generic.ins" - text += "cdboot.img = images/cdboot.img" - edit(os.path.join(self.conf.outdir, ".treeinfo"), - append=True, text=text) - - def run_s390x(self): - self.run_s390() - - def run_alpha(self): - kerneldir = os.path.join(self.conf.outdir, "kernels") - if not os.path.isdir(kerneldir): - os.makedirs(kerneldir) - - # XXX check for the jensen kernel file, how can we differentiate it? - # i don't know the filename... - if self.conf.kernelfile.endswith("jensen"): - copy(self.conf.kernelfile, - os.path.join(kerneldir, "vmlinux.j")) - else: - copy(self.conf.kernelfile, - os.path.join(kerneldir, "vmlinux.gz")) - - os.makedirs(os.path.join(self.conf.outdir, "boot")) - copy(os.path.join(self.conf.bootdiskdir, "bootlx"), - os.path.join(self.conf.outdir, "boot")) - - os.makedirs(os.path.join(self.conf.outdir, "etc")) - abootconf = os.path.join(self.conf.outdir, "etc", "aboot.conf") - touch(abootconf) - - text = "0:/kernels/vmlinux.gz initrd=/images/initrd.img\n" - text += "1:/kernels/vmlinux.gz initrd=/images/initrd.img " - text += "console=ttyS0\n" - text += "2:/kernels/vmlinux.gz initrd=/images/initrd.img text\n" - text += "3:/kernels/vmlinux.gz initrd=/images/initrd.img rescue\n" - edit(abootconf, text=text) - - initrd_filename = "initrd.img" - self.so.info("Compressing the image file '%s'" % (initrd_filename,)) - self.create(os.path.join(self.conf.imagesdir, initrd_filename)) - - def run_ia64(self): - raise NotImplementedError - - def run_ppc(self): - raise NotImplementedError - - def run_ppc64(self): - self.run_ppc() - - -class EFI(object): - - def __init__(self, config, output): - self.conf = config - self.so, self.se = output - - # create the temporary efi directory - tempdir = os.path.join(self.conf.tempdir, "efi") - if os.path.exists(tempdir): - remove(tempdir) - os.makedirs(tempdir) - self.tempdir = tempdir - - def create(self, kernelfile=None, initrd=None, kernelpath=None, initrdpath=None): - # create the temporary efi tree directory - efitreedir = os.path.join(self.tempdir, "tree") - if os.path.exists(efitreedir): - remove(efitreedir) - os.makedirs(efitreedir) - - # copy kernel and initrd files to efi tree directory - if kernelfile and initrd: - shutil.copy2(kernelfile, os.path.join(efitreedir, "vmlinuz")) - shutil.copy2(initrd, os.path.join(efitreedir, "initrd.img")) - efikernelpath = os.path.join("/", "EFI", "BOOT", "vmlinuz") - efiinitrdpath = os.path.join("/", "EFI", "BOOT", "initrd.img") - else: - efikernelpath = kernelpath - efiinitrdpath = initrdpath - - # copy conf files to efi tree directory - copy(src_root=self.conf.bootdiskdir, src_path="*.conf", - dst_root=efitreedir, dst_path="") - - # edit the grub.conf file - grubconf = os.path.join(efitreedir, "grub.conf") - replace(grubconf, "@PRODUCT@", self.conf.product) - replace(grubconf, "@VERSION@", self.conf.version) - replace(grubconf, "@KERNELPATH@", efikernelpath) - replace(grubconf, "@INITRDPATH@", efiinitrdpath) - replace(grubconf, "@SPLASHPATH@", "/EFI/BOOT/splash.xpm.gz") - - # copy grub.efi - src = os.path.join(self.conf.treedir, - "boot", "efi", "EFI", "redhat", "grub.efi") - shutil.copy2(src, efitreedir) - - # the first generation mactel machines get the bootloader name wrong - if self.conf.efiarch == "ia32": - src = os.path.join(efitreedir, "grub.efi") - dst = os.path.join(efitreedir, "BOOT.efi") - shutil.copy2(src, dst) - src = os.path.join(efitreedir, "grub.conf") - dst = os.path.join(efitreedir, "BOOT.conf") - shutil.copy2(src, dst) - - efiarch = self.conf.efiarch - if efiarch == "x64": - efiarch = efiarch.upper() - elif efiarch == "ia32": - efiarch = efiarch.upper() - - src = os.path.join(efitreedir, "grub.efi") - dst = os.path.join(efitreedir, "BOOT%s.efi" % (efiarch,)) - shutil.move(src, dst) - src = os.path.join(efitreedir, "grub.conf") - dst = os.path.join(efitreedir, "BOOT%s.conf" % (efiarch,)) - shutil.move(src, dst) - - # copy splash - src = os.path.join(self.conf.treedir, "boot", "grub", "splash.xpm.gz") - shutil.copy2(src, efitreedir) - - # calculate the size of the efi image - cmd = "du -kcs %s | tail -n1 | awk '{print $1}'" % (efitreedir,) - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) - if err: - self.se.info(out) - return False - - size = int(out) + 100 - - efiimage = os.path.join(self.tempdir, "efiboot.img") - if os.path.exists(efiimage): - remove(efiimage) - - cmd = "mkdosfs -n ANACONDA -C %s %s > /dev/null" % (efiimage, size) - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) - if err: - self.se.info(out) - return False - - # mount the efi image - efiimagedir = os.path.join(self.tempdir, "efiboot.img.d") - if os.path.exists(efiimagedir): - remove(efiimagedir) - os.makedirs(efiimagedir) - - cmd = "mount -o loop,shortname=winnt,umask=0777 -t vfat %s %s" % \ - (efiimage, efiimagedir) - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) - if err: - self.se.info(out) - return False - - # copy the files to the efi image - copy(src_root=efitreedir, src_path="*", - dst_root=efiimagedir, dst_path="") - - # unmount the efi image - cmd = "umount %s" % (efiimagedir,) - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) - if err: - self.se.info(out) - - # copy the conf files to the output directory - if not kernelfile and not initrd: - copy(src_root=efitreedir, src_path="*.conf", - dst_root=self.conf.efibootdir, dst_path="") - - return efiimage - - def create_bootdisk(self, efiimage): - cmd = "ls -l %s | awk '{print $5}'" % (efiimage,) - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) - if err: - self.se.info(out) - return False - - partsize = int(out) - disksize = 17408 + partsize + 17408 - disksize = disksize + (disksize % 512) - - efidiskimg = os.path.join(self.tempdir, "efidisk.img") - if os.path.exists(efidiskimg): - remove(efidiskimg) - touch(efidiskimg) - - cmd = "dd if=/dev/zero of=%s count=1 bs=%s" % (efidiskimg, disksize) - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) - if err: - self.se.info(out) - return False - - cmd = "losetup -v -f %s | awk '{print $4}'" % (efidiskimg,) - self.so.debug(cmd) - err, loop = commands.getstatusoutput(cmd) - if err: - self.se.info(loop) - return False - - cmd = "dmsetup create efiboot --table \"0 %s linear %s 0\"" \ - % (disksize / 512, loop) - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) - if err: - self.se.info(out) - return False - - cmd = "parted --script /dev/mapper/efiboot" \ - " mklabel gpt unit b mkpart '\"EFI System Partition\"'" \ - " fat32 17408 %s set 1 boot on" % (partsize + 17408,) - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) - if err: - self.se.info(out) - return False - - cmd = "dd if=%s of=/dev/mapper/efibootp1" % (efiimage,) - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) - if err: - self.se.info(out) - return False - - cmd = "dmsetup remove /dev/mapper/efibootp1" - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) - if err: - self.se.info(out) - return False - - cmd = "dmsetup remove /dev/mapper/efiboot" - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) - if err: - self.se.info(out) - return False - - cmd = "losetup -d %s" % loop - self.so.debug(cmd) - err, out = commands.getstatusoutput(cmd) - if err: - self.se.info(out) - return False - - return efidiskimg - - def run(self, kernelfile=None, initrd=None, kernelpath=None, initrdpath=None): - self.so.info("Creating the EFI image file") - efiimage = self.create(kernelfile, initrd) - - if not efiimage: - sys.exit(1) - - self.so.info("Creating the boot disk") - bootdisk = self.create_bootdisk(efiimage) - - if not bootdisk: - sys.exit(1) - - # copy the boot disk file to the output directory - dst = os.path.join(self.conf.imagesdir, "efidisk.img") - shutil.copy2(bootdisk, dst) - - self.so.info("Creating the second EFI image file") - efiimage = self.create(kernelpath=kernelpath, initrdpath=initrdpath) - - # copy the efi image to the output directory - dst = os.path.join(self.conf.imagesdir, "efiboot.img") - shutil.copy2(efiimage, dst) diff --git a/src/pylorax/install.py b/src/pylorax/install.py new file mode 100644 index 00000000..e17b8a8b --- /dev/null +++ b/src/pylorax/install.py @@ -0,0 +1,479 @@ +# +# install.py +# + +import os +import shutil +import glob +import fnmatch +import re +import commands +import pwd +import grp +import stat + +import config +import output +import lcs +import utils + + +class InstallImage(object): + + def __init__(self): + self.conf = config.LoraxConfig.get() + self.paths = config.LoraxPaths.get() + self.output = output.Terminal.get() + + self.actions = self.get_actions_from_template() + + def get_actions_from_template(self): + variables = { "instroot" : self.conf.installtree } + + if self.conf.scrubs_template is not None: + template = lcs.TemplateParser(variables) + return template.get_actions(self.conf.scrubs_template) + + return [] + + def move_shared_files(self): + dirs = [os.path.join(self.paths.INSTALLTREE_DATADIR, "noarch"), + os.path.join(self.paths.INSTALLTREE_DATADIR, self.conf.arch)] + + self.output.info(":: copying the custom install tree files") + for dir in [dir for dir in dirs if os.path.isdir(dir)]: + utils.scopy(src_root=dir, src_path="*", + dst_root=self.conf.installtree, dst_path="") + + def process_actions(self): + for action in self.actions: + action.execute() + + # XXX why do we need this? + def copy_stubs(self): + for file in ("raidstart", "raidstop", "losetup", "list-harddrives", + "loadkeys", "mknod", "syslogd"): + + src = os.path.join(self.conf.installtree, "usr", "lib", "anaconda", + "%s-stub" % file) + dst = os.path.join(self.conf.installtree, "usr", "bin", file) + shutil.copy2(src, dst) + + def configure_fedorakmod(self): + utils.replace(self.paths.FEDORAKMODCONF, + r"installforallkernels = 0", r"installforallkernels = 1") + + # XXX why do we need this? + def copy_bootloaders(self): + if self.conf.arch in ("i386", "i586", "x86_64"): + for f in glob.glob(os.path.join(self.paths.BOOTDIR, "memtest*")): + shutil.copy2(f, self.paths.ANACONDA_BOOT) + + elif self.conf.arch == "sparc": + for f in glob.glob(os.path.join(self.paths.BOOTDIR, "*.b")): + shutil.copy2(f, self.paths.ANACONDA_BOOT) + + elif self.conf.arch in ("ppc", "ppc64"): + f = os.path.join(self.paths.BOOTDIR, "efika.forth") + shutil.copy2(f, self.paths.ANACONDA_BOOT) + + # XXX alpha stuff should not be needed anymore + #elif self.conf.arch == "alpha": + # f = os.path.join(self.paths.BOOTDIR, "bootlx") + # shutil.copy2(f, self.paths.ANACONDA_BOOT) + + elif self.conf.arch == "ia64": + utils.scopy(src_root=self.paths.BOOTDIR_IA64, src_path="*", + dst_root=self.paths.ANACONDA_BOOT, dst_dir="") + + # XXX why do we need this? + def move_repos(self): + src = os.path.join(self.conf.installtree, "etc", "yum.repos.d") + dst = os.path.join(self.conf.installtree, "etc", "anaconda.repos.d") + shutil.move(src, dst) + + # XXX why do we need this? + def move_anaconda_files(self): + # move anaconda executable + src = os.path.join(self.conf.installtree, "usr", "sbin", "anaconda") + dst = os.path.join(self.conf.installtree, "usr", "bin", "anaconda") + shutil.move(src, dst) + + # move anaconda libraries + dstdir = os.path.join(self.conf.installtree, "usr", self.conf.libdir) + utils.scopy(src_root=self.paths.ANACONDA_RUNTIME, src_path="lib*", + dst_root=dstdir, dst_path="") + + utils.remove(os.path.join(self.paths.ANACONDA_RUNTIME, "lib*")) + + # XXX this saves 40 MB + def create_modules_symlinks(self): + utils.mkdir(os.path.join(self.conf.installtree, "modules")) + utils.mkdir(os.path.join(self.conf.installtree, "firmware")) + + utils.remove(os.path.join(self.conf.installtree, "lib", "modules")) + utils.remove(os.path.join(self.conf.installtree, "lib", "firmware")) + + utils.symlink("/modules", + os.path.join(self.conf.installtree, "lib", "modules")) + utils.symlink("/firmware", + os.path.join(self.conf.installtree, "lib", "firmware")) + + # XXX why do we need this? + def fix_man_pages(self): + # fix up some links for man page related stuff + for file in ("nroff", "groff", "iconv", "geqn", "gtbl", "gpic", + "grefer"): + + target = os.path.join("/mnt/sysimage/usr/bin", file) + name = os.path.join(self.conf.installtree, "usr", "bin", file) + + if not os.path.isfile(name): + utils.symlink(target, name) + + # fix /etc/man.config to point into /mnt/sysimage + utils.replace(self.paths.MANCONFIG, r"^MANPATH\s+(\S+)", + "MANPATH\t/mnt/sysimage\g<1>") + utils.replace(self.paths.MANCONFIG, r"^MANPATH_MAP\s+(\S+)\s+(\S+)", + "MANPATH_MAP\t\g<1>\t/mnt/sysimage\g<2>") + + # XXX this saves 2 MB + def remove_gtk_stuff(self): + # figure out the gtk+ theme to keep + gtkrc = os.path.join(self.conf.installtree, "etc", "gtk-2.0", "gtkrc") + + gtk_theme_name = None + gtk_engine = None + gtk_icon_themes = [] + + if os.path.isfile(gtkrc): + f = open(gtkrc, "r") + lines = f.readlines() + f.close() + + for line in lines: + line = line.strip() + if line.startswith("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.conf.installtree, "usr", "share", + "themes", gtk_theme_name, "gtk-2.0", "gtkrc") + if os.path.isfile(gtkrc): + f = open(gtkrc, "r") + engine_lines = f.readlines() + f.close() + + for engine_l in engine_lines: + engine_l = engine_l.strip() + if engine_l.find("engine") != -1: + gtk_engine = engine_l[engine_l.find('"') + 1:] + gtk_engine = gtk_engine.replace('"', "").strip() + break + + elif line.startswith("gtk-icon-theme-name"): + 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.conf.installtree, + "usr", "share", "icons", icon_theme, + "index.theme") + + if os.path.isfile(icon_theme_index): + inherits = False + f = open(icon_theme_index, "r") + icon_lines = f.readlines() + f.close() + + for icon_l in icon_lines: + icon_l = icon_l.strip() + if icon_l.startswith("Inherits="): + inherits = True + icon_theme = icon_l[icon_l.find("=") + 1:] + icon_theme = \ + icon_theme.replace('"', "").strip() + + gtk_icon_themes.append(icon_theme) + break + + if not inherits: + break + else: + break + + # remove themes we don't need + theme_path = os.path.join(self.conf.installtree, "usr", "share", + "themes") + + if os.path.isdir(theme_path): + 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.conf.installtree, "usr", "share", + "icons") + + if os.path.isdir(icon_path): + 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) + + # remove engines we don't need + tmp_path = os.path.join(self.conf.installtree, "usr", + self.conf.libdir, "gtk-2.0") + + if os.path.isdir(tmp_path): + 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 e: e.find(gtk_engine) == -1, + os.listdir(dir)) + for engine in engines: + engine = os.path.join(dir, engine) + os.unlink(engine) + + # XXX this saves 5 MB + def remove_locales(self): + if os.path.isfile(self.paths.LANGTABLE): + keep = set() + + with open(self.paths.LANGTABLE, "r") as f: + lines = f.readlines() + + for line in lines: + line = line.strip() + if not line or line.startswith("#"): + continue + + fields = line.split("\t") + + dir = os.path.join(self.paths.LOCALEPATH, fields[1]) + if os.path.isdir(dir): + keep.add(fields[1]) + + locale = fields[3].split(".")[0] + dir = os.path.join(self.paths.LOCALEPATH, locale) + if os.path.isdir(dir): + keep.add(locale) + + for locale in os.listdir(self.paths.LOCALEPATH): + if locale not in keep: + path = os.path.join(self.paths.LOCALEPATH, locale) + utils.remove(path) + + # XXX this saves 5 MB + def remove_unnecessary_files(self): + for root, dirs, files in os.walk(self.conf.installtree): + for file in files: + path = os.path.join(root, file) + + if fnmatch.fnmatch(path, "*.a"): + if path.find("kernel-wrapper/wrapper.a") == -1: + os.unlink(path) + + if fnmatch.fnmatch(path, "lib*.la"): + if path.find("usr/" + self.conf.libdir + "/gtk-2.0") == -1: + os.unlink(path) + + if fnmatch.fnmatch(path, "*.py"): + if os.path.isfile(path + "o"): + os.unlink(path + "o") + if os.path.isfile(path + "c"): + os.unlink(path + "c") + + utils.symlink("/dev/null", path + "c") + + # remove libunicode-lite + utils.remove(os.path.join(self.conf.installtree, "usr", + self.conf.libdir, "libunicode-lite*")) + + # XXX this saves 1 MB + def remove_python_stuff(self): + for fname in ("bsddb", "compiler", "curses", "distutils", "email", + "encodings", "hotshot", "idlelib", "test", + "doctest.py", "pydoc.py"): + + utils.remove(os.path.join(self.conf.installtree, "usr", + self.conf.libdir, "python?.?", fname)) + + # XXX the udev package should get fixed, + # but for now, we have to fix it ourselves, otherwise we get an error + def fix_udev_links(self): + # these links are broken by default (at least on i386) + for filename in ("udevcontrol", "udevsettle", "udevtrigger"): + filename = os.path.join(self.conf.installtree, "sbin", filename) + if os.path.islink(filename): + os.unlink(filename) + os.symlink("udevadm", filename) + + def move_bins(self): + # move bin to usr/bin + utils.scopy(src_root=self.conf.installtree, + src_path=os.path.join("bin", "*"), + dst_root=self.conf.installtree, + dst_path=os.path.join("usr", "bin")) + utils.remove(os.path.join(self.conf.installtree, "bin")) + + # move sbin to /usr/sbin + utils.scopy(src_root=self.conf.installtree, + src_path=os.path.join("sbin", "*"), + dst_root=self.conf.installtree, + dst_path=os.path.join("usr", "sbin")) + utils.remove(os.path.join(self.conf.installtree, "sbin")) + + # fix broken links + brokenlinks = [] + for dir in ("bin", "sbin"): + dir = os.path.join(self.conf.installtree, "usr", dir) + for root, dnames, fnames in os.walk(dir): + for fname in fnames: + fname = os.path.join(root, fname) + if os.path.islink(fname) and not os.path.exists(fname): + brokenlinks.append(fname) + + for link in brokenlinks: + target = os.readlink(link) + newtarget = re.sub(r"^\.\./\.\./(bin|sbin)/(.*)$", + r"../\g<1>/\g<2>", target) + + if newtarget != target: + os.unlink(link) + utils.symlink(newtarget, link) + + def create_ld_so_conf(self): + ldsoconf = os.path.join(self.conf.installtree, "etc", "ld.so.conf") + utils.touch(ldsoconf) + + procdir = os.path.join(self.conf.installtree, "proc") + if not os.path.isdir(procdir): + utils.mkdir(procdir) + + cmd = "mount -t proc proc %s" % procdir + err, output = commands.getstatusoutput(cmd) + + with open(ldsoconf, "w") as f: + f.write("/usr/kerberos/%s\n" % self.conf.libdir) + + cwd = os.getcwd() + os.chdir(self.conf.installtree) + + # XXX os.chroot does not support exiting from the root + cmd = "/usr/sbin/chroot %s /sbin/ldconfig" % self.conf.installtree + err, output = commands.getstatusoutput(cmd) + + os.chdir(cwd) + + cmd = "umount %s" % procdir + err, output = commands.getstatusoutput(cmd) + + os.unlink(ldsoconf) + + def change_tree_permissions(self): + root_uid = pwd.getpwnam("root")[2] + root_gid = grp.getgrnam("root")[2] + + for root, dirs, files in os.walk(self.conf.installtree): + os.chown(root, root_uid, root_gid) + os.chmod(root, 0755) + + for file in files: + # skip broken symlinks + if not os.path.exists(file): + continue + + 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 prepare(self): + # copy the .buildstamp + shutil.copy2(self.conf.buildstamp, self.conf.installtree) + + self.move_shared_files() + self.process_actions() + + self.copy_stubs() + self.configure_fedorakmod() + self.copy_bootloaders() + self.move_repos() + self.move_anaconda_files() + self.create_modules_symlinks() + self.fix_man_pages() + self.remove_gtk_stuff() + self.remove_locales() + self.remove_unnecessary_files() + self.remove_python_stuff() + self.fix_udev_links() + self.move_bins() + + self.create_ld_so_conf() + self.change_tree_permissions() + + def create(self, type="squashfs"): + self.prepare() + + installimg = os.path.join(self.conf.tempdir, "install.img") + + if os.path.exists(installimg): + os.unlink(installimg) + + self.output.info(":: compressing the image file") + + if type == "squashfs": + if not os.path.exists(self.paths.MKSQUASHFS): + self.output.error("'%s' does not exist" % self.paths.MKSQUASHFS) + return None + + cmd = "%s %s %s -all-root -no-fragments -no-progress" % \ + (self.paths.MKSQUASHFS, self.conf.installtree, installimg) + + err, output = commands.getstatusoutput(cmd) + if err: + self.output.error(output) + return None + + elif type == "cramfs": + if not os.path.exists(self.paths.MKCRAMFS): + self.output.error("'%s' does not exist" % self.paths.MKCRAMFS) + return None + + crambs = "" + if self.conf.arch == "sparc64": + crambs = "--blocksize 8192" + elif self.conf.arch == "sparc": + crambs = "--blocksize 4096" + + cmd = "%s %s %s %s" % (self.paths.MKCRAMFS, crambs, + self.conf.installtree, installimg) + + err, output = commands.getstatusoutput(cmd) + if err: + self.output.error(output) + return None + + elif type == "ext2": + # TODO + raise NotImplementedError + + # edit the .treeinfo + text = "[stage2]\nmainimage = images/install.img\n" + utils.edit(self.conf.treeinfo, append=True, text=text) + + return installimg diff --git a/src/pylorax/insttree.py b/src/pylorax/insttree.py deleted file mode 100644 index 1ca9ba45..00000000 --- a/src/pylorax/insttree.py +++ /dev/null @@ -1,551 +0,0 @@ -# -# instroot.py -# install root class -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): Martin Gracik -# - -import os -import glob -import fnmatch -import shutil -import re - -from utils.fileutils import copy, move, remove, replace, touch - -import actions -import actions.base -from template import Template - - -class InstallTree(object): - - def __init__(self, config, yum, output): - self.conf = config - self.yum = yum - - self.so, self.se = output - - def get_packages(self): - required = ["anaconda", "anaconda-runtime", "/etc/gtk-2.0/gtkrc"] - - # kernel packages - required.extend(["kernel", "*firmware*"]) - - # add the XEN kernel package - if self.conf.buildarch == "i386": - required.append("kernel-PAE") - - # add the jensen kernel package - if self.conf.buildarch == "alpha": - required.append("kernel-jensen") - - # get additional packages from the configuration files - packages_files = [] - packages_files.append(os.path.join(self.conf.confdir, "packages", - "packages.all")), - packages_files.append(os.path.join(self.conf.confdir, "packages", - "packages.%s" % (self.conf.buildarch,))) - - packages = set() - for file in packages_files: - if os.path.isfile(file): - try: - f = open(file, "r") - except IOError as why: - self.se.error("Unable to read packages configuration:" - " %s" % (why,)) - else: - for line in f.readlines(): - line, sep, comment = line.partition("#") - line = line.strip() - - if not line: - continue - - if line.startswith("-"): - packages.discard(line[1:]) - else: - packages.add(line) - - f.close() - - required.extend(list(packages)) - - # logos - required.extend(["%s-logos" % (self.conf.product.lower(),), - "%s-release" % (self.conf.product.lower(),)]) - - return required - - def add_packages(self, packages): - for package in packages: - ok = self.yum.add_package(package) - if not ok: - self.se.warning("No package '%s' available" (package,)) - - def install_packages(self): - # XXX why do we need this? - os.symlink(os.path.join("/", "tmp"), - os.path.join(self.conf.treedir, "var", "lib", "xkb")) - - self.yum.install() - - def copy_updates(self): - if self.conf.updates and os.path.isdir(self.conf.updates): - copy(src_root=self.conf.updates, src_path="*", - dst_root=self.conf.treedir, dst_path="") - - self.conf.delAttr("updates") - - def fix_udev_links(self): - # these links are broken by default (at least on i386) - for filename in ("udevcontrol", "udevsettle", "udevtrigger"): - filename = os.path.join(self.conf.treedir, "sbin", filename) - if os.path.islink(filename): - os.unlink(filename) - os.symlink("udevadm", filename) - - def remove_modules_broken_links(self): - # remove build and source links from modules directories - build = os.path.join(self.conf.treedir, "lib", "modules", "*", "build") - build_files = glob.glob(build) - - source = os.path.join(self.conf.treedir, "lib", "modules", "*", "source") - source_files = glob.glob(source) - - [os.unlink(filename) for filename in build_files + source_files - if os.path.islink(filename)] - - def get_kernelfiles(self): - kerneldir = os.path.join(self.conf.treedir, "boot") - - if self.conf.buildarch == "ia64": - kerneldir = os.path.join(kerneldir, "efi", "EFI", "redhat") - - return glob.glob(os.path.join(kerneldir, "vmlinuz-*")) - - def run(self): - self.so.info("Getting the list of packages") - packages = self.get_packages() - - self.so.info("Running yum") - self.add_packages(packages) - self.install_packages() - - self.so.info("Copying the updates") - self.copy_updates() - - self.so.info("Fixing udev links") - self.fix_udev_links() - - self.so.info("Removing build and source links in modules directories") - self.remove_modules_broken_links() - - return self.get_kernelfiles() - - - #################### - ### tree scrubs - - def copy_stubs(self): - for file in ("raidstart", "raidstop", "losetup", "list-harddrives", - "loadkeys", "mknod", "syslogd"): - - src = os.path.join(self.conf.treedir, "usr", "lib", "anaconda", - "%s-stub" % (file,)) - dst = os.path.join(self.conf.treedir, "usr", "bin", file) - - shutil.copy2(src, dst) - - def create_dogtail_conf(self): - dogtailconf = os.path.join(self.conf.datadir, "dogtail", "%gconf.xml") - - if os.path.isfile(dogtailconf): - dst = os.path.join(self.conf.treedir, ".gconf", "desktop", "gnome", - "interface") - - os.makedirs(dst) - shutil.copy2(dogtailconf, dst) - - touch(os.path.join(self.conf.treedir, ".gconf", "desktop", - "%gconf.xml")) - touch(os.path.join(self.conf.treedir, ".gconf", "desktop", "gnome", - "%gconf.xml")) - - def create_libuser_conf(self): - src = os.path.join(self.conf.datadir, "libuser", "libuser.conf") - dst = os.path.join(self.conf.treedir, "etc", "libuser.conf") - shutil.copy2(src, dst) - - def create_selinux_conf(self): - if os.path.exists(os.path.join(self.conf.treedir, "etc", "selinux", - "targeted")): - - src = os.path.join(self.conf.datadir, "selinux", "config") - dst = os.path.join(self.conf.treedir, "etc", "selinux", "config") - shutil.copy2(src, dst) - - def configure_fedorakmod(self): - fedorakmodconf = os.path.join(self.conf.treedir, "etc", "yum", - "pluginconf.d", "fedorakmod.conf") - - replace(fedorakmodconf, r"\(installforallkernels\) = 0", r"\1 = 1") - - def copy_bootloaders(self): - bootpath = os.path.join(self.conf.treedir, "usr", "lib", - "anaconda-runtime", "boot") - - if not os.path.isdir(bootpath): - os.makedirs(bootpath) - - if self.conf.buildarch in ("i386", "i586", "x86_64"): - for file in os.listdir(os.path.join(self.conf.treedir, "boot")): - if file.startswith("memtest"): - src = os.path.join(self.conf.treedir, "boot", file) - dst = os.path.join(bootpath, file) - shutil.copy2(src, dst) - elif self.conf.buildarch == "sparc": - for file in os.listdir(os.path.join(self.conf.treedir, "boot")): - if file.endswith(".b"): - src = os.path.join(self.conf.treedir, "boot", file) - dst = os.path.join(bootpath, file) - shutil.copy2(src, dst) - elif self.conf.buildarch in ("ppc", "ppc64"): - src = os.path.join(self.conf.treedir, "boot", "efika.forth") - shutil.copy2(src, bootpath) - elif self.conf.buildarch == "alpha": - src = os.path.join(self.conf.treedir, "boot", "bootlx") - shutil.copy2(src, bootpath) - elif self.conf.buildarch == "ia64": - srcdir = os.path.join(self.conf.treedir, "boot", "efi", "EFI", "redhat") - copy(src_root=srcdir, src_path="*", - dst_root=bootpath, dst_dir="") - - def move_repos(self): - src = os.path.join(self.conf.treedir, "etc", "yum.repos.d") - dst = os.path.join(self.conf.treedir, "etc", "anaconda.repos.d") - shutil.move(src, dst) - - def move_anaconda_files(self): - # move anaconda executable - src = os.path.join(self.conf.treedir, "usr", "sbin", "anaconda") - dst = os.path.join(self.conf.treedir, "usr", "bin", "anaconda") - shutil.move(src, dst) - - # move anaconda libraries - srcdir = os.path.join(self.conf.treedir, "usr", "lib", "anaconda-runtime") - dst = os.path.join(self.conf.treedir, "usr", self.conf.libdir) - move(src_root=srcdir, src_path="lib*", - dst_root=dst, dst_path="") - - def create_debug_directories(self): - os.makedirs(os.path.join(self.conf.treedir, "usr", "lib", "debug")) - os.makedirs(os.path.join(self.conf.treedir, "usr", "src", "debug")) - - def create_modules_symlinks(self): - os.makedirs(os.path.join(self.conf.treedir, "modules")) - os.makedirs(os.path.join(self.conf.treedir, "firmware")) - - # XXX are we sure we want to do this? - remove(os.path.join(self.conf.treedir, "lib", "modules")) - remove(os.path.join(self.conf.treedir, "lib", "firmware")) - os.symlink("/modules", os.path.join(self.conf.treedir, "lib", "modules")) - os.symlink("/firmware", os.path.join(self.conf.treedir, "lib", "firmware")) - - def fix_joe_links(self): - joedir = os.path.join(self.conf.treedir, "etc", "joe") - - if os.path.isdir(joedir): - os.symlink("jpicorc", os.path.join(joedir, "picorc")) - os.symlink("jpicorc", os.path.join(joedir, "jnanorc")) - os.symlink("jpicorc", os.path.join(joedir, "nanorc")) - os.symlink("jmacsrc", os.path.join(joedir, "emacsrc")) - os.symlink("jmacs", os.path.join(self.conf.treedir, "usr", "bin", - "emacs")) - os.symlink("jpico", os.path.join(self.conf.treedir, "usr", "bin", - "pico")) - os.symlink("jpico", os.path.join(self.conf.treedir, "usr", "bin", - "nano")) - - def fix_man_pages(self): - # fix up some links for man page related stuff - for file in ["nroff", "groff", "iconv", "geqn", "gtbl", "gpic", "grefer"]: - src = os.path.join("mnt", "sysimage", "usr", "bin", file) - dst = os.path.join(self.conf.treedir, "usr", "bin", file) - if not os.path.isfile(dst): - os.symlink(src, dst) - - # fix /etc/man.config to point into /mnt/sysimage - manconfig = os.path.join(self.conf.treedir, "etc", "man.config") - - # don't change MANPATH_MAP lines now - replace(manconfig, r"^MANPATH[^_MAP][ \t]*", r"&/mnt/sysimage") - # change MANPATH_MAP lines now - replace(manconfig, r"^MANPATH_MAP[ \t]*[a-zA-Z0-9/]*[ \t]*", - r"&/mnt/sysimage") - - def remove_gtk_stuff(self): - # figure out the gtk+ theme to keep - gtkrc = os.path.join(self.conf.treedir, "etc", "gtk-2.0", "gtkrc") - - gtk_theme_name = None - gtk_engine = None - gtk_icon_themes = [] - - if os.path.isfile(gtkrc): - f = open(gtkrc, "r") - lines = f.readlines() - f.close() - - for line in lines: - line = line.strip() - if line.startswith("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.conf.treedir, "usr", "share", - "themes", gtk_theme_name, "gtk-2.0", "gtkrc") - if os.path.isfile(gtkrc): - f = open(gtkrc, "r") - engine_lines = f.readlines() - f.close() - - 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:] - gtk_engine = gtk_engine.replace('"', "").strip() - break - - elif line.startswith("gtk-icon-theme-name"): - 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.conf.treedir, "usr", - "share", "icons", icon_theme, "index.theme") - if os.path.isfile(icon_theme_index): - inherits = False - f = open(icon_theme_index, "r") - icon_lines = f.readlines() - f.close() - - for icon_line in icon_lines: - icon_line = icon_line.strip() - if icon_line.startswith("Inherits="): - inherits = True - icon_theme = icon_line[icon_line.find("=") + 1:] - icon_theme = icon_theme.replace('"', "").strip() - gtk_icon_themes.append(icon_theme) - break - - if not inherits: - break - else: - break - - # remove themes we don't need - theme_path = os.path.join(self.conf.treedir, "usr", "share", "themes") - if os.path.isdir(theme_path): - 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.conf.treedir, "usr", "share", "icons") - if os.path.isdir(icon_path): - 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) - - # remove engines we don't need - tmp_path = os.path.join(self.conf.treedir, "usr", self.conf.libdir, - "gtk-2.0") - if os.path.isdir(tmp_path): - 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) - - def remove_locales(self): - langtable = os.path.join(self.conf.treedir, "usr", "lib", "anaconda", - "lang-table") - localepath = os.path.join(self.conf.treedir, "usr", "share", "locale") - - if os.path.isfile(langtable): - locales = set() - all_locales = set() - - f = open(langtable, "r") - lines = f.readlines() - f.close() - - for line in lines: - line = line.strip() - if not line or line.startswith("#"): - continue - - fields = line.split("\t") - - if os.path.isdir(os.path.join(localepath, fields[1])): - locales.add(fields[1]) - - locale = fields[3].split(".")[0] - if os.path.isdir(os.path.join(localepath, locale)): - locales.add(locale) - - for locale in os.listdir(localepath): - all_locales.add(locale) - - locales_to_remove = list(all_locales.difference(locales)) - for locale in locales_to_remove: - rmpath = os.path.join(localepath, locale) - shutil.rmtree(rmpath, ignore_errors=True) - - def remove_unnecessary_files(self): - to_remove = set() - - for root, dirs, files in os.walk(self.conf.treedir): - 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.add(path) - elif fnmatch.fnmatch(path, "lib*.la"): - if path.find("usr/" + self.conf.libdir + "/gtk-2.0") == -1: - to_remove.add(path) - elif fnmatch.fnmatch(path, "*.py"): - to_remove.add(path + "o") - - try: - os.unlink(path + "c") - except OSError: - pass - - os.symlink("/dev/null", path + "c") - - for file in to_remove: - try: - os.unlink(file) - except OSError: - pass - - # remove libunicode-lite - remove(os.path.join(self.conf.treedir, "usr", self.conf.libdir, - "libunicode-lite*")) - - def remove_python_stuff(self): - for fname in ["bsddb", "compiler", "curses", "distutils", "email", - "encodings", "hotshot", "idlelib", "test", - "doctest.py", "pydoc.py"]: - - remove(os.path.join(self.conf.treedir, "usr", self.conf.libdir, - "python?.?", fname)) - - def move_bins(self): - # move bin to usr/bin - move(src_root=self.conf.treedir, - src_path=os.path.join("bin", "*"), - dst_root=self.conf.treedir, - dst_path=os.path.join("usr", "bin")) - remove(os.path.join(self.conf.treedir, "bin")) - - # move sbin to /usr/sbin - copy(src_root=self.conf.treedir, - src_path=os.path.join("sbin", "*"), - dst_root=self.conf.treedir, - dst_path=os.path.join("usr", "sbin")) - remove(os.path.join(self.conf.treedir, "sbin")) - - # fix broken links - brokenlinks = [] - for dir in ("bin", "sbin"): - dir = os.path.join(self.conf.treedir, "usr", dir) - for root, dnames, fnames in os.walk(dir): - for fname in fnames: - fname = os.path.join(root, fname) - if os.path.islink(fname) and not os.path.exists(fname): - brokenlinks.append(fname) - - for link in brokenlinks: - target = os.readlink(link) - newtarget = re.sub(r"^\.\./\.\./(bin|sbin)/(.*)$", "../\g<1>/\g<2>", - target) - - if newtarget != target: - os.unlink(link) - os.symlink(newtarget, link) - - def process_scrubs_from_template(self): - # get supported actions - supported_actions = actions.getActions(verbose=self.conf.debug) - - # variables supported in templates - vars = { "instroot": self.conf.treedir } - - # parse the template file - scrubs = os.path.join(self.conf.confdir, "tree", - "scrubs.%s" % (self.conf.buildarch,)) - - if os.path.exists(scrubs): - self.template = Template() - self.template.preparse(scrubs) - self.template.parse(supported_actions, vars) - - for action in self.template.actions: - action.execute() - - def scrub(self): - self.copy_stubs() - self.create_dogtail_conf() - self.create_libuser_conf() - self.create_selinux_conf() - self.configure_fedorakmod() - - self.copy_bootloaders() - self.move_repos() - self.move_anaconda_files() - - self.create_debug_directories() - self.create_modules_symlinks() - - self.fix_joe_links() - self.fix_man_pages() - - self.remove_gtk_stuff() - self.remove_locales() - self.remove_unnecessary_files() - self.remove_python_stuff() - - self.move_bins() - - self.process_scrubs_from_template() diff --git a/src/pylorax/launcher.py b/src/pylorax/launcher.py new file mode 100644 index 00000000..5e00bbb4 --- /dev/null +++ b/src/pylorax/launcher.py @@ -0,0 +1,205 @@ +# +# launcher.py +# + +from __future__ import print_function + +import sys +import os +from optparse import OptionParser, OptionGroup +import tempfile +import shutil +import ConfigParser + +import yum + +import pylorax + + +def main(args): + version = "%s %s" % (os.path.basename(args[0]), pylorax.__VERSION__) + usage = "%prog -p PRODUCT -v VERSION -r RELEASE -o OUTPUTDIR REPOSITORY" + + parser = OptionParser(usage=usage) + + # required arguments for image creation + required = OptionGroup(parser, "required arguments") + required.add_option("-p", "--product", help="product name", + metavar="STRING") + required.add_option("-v", "--version", help="version identifier", + metavar="STRING") + required.add_option("-r", "--release", help="release information", + metavar="STRING") + required.add_option("-o", "--outputdir", help="output directory", + metavar="PATHSPEC") + + # optional arguments + optional = OptionGroup(parser, "optional arguments") + optional.add_option("-m", "--mirrorlist", + help="mirrorlist repository (may be listed multiple times)", + metavar="REPOSITORY", action="append", default=[]) + optional.add_option("-t", "--variant", + help="variant name", metavar="STRING") + optional.add_option("-b", "--bugurl", + help="bug reporting URL for the product", metavar="URL", + default="your distribution provided bug reporting tool") + optional.add_option("-u", "--updates", + help="directory containing updates", metavar="PATHSPEC") + + # output settings + output = OptionGroup(parser, "output settings") + output.add_option("--no-colors", help="disable color output", + action="store_false", default=True, dest="colors") + output.add_option("--encoding", help="set encoding", + metavar="STRING", default="utf-8") + output.add_option("-d", "--debug", help="enable debugging messages", + action="store_true", default=False) + + # lorax settings + settings = OptionGroup(parser, "lorax settings") + settings.add_option("-c", "--cleanup", help="clean up on exit", + action="store_true", default=False) + + # add the option groups to the parser + parser.add_option_group(required) + parser.add_option_group(optional) + parser.add_option_group(output) + parser.add_option_group(settings) + + # add the show version option + parser.add_option("-V", help="show program's version number and exit", + action="store_true", default=False, dest="showver") + + # parse the arguments + opts, args = parser.parse_args() + repositories = args + + if opts.showver: + print(version) + sys.exit(0) + + # check for the required arguments + if not opts.product or not opts.version or not opts.release \ + or not opts.outputdir or not repositories: + parser.error("missing one or more required arguments") + + # create the temporary directory for lorax + tempdir = tempfile.mkdtemp(prefix="lorax.", dir=tempfile.gettempdir()) + + # create the yumbase object + installtree = os.path.join(tempdir, "installtree") + os.mkdir(installtree) + + yumtempdir = os.path.join(tempdir, "yum") + os.mkdir(yumtempdir) + + yumconf = create_yumconf(repositories, opts.mirrorlist, yumtempdir) + yb = create_yumbase_object(yumconf, installtree) + + if yb is None: + print("error: unable to create the yumbase object", file=sys.stderr) + shutil.rmtree(tempdir) + sys.exit(1) + + # run lorax + params = { "product" : opts.product, + "version" : opts.version, + "release" : opts.release, + "outputdir" : opts.outputdir, + "tempdir" : tempdir, + "installtree" : installtree, + "colors" : opts.colors, + "encoding" : opts.encoding, + "debug" : opts.debug, + "cleanup" : opts.cleanup, + "variant" : opts.variant, + "bugurl" : opts.bugurl, + "updates" : opts.updates } + + lorax = pylorax.Lorax(yb, **params) + lorax.run() + + +def create_yumconf(repositories, mirrorlists=[], tempdir="/tmp/yum"): + + def sanitize_repo(repo): + if repo.startswith("/"): + return "file://%s" % repo + elif repo.startswith("http://") or repo.startswith("ftp://"): + return repo + else: + return None + + # sanitize the repositories + repositories = map(sanitize_repo, repositories) + + # remove invalid repositories + repositories = filter(bool, repositories) + + cachedir = os.path.join(tempdir, "cache") + if not os.path.isdir(cachedir): + os.mkdir(cachedir) + + yumconf = os.path.join(tempdir, "yum.conf") + c = ConfigParser.ConfigParser() + + # add the main section + section = "main" + data = { "cachedir" : cachedir, + "keepcache" : 0, + "gpgcheck" : 0, + "plugins" : 0, + "reposdir" : "", + "tsflags" : "nodocs" } + + c.add_section(section) + map(lambda (key, value): c.set(section, key, value), data.items()) + + # add the main repository - the first repository from list + section = "lorax-repo" + data = { "name" : "lorax repo", + "baseurl" : repositories[0], + "enabled" : 1 } + + c.add_section(section) + map(lambda (key, value): c.set(section, key, value), data.items()) + + # add the extra repositories + for n, extra in enumerate(repositories[1:], start=1): + section = "lorax-extra-repo-%d" % n + data = { "name" : "lorax extra repo %d" % n, + "baseurl" : extra, + "enabled" : 1 } + + c.add_section(section) + map(lambda (key, value): c.set(section, key, value), data.items()) + + # add the mirrorlists + for n, mirror in enumerate(mirrorlists, start=1): + section = "lorax-mirrorlist-%d" % n + data = { "name" : "lorax mirrorlist %d" % n, + "mirrorlist" : mirror, + "enabled" : 1 } + + c.add_section(section) + map(lambda (key, value): c.set(section, key, value), data.items()) + + # write the yumconf file + with open(yumconf, "w") as f: + c.write(f) + + return yumconf + + +def create_yumbase_object(yumconf, installroot="/"): + yb = yum.YumBase() + + yb.preconf.fn = yumconf + yb.preconf.root = installroot + yb._getConfig() + + yb._getRpmDB() + yb._getRepos() + yb._getSacks() + + return yb diff --git a/src/pylorax/lcs/__init__.py b/src/pylorax/lcs/__init__.py new file mode 100644 index 00000000..7388121a --- /dev/null +++ b/src/pylorax/lcs/__init__.py @@ -0,0 +1,58 @@ +# +# __init__.py +# + +import sys +import os +import re + +from mako.template import Template as MakoTemplate +from mako.lookup import TemplateLookup as MakoTemplateLookup + +import actions + + +class TemplateParserError(Exception): + pass + + +class TemplateParser(object): + + def __init__(self, variables): + self.variables = variables + self.actions_map = actions.get_map() + + def get_actions(self, file): + template_actions = [] + + # we have to set the template lookup directories to ["/"], + # otherwise the relative and absolute includes don't work properly + lookup = MakoTemplateLookup(directories=["/"]) + template = MakoTemplate(filename=file, lookup=lookup) + s = template.render(**self.variables) + + # concatenate lines ending with "\" + #s = re.sub(r"\s*\\\s*\n", " ", s) + + for lineno, line in enumerate(s.splitlines(), start=1): + # remove multiple whitespaces + line = re.sub(r"\s+", " ", line.strip()) + if not line: + continue + + # get the command + command, line = line.split(None, 1) + if command not in self.actions_map: + raise TemplateParserError("%s: %d: invalid command" % \ + (file, lineno)) + + # create the action object + m = re.match(self.actions_map[command].REGEX, line) + if m: + new_action = self.actions_map[command](**m.groupdict()) + template_actions.append(new_action) + else: + raise TemplateParserError("%s: %d: invalid command format" % \ + (file, lineno)) + + return template_actions diff --git a/src/pylorax/lcs/actions/__init__.py b/src/pylorax/lcs/actions/__init__.py new file mode 100644 index 00000000..1958643e --- /dev/null +++ b/src/pylorax/lcs/actions/__init__.py @@ -0,0 +1,31 @@ +# +# __init__.py +# + +import sys +import os + + +def get_map(): + actions = {} + + root, actions_dir = os.path.split(os.path.dirname(__file__)) + + sys.path.insert(0, root) + + modules = set() + for filename in os.listdir(os.path.join(root, actions_dir)): + if filename.endswith(".py") and not filename == "__init__.py": + basename, extension = os.path.splitext(filename) + modules.add(os.path.join(actions_dir, basename).replace("/", ".")) + + for module in modules: + imported = __import__(module, globals(), locals(), [module], -1) + + commands = getattr(imported, "COMMANDS", {}) + for command, classname in commands.items(): + actions[command] = getattr(imported, classname) + + sys.path.pop(0) + + return actions diff --git a/src/pylorax/lcs/actions/base.py b/src/pylorax/lcs/actions/base.py new file mode 100644 index 00000000..f90a6751 --- /dev/null +++ b/src/pylorax/lcs/actions/base.py @@ -0,0 +1,37 @@ +# +# base.py +# + +class LCSAction(object): + """LCS Action base class. + + To create your own custom action, subclass this class, and override + the methods you need. + + A valid action has to have a REGEX class variable, which specifies + the format of the action command, so the needed parameters can be + properly extracted, and an execute() method, where all the work + should be done. This medhod will be called by Lorax. + + Don't forget to include a command : action map for your new action + in the COMMANDS dictionary in the beginning of your file. + Action classes which are not in the COMMANDS dictionary will not + be loaded by Lorax. + + """ + + # regular expression for extracting the parameters from the command + REGEX = r"" + + def __init__(self): + if self.__class__ is LCSAction: + raise TypeError("LCSAction is an abstract class, " \ + "cannot be used this way") + + self._attrs = {} + + def __str__(self): + return "%s: %s" % (self.__class__.__name__, self._attrs) + + def execute(self): + raise NotImplementedError("execute() method not implemented") diff --git a/src/pylorax/lcs/actions/file.py b/src/pylorax/lcs/actions/file.py new file mode 100644 index 00000000..c0591796 --- /dev/null +++ b/src/pylorax/lcs/actions/file.py @@ -0,0 +1,282 @@ +# +# file.py +# + +import os + +from base import LCSAction +import pylorax.utils as utils + + +COMMANDS = { "remove" : "Remove", + "copy" : "Copy", + "symlink" : "SymLink", + "touch" : "Touch", + "mkdir" : "MkDir", + "makedirs" : "MakeDirs", + "chown" : "Chown", + "chmod" : "Chmod", + "edit" : "Edit", + "replace" : "Replace" } + + +class Remove(LCSAction): + + REGEX = r"^(?P.*?)$" + + def __init__(self, **kwargs): + LCSAction.__init__(self) + self._attrs["filename"] = kwargs.get("filename") + + def execute(self): + utils.remove(self.filename) + + @property + def filename(self): + return self._attrs["filename"] + + +# TODO add the ignore_errors flag +class Copy(LCSAction): + + REGEX = r"^(?P.*?)\s(?P.*?)\sto\s" \ + "(?P.*?)\s(?P.*?)" \ + "(\s(?Pnosymlinks))?$" + + def __init__(self, **kwargs): + LCSAction.__init__(self) + self._attrs["src_root"] = kwargs.get("src_root") + self._attrs["src_path"] = kwargs.get("src_path") + self._attrs["dst_root"] = kwargs.get("dst_root") + self._attrs["dst_path"] = kwargs.get("dst_path") + + nosymlinks = kwargs.get("nosymlinks") + if nosymlinks is not None: + self._attrs["symlinks"] = False + else: + self._attrs["symlinks"] = True + + def execute(self): + utils.dcopy(src_root=self.src_root, src_path=self.src_path, + dst_root=self.dst_root, dst_path=self.dst_path, + symlinks=self.symlinks) + + @property + def src(self): + path = os.path.join(self._attrs["src_root"], self._attrs["src_path"]) + return os.path.normpath(path) + + @property + def src_root(self): + return self._attrs["src_root"] + + @property + def src_path(self): + return self._attrs["src_path"] + + @property + def dst(self): + path = os.path.join(self._attrs["dst_root"], self._attrs["dst_path"]) + return os.path.normpath(path) + + @property + def dst_root(self): + return self._attrs["dst_root"] + + @property + def dst_path(self): + return self._attrs["dst_path"] + + @property + def symlinks(self): + return self._attrs["symlinks"] + + +class SymLink(LCSAction): + + REGEX = r"^name\s(?P.*?)\starget\s(?P.*?)$" + + def __init__(self, **kwargs): + LCSAction.__init__(self) + self._attrs["name"] = kwargs.get("name") + self._attrs["target"] = kwargs.get("target") + + def execute(self): + utils.symlink(link_name=self.name, link_target=self.target) + + @property + def name(self): + return self._attrs["name"] + + @property + def target(self): + return self._attrs["target"] + + +class Touch(LCSAction): + + REGEX = r"^(?P.*?)$" + + def __init__(self, **kwargs): + LCSAction.__init__(self) + self._attrs["filename"] = kwargs.get("filename") + + def execute(self): + utils.touch(self.filename) + + @property + def filename(self): + return self._attrs["filename"] + + +class MkDir(LCSAction): + + REGEX = r"^(?P.*?)(\smode\s(?P.*?))?$" + + def __init__(self, **kwargs): + LCSAction.__init__(self) + self._attrs["dir"] = kwargs.get("dir") + + mode = kwargs.get("mode") + if mode is not None: + self._attrs["mode"] = int(mode, 8) + else: + self._attrs["mode"] = None + + def execute(self): + utils.mkdir(self.dir, self.mode) + + @property + def dir(self): + return self._attrs["dir"] + + @property + def mode(self): + return self._attrs["mode"] + + +class MakeDirs(MkDir): + + def __init__(self, **kwargs): + MkDir.__init__(self, **kwargs) + + def execute(self): + utils.makedirs(self.dir, self.mode) + + +class Chown(LCSAction): + + REGEX = r"^(?P.*?)\suser\s(?P.*?)" \ + "\sgroup\s(?P.*?)(\s(?Precursive))?$" + + def __init__(self, **kwargs): + LCSAction.__init__(self) + self._attrs["filename"] = kwargs.get("filename") + self._attrs["user"] = kwargs.get("user") + self._attrs["group"] = kwargs.get("group") + + recursive = kwargs.get("recursive") + if recursive is not None: + self._attrs["recursive"] = True + else: + self._attrs["recursive"] = False + + def execute(self): + utils.chown(self.filename, self.user, self.group, self.recursive) + + @property + def filename(self): + return self._attrs["filename"] + + @property + def user(self): + return self._attrs["user"] + + @property + def group(self): + return self._attrs["group"] + + @property + def recursive(self): + return self._attrs["recursive"] + + +class Chmod(LCSAction): + + REGEX = r"^(?P.*?)\smode\s(?P[0-7]*?)" \ + "(\s(?Precursive))?$" + + def __init__(self, **kwargs): + LCSAction.__init__(self) + self._attrs["filename"] = kwargs.get("filename") + self._attrs["mode"] = int(kwargs.get("mode"), 8) + + recursive = kwargs.get("recursive") + if recursive is not None: + self._attrs["recursive"] = True + else: + self._attrs["recursive"] = False + + def execute(self): + utils.chmod(self.filename, self.mode, self.recursive) + + @property + def filename(self): + return self._attrs["filename"] + + @property + def mode(self): + return self._attrs["mode"] + + @property + def recursive(self): + return self._attrs["recursive"] + + +class Edit(Touch): + + REGEX = r'^(?P.*?)\stext\s"(?P.*?)"' \ + '(\s(?Pappend))?$' + + def __init__(self, **kwargs): + Touch.__init__(self, **kwargs) + self._attrs["text"] = kwargs.get("text") + + append = kwargs.get("append") + if append is not None: + self._attrs["append"] = True + else: + self._attrs["append"] = False + + def execute(self): + utils.edit(self.filename, self.text, self.append) + + @property + def text(self): + return self._attrs["text"] + + @property + def append(self): + return self._attrs["append"] + + +class Replace(Touch): + + REGEX = r'^(?P.*?)\sfind\s"(?P.*?)"' \ + '\sreplace\s"(?P.*?)"$' + + def __init__(self, **kwargs): + Touch.__init__(self, **kwargs) + self._attrs["find"] = kwargs.get("find") + self._attrs["replace"] = kwargs.get("replace") + + def execute(self): + utils.replace(self.filename, self.find, self.replace) + + @property + def find(self): + return self._attrs["find"] + + @property + def replace(self): + return self._attrs["replace"] diff --git a/src/pylorax/lcs/actions/ssh.py b/src/pylorax/lcs/actions/ssh.py new file mode 100644 index 00000000..6e9e617c --- /dev/null +++ b/src/pylorax/lcs/actions/ssh.py @@ -0,0 +1,39 @@ +# +# ssh.py +# + +import commands + +from base import LCSAction +import pylorax.utils as utils + + +COMMANDS = { "gensshkey" : "GenerateSSHKey" } + + +class GenerateSSHKey(LCSAction): + + REGEX = r"^(?P.*?)\stype\s(?P.*?)$" + + def __init__(self, **kwargs): + LCSAction.__init__(self) + self._attrs["filename"] = kwargs.get("filename") + self._attrs["type"] = kwargs.get("type") + + def execute(self): + cmd = "/usr/bin/ssh-keygen -q -t %s -f %s -C '' -N ''" % \ + (self.type, self.filename) + + err, output = commands.getstatusoutput(cmd) + + if not err: + utils.chmod(self.filename, 0600) + utils.chmod(self.filename + ".pub", 0644) + + @property + def filename(self): + return self._attrs["filename"] + + @property + def type(self): + return self._attrs["type"] diff --git a/src/pylorax/misc.py b/src/pylorax/misc.py deleted file mode 100644 index 5a1b4cb4..00000000 --- a/src/pylorax/misc.py +++ /dev/null @@ -1,41 +0,0 @@ -# -# misc.py -# miscellaneous functions -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): Martin Gracik -# - -import commands - - -def seq(arg): - if type(arg) not in (type([]), type(())): - return [arg] - else: - return arg - -def get_console_size(): - err, output = commands.getstatusoutput("stty size") - if not err: - height, width = output.split() - height, width = int(height), int(width) - else: - # set defaults - height, width = 24, 80 - - return height, width diff --git a/src/pylorax/output.py b/src/pylorax/output.py index 06929d4c..bcd154a0 100644 --- a/src/pylorax/output.py +++ b/src/pylorax/output.py @@ -1,35 +1,15 @@ # # output.py -# output control -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): Martin Gracik # import sys +import singleton -# color codes +### color codes C_DEFAULT = "\x1b[39m" C_RESET = "\x1b[0m" -C_BOLD = "\x1b[1m" -C_UNDERLINE = "\x1b[4m" - C_BLACK = "\x1b[0;30m" C_WHITE = "\x1b[1;37m" C_RED = "\x1b[0;31m" @@ -39,53 +19,39 @@ C_LIGHTRED = "\x1b[1;31m" C_LIGHTGREEN = "\x1b[1;32m" C_LIGHTBLUE = "\x1b[1;34m" -# font types +C_BOLD = "\x1b[1m" +C_UNDERLINE = "\x1b[4m" + +### font types BOLD = 0b01 UNDERLINE = 0b10 +### output levels +CRITICAL = 50 +ERROR = 40 +WARNING = 30 +INFO = 20 +DEBUG = 10 +NOTSET = 0 -class OutputError(Exception): - pass -class Output(object): +class Terminal(singleton.Singleton): - def __init__(self, output=sys.stdout, colors=True, encoding="utf-8", - verbose=False): + def __init__(self): + self.__colors = True + self.__encoding = "utf-8" + self.__output_level = INFO + self.__indent_level = 0 - self.output = output - if not hasattr(self.output, "write"): - raise OutputError, "output does not support write()" - - self.is_flushable = hasattr(self.output, "flush") + def basic_config(self, colors=None, encoding=None, level=None): + if colors is not None: + self.__colors = colors - self.colors = colors - self.encoding = encoding - self.verbose = verbose + if encoding is not None: + self.__encoding = encoding - self.__indent_level = 0 - - def write(self, s, color=C_RESET, type=None): - s = self.format(s, color=color, type=type) - self.output.write(s) - - if self.is_flushable: - self.output.flush() - - def format(self, s, color=C_RESET, type=None): - s = s.encode(self.encoding) - - if self.colors: - if type is not None and (type & BOLD): - s = "%s%s" % (C_BOLD, s) - if type is not None and (type & UNDERLINE): - s = "%s%s" % (C_UNDERLINE, s) - s = "%s%s%s" % (color, s, C_RESET) - - return s - - def writeline(self, s, color=C_RESET, type=None): - s = "%s%s\n" % (" " * self.__indent_level, s) - self.write(s, color=color, type=type) + if level is not None: + self.__output_level = level def indent(self): self.__indent_level += 1 @@ -94,31 +60,43 @@ class Output(object): if self.__indent_level > 0: self.__indent_level -= 1 - def newline(self): - self.output.write("\n") + def write(self, s, color=C_RESET, type=None, file=sys.stdout): + s = self.format(s, color=color, type=type) + file.write(s) + file.flush() - def banner(self, s): - self.writeline(s, color=C_GREEN, type=BOLD) + def format(self, s, color=C_RESET, type=None): + s = s.encode(self.__encoding) - def header(self, s): - self.writeline(s, type=BOLD) + if self.__colors: + if type is not None and (type & BOLD): + s = "%s%s" % (C_BOLD, s) + if type is not None and (type & UNDERLINE): + s = "%s%s" % (C_UNDERLINE, s) + s = "%s%s%s" % (color, s, C_RESET) - def info(self, s): - self.writeline(s) + return s - def error(self, s): - self.writeline(s, color=C_RED, type=BOLD) + def writeline(self, s, color=C_RESET, type=None, file=sys.stdout): + s = "%s%s" % (" " * self.__indent_level, s) + self.write(s + "\n", color=color, type=type, file=file) - def warning(self, s): - self.writeline(s, color=C_RED) + def critical(self, s, file=sys.stdout): + if self.__output_level <= CRITICAL: + self.writeline("** critical: %s" % s, file=file) - def debug(self, s): - if self.verbose: - self.writeline(s) + def error(self, s, file=sys.stdout): + if self.__output_level <= ERROR: + self.writeline("** error: %s" % s, file=file) + def warning(self, s, file=sys.stdout): + if self.__output_level <= WARNING: + self.writeline("** warning: %s" % s, file=file) -def initialize(verbose=False): - stdout = Output(output=sys.stdout, verbose=verbose) - stderr = Output(output=sys.stderr, verbose=verbose) - - return stdout, stderr + def info(self, s, file=sys.stdout): + if self.__output_level <= INFO: + self.writeline(s, file=file) + + def debug(self, s, file=sys.stdout): + if self.__output_level <= DEBUG: + self.writeline(s, file=file) diff --git a/src/pylorax/ramdisk.py b/src/pylorax/ramdisk.py new file mode 100644 index 00000000..d86e7f89 --- /dev/null +++ b/src/pylorax/ramdisk.py @@ -0,0 +1,435 @@ +# +# ramdisk.py +# + +import sys +import os +import glob +import shutil +import commands +import re +import gzip + +import config +import output +import lcs +import utils + + +class Ramdisk(object): + + def __init__(self): + # get the config, paths and output objects + self.conf = config.LoraxConfig.get() + self.paths = config.LoraxPaths.get() + self.output = output.Terminal.get() + + self.actions = self.get_actions_from_template() + + def get_actions_from_template(self): + variables = { "instroot" : self.conf.installtree, + "initrd" : self.conf.ramdisktree, + "libdir" : self.conf.libdir, + "arch" : self.conf.arch, + "basearch" : self.conf.basearch, + "confdir" : self.conf.confdir, + "datadir" : self.conf.datadir } + + if self.conf.initrd_template is not None: + template = lcs.TemplateParser(variables) + return template.get_actions(self.conf.initrd_template) + + return [] + + # XXX we have to do this, otherwise we get an error, when copying + def remove_modules_broken_links(self): + # remove build and source links from modules directories + build = os.path.join(self.paths.MODULES_DIR, "build") + if os.path.islink(build): + utils.remove(build) + + source = os.path.join(self.paths.MODULES_DIR, "source") + if os.path.islink(source): + utils.remove(source) + + def move_shared_files(self): + dirs = [os.path.join(self.paths.INITRD_DATADIR, "noarch"), + os.path.join(self.paths.INITRD_DATADIR, self.conf.arch)] + + self.output.info(":: copying the custom initrd files") + for dir in [dir for dir in dirs if os.path.isdir(dir)]: + utils.scopy(src_root=dir, src_path="*", + dst_root=self.conf.ramdisktree, dst_path="") + + def process_actions(self): + for action in self.actions: + action.execute() + + def create_modinfo(self, moddir, target): + modules_map = {} + for root, dirs, files in os.walk(moddir): + for file in files: + modules_map[file] = os.path.join(root, file) + + modules = { "scsi_hostadapter" : "block", + "eth" : "networking" } + + blacklist = ( "floppy", + "scsi_mod", + "libiscsi" ) + + list = {} + for type, file_suffix in modules.items(): + list[type] = {} + + filename = os.path.join(moddir, "modules.%s" % file_suffix) + if not os.path.isfile(filename): + continue + + with open(filename, "r") as f: + for line in f: + line = line.strip() + + if line in modules_map: + modname, ext = os.path.splitext(line) + if modname in blacklist: + continue + + cmd = "%s -F description %s" % (self.paths.MODINFO, + modules_map[line]) + + err, output = commands.getstatusoutput(cmd) + if err: + self.output.warning(output) + desc = "" + else: + desc = output.split("\n")[0] + desc = desc.strip() + desc = desc[:65] + + if not desc: + desc = "%s driver" % modname + info = '%s\n\t%s\n\t"%s"\n' % (modname, type, desc) + list[type][modname] = info + + with open(target, "w") as f: + f.write("Version 0\n") + for type in list: + modlist = sorted(list[type].keys()) + for mod in modlist: + f.write("%s\n" % list[type][mod]) + + def get_kernel_modules(self): + src_moddir = self.paths.MODULES_DIR + dst_moddir = os.path.join(self.conf.ramdisktree, "lib", "modules", + self.conf.kernelver) + + # expand modules + modules = set() + + for name in self.conf.modules: + if name.startswith("="): + group = name[1:] + + if group in ("scsi", "ata"): + path = os.path.join(src_moddir, "modules.block") + elif group == "net": + path = os.path.join(src_moddir, "modules.networking") + else: + path = os.path.join(src_moddir, "modules.%s" % group) + + if os.path.isfile(path): + with open(path, "r") as f: + for line in f: + module = re.sub(r"\.ko$", "", line.strip()) + modules.add(module) + + else: + modules.add(name) + + # resolve modules dependencies + with open(self.paths.MODULES_DEP, "r") as f: + lines = map(lambda l: l.strip(), f.readlines()) + + modpattern = re.compile(r"^.*/(?P.*)\.ko:(?P.*)$") + deppattern = re.compile(r"^.*/(?P.*)\.ko$") + changed = True + + while changed: + for line in lines: + changed = False + + m = modpattern.match(line) + modname = m.group("name") + + if modname in modules: + # add the dependencies + for dep in m.group("deps").split(): + m = deppattern.match(dep) + depname = m.group("name") + + if depname not in modules: + changed = True + modules.add(depname) + + # copy all modules to the ramdisk tree + src_path = src_moddir.replace(self.conf.installtree, "", 1) + if src_path.startswith("/"): + src_path = src_path[1:] + + dst_path = "lib/modules" + + utils.scopy(src_root=self.conf.installtree, src_path=src_path, + dst_root=self.conf.ramdisktree, dst_path=dst_path) + + # remove not needed modules + for root, dirs, files in os.walk(dst_moddir): + for file in files: + full_path = os.path.join(root, file) + name, ext = os.path.splitext(file) + + if ext == ".ko": + if name not in modules: + utils.remove(full_path) + else: + # get the required firmware + cmd = "%s -F firmware %s" % (self.paths.MODINFO, + full_path) + err, output = commands.getstatusoutput(cmd) + if err: + self.output.warning(output) + continue + + for fw in output.split(): + dst = os.path.join(self.conf.ramdisktree, + "lib", "firmware", fw) + + # create the destination directory + dir = os.path.dirname(dst) + if not os.path.isdir(dir): + utils.makedirs(dir) + + # copy the firmware + path = os.path.join("lib", "firmware", fw) + utils.scopy(src_root=self.conf.installtree, + src_path=path, + dst_root=self.conf.ramdisktree, + dst_path=path) + + # copy additional firmware + fw = [ ("ipw2100", "ipw2100*"), + ("ipw2200", "ipw2200*"), + ("iwl3945", "iwlwifi-3945*"), + ("iwl4965", "iwlwifi-4965*"), + ("atmel", "atmel_*.bin"), + ("zd1211rw", "zd1211"), + ("qla2xxx", "ql*") ] + + for module, file in fw: + if module in modules: + utils.scopy(src_root=self.conf.installtree, + src_path=os.path.join("lib", "firmware", file), + dst_root=self.conf.ramdisktree, + dst_path=os.path.join("lib", "firmware")) + + # compress modules + for root, dirs, files in os.walk(dst_moddir): + for file in files: + if not file.endswith(".ko"): + continue + + kopath = os.path.join(root, file) + with open(kopath, "rb") as f: + kodata = f.read() + + gzipped = gzip.open(kopath + ".gz", "wb") + gzipped.write(kodata) + gzipped.close() + + os.unlink(kopath) + + # create modinfo + modinfo = os.path.join(self.conf.tempdir, "module-info") + self.create_modinfo(src_moddir, modinfo) + + target = os.path.join(self.conf.ramdisktree, "lib", "modules", + "module-info") + + cmd = "%s --modinfo-file %s --ignore-missing --modinfo %s > %s" % \ + (self.paths.MODLIST, modinfo, " ".join(list(modules)), target) + + err, output = commands.getstatusoutput(cmd) + if err: + self.output.warning(output) + + # run depmod + cmd = "%s -a -F %s -b %s %s" % ( + self.paths.DEPMOD, self.paths.SYSTEM_MAP, self.conf.installtree, + self.conf.kernelver) + + err, output = commands.getstatusoutput(cmd) + if err: + self.output.warning(output) + + # remove leftovers + utils.remove(os.path.join(dst_moddir, "modules.*map")) + + def get_keymaps(self): + if os.path.isfile(self.paths.KEYMAPS_OVERRIDE): + dst = os.path.join(self.conf.ramdisktree, "etc", "keymaps.gz") + shutil.copy2(self.paths.KEYMAPS_OVERRIDE, dst) + else: + cmd = "%s %s %s %s" % ( + self.paths.GETKEYMAPS, self.conf.arch, + os.path.join(self.conf.ramdisktree, "etc", "keymaps.gz"), + self.conf.installtree) + + err, output = commands.getstatusoutput(cmd) + if err: + self.output.error(output) + return False + + return True + + def create_locales(self): + dir = os.path.join(self.conf.ramdisktree, "usr", "lib", "locale") + utils.makedirs(dir) + + cmd = "%s -c -i en_US -f UTF-8 --prefix %s en_US" % \ + (self.paths.LOCALEDEF, self.conf.ramdisktree) + + err, output = commands.getstatusoutput(cmd) + if err: + self.output.error(output) + return False + + return True + + def compress(self, filename): + self.output.info(":: compressing the image file") + cwd = os.getcwd() + os.chdir(self.conf.ramdisktree) + + # XXX python cpioarchive does not support writing + cpioarchive = filename + ".cpio" + + cmd = "find . | cpio --quiet -c -o > %s" % cpioarchive + err, output = commands.getstatusoutput(cmd) + if err: + return False + + os.chdir(cwd) + + with open(cpioarchive, "rb") as f: + cpiodata = f.read() + + gzipped = gzip.open(filename, "wb") + gzipped.write(cpiodata) + gzipped.close() + + os.unlink(cpioarchive) + + return True + + def prepare(self): + # copy the .buildstamp file + shutil.copy2(self.conf.buildstamp, self.conf.ramdisktree) + + self.remove_modules_broken_links() + self.move_shared_files() + self.process_actions() + self.get_kernel_modules() + self.get_keymaps() + self.create_locales() + + def create(self): + self.prepare() + + f = getattr(self, "create_%s" % self.conf.arch, None) + if f: + return f() + + def create_i386(self): + initrd_filename = "initrd.img" + kernel_filename = "vmlinuz" + + if self.conf.kernelfile.endswith("PAE"): + initrd_filename = "initrd-PAE.img" + kernel_filename = "vmlinuz-PAE" + + text = """[images-xen] +kernel = images/pxeboot/vmlinuz-PAE +initrd = images/pxeboot/initrd-PAE.img + +""" + + utils.edit(self.conf.treeinfo, append=True, text=text) + + initrd_filename = os.path.join(self.conf.tempdir, initrd_filename) + self.compress(initrd_filename) + + kernel_filename = os.path.join(self.conf.tempdir, kernel_filename) + shutil.copy2(self.conf.kernelfile, kernel_filename) + + return kernel_filename, initrd_filename + + def create_x86_64(self): + return self.create_i386() + + def run_s390(self): + initrd_filename = os.path.join(self.conf.tempdir, "initrd.img") + self.compress(initrd_filename) + + kernel_filename = os.path.join(self.conf.tempdir, "kernel.img") + shutil.copy2(self.conf.kernelfile, kernel_filename) + + cmd = "%s %s %s" % (self.paths.GENINITRDSZ, + os.path.getsize(initrd_filename), + os.path.join(self.conf.imagesdir, "initrd.size")) + + err, output = commands.getstatusoutput(cmd) + if err: + self.output.warning(output) + + for filename in (self.paths.REDHAT_EXEC, self.paths.GENERIC_PRM): + shutil.copy2(filename, self.conf.imagesdir) + shutil.copy2(filename, self.conf.outputdir) + + cmd = "%s -i %s -r %s -p %s -o %s" % ( + MKS390CD, kernel_filename, initrd_filename, + self.paths.GENERIC_PRM, + os.path.join(self.conf.imagesdir, "cdboot.img")) + + err, output = commands.getstatusoutput(cmd) + if err: + self.output.warning(output) + + text = """[images-%s] +kernel = images/kernel.img +initrd = images/initrd.img +initrd.size = images/initrd.size +generic.prm = images/generic.prm +generic.ins = generic.ins +cdboot.img = images/cdboot.img + +""" % self.conf.arch + + utils.edit(self.conf.treeinfo, append=True, text=text) + + return kernel_filename, initrd_filename + + def run_s390x(self): + return self.run_s390() + + # XXX this should be removed + def run_alpha(self): + raise NotImplementedError + + def run_ia64(self): + raise NotImplementedError + + def run_ppc(self): + raise NotImplementedError + + def run_ppc64(self): + raise NotImplementedError diff --git a/src/pylorax/singleton.py b/src/pylorax/singleton.py new file mode 100644 index 00000000..fbcf4930 --- /dev/null +++ b/src/pylorax/singleton.py @@ -0,0 +1,14 @@ +# +# singleton.py +# + +class Singleton(object): + + __instance = None + + @classmethod + def get(cls): + if cls.__instance is None: + cls.__instance = cls() + + return cls.__instance diff --git a/src/pylorax/template.py b/src/pylorax/template.py deleted file mode 100644 index ce4efb00..00000000 --- a/src/pylorax/template.py +++ /dev/null @@ -1,113 +0,0 @@ -# -# template.py -# initrd template class -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): Martin Gracik -# - -import sys -import os -import re - - -class TemplateError(Exception): - pass - -class Template(object): - def __init__(self): - self._actions = [] - - self.lines = [] - self.included_files = [] - - def preparse(self, filename): - try: - f = open(filename, 'r') - except IOError as why: - sys.stderr.write("ERROR: Unable to open template file '%s': %s\n" % (filename, why)) - return False - else: - lines = f.readlines() - f.close() - - self.included_files.append(filename) - - for line in lines: - line = line.strip() - - if line.startswith('#include'): - file_to_include = line.split()[1] - path = os.path.join(os.path.dirname(filename), file_to_include) - if path not in self.included_files: - self.preparse(path) - else: - self.lines.append(line) - - def parse(self, supported_actions, variables): - lines = self.lines - - # append next line if line ends with '\' - temp = [] - for line in lines: - line = line.strip() - if line.endswith('\\'): - line = line[:-1] - line = line.rstrip() - line = line + ' ' - else: - line = line + '\n' - temp.append(line) - temp = ''.join(temp) - lines = temp.splitlines() - - # check template variables - for lineno, line in enumerate(lines, start=1): - for var in filter(lambda var: var not in variables, re.findall(r'@(.*?)@', line)): - raise TemplateError, "unknown variable '%s' on line %d" % (var, lineno) - - # parse the template - for lineno, line in enumerate(lines, start=1): - line, sep, comment = line.partition('#') - if not line: - continue - - # expand variables - for var, value in variables.items(): - line = re.sub(r'@%s@' % var, value, line) - - # get the command - command, line = line.split(None, 1) - if command not in supported_actions: - raise TemplateError, "unknown command '%s' on line %d" % (command, lineno) - - # create the action object - regex = supported_actions[command].REGEX - m = re.match(regex, line) - if m: - new_action = supported_actions[command](**m.groupdict()) - self._actions.append(new_action) - else: - # didn't match the regex - raise TemplateError, "invalid command format '%s' on line %d" % (line, lineno) - - return True - - @property - def actions(self): - return self._actions - diff --git a/src/pylorax/utils.py b/src/pylorax/utils.py new file mode 100644 index 00000000..f8f1594f --- /dev/null +++ b/src/pylorax/utils.py @@ -0,0 +1,405 @@ +# +# utils.py +# + +import sys +import os +import shutil +import glob +import fileinput +import re +import pwd +import grp +import commands + + +def expand_path(path, globs=True): + l = [] + + m = re.match(r"(?P.*){(?P.*?)}(?P.*)", path) + if m: + for f in re.split(r"\s*,\s*", m.group("expand")): + l.extend(expand_path(m.group("prefix") + f + m.group("suffix"), + globs=globs)) + else: + if globs: + l.extend(glob.glob(path)) + else: + l.append(path) + + return l + + +def remove(file): + for fname in expand_path(file): + if os.path.islink(fname) or os.path.isfile(fname): + os.unlink(fname) + else: + shutil.rmtree(fname) + + +def __copy(src_path, dst_path, src_root="/", dst_root="/", symlinks=True, + ignore_errors=False, deps=False): + + # ensure that roots end with "/" + if not src_root.endswith("/"): + src_root = src_root + "/" + if not dst_root.endswith("/"): + dst_root = dst_root + "/" + + smartcopy = SmartCopy(src_root, dst_root, symlinks, ignore_errors) + + src = os.path.join(src_root, src_path) + for fname in expand_path(src): + fname = fname.replace(src_root, "", 1) + smartcopy.copy(fname, dst_path) + + if deps: + smartcopy.get_deps() + + smartcopy.process() + + +def scopy(src_path, dst_path, src_root="/", dst_root="/", symlinks=True, + ignore_errors=False): + + __copy(src_path, dst_path, src_root, dst_root, symlinks, + ignore_errors, deps=False) + + +def dcopy(src_path, dst_path, src_root="/", dst_root="/", symlinks=True, + ignore_errors=False): + + __copy(src_path, dst_path, src_root, dst_root, symlinks, + ignore_errors, deps=True) + + +def symlink(link_target, link_name): + if os.path.islink(link_name) or os.path.isfile(link_name): + os.unlink(link_name) + + os.symlink(link_target, link_name) + + +def touch(file): + if os.path.exists(file): + os.utime(file, None) + else: + with open(file, "w") as f: + pass + + +def mkdir(dir, mode=None): + if mode is None: + mode = 0755 + + for d in expand_path(dir, globs=False): + if not os.path.isdir(d): + os.mkdir(d, mode) + + +def makedirs(dir, mode=None): + if mode is None: + mode = 0755 + + for d in expand_path(dir, globs=False): + if not os.path.isdir(d): + os.makedirs(d, mode) + + +def chown(file, user=None, group=None, recursive=False): + # if uid or gid is set to -1, it will not be changed + uid = gid = -1 + + if user is not None: + uid = pwd.getpwnam(user)[2] + if group is not None: + gid = grp.getgrnam(group)[2] + + for fname in expand_path(file): + os.chown(fname, uid, gid) + + if recursive and os.path.isdir(fname): + for nested in os.listdir(fname): + nested = os.path.join(fname, nested) + chown(nested, user, group, recursive) + + +def chmod(file, mode, recursive=False): + for fname in expand_path(file): + os.chmod(fname, mode) + + if recursive and os.path.isdir(fname): + for nested in os.listdir(fname): + nested = os.path.join(fname, nested) + chmod(nested, mode, recursive) + + +def edit(file, text, append=False): + mode = "w" + if append: + mode = "a" + + with open(file, mode) as f: + f.write(text) + + +def replace(file, find, replace): + fin = fileinput.input(file, inplace=1) + + for line in fin: + line = re.sub(find, replace, line) + sys.stdout.write(line) + + fin.close() + + +class SmartCopyError(Exception): + pass + + +class SmartCopy(object): + + def __init__(self, src_root="/", dst_root="/", symlinks=True, + ignore_errors=False): + + self.src_root = src_root + self.dst_root = dst_root + self.symlinks = symlinks + self.ignore_errors = ignore_errors + + self.linker = Linker(src_root) + + self.clear() + + def clear(self): + self.makedirs = [] + self.copyfiles = set() + self.links = set() + self.errors = [] + + def copy(self, src_path, dst_path): + src = os.path.normpath(os.path.join(self.src_root, src_path)) + dst = os.path.normpath(os.path.join(self.dst_root, dst_path)) + + # check if the source exists + if not os.path.exists(src): + err_msg = "cannot stat '%s': No such file or directory" % src + if not self.ignore_errors: + raise SmartCopyError(err_msg) + else: + self.errors.append(err_msg) + return # EXIT + + if os.path.isfile(src): + self.__copy_file(src_path, dst_path, src, dst) + elif os.path.isdir(src): + self.__copy_dir(src_path, dst_path, src, dst) + + def __copy_file(self, src_path, dst_path, src, dst): + # if destination is an existing directory, + # append the source filename to the destination path + if os.path.isdir(dst): + dst = os.path.join(dst, os.path.basename(src)) + + # check if the new destination is still an existing directory + if os.path.isdir(dst): + + # do not overwrite a directory with a file + err_msg = "cannot overwrite directory '%s' " \ + "with non-directory" % dst + if not self.ignore_errors: + raise SmartCopyError(err_msg) + else: + self.errors.append(err_msg) + return # EXIT + + if os.path.islink(src): + + if not self.symlinks: + real_src = os.path.realpath(src) + self.copyfiles.add((real_src, dst)) + else: + self.__copy_link(src_path, dst_path, src, dst) + + else: + + self.copyfiles.add((src, dst)) + + def __copy_dir(self, src_path, dst_path, src, dst): + # append the source directory name to the destination path + dirname = os.path.basename(src) + new_dst = os.path.join(dst, dirname) + + # remove the trailing "/", + # to make sure, that we don't try to create "dir" and "dir/" + if new_dst.endswith("/"): + new_dst = new_dst[:-1] + + if os.path.islink(src): + + if not self.symlinks: + real_src = os.path.realpath(src) + + if not os.path.exists(new_dst) and \ + new_dst not in self.makedirs: + self.makedirs.append(new_dst) + + for fname in os.listdir(real_src): + fname = os.path.join(real_src, fname) + self.copy(fname, new_dst) + + else: + self.__copy_link(src_path, dst_path, src, new_dst) + + else: + + # create the destination directory, if it does not exist + if not os.path.exists(new_dst) and \ + new_dst not in self.makedirs: + self.makedirs.append(new_dst) + + elif os.path.isfile(new_dst): + err_msg = "cannot overwrite file '%s' with a directory" \ + % new_dst + if not self.ignore_errors: + raise SmartCopyError(err_msg) + else: + self.errors.append(err_msg) + return # EXIT + + new_dst_path = os.path.join(dst_path, dirname) + + try: + fnames = os.listdir(src) + except OSError as why: + err_msg = "cannot list directory '%s': %s'" % (src, why) + if not self.ignore_errors: + raise SmartCopyError(err_msg) + else: + self.errors.append(err_msg) + return # EXIT + + for fname in fnames: + fname = os.path.join(src_path, fname) + self.copy(fname, new_dst_path) + + def __copy_link(self, src_path, dst_path, src, dst): + # read the link target + link_target = os.readlink(src) + + # get the target source and destination paths + target_src_path = os.path.join(os.path.dirname(src_path), link_target) + target_dst_dir = os.path.join(dst_path, os.path.dirname(link_target)) + + # if the link target is an absolute path, + # make sure we copy it relative to the dst_root + if target_dst_dir.startswith("/"): + target_dst_dir = target_dst_dir[1:] + + # remove the trailing "/" + if target_dst_dir.endswith("/"): + target_dst_dir = target_dst_dir[:-1] + + # create the destination directory, if it doesn't exist + target_dst = os.path.join(self.dst_root, target_dst_dir) + if not os.path.exists(target_dst) and \ + target_dst not in self.makedirs: + self.makedirs.append(target_dst) + + # copy the target along with the link + self.copy(target_src_path, target_dst_dir) + + # create the symlink named dst, pointing to link_target + self.links.add((link_target, dst)) + + def get_deps(self): + deps = set() + + for src, dst in self.copyfiles: + if self.linker.is_elf(src): + deps = deps.union(self.linker.get_deps(src)) + + for src in deps: + src_path = src.replace(self.src_root, "", 1) + dst_path = os.path.dirname(src_path) + + # create the destination directory + dst_dir = os.path.join(self.dst_root, dst_path) + if not os.path.exists(dst_dir) and \ + dst_dir not in self.makedirs: + self.makedirs.append(dst_dir) + + self.copy(src_path, dst_path) + + def process(self): + # create required directories + map(mkdir, self.makedirs) + + # copy all the files + + # remove the dst, if it is a link to src + for src, dst in self.copyfiles: + if os.path.realpath(dst) == src: + os.unlink(dst) + + map(lambda (src, dst): shutil.copy2(src, dst), self.copyfiles) + + # create symlinks + map(lambda (target, name): symlink(target, name), self.links) + + +class LinkerError(Exception): + pass + + +class Linker(object): + + LIBDIRS = ( "lib64", + "usr/lib64", + "lib", + "usr/lib" ) + + def __init__(self, root="/"): + libdirs = map(lambda path: os.path.join(root, path), self.LIBDIRS) + libdirs = ":".join(libdirs) + + ld_linux = None + + with open("/usr/bin/ldd", "r") as f: + for line in f: + m = re.match(r"^RTLDLIST=(?P.*)$", line.strip()) + if m: + ld_linux = m.group("ld_linux") + break + + if ld_linux is None: + raise LinkerError("unable to find the ld_linux executable") + + self.lddcmd = "LD_LIBRARY_PATH=%s %s --list" % (libdirs, ld_linux) + self.pattern = re.compile(r"^[a-zA-Z0-9.-_/]*\s=>\s" \ + r"(?P[a-zA-Z0-9.-_/]*)" \ + r"\s\(0x[0-9a-f]*\)$") + + def is_elf(self, file): + err, output = commands.getstatusoutput("file --brief %s" % file) + if err: + raise LinkerError("error getting the file type") + + if not output.startswith("ELF"): + return False + + return True + + def get_deps(self, file): + err, output = commands.getstatusoutput("%s %s" % (self.lddcmd, file)) + if err: + raise LinkerError("error getting the file dependencies") + + deps = set() + for line in output.splitlines(): + m = self.pattern.match(line.strip()) + if m: + deps.add(m.group("lib")) + + return deps diff --git a/src/pylorax/utils/fileutils.py b/src/pylorax/utils/fileutils.py deleted file mode 100644 index a63211d2..00000000 --- a/src/pylorax/utils/fileutils.py +++ /dev/null @@ -1,306 +0,0 @@ -# -# fileutils.py -# functions for working with files -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): Martin Gracik -# - -import sys -import os -import shutil -import glob -import fileinput -import re - - -def normalize(src_root, src_path, dst_root, dst_path): - src = os.path.join(src_root, src_path) - dst = os.path.join(dst_root, dst_path) - src = os.path.normpath(src) - dst = os.path.normpath(dst) - - return src, dst - - -def remove(target, verbose=False): - for fname in glob.iglob(target): - if verbose: - print "removing '%s'" % (fname,) - - if os.path.islink(fname) or os.path.isfile(fname): - os.unlink(fname) - else: - shutil.rmtree(fname, ignore_errors=True) - -def touch(filename, verbose=False): - if verbose: - print "touching '%s'" % (filename,) - - if os.path.exists(filename): - os.utime(filename, None) - else: - try: - f = open(filename, "w") - except IOError as why: - print >> sys.stderr, "cannot create '%s': %s" % (filename, why) - return False - else: - f.close() - - return True - -def copy(src_path, dst_path, src_root="/", dst_root="/", - nolinks=False, ignore_errors=False, verbose=False): - - filecopy = Copy(ignore_errors, verbose) - - src = os.path.join(src_root, src_path) - for fname in glob.iglob(src): - fname = fname.replace(src_root, "", 1) - - if src_path[0] != "/" and fname[0] == "/": - fname = fname[1:] - - filecopy.copy(fname, dst_path, src_root, dst_root, nolinks) - - return filecopy.errors - -def move(src_path, dst_path, src_root="/", dst_root="/", - nolinks=False, ignore_errors=False, verbose=False): - - errors = copy(src_path, dst_path, src_root, dst_root, - nolinks, ignore_errors, verbose) - - # if everything was copied ok, remove the source - if not errors: - src, dst = normalize(src_root, src_path, dst_root, dst_path) - remove(src, verbose) - - return errors - -def chmod(target, mode, recursive=False, verbose=False): - mode = int(mode) - - for fname in glob.iglob(target): - if verbose: - print "changing permissions on '%s'" % (fname,) - - os.chmod(fname, mode) - - if recursive and os.path.isdir(fname): - for nested in os.listdir(fname): - nested = os.path.join(fname, nested) - chmod(nested, mode, recursive, verbose) - -def edit(filename, text, append=False, verbose=False): - mode = "w" - if append: - mode = "a" - - if verbose: - print "editing '%s'" % (filename,) - - try: - f = open(filename, mode) - except IOError as why: - print >> sys.stderr, "cannot edit '%s': %s" % (filename, why) - return False - else: - f.write(text) - f.close() - - return True - -def replace(filename, find, replace, verbose=False): - if verbose: - print "replacing '%s' for '%s' in '%s'" % (find, replace, filename) - - fin = fileinput.input(filename, inplace=1) - for line in fin: - line = re.sub(find, replace, line) - sys.stdout.write(line) - fin.close() - - return True - - -class CopyError(Exception): - pass - -class Copy(object): - def __init__(self, ignore_errors=False, verbose=False): - self.Error = CopyError - - self.ignore_errors = ignore_errors - self.verbose = verbose - - self.errors = [] - - def copy(self, src_path, dst_path, src_root="/", dst_root="/", nolinks=False): - # normalize the source and destination paths - src, dst = normalize(src_root, src_path, dst_root, dst_path) - - # check if the source exists - if not os.path.exists(src): - err_msg = "cannot stat '%s': No such file or directory" % (src,) - if not self.ignore_errors: - raise self.Error, err_msg - else: - print >> sys.stderr, err_msg - self.errors.append(err_msg) - return False # EXIT - - if os.path.isfile(src): - - # if destination is an existing directory, append the source filename - # to the destination path - if os.path.isdir(dst): - dst = os.path.join(dst, os.path.basename(src)) - - # check if the destination exists - if os.path.isfile(dst): - - # overwrite file - try: - if self.verbose: - print "overwriting '%s'" % (dst,) - os.unlink(dst) - except OSError as why: - err_msg = "cannot overwrite file '%s': %s" % (dst, why) - if not self.ignore_errors: - raise self.Error, err_msg - else: - print >> sys.stderr, err_msg - self.errors.append(err_msg) - return False # EXIT - - elif os.path.isdir(dst): - - # do not overwrite directory with a file - err_msg = "cannot overwrite directory '%s' with non-directory" \ - % (dst,) - if not self.ignore_errors: - raise self.Error, err_msg - else: - print >> sys.stderr, err_msg - self.errors.append(err_msg) - return False # EXIT - - if os.path.islink(src): - - if nolinks: - self.__copy_file(os.path.realpath(src), dst) - else: - self.__copy_link(src_path, dst_path, src_root, dst_root, - src, dst) - - else: - - self.__copy_file(src, dst) - - elif os.path.isdir(src): - - # append the source directory name to the destination path - dirname = os.path.basename(src) - new_dst = os.path.join(dst, dirname) - - if os.path.islink(src): - - if nolinks: - real_src = os.path.realpath(src) - - if not os.path.exists(new_dst): - os.makedirs(new_dst) - - for fname in os.listdir(real_src): - fname = os.path.join(real_src, fname) - - if os.path.isfile(fname): - self.__copy_file(fname, new_dst) - else: - dst = os.path.join(new_dst, os.path.basename(fname)) - shutil.copytree(fname, dst, symlinks=False) - else: - self.__copy_link(src_path, dst_path, src_root, dst_root, - src, new_dst) - - else: - - # create the destination directory if it does not exist - if not os.path.exists(new_dst): - os.makedirs(new_dst) - - if os.path.isfile(new_dst): - err_msg = "cannot overwrite file '%s' with a directory" \ - % (new_dst,) - if not self.ignore_errors: - raise self.Error, err_msg - else: - print >> sys.stderr, err_msg - self.errors.append(err_msg) - return False # EXIT - - new_dst_path = os.path.join(dst_path, dirname) - - fnames = [] - try: - fnames = os.listdir(src) - except OSError as why: - err_msg = "cannot list directory '%s': %s'" % (src, why) - if not self.ignore_errors: - raise self.Error, err_msg - else: - print >> sys.stderr, err_msg - self.errors.append(err_msg) - - for fname in fnames: - fname = os.path.join(src_path, fname) - self.copy(fname, new_dst_path, src_root, dst_root) - - def __copy_file(self, src, dst): - if self.verbose: - print "copying '%s' to '%s'" % (src, dst) - - try: - shutil.copy(src, dst) - except (shutil.Error, IOError) as why: - err_msg = "cannot copy '%s' to '%s': %s" % (src, dst, why) - if not self.ignore_errors: - raise self.Error, err_msg - else: - print >> sys.stderr, err_msg - self.errors.append(err_msg) - - def __copy_link(self, src_path, dst_path, src_root, dst_root, src, dst): - # read the link target - link_target = os.readlink(src) - - # get the target source and destination paths - target_src_path = os.path.join(os.path.dirname(src_path), link_target) - target_dst_path = os.path.join(dst_path, os.path.dirname(link_target)) - - # create the destination directory if it doesn't exist - target_dst = os.path.join(dst_root, target_dst_path) - if not os.path.exists(target_dst): - os.makedirs(target_dst) - - # copy the target along with the link - self.copy(target_src_path, target_dst_path, src_root, dst_root) - - # create the symlink named dst, pointing to link_target - os.symlink(link_target, dst) diff --git a/src/pylorax/utils/ldd.py b/src/pylorax/utils/ldd.py deleted file mode 100644 index 10ddd7e3..00000000 --- a/src/pylorax/utils/ldd.py +++ /dev/null @@ -1,88 +0,0 @@ -# -# ldd.py -# library dependencies -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): Martin Gracik -# - -import os -import re -import commands - - -class LDD(object): - - def __init__(self, libroots=["/lib", "/usr/lib"]): - f = open("/usr/bin/ldd", "r") - for line in f.readlines(): - line = line.strip() - if line.startswith("RTLDLIST="): - rtldlist, sep, ld_linux = line.partition("=") - break - f.close() - - self._lddcmd = "LD_LIBRARY_PATH=%s %s --list" % (":".join(libroots), - ld_linux) - - pattern = r"^([a-zA-Z0-9.]*\s=>\s)(?P[a-zA-Z0-9./-]*)\s\(0x[0-9a-f]*\)$" - self.pattern = re.compile(pattern) - - self._deps = set() - - self._errors = [] - - def is_elf(self, filename): - cmd = "file --brief %s" % (filename) - err, out = commands.getstatusoutput(cmd) - if err: - return False - - if not out.split()[0] == "ELF": - return False - - return True - - def getDeps(self, filename): - # skip no elf files - if not self.is_elf(filename): - return - - cmd = "%s %s" % (self._lddcmd, filename) - err, out = commands.getstatusoutput(cmd) - if err: - self._errors.append((filename, out)) - return - - lines = out.splitlines() - for line in lines: - line = line.strip() - - m = self.pattern.match(line) - if m: - lib = m.group("lib") - if lib not in self._deps: - self._deps.add(lib) - self.getDeps(lib) - - @property - def deps(self): - return self._deps - - @property - def errors(self): - return self._errors diff --git a/src/pylorax/utils/yumwrapper.py b/src/pylorax/utils/yumwrapper.py deleted file mode 100644 index 53adfdf3..00000000 --- a/src/pylorax/utils/yumwrapper.py +++ /dev/null @@ -1,129 +0,0 @@ -# -# yumwrapper.py -# yum wrapper -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Red Hat Author(s): Martin Gracik -# - -import sys -import os -import yum -import yum.callbacks -import yum.rpmtrans - -from pylorax.misc import seq, get_console_size - - -class Callback(yum.rpmtrans.SimpleCliCallBack): - - def __init__(self): - yum.rpmtrans.SimpleCliCallBack.__init__(self) - self.height, self.width = get_console_size() - - def event(self, package, action, te_current, te_total, ts_current, ts_total): - progress = float(te_current) / float(te_total) - percentage = int(progress * 100) - - bar_length = 20 - bar = int(percentage / (100 / bar_length)) - - total_progress_str = "[%s/%s] " % (ts_current, ts_total) - package_progress_str = " [%s%s] %3d%%" % ("#" * bar, "-" * (bar_length - bar), - percentage) - - action_str = "%s %s" % (self.action[action], package) - chars_left = self.width - len(total_progress_str) - len(package_progress_str) - - if len(action_str) > chars_left: - action_str = action_str[:chars_left-3] - action_str = action_str + "..." - else: - action_str = action_str + " " * (chars_left - len(action_str)) - - msg = total_progress_str + action_str + package_progress_str - - sys.stdout.write(msg) - sys.stdout.write("\r") - - if percentage == 100: - sys.stdout.write("\n") - - sys.stdout.flush() - - -class Yum(object): - - def __init__(self, yumconf="/etc/yum/yum.conf", installroot="/", - errfile="/dev/null"): - - self.yb = yum.YumBase() - - self.yumconf = os.path.abspath(yumconf) - self.installroot = os.path.abspath(installroot) - self.errfile = errfile - - self.yb.preconf.fn = self.yumconf - self.yb.preconf.root = self.installroot - self.yb._getConfig() - - self.yb._getRpmDB() - self.yb._getRepos() - self.yb._getSacks() - - def find(self, patterns): - pl = self.yb.doPackageLists(patterns=seq(patterns)) - return pl.installed, pl.available - - def add_package(self, pattern): - try: - self.yb.install(name=pattern) - except yum.Errors.InstallError: - # didn't find an exact package name match - try: - self.yb.install(pattern=pattern) - except yum.Errors.InstallError: - # no package found - return False - - return True - - def install(self): - self.yb.resolveDeps() - self.yb.buildTransaction() - - cb = yum.callbacks.ProcessTransBaseCallback() - #cb = yum.callbacks.ProcessTransNoOutputCallback() - rpmcb = Callback() - - # XXX ATTENTION! ugly rpm error output hack - # we redirect the error output from rpm to errfile, - # so it does not show up in our "nice" output - # 2 = err descriptor - standard_err = os.dup(2) - my_err = open(self.errfile, "a") - os.dup2(my_err.fileno(), 2) - - # now we process the transactions without errors showing up in the output - self.yb.processTransaction(callback=cb, rpmDisplay=rpmcb) - - # and we put the standard error output back, so nobody will notice - os.dup2(standard_err, 2) - my_err.close() - - self.yb.closeRpmDB() - self.yb.close() diff --git a/share/pam.d/login b/usr/share/lorax/initrd/s390/etc/pam.d/login similarity index 100% rename from share/pam.d/login rename to usr/share/lorax/initrd/s390/etc/pam.d/login diff --git a/usr/share/lorax/initrd/s390/etc/pam.d/remote b/usr/share/lorax/initrd/s390/etc/pam.d/remote new file mode 100644 index 00000000..5e8d5794 --- /dev/null +++ b/usr/share/lorax/initrd/s390/etc/pam.d/remote @@ -0,0 +1,9 @@ +#%PAM-1.0 +auth required pam_env.so +auth sufficient pam_unix.so likeauth nullok +auth required pam_deny.so +account required pam_unix.so +password sufficient pam_unix.sp nullok use_authtok md5 shadow +password required pam_deny.so +session required pam_limits.so +session required pam_unix.so diff --git a/usr/share/lorax/initrd/s390/etc/pam.d/sshd b/usr/share/lorax/initrd/s390/etc/pam.d/sshd new file mode 100644 index 00000000..5e8d5794 --- /dev/null +++ b/usr/share/lorax/initrd/s390/etc/pam.d/sshd @@ -0,0 +1,9 @@ +#%PAM-1.0 +auth required pam_env.so +auth sufficient pam_unix.so likeauth nullok +auth required pam_deny.so +account required pam_unix.so +password sufficient pam_unix.sp nullok use_authtok md5 shadow +password required pam_deny.so +session required pam_limits.so +session required pam_unix.so diff --git a/share/sshd/sshd_config b/usr/share/lorax/initrd/s390/etc/ssh/sshd_config similarity index 100% rename from share/sshd/sshd_config rename to usr/share/lorax/initrd/s390/etc/ssh/sshd_config diff --git a/usr/share/lorax/initrd/s390x b/usr/share/lorax/initrd/s390x new file mode 120000 index 00000000..ba766cae --- /dev/null +++ b/usr/share/lorax/initrd/s390x @@ -0,0 +1 @@ +s390 \ No newline at end of file diff --git a/src/pylorax/utils/__init__.py b/usr/share/lorax/installtree/noarch/.gconf/desktop/%gconf.xml similarity index 100% rename from src/pylorax/utils/__init__.py rename to usr/share/lorax/installtree/noarch/.gconf/desktop/%gconf.xml diff --git a/usr/share/lorax/installtree/noarch/.gconf/desktop/gnome/%gconf.xml b/usr/share/lorax/installtree/noarch/.gconf/desktop/gnome/%gconf.xml new file mode 100644 index 00000000..e69de29b diff --git a/share/dogtail/%gconf.xml b/usr/share/lorax/installtree/noarch/.gconf/desktop/gnome/interface/%gconf.xml similarity index 100% rename from share/dogtail/%gconf.xml rename to usr/share/lorax/installtree/noarch/.gconf/desktop/gnome/interface/%gconf.xml diff --git a/share/libuser/libuser.conf b/usr/share/lorax/installtree/noarch/etc/libuser.conf similarity index 100% rename from share/libuser/libuser.conf rename to usr/share/lorax/installtree/noarch/etc/libuser.conf diff --git a/share/selinux/config b/usr/share/lorax/installtree/noarch/etc/selinux/config similarity index 100% rename from share/selinux/config rename to usr/share/lorax/installtree/noarch/etc/selinux/config diff --git a/share/images/README b/usr/share/lorax/outputdir/images/README similarity index 100% rename from share/images/README rename to usr/share/lorax/outputdir/images/README diff --git a/share/images/pxeboot/README b/usr/share/lorax/outputdir/images/pxeboot/README similarity index 100% rename from share/images/pxeboot/README rename to usr/share/lorax/outputdir/images/pxeboot/README