[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[PATCH 1/4] Structure the sources so it matches final structure better and make isys a package



---
 70-anaconda.rules                                 |   56 -
 Makefile.am                                       |   33 +-
 __init__.py                                       |  395 ---
 anaconda                                          |  932 ------
 anaconda.py                                       |  932 ++++++
 anaconda_log.py                                   |  170 -
 backend.py                                        |  301 --
 backend_log.py                                    |   88 -
 baseudev.py                                       |   92 -
 bin/Makefile.am                                   |   23 +
 bin/gptsync/.gitignore                            |    2 +
 bin/gptsync/Makefile.am                           |   35 +
 bin/gptsync/README                                |   41 +
 bin/gptsync/gptsync.c                             |  470 +++
 bin/gptsync/gptsync.h                             |  219 ++
 bin/gptsync/lib.c                                 |  469 +++
 bin/gptsync/os_unix.c                             |  267 ++
 bin/gptsync/showpart.c                            |  257 ++
 bin/gptsync/syslinux_mbr.h                        |   90 +
 bin/loader/.gitignore                             |   12 +
 bin/loader/Makefile.am                            |  118 +
 bin/loader/cdinstall.c                            |  509 +++
 bin/loader/cdinstall.h                            |   34 +
 bin/loader/copy.c                                 |  141 +
 bin/loader/copy.h                                 |   26 +
 bin/loader/devices.h                              |  103 +
 bin/loader/devt.h                                 |   39 +
 bin/loader/dirbrowser.c                           |  199 ++
 bin/loader/dirbrowser.h                           |   28 +
 bin/loader/driverdisk.c                           |  861 +++++
 bin/loader/driverdisk.h                           |   51 +
 bin/loader/driverselect.c                         |  251 ++
 bin/loader/fwloader.c                             |  675 ++++
 bin/loader/fwloader.h                             |   35 +
 bin/loader/getparts.c                             |  180 ++
 bin/loader/getparts.h                             |   27 +
 bin/loader/hardware.c                             |  150 +
 bin/loader/hardware.h                             |   28 +
 bin/loader/hdinstall.c                            |  496 +++
 bin/loader/hdinstall.h                            |   38 +
 bin/loader/ibft.c                                 |  105 +
 bin/loader/ibft.h                                 |   45 +
 bin/loader/init.c                                 |  798 +++++
 bin/loader/init.h                                 |   31 +
 bin/loader/kbd.c                                  |  164 +
 bin/loader/kbd.h                                  |   27 +
 bin/loader/keymaps-i386                           |  Bin 0 -> 12173 bytes
 bin/loader/keymaps-ppc                            |  Bin 0 -> 12871 bytes
 bin/loader/keymaps-x86_64                         |  Bin 0 -> 12173 bytes
 bin/loader/kickstart.c                            |  559 ++++
 bin/loader/kickstart.h                            |   54 +
 bin/loader/lang.c                                 |  399 +++
 bin/loader/lang.h                                 |   41 +
 bin/loader/linuxrc.s390                           | 3118 ++++++++++++++++++
 bin/loader/loader.c                               | 2378 ++++++++++++++
 bin/loader/loader.h                               |  193 ++
 bin/loader/loadermisc.c                           |  150 +
 bin/loader/loadermisc.h                           |   33 +
 bin/loader/mediacheck.c                           |  115 +
 bin/loader/mediacheck.h                           |   25 +
 bin/loader/method.c                               |  570 ++++
 bin/loader/method.h                               |   60 +
 bin/loader/mkctype.c                              |   76 +
 bin/loader/moduleinfo.c                           |  276 ++
 bin/loader/moduleinfo.h                           |   78 +
 bin/loader/modules.c                              |  530 +++
 bin/loader/modules.h                              |   47 +
 bin/loader/net.c                                  | 2122 ++++++++++++
 bin/loader/net.h                                  |   77 +
 bin/loader/nfsinstall.c                           |  586 ++++
 bin/loader/nfsinstall.h                           |   40 +
 bin/loader/rpmextract.c                           |  325 ++
 bin/loader/rpmextract.h                           |   45 +
 bin/loader/selinux.c                              |   56 +
 bin/loader/selinux.h                              |   27 +
 bin/loader/shutdown.c                             |  153 +
 bin/loader/simplemot                              |   81 +
 bin/loader/telnet.c                               |  273 ++
 bin/loader/telnet.h                               |   40 +
 bin/loader/telnetd.c                              |  256 ++
 bin/loader/telnetd.h                              |   25 +
 bin/loader/udelay.h                               |  199 ++
 bin/loader/undomounts.c                           |  239 ++
 bin/loader/unicode-linedraw-chars.txt             |   22 +
 bin/loader/urlinstall.c                           |  414 +++
 bin/loader/urlinstall.h                           |   36 +
 bin/loader/urls.c                                 |  371 +++
 bin/loader/urls.h                                 |   35 +
 bin/loader/windows.c                              |  121 +
 bin/loader/windows.h                              |   43 +
 bootdisk/Makefile.am                              |   22 -
 bootdisk/i386/Makefile.am                         |   25 -
 bootdisk/i386/boot.msg                            |    5 -
 bootdisk/i386/grub.conf                           |    8 -
 bootdisk/i386/syslinux.cfg                        |   33 -
 bootdisk/ppc/Makefile.am                          |   26 -
 bootdisk/ppc/bootinfo.txt                         |  169 -
 bootdisk/ppc/magic                                |   81 -
 bootdisk/ppc/mapping                              |   27 -
 bootdisk/ppc/ofboot.b                             |   74 -
 bootdisk/ppc/yaboot.conf.3264                     |   14 -
 bootdisk/ppc/yaboot.conf.in                       |    8 -
 bootdisk/s390x/Makefile.am                        |   25 -
 bootdisk/s390x/generic.ins                        |    5 -
 bootdisk/s390x/generic.prm                        |    1 -
 bootdisk/s390x/redhat.exec                        |    9 -
 bootdisk/sparc/Makefile.am                        |   25 -
 bootdisk/sparc/boot.msg                           |    9 -
 bootdisk/sparc/silo.conf                          |   17 -
 bootdisk/x86_64/Makefile.am                       |   25 -
 bootdisk/x86_64/boot.msg                          |    5 -
 bootdisk/x86_64/grub.conf                         |    8 -
 bootdisk/x86_64/syslinux.cfg                      |   33 -
 bootloader.py                                     |  244 --
 cmdline.py                                        |  221 --
 command-stubs/Makefile.am                         |   23 -
 command-stubs/list-harddrives-stub                |   45 -
 command-stubs/loadkeys-stub                       |   41 -
 command-stubs/losetup-stub                        |   50 -
 command-stubs/mknod-stub                          |   54 -
 command-stubs/raidstart-stub                      |   44 -
 command-stubs/raidstop-stub                       |   31 -
 compssort.py                                      |   69 -
 configure.ac                                      |   53 +-
 constants.py                                      |   89 -
 data/70-anaconda.rules                            |   56 +
 data/Makefile.am                                  |   36 +
 data/bootdisk/Makefile.am                         |   22 +
 data/bootdisk/i386/Makefile.am                    |   25 +
 data/bootdisk/i386/boot.msg                       |    5 +
 data/bootdisk/i386/grub.conf                      |    8 +
 data/bootdisk/i386/syslinux.cfg                   |   33 +
 data/bootdisk/ppc/Makefile.am                     |   26 +
 data/bootdisk/ppc/bootinfo.txt                    |  169 +
 data/bootdisk/ppc/magic                           |   81 +
 data/bootdisk/ppc/mapping                         |   27 +
 data/bootdisk/ppc/ofboot.b                        |   74 +
 data/bootdisk/ppc/yaboot.conf.3264                |   14 +
 data/bootdisk/ppc/yaboot.conf.in                  |    8 +
 data/bootdisk/s390x/Makefile.am                   |   25 +
 data/bootdisk/s390x/generic.ins                   |    5 +
 data/bootdisk/s390x/generic.prm                   |    1 +
 data/bootdisk/s390x/redhat.exec                   |    9 +
 data/bootdisk/sparc/Makefile.am                   |   25 +
 data/bootdisk/sparc/boot.msg                      |    9 +
 data/bootdisk/sparc/silo.conf                     |   17 +
 data/bootdisk/x86_64/Makefile.am                  |   25 +
 data/bootdisk/x86_64/boot.msg                     |    5 +
 data/bootdisk/x86_64/grub.conf                    |    8 +
 data/bootdisk/x86_64/syslinux.cfg                 |   33 +
 data/command-stubs/Makefile.am                    |   23 +
 data/command-stubs/list-harddrives-stub           |   45 +
 data/command-stubs/loadkeys-stub                  |   41 +
 data/command-stubs/losetup-stub                   |   50 +
 data/command-stubs/mknod-stub                     |   54 +
 data/command-stubs/raidstart-stub                 |   44 +
 data/command-stubs/raidstop-stub                  |   31 +
 data/fonts/Makefile.am                            |   39 +
 data/fonts/screenfont-alpha.gz                    |  Bin 0 -> 4893 bytes
 data/fonts/screenfont-i386.gz                     |  Bin 0 -> 5507 bytes
 data/fonts/screenfont-ia64.gz                     |  Bin 0 -> 3821 bytes
 data/fonts/screenfont-ppc.gz                      |  Bin 0 -> 5305 bytes
 data/fonts/screenfont-sparc.gz                    |  Bin 0 -> 6455 bytes
 data/fonts/screenfont-x86_64.gz                   |  Bin 0 -> 5473 bytes
 data/fonts/updfonts                               |   11 +
 data/icons/Makefile.am                            |   22 +
 data/icons/hicolor/16x16/Makefile.am              |   22 +
 data/icons/hicolor/16x16/apps/Makefile.am         |   23 +
 data/icons/hicolor/16x16/apps/anaconda.png        |  Bin 0 -> 925 bytes
 data/icons/hicolor/22x22/Makefile.am              |   22 +
 data/icons/hicolor/22x22/apps/Makefile.am         |   23 +
 data/icons/hicolor/22x22/apps/anaconda.png        |  Bin 0 -> 1326 bytes
 data/icons/hicolor/24x24/Makefile.am              |   22 +
 data/icons/hicolor/24x24/apps/Makefile.am         |   23 +
 data/icons/hicolor/24x24/apps/anaconda.png        |  Bin 0 -> 1368 bytes
 data/icons/hicolor/32x32/Makefile.am              |   22 +
 data/icons/hicolor/32x32/apps/Makefile.am         |   23 +
 data/icons/hicolor/32x32/apps/anaconda.png        |  Bin 0 -> 1860 bytes
 data/icons/hicolor/48x48/Makefile.am              |   22 +
 data/icons/hicolor/48x48/apps/Makefile.am         |   23 +
 data/icons/hicolor/48x48/apps/anaconda.png        |  Bin 0 -> 3020 bytes
 data/icons/hicolor/Makefile.am                    |   22 +
 data/lang-table                                   |   61 +
 data/liveinst/.gitignore                          |    1 +
 data/liveinst/Makefile.am                         |   56 +
 data/liveinst/README                              |    1 +
 data/liveinst/console.apps/Makefile.am            |   26 +
 data/liveinst/console.apps/liveinst               |    6 +
 data/liveinst/liveinst                            |   95 +
 data/liveinst/liveinst.desktop.in                 |   12 +
 data/liveinst/pam.d/Makefile.am                   |   25 +
 data/liveinst/pam.d/liveinst                      |    4 +
 data/liveinst/zz-liveinst.sh                      |   14 +
 data/pixmaps/Makefile.am                          |   23 +
 data/pixmaps/about-to-install.png                 |  Bin 0 -> 10818 bytes
 data/pixmaps/checkMark.png                        |  Bin 0 -> 347 bytes
 data/pixmaps/config-language.png                  |  Bin 0 -> 3079 bytes
 data/pixmaps/done.png                             |  Bin 0 -> 25801 bytes
 data/pixmaps/filter-menu.png                      |  Bin 0 -> 456 bytes
 data/pixmaps/gnome-lock.png                       |  Bin 0 -> 810 bytes
 data/pixmaps/gnome-mouse.png                      |  Bin 0 -> 2744 bytes
 data/pixmaps/install.png                          |  Bin 0 -> 4180 bytes
 data/pixmaps/network.png                          |  Bin 0 -> 2458 bytes
 data/pixmaps/partscheme-all.png                   |  Bin 0 -> 1594 bytes
 data/pixmaps/partscheme-custom.png                |  Bin 0 -> 805 bytes
 data/pixmaps/partscheme-freespace.png             |  Bin 0 -> 1724 bytes
 data/pixmaps/partscheme-replace.png               |  Bin 0 -> 1783 bytes
 data/pixmaps/partscheme-shrink.png                |  Bin 0 -> 1875 bytes
 data/pixmaps/root-password.png                    |  Bin 0 -> 4316 bytes
 data/pixmaps/upgrade.png                          |  Bin 0 -> 4632 bytes
 data/ui/GroupSelector.glade                       |  394 +++
 data/ui/Makefile.am                               |   25 +
 data/ui/account.glade                             |  278 ++
 data/ui/adddrive.glade                            |  196 ++
 data/ui/addrepo.glade                             | 1016 ++++++
 data/ui/anaconda.glade                            |  270 ++
 data/ui/autopart.glade                            |  300 ++
 data/ui/blwhere.glade                             |  378 +++
 data/ui/cleardisks.glade                          |  300 ++
 data/ui/create-storage.glade                      |  379 +++
 data/ui/detailed-dialog.glade                     |  171 +
 data/ui/fcoe-config.glade                         |  130 +
 data/ui/filter.glade                              | 1387 ++++++++
 data/ui/iscsi-config.glade                        |  456 +++
 data/ui/lukspassphrase.glade                      |  446 +++
 data/ui/netconfig.glade                           |  538 ++++
 data/ui/network.glade                             |  259 ++
 data/ui/tasksel.glade                             |  335 ++
 data/ui/zfcp-config.glade                         |  276 ++
 desktop.py                                        |   71 -
 dispatch.py                                       |  254 --
 errors.py                                         |  159 -
 exception.py                                      |  132 -
 firewall.py                                       |   93 -
 flags.py                                          |  122 -
 fonts/Makefile.am                                 |   39 -
 fonts/screenfont-alpha.gz                         |  Bin 4893 -> 0 bytes
 fonts/screenfont-i386.gz                          |  Bin 5507 -> 0 bytes
 fonts/screenfont-ia64.gz                          |  Bin 3821 -> 0 bytes
 fonts/screenfont-ppc.gz                           |  Bin 5305 -> 0 bytes
 fonts/screenfont-sparc.gz                         |  Bin 6455 -> 0 bytes
 fonts/screenfont-x86_64.gz                        |  Bin 5473 -> 0 bytes
 fonts/updfonts                                    |   11 -
 gptsync/.gitignore                                |    2 -
 gptsync/Makefile.am                               |   35 -
 gptsync/README                                    |   41 -
 gptsync/gptsync.c                                 |  470 ---
 gptsync/gptsync.h                                 |  219 --
 gptsync/lib.c                                     |  469 ---
 gptsync/os_unix.c                                 |  267 --
 gptsync/showpart.c                                |  257 --
 gptsync/syslinux_mbr.h                            |   90 -
 gui.py                                            | 1530 ---------
 icons/Makefile.am                                 |   22 -
 icons/hicolor/16x16/Makefile.am                   |   22 -
 icons/hicolor/16x16/apps/Makefile.am              |   23 -
 icons/hicolor/16x16/apps/anaconda.png             |  Bin 925 -> 0 bytes
 icons/hicolor/22x22/Makefile.am                   |   22 -
 icons/hicolor/22x22/apps/Makefile.am              |   23 -
 icons/hicolor/22x22/apps/anaconda.png             |  Bin 1326 -> 0 bytes
 icons/hicolor/24x24/Makefile.am                   |   22 -
 icons/hicolor/24x24/apps/Makefile.am              |   23 -
 icons/hicolor/24x24/apps/anaconda.png             |  Bin 1368 -> 0 bytes
 icons/hicolor/32x32/Makefile.am                   |   22 -
 icons/hicolor/32x32/apps/Makefile.am              |   23 -
 icons/hicolor/32x32/apps/anaconda.png             |  Bin 1860 -> 0 bytes
 icons/hicolor/48x48/Makefile.am                   |   22 -
 icons/hicolor/48x48/apps/Makefile.am              |   23 -
 icons/hicolor/48x48/apps/anaconda.png             |  Bin 3020 -> 0 bytes
 icons/hicolor/Makefile.am                         |   22 -
 image.py                                          |  326 --
 installclass.py                                   |  336 --
 installclasses/Makefile.am                        |   24 -
 installclasses/fedora.py                          |  127 -
 installclasses/rhel.py                            |  113 -
 installinterfacebase.py                           |   76 -
 installmethod.py                                  |   56 -
 isys/.gitignore                                   |    6 -
 isys/Makefile.am                                  |   56 -
 isys/auditd.c                                     |  134 -
 isys/auditd.h                                     |   30 -
 isys/cpio.c                                       |   46 -
 isys/cpio.h                                       |  102 -
 isys/devices.c                                    |  221 --
 isys/devices.h                                    |   42 -
 isys/eddsupport.c                                 |  339 --
 isys/eddsupport.h                                 |   28 -
 isys/ethtool.c                                    |  119 -
 isys/ethtool.h                                    |   41 -
 isys/iface.c                                      |  543 ----
 isys/iface.h                                      |  166 -
 isys/imount.c                                     |  328 --
 isys/imount.h                                     |   50 -
 isys/isofs.c                                      |   55 -
 isys/isys.c                                       |  701 ----
 isys/isys.h                                       |   39 -
 isys/isys.py                                      |  560 ----
 isys/lang.c                                       |  207 --
 isys/lang.h                                       |   44 -
 isys/linkdetect.c                                 |  202 --
 isys/log.c                                        |  224 --
 isys/log.h                                        |   51 -
 isys/stubs.h                                      |   44 -
 isys/uncpio.c                                     |  798 -----
 isys/vio.c                                        |  106 -
 iutil.py                                          | 1073 -------
 iw/DeviceSelector.py                              |  217 --
 iw/GroupSelector.py                               |  620 ----
 iw/Makefile.am                                    |   24 -
 iw/account_gui.py                                 |  148 -
 iw/advanced_storage.py                            |  256 --
 iw/autopart_type.py                               |  284 --
 iw/blpasswidget.py                                |  164 -
 iw/bootloader_main_gui.py                         |  244 --
 iw/checklist.py                                   |  225 --
 iw/cleardisks_gui.py                              |  240 --
 iw/congrats_gui.py                                |  103 -
 iw/datacombo.py                                   |   99 -
 iw/examine_gui.py                                 |  163 -
 iw/filter_gui.py                                  |  764 -----
 iw/filter_type.py                                 |   80 -
 iw/iw_gui.py                                      |   53 -
 iw/kbd_gui.py                                     |   39 -
 iw/language_gui.py                                |  134 -
 iw/lvm_dialog_gui.py                              | 1466 ---------
 iw/netconfig_dialog.py                            |  329 --
 iw/network_gui.py                                 |  106 -
 iw/osbootwidget.py                                |  397 ---
 iw/package_gui.py                                 |   39 -
 iw/partition_dialog_gui.py                        |  534 ---
 iw/partition_gui.py                               | 1835 -----------
 iw/partition_ui_helpers_gui.py                    |  445 ---
 iw/pixmapRadioButtonGroup_gui.py                  |  248 --
 iw/progress_gui.py                                |  150 -
 iw/raid_dialog_gui.py                             |  615 ----
 iw/task_gui.py                                    |  705 ----
 iw/timezone_gui.py                                |  181 --
 iw/upgrade_bootloader_gui.py                      |  209 --
 iw/upgrade_migratefs_gui.py                       |  118 -
 iw/upgrade_swap_gui.py                            |  209 --
 iw/welcome_gui.py                                 |   68 -
 iw/zipl_gui.py                                    |  132 -
 kickstart.py                                      | 1499 ---------
 lang-table                                        |   61 -
 language.py                                       |  280 --
 livecd.py                                         |  469 ---
 liveinst/.gitignore                               |    1 -
 liveinst/Makefile.am                              |   56 -
 liveinst/README                                   |    1 -
 liveinst/console.apps/Makefile.am                 |   26 -
 liveinst/console.apps/liveinst                    |    6 -
 liveinst/liveinst                                 |   95 -
 liveinst/liveinst.desktop.in                      |   12 -
 liveinst/pam.d/Makefile.am                        |   25 -
 liveinst/pam.d/liveinst                           |    4 -
 liveinst/zz-liveinst.sh                           |   14 -
 loader/.gitignore                                 |   12 -
 loader/Makefile.am                                |  118 -
 loader/cdinstall.c                                |  509 ---
 loader/cdinstall.h                                |   34 -
 loader/copy.c                                     |  141 -
 loader/copy.h                                     |   26 -
 loader/devices.h                                  |  103 -
 loader/devt.h                                     |   39 -
 loader/dirbrowser.c                               |  199 --
 loader/dirbrowser.h                               |   28 -
 loader/driverdisk.c                               |  861 -----
 loader/driverdisk.h                               |   51 -
 loader/driverselect.c                             |  251 --
 loader/fwloader.c                                 |  675 ----
 loader/fwloader.h                                 |   35 -
 loader/getparts.c                                 |  180 --
 loader/getparts.h                                 |   27 -
 loader/hardware.c                                 |  150 -
 loader/hardware.h                                 |   28 -
 loader/hdinstall.c                                |  496 ---
 loader/hdinstall.h                                |   38 -
 loader/ibft.c                                     |  105 -
 loader/ibft.h                                     |   45 -
 loader/init.c                                     |  798 -----
 loader/init.h                                     |   31 -
 loader/kbd.c                                      |  164 -
 loader/kbd.h                                      |   27 -
 loader/keymaps-i386                               |  Bin 12173 -> 0 bytes
 loader/keymaps-ppc                                |  Bin 12871 -> 0 bytes
 loader/keymaps-x86_64                             |  Bin 12173 -> 0 bytes
 loader/kickstart.c                                |  559 ----
 loader/kickstart.h                                |   54 -
 loader/lang.c                                     |  399 ---
 loader/lang.h                                     |   41 -
 loader/linuxrc.s390                               | 3118 ------------------
 loader/loader.c                                   | 2378 --------------
 loader/loader.h                                   |  193 --
 loader/loadermisc.c                               |  150 -
 loader/loadermisc.h                               |   33 -
 loader/mediacheck.c                               |  115 -
 loader/mediacheck.h                               |   25 -
 loader/method.c                                   |  570 ----
 loader/method.h                                   |   60 -
 loader/mkctype.c                                  |   76 -
 loader/moduleinfo.c                               |  276 --
 loader/moduleinfo.h                               |   78 -
 loader/modules.c                                  |  530 ---
 loader/modules.h                                  |   47 -
 loader/net.c                                      | 2122 ------------
 loader/net.h                                      |   77 -
 loader/nfsinstall.c                               |  586 ----
 loader/nfsinstall.h                               |   40 -
 loader/rpmextract.c                               |  325 --
 loader/rpmextract.h                               |   45 -
 loader/selinux.c                                  |   56 -
 loader/selinux.h                                  |   27 -
 loader/shutdown.c                                 |  153 -
 loader/simplemot                                  |   81 -
 loader/telnet.c                                   |  273 --
 loader/telnet.h                                   |   40 -
 loader/telnetd.c                                  |  256 --
 loader/telnetd.h                                  |   25 -
 loader/udelay.h                                   |  199 --
 loader/undomounts.c                               |  239 --
 loader/unicode-linedraw-chars.txt                 |   22 -
 loader/urlinstall.c                               |  414 ---
 loader/urlinstall.h                               |   36 -
 loader/urls.c                                     |  371 ---
 loader/urls.h                                     |   35 -
 loader/windows.c                                  |  121 -
 loader/windows.h                                  |   43 -
 network.py                                        |  839 -----
 packages.py                                       |  360 ---
 partIntfHelpers.py                                |  354 --
 pixmaps/Makefile.am                               |   23 -
 pixmaps/about-to-install.png                      |  Bin 10818 -> 0 bytes
 pixmaps/checkMark.png                             |  Bin 347 -> 0 bytes
 pixmaps/config-language.png                       |  Bin 3079 -> 0 bytes
 pixmaps/done.png                                  |  Bin 25801 -> 0 bytes
 pixmaps/filter-menu.png                           |  Bin 456 -> 0 bytes
 pixmaps/gnome-lock.png                            |  Bin 810 -> 0 bytes
 pixmaps/gnome-mouse.png                           |  Bin 2744 -> 0 bytes
 pixmaps/install.png                               |  Bin 4180 -> 0 bytes
 pixmaps/network.png                               |  Bin 2458 -> 0 bytes
 pixmaps/partscheme-all.png                        |  Bin 1594 -> 0 bytes
 pixmaps/partscheme-custom.png                     |  Bin 805 -> 0 bytes
 pixmaps/partscheme-freespace.png                  |  Bin 1724 -> 0 bytes
 pixmaps/partscheme-replace.png                    |  Bin 1783 -> 0 bytes
 pixmaps/partscheme-shrink.png                     |  Bin 1875 -> 0 bytes
 pixmaps/root-password.png                         |  Bin 4316 -> 0 bytes
 pixmaps/upgrade.png                               |  Bin 4632 -> 0 bytes
 platform.py                                       |  574 ----
 product.py                                        |   63 -
 pyanaconda/Makefile.am                            |   34 +
 pyanaconda/__init__.py                            |  395 +++
 pyanaconda/anaconda_log.py                        |  170 +
 pyanaconda/backend.py                             |  301 ++
 pyanaconda/backend_log.py                         |   88 +
 pyanaconda/baseudev.py                            |   92 +
 pyanaconda/bootloader.py                          |  244 ++
 pyanaconda/cmdline.py                             |  221 ++
 pyanaconda/compssort.py                           |   69 +
 pyanaconda/constants.py                           |   89 +
 pyanaconda/desktop.py                             |   71 +
 pyanaconda/dispatch.py                            |  254 ++
 pyanaconda/errors.py                              |  159 +
 pyanaconda/exception.py                           |  132 +
 pyanaconda/firewall.py                            |   93 +
 pyanaconda/flags.py                               |  122 +
 pyanaconda/gui.py                                 | 1530 +++++++++
 pyanaconda/image.py                               |  326 ++
 pyanaconda/installclass.py                        |  336 ++
 pyanaconda/installclasses/Makefile.am             |   24 +
 pyanaconda/installclasses/fedora.py               |  127 +
 pyanaconda/installclasses/rhel.py                 |  113 +
 pyanaconda/installinterfacebase.py                |   76 +
 pyanaconda/installmethod.py                       |   56 +
 pyanaconda/isys/.gitignore                        |    6 +
 pyanaconda/isys/Makefile.am                       |   56 +
 pyanaconda/isys/__init__.py                       |  560 ++++
 pyanaconda/isys/auditd.c                          |  134 +
 pyanaconda/isys/auditd.h                          |   30 +
 pyanaconda/isys/cpio.c                            |   46 +
 pyanaconda/isys/cpio.h                            |  102 +
 pyanaconda/isys/devices.c                         |  221 ++
 pyanaconda/isys/devices.h                         |   42 +
 pyanaconda/isys/eddsupport.c                      |  339 ++
 pyanaconda/isys/eddsupport.h                      |   28 +
 pyanaconda/isys/ethtool.c                         |  119 +
 pyanaconda/isys/ethtool.h                         |   41 +
 pyanaconda/isys/iface.c                           |  543 ++++
 pyanaconda/isys/iface.h                           |  166 +
 pyanaconda/isys/imount.c                          |  328 ++
 pyanaconda/isys/imount.h                          |   50 +
 pyanaconda/isys/isofs.c                           |   55 +
 pyanaconda/isys/isys.c                            |  701 ++++
 pyanaconda/isys/isys.h                            |   39 +
 pyanaconda/isys/lang.c                            |  207 ++
 pyanaconda/isys/lang.h                            |   44 +
 pyanaconda/isys/linkdetect.c                      |  202 ++
 pyanaconda/isys/log.c                             |  224 ++
 pyanaconda/isys/log.h                             |   51 +
 pyanaconda/isys/stubs.h                           |   44 +
 pyanaconda/isys/uncpio.c                          |  798 +++++
 pyanaconda/isys/vio.c                             |  106 +
 pyanaconda/iutil.py                               | 1073 +++++++
 pyanaconda/iw/DeviceSelector.py                   |  217 ++
 pyanaconda/iw/GroupSelector.py                    |  620 ++++
 pyanaconda/iw/Makefile.am                         |   24 +
 pyanaconda/iw/account_gui.py                      |  148 +
 pyanaconda/iw/advanced_storage.py                 |  256 ++
 pyanaconda/iw/autopart_type.py                    |  284 ++
 pyanaconda/iw/blpasswidget.py                     |  164 +
 pyanaconda/iw/bootloader_main_gui.py              |  244 ++
 pyanaconda/iw/checklist.py                        |  225 ++
 pyanaconda/iw/cleardisks_gui.py                   |  240 ++
 pyanaconda/iw/congrats_gui.py                     |  103 +
 pyanaconda/iw/datacombo.py                        |   99 +
 pyanaconda/iw/examine_gui.py                      |  163 +
 pyanaconda/iw/filter_gui.py                       |  764 +++++
 pyanaconda/iw/filter_type.py                      |   80 +
 pyanaconda/iw/iw_gui.py                           |   53 +
 pyanaconda/iw/kbd_gui.py                          |   39 +
 pyanaconda/iw/language_gui.py                     |  134 +
 pyanaconda/iw/lvm_dialog_gui.py                   | 1466 +++++++++
 pyanaconda/iw/netconfig_dialog.py                 |  329 ++
 pyanaconda/iw/network_gui.py                      |  106 +
 pyanaconda/iw/osbootwidget.py                     |  397 +++
 pyanaconda/iw/package_gui.py                      |   39 +
 pyanaconda/iw/partition_dialog_gui.py             |  534 +++
 pyanaconda/iw/partition_gui.py                    | 1835 +++++++++++
 pyanaconda/iw/partition_ui_helpers_gui.py         |  445 +++
 pyanaconda/iw/pixmapRadioButtonGroup_gui.py       |  248 ++
 pyanaconda/iw/progress_gui.py                     |  150 +
 pyanaconda/iw/raid_dialog_gui.py                  |  615 ++++
 pyanaconda/iw/task_gui.py                         |  705 ++++
 pyanaconda/iw/timezone_gui.py                     |  181 ++
 pyanaconda/iw/upgrade_bootloader_gui.py           |  209 ++
 pyanaconda/iw/upgrade_migratefs_gui.py            |  118 +
 pyanaconda/iw/upgrade_swap_gui.py                 |  209 ++
 pyanaconda/iw/welcome_gui.py                      |   68 +
 pyanaconda/iw/zipl_gui.py                         |  132 +
 pyanaconda/kickstart.py                           | 1499 +++++++++
 pyanaconda/language.py                            |  280 ++
 pyanaconda/livecd.py                              |  469 +++
 pyanaconda/network.py                             |  839 +++++
 pyanaconda/packages.py                            |  360 +++
 pyanaconda/partIntfHelpers.py                     |  354 ++
 pyanaconda/platform.py                            |  574 ++++
 pyanaconda/product.py                             |   63 +
 pyanaconda/pyudev.py                              |  225 ++
 pyanaconda/rescue.py                              |  508 +++
 pyanaconda/run_test.py                            |  109 +
 pyanaconda/security.py                            |   87 +
 pyanaconda/simpleconfig.py                        |   88 +
 pyanaconda/sitecustomize.py                       |   22 +
 pyanaconda/sortedtransaction.py                   |   87 +
 pyanaconda/storage/Makefile.am                    |   26 +
 pyanaconda/storage/__init__.py                    | 2252 +++++++++++++
 pyanaconda/storage/dasd.py                        |  225 ++
 pyanaconda/storage/deviceaction.py                |  376 +++
 pyanaconda/storage/devicelibs/Makefile.am         |   24 +
 pyanaconda/storage/devicelibs/crypto.py           |  193 ++
 pyanaconda/storage/devicelibs/dm.py               |  130 +
 pyanaconda/storage/devicelibs/edd.py              |   97 +
 pyanaconda/storage/devicelibs/lvm.py              |  419 +++
 pyanaconda/storage/devicelibs/mdraid.py           |  236 ++
 pyanaconda/storage/devicelibs/mpath.py            |  228 ++
 pyanaconda/storage/devicelibs/swap.py             |  125 +
 pyanaconda/storage/devices.py                     | 3564 +++++++++++++++++++++
 pyanaconda/storage/devicetree.py                  | 2278 +++++++++++++
 pyanaconda/storage/errors.py                      |  153 +
 pyanaconda/storage/fcoe.py                        |  164 +
 pyanaconda/storage/formats/Makefile.am            |   24 +
 pyanaconda/storage/formats/__init__.py            |  403 +++
 pyanaconda/storage/formats/disklabel.py           |  356 ++
 pyanaconda/storage/formats/dmraid.py              |  114 +
 pyanaconda/storage/formats/fs.py                  | 1488 +++++++++
 pyanaconda/storage/formats/luks.py                |  352 ++
 pyanaconda/storage/formats/lvmpv.py               |  156 +
 pyanaconda/storage/formats/mdraid.py              |  124 +
 pyanaconda/storage/formats/multipath.py           |   95 +
 pyanaconda/storage/formats/prepboot.py            |   64 +
 pyanaconda/storage/formats/swap.py                |  186 ++
 pyanaconda/storage/iscsi.py                       |  333 ++
 pyanaconda/storage/miscutils.py                   |   57 +
 pyanaconda/storage/partitioning.py                | 1707 ++++++++++
 pyanaconda/storage/partspec.py                    |   66 +
 pyanaconda/storage/storage_log.py                 |   32 +
 pyanaconda/storage/udev.py                        |  523 +++
 pyanaconda/storage/zfcp.py                        |  441 +++
 pyanaconda/text.py                                |  692 ++++
 pyanaconda/textw/Makefile.am                      |   24 +
 pyanaconda/textw/add_drive_text.py                |  180 ++
 pyanaconda/textw/complete_text.py                 |   65 +
 pyanaconda/textw/constants_text.py                |   68 +
 pyanaconda/textw/keyboard_text.py                 |   67 +
 pyanaconda/textw/language_text.py                 |   70 +
 pyanaconda/textw/netconfig_text.py                |  285 ++
 pyanaconda/textw/network_text.py                  |   33 +
 pyanaconda/textw/partition_text.py                |  162 +
 pyanaconda/textw/progress_text.py                 |  131 +
 pyanaconda/textw/statusline_text.py               |   78 +
 pyanaconda/textw/task_text.py                     |   28 +
 pyanaconda/textw/timezone_text.py                 |  131 +
 pyanaconda/textw/upgrade_bootloader_text.py       |  183 ++
 pyanaconda/textw/upgrade_text.py                  |  258 ++
 pyanaconda/textw/userauth_text.py                 |  107 +
 pyanaconda/textw/welcome_text.py                  |   47 +
 pyanaconda/textw/zipl_text.py                     |  102 +
 pyanaconda/timezone.py                            |   76 +
 pyanaconda/upgrade.py                             |  344 ++
 pyanaconda/users.py                               |  307 ++
 pyanaconda/vnc.py                                 |  437 +++
 pyanaconda/xutils.c                               |  268 ++
 pyanaconda/yuminstall.py                          | 2024 ++++++++++++
 pyudev.py                                         |  225 --
 rescue.py                                         |  508 ---
 run_test.py                                       |  109 -
 security.py                                       |   87 -
 simpleconfig.py                                   |   88 -
 sitecustomize.py                                  |   22 -
 sortedtransaction.py                              |   87 -
 storage/Makefile.am                               |   26 -
 storage/__init__.py                               | 2252 -------------
 storage/dasd.py                                   |  225 --
 storage/deviceaction.py                           |  376 ---
 storage/devicelibs/Makefile.am                    |   24 -
 storage/devicelibs/crypto.py                      |  193 --
 storage/devicelibs/dm.py                          |  130 -
 storage/devicelibs/edd.py                         |   97 -
 storage/devicelibs/lvm.py                         |  419 ---
 storage/devicelibs/mdraid.py                      |  236 --
 storage/devicelibs/mpath.py                       |  228 --
 storage/devicelibs/swap.py                        |  125 -
 storage/devices.py                                | 3564 ---------------------
 storage/devicetree.py                             | 2278 -------------
 storage/errors.py                                 |  153 -
 storage/fcoe.py                                   |  164 -
 storage/formats/Makefile.am                       |   24 -
 storage/formats/__init__.py                       |  403 ---
 storage/formats/disklabel.py                      |  356 --
 storage/formats/dmraid.py                         |  114 -
 storage/formats/fs.py                             | 1488 ---------
 storage/formats/luks.py                           |  352 --
 storage/formats/lvmpv.py                          |  156 -
 storage/formats/mdraid.py                         |  124 -
 storage/formats/multipath.py                      |   95 -
 storage/formats/prepboot.py                       |   64 -
 storage/formats/swap.py                           |  186 --
 storage/iscsi.py                                  |  333 --
 storage/miscutils.py                              |   57 -
 storage/partitioning.py                           | 1707 ----------
 storage/partspec.py                               |   66 -
 storage/storage_log.py                            |   32 -
 storage/udev.py                                   |  523 ---
 storage/zfcp.py                                   |  441 ---
 stubs/.gitignore                                  |    2 -
 tests/Makefile.am                                 |    2 +-
 tests/__init__.py                                 |   31 -
 tests/kickstart/Makefile.am                       |   26 -
 tests/kickstart/commands.py                       |   61 -
 tests/kickstart_test/Makefile.am                  |   26 +
 tests/kickstart_test/commands_test.py             |   90 +
 tests/mock/Makefile.am                            |   24 +
 tests/mock/__init__.py                            |   17 +
 tests/storage/Makefile.am                         |   24 -
 tests/storage/devicelibs/Makefile.am              |   30 -
 tests/storage/devicelibs/baseclass.py             |   55 -
 tests/storage/devicelibs/crypto.py                |  131 -
 tests/storage/devicelibs/lvm.py                   |  234 --
 tests/storage/devicelibs/mdraid.py                |  110 -
 tests/storage/devicelibs/mpath.py                 |   33 -
 tests/storage/devicelibs/swap.py                  |   70 -
 tests/storage_test/Makefile.am                    |   24 +
 tests/storage_test/devicelibs_test/Makefile.am    |   30 +
 tests/storage_test/devicelibs_test/baseclass.py   |   55 +
 tests/storage_test/devicelibs_test/crypto_test.py |  131 +
 tests/storage_test/devicelibs_test/lvm_test.py    |  234 ++
 tests/storage_test/devicelibs_test/mdraid_test.py |  110 +
 tests/storage_test/devicelibs_test/mpath_test.py  |   33 +
 tests/storage_test/devicelibs_test/swap_test.py   |   70 +
 text.py                                           |  692 ----
 textw/Makefile.am                                 |   24 -
 textw/add_drive_text.py                           |  180 --
 textw/complete_text.py                            |   65 -
 textw/constants_text.py                           |   68 -
 textw/keyboard_text.py                            |   67 -
 textw/language_text.py                            |   70 -
 textw/netconfig_text.py                           |  285 --
 textw/network_text.py                             |   33 -
 textw/partition_text.py                           |  162 -
 textw/progress_text.py                            |  131 -
 textw/statusline_text.py                          |   78 -
 textw/task_text.py                                |   28 -
 textw/timezone_text.py                            |  131 -
 textw/upgrade_bootloader_text.py                  |  183 --
 textw/upgrade_text.py                             |  258 --
 textw/userauth_text.py                            |  107 -
 textw/welcome_text.py                             |   47 -
 textw/zipl_text.py                                |  102 -
 timezone.py                                       |   76 -
 ui/GroupSelector.glade                            |  394 ---
 ui/Makefile.am                                    |   25 -
 ui/account.glade                                  |  278 --
 ui/adddrive.glade                                 |  196 --
 ui/addrepo.glade                                  | 1016 ------
 ui/anaconda.glade                                 |  270 --
 ui/autopart.glade                                 |  300 --
 ui/blwhere.glade                                  |  378 ---
 ui/cleardisks.glade                               |  300 --
 ui/create-storage.glade                           |  379 ---
 ui/detailed-dialog.glade                          |  171 -
 ui/fcoe-config.glade                              |  130 -
 ui/filter.glade                                   | 1387 --------
 ui/iscsi-config.glade                             |  456 ---
 ui/lukspassphrase.glade                           |  446 ---
 ui/netconfig.glade                                |  538 ----
 ui/network.glade                                  |  259 --
 ui/tasksel.glade                                  |  335 --
 ui/zfcp-config.glade                              |  276 --
 upgrade.py                                        |  344 --
 users.py                                          |  307 --
 vnc.py                                            |  437 ---
 xutils.c                                          |  268 --
 yuminstall.py                                     | 2024 ------------
 722 files changed, 84215 insertions(+), 84105 deletions(-)
 delete mode 100644 70-anaconda.rules
 delete mode 100644 __init__.py
 delete mode 100755 anaconda
 create mode 100755 anaconda.py
 delete mode 100644 anaconda_log.py
 delete mode 100644 backend.py
 delete mode 100644 backend_log.py
 delete mode 100644 baseudev.py
 create mode 100644 bin/Makefile.am
 create mode 100644 bin/gptsync/.gitignore
 create mode 100644 bin/gptsync/Makefile.am
 create mode 100644 bin/gptsync/README
 create mode 100644 bin/gptsync/gptsync.c
 create mode 100644 bin/gptsync/gptsync.h
 create mode 100644 bin/gptsync/lib.c
 create mode 100644 bin/gptsync/os_unix.c
 create mode 100644 bin/gptsync/showpart.c
 create mode 100644 bin/gptsync/syslinux_mbr.h
 create mode 100644 bin/loader/.gitignore
 create mode 100644 bin/loader/Makefile.am
 create mode 100644 bin/loader/cdinstall.c
 create mode 100644 bin/loader/cdinstall.h
 create mode 100644 bin/loader/copy.c
 create mode 100644 bin/loader/copy.h
 create mode 100644 bin/loader/devices.h
 create mode 100644 bin/loader/devt.h
 create mode 100644 bin/loader/dirbrowser.c
 create mode 100644 bin/loader/dirbrowser.h
 create mode 100644 bin/loader/driverdisk.c
 create mode 100644 bin/loader/driverdisk.h
 create mode 100644 bin/loader/driverselect.c
 create mode 100644 bin/loader/fwloader.c
 create mode 100644 bin/loader/fwloader.h
 create mode 100644 bin/loader/getparts.c
 create mode 100644 bin/loader/getparts.h
 create mode 100644 bin/loader/hardware.c
 create mode 100644 bin/loader/hardware.h
 create mode 100644 bin/loader/hdinstall.c
 create mode 100644 bin/loader/hdinstall.h
 create mode 100644 bin/loader/ibft.c
 create mode 100644 bin/loader/ibft.h
 create mode 100644 bin/loader/init.c
 create mode 100644 bin/loader/init.h
 create mode 100644 bin/loader/kbd.c
 create mode 100644 bin/loader/kbd.h
 create mode 100644 bin/loader/keymaps-i386
 create mode 100644 bin/loader/keymaps-ppc
 create mode 100644 bin/loader/keymaps-x86_64
 create mode 100644 bin/loader/kickstart.c
 create mode 100644 bin/loader/kickstart.h
 create mode 100644 bin/loader/lang.c
 create mode 100644 bin/loader/lang.h
 create mode 100644 bin/loader/linuxrc.s390
 create mode 100644 bin/loader/loader.c
 create mode 100644 bin/loader/loader.h
 create mode 100644 bin/loader/loadermisc.c
 create mode 100644 bin/loader/loadermisc.h
 create mode 100644 bin/loader/mediacheck.c
 create mode 100644 bin/loader/mediacheck.h
 create mode 100644 bin/loader/method.c
 create mode 100644 bin/loader/method.h
 create mode 100644 bin/loader/mkctype.c
 create mode 100644 bin/loader/moduleinfo.c
 create mode 100644 bin/loader/moduleinfo.h
 create mode 100644 bin/loader/modules.c
 create mode 100644 bin/loader/modules.h
 create mode 100644 bin/loader/net.c
 create mode 100644 bin/loader/net.h
 create mode 100644 bin/loader/nfsinstall.c
 create mode 100644 bin/loader/nfsinstall.h
 create mode 100644 bin/loader/rpmextract.c
 create mode 100644 bin/loader/rpmextract.h
 create mode 100644 bin/loader/selinux.c
 create mode 100644 bin/loader/selinux.h
 create mode 100644 bin/loader/shutdown.c
 create mode 100755 bin/loader/simplemot
 create mode 100644 bin/loader/telnet.c
 create mode 100644 bin/loader/telnet.h
 create mode 100644 bin/loader/telnetd.c
 create mode 100644 bin/loader/telnetd.h
 create mode 100644 bin/loader/udelay.h
 create mode 100644 bin/loader/undomounts.c
 create mode 100644 bin/loader/unicode-linedraw-chars.txt
 create mode 100644 bin/loader/urlinstall.c
 create mode 100644 bin/loader/urlinstall.h
 create mode 100644 bin/loader/urls.c
 create mode 100644 bin/loader/urls.h
 create mode 100644 bin/loader/windows.c
 create mode 100644 bin/loader/windows.h
 delete mode 100644 bootdisk/Makefile.am
 delete mode 100644 bootdisk/i386/Makefile.am
 delete mode 100644 bootdisk/i386/boot.msg
 delete mode 100644 bootdisk/i386/grub.conf
 delete mode 100644 bootdisk/i386/syslinux.cfg
 delete mode 100644 bootdisk/ppc/Makefile.am
 delete mode 100644 bootdisk/ppc/bootinfo.txt
 delete mode 100644 bootdisk/ppc/magic
 delete mode 100644 bootdisk/ppc/mapping
 delete mode 100644 bootdisk/ppc/ofboot.b
 delete mode 100644 bootdisk/ppc/yaboot.conf.3264
 delete mode 100644 bootdisk/ppc/yaboot.conf.in
 delete mode 100644 bootdisk/s390x/Makefile.am
 delete mode 100644 bootdisk/s390x/generic.ins
 delete mode 100644 bootdisk/s390x/generic.prm
 delete mode 100644 bootdisk/s390x/redhat.exec
 delete mode 100644 bootdisk/sparc/Makefile.am
 delete mode 100644 bootdisk/sparc/boot.msg
 delete mode 100644 bootdisk/sparc/silo.conf
 delete mode 100644 bootdisk/x86_64/Makefile.am
 delete mode 100644 bootdisk/x86_64/boot.msg
 delete mode 100644 bootdisk/x86_64/grub.conf
 delete mode 100644 bootdisk/x86_64/syslinux.cfg
 delete mode 100644 bootloader.py
 delete mode 100644 cmdline.py
 delete mode 100644 command-stubs/Makefile.am
 delete mode 100755 command-stubs/list-harddrives-stub
 delete mode 100755 command-stubs/loadkeys-stub
 delete mode 100755 command-stubs/losetup-stub
 delete mode 100755 command-stubs/mknod-stub
 delete mode 100755 command-stubs/raidstart-stub
 delete mode 100755 command-stubs/raidstop-stub
 delete mode 100644 compssort.py
 delete mode 100644 constants.py
 create mode 100644 data/70-anaconda.rules
 create mode 100644 data/Makefile.am
 create mode 100644 data/bootdisk/Makefile.am
 create mode 100644 data/bootdisk/i386/Makefile.am
 create mode 100644 data/bootdisk/i386/boot.msg
 create mode 100644 data/bootdisk/i386/grub.conf
 create mode 100644 data/bootdisk/i386/syslinux.cfg
 create mode 100644 data/bootdisk/ppc/Makefile.am
 create mode 100644 data/bootdisk/ppc/bootinfo.txt
 create mode 100644 data/bootdisk/ppc/magic
 create mode 100644 data/bootdisk/ppc/mapping
 create mode 100644 data/bootdisk/ppc/ofboot.b
 create mode 100644 data/bootdisk/ppc/yaboot.conf.3264
 create mode 100644 data/bootdisk/ppc/yaboot.conf.in
 create mode 100644 data/bootdisk/s390x/Makefile.am
 create mode 100644 data/bootdisk/s390x/generic.ins
 create mode 100644 data/bootdisk/s390x/generic.prm
 create mode 100644 data/bootdisk/s390x/redhat.exec
 create mode 100644 data/bootdisk/sparc/Makefile.am
 create mode 100644 data/bootdisk/sparc/boot.msg
 create mode 100644 data/bootdisk/sparc/silo.conf
 create mode 100644 data/bootdisk/x86_64/Makefile.am
 create mode 100644 data/bootdisk/x86_64/boot.msg
 create mode 100644 data/bootdisk/x86_64/grub.conf
 create mode 100644 data/bootdisk/x86_64/syslinux.cfg
 create mode 100644 data/command-stubs/Makefile.am
 create mode 100755 data/command-stubs/list-harddrives-stub
 create mode 100755 data/command-stubs/loadkeys-stub
 create mode 100755 data/command-stubs/losetup-stub
 create mode 100755 data/command-stubs/mknod-stub
 create mode 100755 data/command-stubs/raidstart-stub
 create mode 100755 data/command-stubs/raidstop-stub
 create mode 100644 data/fonts/Makefile.am
 create mode 100644 data/fonts/screenfont-alpha.gz
 create mode 100644 data/fonts/screenfont-i386.gz
 create mode 100644 data/fonts/screenfont-ia64.gz
 create mode 100644 data/fonts/screenfont-ppc.gz
 create mode 100644 data/fonts/screenfont-sparc.gz
 create mode 100644 data/fonts/screenfont-x86_64.gz
 create mode 100755 data/fonts/updfonts
 create mode 100644 data/icons/Makefile.am
 create mode 100644 data/icons/hicolor/16x16/Makefile.am
 create mode 100644 data/icons/hicolor/16x16/apps/Makefile.am
 create mode 100644 data/icons/hicolor/16x16/apps/anaconda.png
 create mode 100644 data/icons/hicolor/22x22/Makefile.am
 create mode 100644 data/icons/hicolor/22x22/apps/Makefile.am
 create mode 100644 data/icons/hicolor/22x22/apps/anaconda.png
 create mode 100644 data/icons/hicolor/24x24/Makefile.am
 create mode 100644 data/icons/hicolor/24x24/apps/Makefile.am
 create mode 100644 data/icons/hicolor/24x24/apps/anaconda.png
 create mode 100644 data/icons/hicolor/32x32/Makefile.am
 create mode 100644 data/icons/hicolor/32x32/apps/Makefile.am
 create mode 100644 data/icons/hicolor/32x32/apps/anaconda.png
 create mode 100644 data/icons/hicolor/48x48/Makefile.am
 create mode 100644 data/icons/hicolor/48x48/apps/Makefile.am
 create mode 100644 data/icons/hicolor/48x48/apps/anaconda.png
 create mode 100644 data/icons/hicolor/Makefile.am
 create mode 100644 data/lang-table
 create mode 100644 data/liveinst/.gitignore
 create mode 100644 data/liveinst/Makefile.am
 create mode 100644 data/liveinst/README
 create mode 100644 data/liveinst/console.apps/Makefile.am
 create mode 100644 data/liveinst/console.apps/liveinst
 create mode 100755 data/liveinst/liveinst
 create mode 100644 data/liveinst/liveinst.desktop.in
 create mode 100644 data/liveinst/pam.d/Makefile.am
 create mode 100644 data/liveinst/pam.d/liveinst
 create mode 100755 data/liveinst/zz-liveinst.sh
 create mode 100644 data/pixmaps/Makefile.am
 create mode 100644 data/pixmaps/about-to-install.png
 create mode 100644 data/pixmaps/checkMark.png
 create mode 100644 data/pixmaps/config-language.png
 create mode 100644 data/pixmaps/done.png
 create mode 100644 data/pixmaps/filter-menu.png
 create mode 100644 data/pixmaps/gnome-lock.png
 create mode 100644 data/pixmaps/gnome-mouse.png
 create mode 100644 data/pixmaps/install.png
 create mode 100644 data/pixmaps/network.png
 create mode 100644 data/pixmaps/partscheme-all.png
 create mode 100644 data/pixmaps/partscheme-custom.png
 create mode 100644 data/pixmaps/partscheme-freespace.png
 create mode 100644 data/pixmaps/partscheme-replace.png
 create mode 100644 data/pixmaps/partscheme-shrink.png
 create mode 100644 data/pixmaps/root-password.png
 create mode 100644 data/pixmaps/upgrade.png
 create mode 100644 data/ui/GroupSelector.glade
 create mode 100644 data/ui/Makefile.am
 create mode 100644 data/ui/account.glade
 create mode 100644 data/ui/adddrive.glade
 create mode 100644 data/ui/addrepo.glade
 create mode 100644 data/ui/anaconda.glade
 create mode 100644 data/ui/autopart.glade
 create mode 100644 data/ui/blwhere.glade
 create mode 100644 data/ui/cleardisks.glade
 create mode 100644 data/ui/create-storage.glade
 create mode 100644 data/ui/detailed-dialog.glade
 create mode 100644 data/ui/fcoe-config.glade
 create mode 100644 data/ui/filter.glade
 create mode 100644 data/ui/iscsi-config.glade
 create mode 100644 data/ui/lukspassphrase.glade
 create mode 100644 data/ui/netconfig.glade
 create mode 100644 data/ui/network.glade
 create mode 100644 data/ui/tasksel.glade
 create mode 100644 data/ui/zfcp-config.glade
 delete mode 100644 desktop.py
 delete mode 100644 dispatch.py
 delete mode 100644 errors.py
 delete mode 100644 exception.py
 delete mode 100644 firewall.py
 delete mode 100644 flags.py
 delete mode 100644 fonts/Makefile.am
 delete mode 100644 fonts/screenfont-alpha.gz
 delete mode 100644 fonts/screenfont-i386.gz
 delete mode 100644 fonts/screenfont-ia64.gz
 delete mode 100644 fonts/screenfont-ppc.gz
 delete mode 100644 fonts/screenfont-sparc.gz
 delete mode 100644 fonts/screenfont-x86_64.gz
 delete mode 100755 fonts/updfonts
 delete mode 100644 gptsync/.gitignore
 delete mode 100644 gptsync/Makefile.am
 delete mode 100644 gptsync/README
 delete mode 100644 gptsync/gptsync.c
 delete mode 100644 gptsync/gptsync.h
 delete mode 100644 gptsync/lib.c
 delete mode 100644 gptsync/os_unix.c
 delete mode 100644 gptsync/showpart.c
 delete mode 100644 gptsync/syslinux_mbr.h
 delete mode 100755 gui.py
 delete mode 100644 icons/Makefile.am
 delete mode 100644 icons/hicolor/16x16/Makefile.am
 delete mode 100644 icons/hicolor/16x16/apps/Makefile.am
 delete mode 100644 icons/hicolor/16x16/apps/anaconda.png
 delete mode 100644 icons/hicolor/22x22/Makefile.am
 delete mode 100644 icons/hicolor/22x22/apps/Makefile.am
 delete mode 100644 icons/hicolor/22x22/apps/anaconda.png
 delete mode 100644 icons/hicolor/24x24/Makefile.am
 delete mode 100644 icons/hicolor/24x24/apps/Makefile.am
 delete mode 100644 icons/hicolor/24x24/apps/anaconda.png
 delete mode 100644 icons/hicolor/32x32/Makefile.am
 delete mode 100644 icons/hicolor/32x32/apps/Makefile.am
 delete mode 100644 icons/hicolor/32x32/apps/anaconda.png
 delete mode 100644 icons/hicolor/48x48/Makefile.am
 delete mode 100644 icons/hicolor/48x48/apps/Makefile.am
 delete mode 100644 icons/hicolor/48x48/apps/anaconda.png
 delete mode 100644 icons/hicolor/Makefile.am
 delete mode 100644 image.py
 delete mode 100644 installclass.py
 delete mode 100644 installclasses/Makefile.am
 delete mode 100644 installclasses/fedora.py
 delete mode 100644 installclasses/rhel.py
 delete mode 100644 installinterfacebase.py
 delete mode 100644 installmethod.py
 delete mode 100644 isys/.gitignore
 delete mode 100644 isys/Makefile.am
 delete mode 100644 isys/auditd.c
 delete mode 100644 isys/auditd.h
 delete mode 100644 isys/cpio.c
 delete mode 100644 isys/cpio.h
 delete mode 100644 isys/devices.c
 delete mode 100644 isys/devices.h
 delete mode 100644 isys/eddsupport.c
 delete mode 100644 isys/eddsupport.h
 delete mode 100644 isys/ethtool.c
 delete mode 100644 isys/ethtool.h
 delete mode 100644 isys/iface.c
 delete mode 100644 isys/iface.h
 delete mode 100644 isys/imount.c
 delete mode 100644 isys/imount.h
 delete mode 100644 isys/isofs.c
 delete mode 100644 isys/isys.c
 delete mode 100644 isys/isys.h
 delete mode 100755 isys/isys.py
 delete mode 100644 isys/lang.c
 delete mode 100644 isys/lang.h
 delete mode 100644 isys/linkdetect.c
 delete mode 100644 isys/log.c
 delete mode 100644 isys/log.h
 delete mode 100644 isys/stubs.h
 delete mode 100644 isys/uncpio.c
 delete mode 100644 isys/vio.c
 delete mode 100644 iutil.py
 delete mode 100644 iw/DeviceSelector.py
 delete mode 100644 iw/GroupSelector.py
 delete mode 100644 iw/Makefile.am
 delete mode 100644 iw/account_gui.py
 delete mode 100644 iw/advanced_storage.py
 delete mode 100644 iw/autopart_type.py
 delete mode 100644 iw/blpasswidget.py
 delete mode 100644 iw/bootloader_main_gui.py
 delete mode 100644 iw/checklist.py
 delete mode 100644 iw/cleardisks_gui.py
 delete mode 100644 iw/congrats_gui.py
 delete mode 100644 iw/datacombo.py
 delete mode 100644 iw/examine_gui.py
 delete mode 100644 iw/filter_gui.py
 delete mode 100644 iw/filter_type.py
 delete mode 100644 iw/iw_gui.py
 delete mode 100644 iw/kbd_gui.py
 delete mode 100644 iw/language_gui.py
 delete mode 100644 iw/lvm_dialog_gui.py
 delete mode 100644 iw/netconfig_dialog.py
 delete mode 100644 iw/network_gui.py
 delete mode 100644 iw/osbootwidget.py
 delete mode 100644 iw/package_gui.py
 delete mode 100644 iw/partition_dialog_gui.py
 delete mode 100644 iw/partition_gui.py
 delete mode 100644 iw/partition_ui_helpers_gui.py
 delete mode 100644 iw/pixmapRadioButtonGroup_gui.py
 delete mode 100644 iw/progress_gui.py
 delete mode 100644 iw/raid_dialog_gui.py
 delete mode 100644 iw/task_gui.py
 delete mode 100644 iw/timezone_gui.py
 delete mode 100644 iw/upgrade_bootloader_gui.py
 delete mode 100644 iw/upgrade_migratefs_gui.py
 delete mode 100644 iw/upgrade_swap_gui.py
 delete mode 100644 iw/welcome_gui.py
 delete mode 100644 iw/zipl_gui.py
 delete mode 100644 kickstart.py
 delete mode 100644 lang-table
 delete mode 100644 language.py
 delete mode 100644 livecd.py
 delete mode 100644 liveinst/.gitignore
 delete mode 100644 liveinst/Makefile.am
 delete mode 100644 liveinst/README
 delete mode 100644 liveinst/console.apps/Makefile.am
 delete mode 100644 liveinst/console.apps/liveinst
 delete mode 100755 liveinst/liveinst
 delete mode 100644 liveinst/liveinst.desktop.in
 delete mode 100644 liveinst/pam.d/Makefile.am
 delete mode 100644 liveinst/pam.d/liveinst
 delete mode 100755 liveinst/zz-liveinst.sh
 delete mode 100644 loader/.gitignore
 delete mode 100644 loader/Makefile.am
 delete mode 100644 loader/cdinstall.c
 delete mode 100644 loader/cdinstall.h
 delete mode 100644 loader/copy.c
 delete mode 100644 loader/copy.h
 delete mode 100644 loader/devices.h
 delete mode 100644 loader/devt.h
 delete mode 100644 loader/dirbrowser.c
 delete mode 100644 loader/dirbrowser.h
 delete mode 100644 loader/driverdisk.c
 delete mode 100644 loader/driverdisk.h
 delete mode 100644 loader/driverselect.c
 delete mode 100644 loader/fwloader.c
 delete mode 100644 loader/fwloader.h
 delete mode 100644 loader/getparts.c
 delete mode 100644 loader/getparts.h
 delete mode 100644 loader/hardware.c
 delete mode 100644 loader/hardware.h
 delete mode 100644 loader/hdinstall.c
 delete mode 100644 loader/hdinstall.h
 delete mode 100644 loader/ibft.c
 delete mode 100644 loader/ibft.h
 delete mode 100644 loader/init.c
 delete mode 100644 loader/init.h
 delete mode 100644 loader/kbd.c
 delete mode 100644 loader/kbd.h
 delete mode 100644 loader/keymaps-i386
 delete mode 100644 loader/keymaps-ppc
 delete mode 100644 loader/keymaps-x86_64
 delete mode 100644 loader/kickstart.c
 delete mode 100644 loader/kickstart.h
 delete mode 100644 loader/lang.c
 delete mode 100644 loader/lang.h
 delete mode 100644 loader/linuxrc.s390
 delete mode 100644 loader/loader.c
 delete mode 100644 loader/loader.h
 delete mode 100644 loader/loadermisc.c
 delete mode 100644 loader/loadermisc.h
 delete mode 100644 loader/mediacheck.c
 delete mode 100644 loader/mediacheck.h
 delete mode 100644 loader/method.c
 delete mode 100644 loader/method.h
 delete mode 100644 loader/mkctype.c
 delete mode 100644 loader/moduleinfo.c
 delete mode 100644 loader/moduleinfo.h
 delete mode 100644 loader/modules.c
 delete mode 100644 loader/modules.h
 delete mode 100644 loader/net.c
 delete mode 100644 loader/net.h
 delete mode 100644 loader/nfsinstall.c
 delete mode 100644 loader/nfsinstall.h
 delete mode 100644 loader/rpmextract.c
 delete mode 100644 loader/rpmextract.h
 delete mode 100644 loader/selinux.c
 delete mode 100644 loader/selinux.h
 delete mode 100644 loader/shutdown.c
 delete mode 100755 loader/simplemot
 delete mode 100644 loader/telnet.c
 delete mode 100644 loader/telnet.h
 delete mode 100644 loader/telnetd.c
 delete mode 100644 loader/telnetd.h
 delete mode 100644 loader/udelay.h
 delete mode 100644 loader/undomounts.c
 delete mode 100644 loader/unicode-linedraw-chars.txt
 delete mode 100644 loader/urlinstall.c
 delete mode 100644 loader/urlinstall.h
 delete mode 100644 loader/urls.c
 delete mode 100644 loader/urls.h
 delete mode 100644 loader/windows.c
 delete mode 100644 loader/windows.h
 delete mode 100644 network.py
 delete mode 100644 packages.py
 delete mode 100644 partIntfHelpers.py
 delete mode 100644 pixmaps/Makefile.am
 delete mode 100644 pixmaps/about-to-install.png
 delete mode 100644 pixmaps/checkMark.png
 delete mode 100644 pixmaps/config-language.png
 delete mode 100644 pixmaps/done.png
 delete mode 100644 pixmaps/filter-menu.png
 delete mode 100644 pixmaps/gnome-lock.png
 delete mode 100644 pixmaps/gnome-mouse.png
 delete mode 100644 pixmaps/install.png
 delete mode 100644 pixmaps/network.png
 delete mode 100644 pixmaps/partscheme-all.png
 delete mode 100644 pixmaps/partscheme-custom.png
 delete mode 100644 pixmaps/partscheme-freespace.png
 delete mode 100644 pixmaps/partscheme-replace.png
 delete mode 100644 pixmaps/partscheme-shrink.png
 delete mode 100644 pixmaps/root-password.png
 delete mode 100644 pixmaps/upgrade.png
 delete mode 100644 platform.py
 delete mode 100644 product.py
 create mode 100644 pyanaconda/Makefile.am
 create mode 100644 pyanaconda/__init__.py
 create mode 100644 pyanaconda/anaconda_log.py
 create mode 100644 pyanaconda/backend.py
 create mode 100644 pyanaconda/backend_log.py
 create mode 100644 pyanaconda/baseudev.py
 create mode 100644 pyanaconda/bootloader.py
 create mode 100644 pyanaconda/cmdline.py
 create mode 100644 pyanaconda/compssort.py
 create mode 100644 pyanaconda/constants.py
 create mode 100644 pyanaconda/desktop.py
 create mode 100644 pyanaconda/dispatch.py
 create mode 100644 pyanaconda/errors.py
 create mode 100644 pyanaconda/exception.py
 create mode 100644 pyanaconda/firewall.py
 create mode 100644 pyanaconda/flags.py
 create mode 100755 pyanaconda/gui.py
 create mode 100644 pyanaconda/image.py
 create mode 100644 pyanaconda/installclass.py
 create mode 100644 pyanaconda/installclasses/Makefile.am
 create mode 100644 pyanaconda/installclasses/fedora.py
 create mode 100644 pyanaconda/installclasses/rhel.py
 create mode 100644 pyanaconda/installinterfacebase.py
 create mode 100644 pyanaconda/installmethod.py
 create mode 100644 pyanaconda/isys/.gitignore
 create mode 100644 pyanaconda/isys/Makefile.am
 create mode 100755 pyanaconda/isys/__init__.py
 create mode 100644 pyanaconda/isys/auditd.c
 create mode 100644 pyanaconda/isys/auditd.h
 create mode 100644 pyanaconda/isys/cpio.c
 create mode 100644 pyanaconda/isys/cpio.h
 create mode 100644 pyanaconda/isys/devices.c
 create mode 100644 pyanaconda/isys/devices.h
 create mode 100644 pyanaconda/isys/eddsupport.c
 create mode 100644 pyanaconda/isys/eddsupport.h
 create mode 100644 pyanaconda/isys/ethtool.c
 create mode 100644 pyanaconda/isys/ethtool.h
 create mode 100644 pyanaconda/isys/iface.c
 create mode 100644 pyanaconda/isys/iface.h
 create mode 100644 pyanaconda/isys/imount.c
 create mode 100644 pyanaconda/isys/imount.h
 create mode 100644 pyanaconda/isys/isofs.c
 create mode 100644 pyanaconda/isys/isys.c
 create mode 100644 pyanaconda/isys/isys.h
 create mode 100644 pyanaconda/isys/lang.c
 create mode 100644 pyanaconda/isys/lang.h
 create mode 100644 pyanaconda/isys/linkdetect.c
 create mode 100644 pyanaconda/isys/log.c
 create mode 100644 pyanaconda/isys/log.h
 create mode 100644 pyanaconda/isys/stubs.h
 create mode 100644 pyanaconda/isys/uncpio.c
 create mode 100644 pyanaconda/isys/vio.c
 create mode 100644 pyanaconda/iutil.py
 create mode 100644 pyanaconda/iw/DeviceSelector.py
 create mode 100644 pyanaconda/iw/GroupSelector.py
 create mode 100644 pyanaconda/iw/Makefile.am
 create mode 100644 pyanaconda/iw/account_gui.py
 create mode 100644 pyanaconda/iw/advanced_storage.py
 create mode 100644 pyanaconda/iw/autopart_type.py
 create mode 100644 pyanaconda/iw/blpasswidget.py
 create mode 100644 pyanaconda/iw/bootloader_main_gui.py
 create mode 100644 pyanaconda/iw/checklist.py
 create mode 100644 pyanaconda/iw/cleardisks_gui.py
 create mode 100644 pyanaconda/iw/congrats_gui.py
 create mode 100644 pyanaconda/iw/datacombo.py
 create mode 100644 pyanaconda/iw/examine_gui.py
 create mode 100644 pyanaconda/iw/filter_gui.py
 create mode 100644 pyanaconda/iw/filter_type.py
 create mode 100644 pyanaconda/iw/iw_gui.py
 create mode 100644 pyanaconda/iw/kbd_gui.py
 create mode 100644 pyanaconda/iw/language_gui.py
 create mode 100644 pyanaconda/iw/lvm_dialog_gui.py
 create mode 100644 pyanaconda/iw/netconfig_dialog.py
 create mode 100644 pyanaconda/iw/network_gui.py
 create mode 100644 pyanaconda/iw/osbootwidget.py
 create mode 100644 pyanaconda/iw/package_gui.py
 create mode 100644 pyanaconda/iw/partition_dialog_gui.py
 create mode 100644 pyanaconda/iw/partition_gui.py
 create mode 100644 pyanaconda/iw/partition_ui_helpers_gui.py
 create mode 100644 pyanaconda/iw/pixmapRadioButtonGroup_gui.py
 create mode 100644 pyanaconda/iw/progress_gui.py
 create mode 100644 pyanaconda/iw/raid_dialog_gui.py
 create mode 100644 pyanaconda/iw/task_gui.py
 create mode 100644 pyanaconda/iw/timezone_gui.py
 create mode 100644 pyanaconda/iw/upgrade_bootloader_gui.py
 create mode 100644 pyanaconda/iw/upgrade_migratefs_gui.py
 create mode 100644 pyanaconda/iw/upgrade_swap_gui.py
 create mode 100644 pyanaconda/iw/welcome_gui.py
 create mode 100644 pyanaconda/iw/zipl_gui.py
 create mode 100644 pyanaconda/kickstart.py
 create mode 100644 pyanaconda/language.py
 create mode 100644 pyanaconda/livecd.py
 create mode 100644 pyanaconda/network.py
 create mode 100644 pyanaconda/packages.py
 create mode 100644 pyanaconda/partIntfHelpers.py
 create mode 100644 pyanaconda/platform.py
 create mode 100644 pyanaconda/product.py
 create mode 100644 pyanaconda/pyudev.py
 create mode 100644 pyanaconda/rescue.py
 create mode 100755 pyanaconda/run_test.py
 create mode 100644 pyanaconda/security.py
 create mode 100644 pyanaconda/simpleconfig.py
 create mode 100644 pyanaconda/sitecustomize.py
 create mode 100644 pyanaconda/sortedtransaction.py
 create mode 100644 pyanaconda/storage/Makefile.am
 create mode 100644 pyanaconda/storage/__init__.py
 create mode 100644 pyanaconda/storage/dasd.py
 create mode 100644 pyanaconda/storage/deviceaction.py
 create mode 100644 pyanaconda/storage/devicelibs/Makefile.am
 create mode 100644 pyanaconda/storage/devicelibs/__init__.py
 create mode 100644 pyanaconda/storage/devicelibs/crypto.py
 create mode 100644 pyanaconda/storage/devicelibs/dm.py
 create mode 100644 pyanaconda/storage/devicelibs/edd.py
 create mode 100644 pyanaconda/storage/devicelibs/lvm.py
 create mode 100644 pyanaconda/storage/devicelibs/mdraid.py
 create mode 100644 pyanaconda/storage/devicelibs/mpath.py
 create mode 100644 pyanaconda/storage/devicelibs/swap.py
 create mode 100644 pyanaconda/storage/devices.py
 create mode 100644 pyanaconda/storage/devicetree.py
 create mode 100644 pyanaconda/storage/errors.py
 create mode 100644 pyanaconda/storage/fcoe.py
 create mode 100644 pyanaconda/storage/formats/Makefile.am
 create mode 100644 pyanaconda/storage/formats/__init__.py
 create mode 100644 pyanaconda/storage/formats/disklabel.py
 create mode 100644 pyanaconda/storage/formats/dmraid.py
 create mode 100644 pyanaconda/storage/formats/fs.py
 create mode 100644 pyanaconda/storage/formats/luks.py
 create mode 100644 pyanaconda/storage/formats/lvmpv.py
 create mode 100644 pyanaconda/storage/formats/mdraid.py
 create mode 100644 pyanaconda/storage/formats/multipath.py
 create mode 100644 pyanaconda/storage/formats/prepboot.py
 create mode 100644 pyanaconda/storage/formats/swap.py
 create mode 100644 pyanaconda/storage/iscsi.py
 create mode 100644 pyanaconda/storage/miscutils.py
 create mode 100644 pyanaconda/storage/partitioning.py
 create mode 100644 pyanaconda/storage/partspec.py
 create mode 100644 pyanaconda/storage/storage_log.py
 create mode 100644 pyanaconda/storage/udev.py
 create mode 100644 pyanaconda/storage/zfcp.py
 create mode 100644 pyanaconda/text.py
 create mode 100644 pyanaconda/textw/Makefile.am
 create mode 100644 pyanaconda/textw/add_drive_text.py
 create mode 100644 pyanaconda/textw/complete_text.py
 create mode 100644 pyanaconda/textw/constants_text.py
 create mode 100644 pyanaconda/textw/keyboard_text.py
 create mode 100644 pyanaconda/textw/language_text.py
 create mode 100644 pyanaconda/textw/netconfig_text.py
 create mode 100644 pyanaconda/textw/network_text.py
 create mode 100644 pyanaconda/textw/partition_text.py
 create mode 100644 pyanaconda/textw/progress_text.py
 create mode 100644 pyanaconda/textw/statusline_text.py
 create mode 100644 pyanaconda/textw/task_text.py
 create mode 100644 pyanaconda/textw/timezone_text.py
 create mode 100644 pyanaconda/textw/upgrade_bootloader_text.py
 create mode 100644 pyanaconda/textw/upgrade_text.py
 create mode 100644 pyanaconda/textw/userauth_text.py
 create mode 100644 pyanaconda/textw/welcome_text.py
 create mode 100644 pyanaconda/textw/zipl_text.py
 create mode 100644 pyanaconda/timezone.py
 create mode 100644 pyanaconda/upgrade.py
 create mode 100644 pyanaconda/users.py
 create mode 100644 pyanaconda/vnc.py
 create mode 100644 pyanaconda/xutils.c
 create mode 100644 pyanaconda/yuminstall.py
 delete mode 100644 pyudev.py
 delete mode 100644 rescue.py
 delete mode 100755 run_test.py
 delete mode 100644 security.py
 delete mode 100644 simpleconfig.py
 delete mode 100644 sitecustomize.py
 delete mode 100644 sortedtransaction.py
 delete mode 100644 storage/Makefile.am
 delete mode 100644 storage/__init__.py
 delete mode 100644 storage/dasd.py
 delete mode 100644 storage/deviceaction.py
 delete mode 100644 storage/devicelibs/Makefile.am
 delete mode 100644 storage/devicelibs/__init__.py
 delete mode 100644 storage/devicelibs/crypto.py
 delete mode 100644 storage/devicelibs/dm.py
 delete mode 100644 storage/devicelibs/edd.py
 delete mode 100644 storage/devicelibs/lvm.py
 delete mode 100644 storage/devicelibs/mdraid.py
 delete mode 100644 storage/devicelibs/mpath.py
 delete mode 100644 storage/devicelibs/swap.py
 delete mode 100644 storage/devices.py
 delete mode 100644 storage/devicetree.py
 delete mode 100644 storage/errors.py
 delete mode 100644 storage/fcoe.py
 delete mode 100644 storage/formats/Makefile.am
 delete mode 100644 storage/formats/__init__.py
 delete mode 100644 storage/formats/disklabel.py
 delete mode 100644 storage/formats/dmraid.py
 delete mode 100644 storage/formats/fs.py
 delete mode 100644 storage/formats/luks.py
 delete mode 100644 storage/formats/lvmpv.py
 delete mode 100644 storage/formats/mdraid.py
 delete mode 100644 storage/formats/multipath.py
 delete mode 100644 storage/formats/prepboot.py
 delete mode 100644 storage/formats/swap.py
 delete mode 100644 storage/iscsi.py
 delete mode 100644 storage/miscutils.py
 delete mode 100644 storage/partitioning.py
 delete mode 100644 storage/partspec.py
 delete mode 100644 storage/storage_log.py
 delete mode 100644 storage/udev.py
 delete mode 100644 storage/zfcp.py
 delete mode 100644 stubs/.gitignore
 delete mode 100644 tests/__init__.py
 delete mode 100644 tests/kickstart/Makefile.am
 delete mode 100644 tests/kickstart/__init__.py
 delete mode 100755 tests/kickstart/commands.py
 create mode 100644 tests/kickstart_test/Makefile.am
 create mode 100644 tests/kickstart_test/commands_test.py
 create mode 100644 tests/mock/Makefile.am
 delete mode 100644 tests/storage/Makefile.am
 delete mode 100644 tests/storage/__init__.py
 delete mode 100644 tests/storage/devicelibs/Makefile.am
 delete mode 100644 tests/storage/devicelibs/__init__.py
 delete mode 100644 tests/storage/devicelibs/baseclass.py
 delete mode 100755 tests/storage/devicelibs/crypto.py
 delete mode 100755 tests/storage/devicelibs/lvm.py
 delete mode 100755 tests/storage/devicelibs/mdraid.py
 delete mode 100755 tests/storage/devicelibs/mpath.py
 delete mode 100755 tests/storage/devicelibs/swap.py
 create mode 100644 tests/storage_test/Makefile.am
 create mode 100644 tests/storage_test/devicelibs_test/Makefile.am
 create mode 100644 tests/storage_test/devicelibs_test/baseclass.py
 create mode 100644 tests/storage_test/devicelibs_test/crypto_test.py
 create mode 100644 tests/storage_test/devicelibs_test/lvm_test.py
 create mode 100644 tests/storage_test/devicelibs_test/mdraid_test.py
 create mode 100644 tests/storage_test/devicelibs_test/mpath_test.py
 create mode 100644 tests/storage_test/devicelibs_test/swap_test.py
 delete mode 100644 text.py
 delete mode 100644 textw/Makefile.am
 delete mode 100644 textw/add_drive_text.py
 delete mode 100644 textw/complete_text.py
 delete mode 100644 textw/constants_text.py
 delete mode 100644 textw/keyboard_text.py
 delete mode 100644 textw/language_text.py
 delete mode 100644 textw/netconfig_text.py
 delete mode 100644 textw/network_text.py
 delete mode 100644 textw/partition_text.py
 delete mode 100644 textw/progress_text.py
 delete mode 100644 textw/statusline_text.py
 delete mode 100644 textw/task_text.py
 delete mode 100644 textw/timezone_text.py
 delete mode 100644 textw/upgrade_bootloader_text.py
 delete mode 100644 textw/upgrade_text.py
 delete mode 100644 textw/userauth_text.py
 delete mode 100644 textw/welcome_text.py
 delete mode 100644 textw/zipl_text.py
 delete mode 100644 timezone.py
 delete mode 100644 ui/GroupSelector.glade
 delete mode 100644 ui/Makefile.am
 delete mode 100644 ui/account.glade
 delete mode 100644 ui/adddrive.glade
 delete mode 100644 ui/addrepo.glade
 delete mode 100644 ui/anaconda.glade
 delete mode 100644 ui/autopart.glade
 delete mode 100644 ui/blwhere.glade
 delete mode 100644 ui/cleardisks.glade
 delete mode 100644 ui/create-storage.glade
 delete mode 100644 ui/detailed-dialog.glade
 delete mode 100644 ui/fcoe-config.glade
 delete mode 100644 ui/filter.glade
 delete mode 100644 ui/iscsi-config.glade
 delete mode 100644 ui/lukspassphrase.glade
 delete mode 100644 ui/netconfig.glade
 delete mode 100644 ui/network.glade
 delete mode 100644 ui/tasksel.glade
 delete mode 100644 ui/zfcp-config.glade
 delete mode 100644 upgrade.py
 delete mode 100644 users.py
 delete mode 100644 vnc.py
 delete mode 100644 xutils.c
 delete mode 100644 yuminstall.py

diff --git a/70-anaconda.rules b/70-anaconda.rules
deleted file mode 100644
index bba0bfb..0000000
--- a/70-anaconda.rules
+++ /dev/null
@@ -1,56 +0,0 @@
-# If $ANACONDA isn't set in the environment, skip all these rules.
-ENV{ANACONDA}!="?*", GOTO="anaconda_end"
-
-ACTION!="add|change", GOTO="anaconda_end"
-SUBSYSTEM!="block", GOTO="anaconda_end"
-
-# for device-mapper device we are supposed to only operate on "change" events
-KERNEL=="dm-*", ACTION=="add", GOTO="anaconda_end"
-
-ENV{ANACBIN}="/sbin"
-TEST!="$env{ANACBIN}/dmsetup", ENV{ANACBIN}="/usr/sbin"
-
-KERNEL=="dm-*", ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}=="1", GOTO="anaconda_end"
-KERNEL=="dm-*", ENV{DM_NAME}!="?*", GOTO="anaconda_end"
-KERNEL=="dm-*", ENV{DM_SUSPENDED}=="1", GOTO="anaconda_end"
-KERNEL=="dm-*", ENV{DM_SUSPENDED}=="Suspended", GOTO="anaconda_end"
-
-IMPORT{program}="$env{ANACBIN}/blkid -o udev -p $tempnode"
-
-LABEL="anaconda_mdraid"
-KERNEL!="md*", GOTO="anaconda_mdraid_member"
-
-# container devices have a metadata version of e.g. 'external:ddf' and
-# never leave state 'inactive'
-ATTR{md/metadata_version}=="external:[A-Za-z]*", ATTR{md/array_state}=="inactive", GOTO="md_ignore_state"
-TEST!="md/array_state", GOTO="anaconda_mdraid_member"
-ATTR{md/array_state}=="|clear|inactive", GOTO="anaconda_mdraid_member"
-LABEL="md_ignore_state"
-
-IMPORT{program}="$env{ANACBIN}/mdadm --detail --export $tempnode"
-ENV{DEVTYPE}=="disk", ENV{MD_NAME}=="?*", SYMLINK+="disk/by-id/md-name-$env{MD_NAME}", OPTIONS+="string_escape=replace"
-ENV{DEVTYPE}=="disk", ENV{MD_UUID}=="?*", SYMLINK+="disk/by-id/md-uuid-$env{MD_UUID}"
-ENV{DEVTYPE}=="disk", ENV{MD_DEVNAME}=="?*", SYMLINK+="md/$env{MD_DEVNAME}"
-ENV{DEVTYPE}=="partition", ENV{MD_NAME}=="?*", SYMLINK+="disk/by-id/md-name-$env{MD_NAME}-part%n", OPTIONS+="string_escape=replace"
-ENV{DEVTYPE}=="partition", ENV{MD_UUID}=="?*", SYMLINK+="disk/by-id/md-uuid-$env{MD_UUID}-part%n"
-ENV{DEVTYPE}=="partition", ENV{MD_DEVNAME}=="*[^0-9]", SYMLINK+="md/$env{MD_DEVNAME}%n"
-ENV{DEVTYPE}=="partition", ENV{MD_DEVNAME}=="*[0-9]", SYMLINK+="md/$env{MD_DEVNAME}p%n"
-
-OPTIONS+="link_priority=100"
-OPTIONS+="watch"
-ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}"
-ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}"
-
-LABEL="anaconda_mdraid_member"
-# probe raid metadata of mdraid member devices
-ENV{ID_FS_TYPE}=="linux_raid_member", IMPORT{program}="$env{ANACBIN}/mdadm --examine --export $tempnode"
-ENV{ID_FS_TYPE}=="isw_raid_member", IMPORT{program}="$env{ANACBIN}/mdadm --examine --export $tempnode"
-
-# probe metadata of LVM2 physical volumes
-ENV{ID_FS_TYPE}=="LVM2_member", IMPORT{program}="$env{ANACBIN}/lvm pvs --ignorelockingfailure --units k --nosuffix --nameprefixes --rows --unquoted --noheadings -opv_name,pv_uuid,pv_size,vg_name,vg_uuid,pv_pe_count,pv_pe_alloc_count,pe_start $tempnode"
-ENV{LVM2_VG_NAME}!="?*", GOTO="anaconda_end"
-ENV{ID_FS_TYPE}=="LVM2_member", IMPORT{program}="$env{ANACBIN}/lvm vgs --ignorelockingfailure --units k --nosuffix --nameprefixes --rows --unquoted --noheadings -ouuid,size,free,extent_size,extent_count,free_count,pv_count $env{LVM2_VG_NAME}"
-ENV{ID_FS_TYPE}=="LVM2_member", IMPORT{program}="$env{ANACBIN}/lvm lvs -a --ignorelockingfailure --units k --nosuffix --nameprefixes --rows --unquoted --noheadings -olv_name,lv_uuid,lv_size,lv_attr $env{LVM2_VG_NAME}"
-
-LABEL="anaconda_end"
-
diff --git a/Makefile.am b/Makefile.am
index 9ceac51..7beccbf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,44 +19,24 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = isys po loader booty storage textw utils scripts bootdisk \
-          installclasses iw command-stubs ui docs pixmaps tests fonts \
-          gptsync liveinst icons
+SUBDIRS = po loader utils scripts \
+          command-stubs docs tests \
+          data bin booty pyanaconda
 
 EXTRA_DIST = config.rpath COPYING \
-             lang-table \
              anaconda.spec.in
 
 MAINTAINERCLEANFILES = Makefile.in config.guess config.h.in config.sub \
                        depcomp install-sh ltmain.sh missing ABOUT-NLS \
                        INSTALL aclocal.m4 configure *.pyc py-compile
 
-CLEANFILES = *~ lang-names anaconda.spec
+CLEANFILES = *~ anaconda.spec
 
 MOSTLYCLEANDIRS = m4
 
-pkgpyexecdir          = $(pyexecdir)/py$(PACKAGE_NAME)
-
 dist_noinst_DATA      = $(PACKAGE_NAME).spec
 
-dist_sbin_SCRIPTS     = anaconda
-
-udevdir               = /lib/udev/rules.d
-dist_udev_DATA        = 70-anaconda.rules
-
-langdir               = $(datadir)/$(PACKAGE_NAME)
-lang_DATA             = lang-names
-dist_lang_DATA        = lang-table
-
-pkgpyexec_LTLIBRARIES = xutils.la
-xutils_la_CFLAGS      = $(PYTHON_INCLUDES) $(GDK_CFLAGS) -fno-strict-aliasing
-xutils_la_LDFLAGS     = -module -avoid-version $(PYTHON_LDFLAGS) $(GDK_LDFLAGS)
-xutils_la_LIBADD      = $(PYTHON_LIBS) $(GDK_LIBS)
-xutils_la_SOURCES     = xutils.c
-
-# anaconda Python code
-anacondadir     = $(pkgpyexecdir)
-anaconda_PYTHON = *.py
+dist_sbin_SCRIPTS     = anaconda.py
 
 ARCHIVE_TAG   = $(PACKAGE_NAME)-$(PACKAGE_VERSION)-$(PACKAGE_RELEASE)
 
@@ -67,9 +47,6 @@ sed_verbose_0 = @echo "  SED    "$@;
 $(PACKAGE_NAME).spec: $(PACKAGE_NAME).spec.in
 	$(sed_verbose)sed -e 's/#VERSION#/$(PACKAGE_VERSION)/' < $< > $@
 
-lang-names: lang-table
-	PYTHONPATH="." $(PYTHON) scripts/getlangnames.py > lang-names
-
 testiso: install
 	@if [ "$(REPO)" = "" ]; then echo "ERROR: Need a repo to pull packages from!" ; exit 1 ; fi
 	@pushd scripts ; sudo ./buildinstall --version $(PACKAGE_VERSION) --product $(PACKAGE_NAME) --release $(PACKAGE_NAME)-$(PACKAGE_VERSION) --output $(shell pwd)/outiso --updates $(DESTDIR) $(REPO) ; popd ; cp outiso/images/boot.iso ./boot.iso ; sudo rm -rf outiso
diff --git a/__init__.py b/__init__.py
deleted file mode 100644
index b53877c..0000000
--- a/__init__.py
+++ /dev/null
@@ -1,395 +0,0 @@
-#!/usr/bin/python
-#
-# anaconda: The Red Hat Linux Installation program
-#
-# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-# Red Hat, Inc.  All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author(s): Brent Fox <bfox redhat com>
-#            Mike Fulbright <msf redhat com>
-#            Jakub Jelinek <jakub redhat com>
-#            Jeremy Katz <katzj redhat com>
-#            Chris Lumens <clumens redhat com>
-#            Paul Nasrat <pnasrat redhat com>
-#            Erik Troan <ewt rpath com>
-#            Matt Wilson <msw rpath com>
-#
-
-import os, time, string
-import iutil
-import isys
-from tempfile import mkstemp
-
-import logging
-log = logging.getLogger("anaconda")
-stdoutLog = logging.getLogger("anaconda.stdout")
-
-import gettext
-_ = lambda x: gettext.ldgettext("anaconda", x)
-
-class Anaconda(object):
-    def __init__(self):
-        import desktop, dispatch, firewall, security
-        import system_config_keyboard.keyboard as keyboard
-        from flags import flags
-
-        self._backend = None
-        self._bootloader = None
-        self.canReIPL = False
-        self.desktop = desktop.Desktop()
-        self.dir = None
-        self.dispatch = dispatch.Dispatcher(self)
-        self.displayMode = None
-        self.extraModules = []
-        self.firewall = firewall.Firewall()
-        self.id = None
-        self._instClass = None
-        self._instLanguage = None
-        self._intf = None
-        self.isHeadless = False
-        self.keyboard = keyboard.Keyboard()
-        self.ksdata = None
-        self.mediaDevice = None
-        self.methodstr = None
-        self._network = None
-        self._platform = None
-        self.proxy = None
-        self.proxyUsername = None
-        self.proxyPassword = None
-        self.reIPLMessage = None
-        self.rescue = False
-        self.rescue_mount = True
-        self.rootParts = None
-        self.rootPath = "/mnt/sysimage"
-        self.security = security.Security()
-        self.simpleFilter = not iutil.isS390()
-        self.stage2 = None
-        self._storage = None
-        self._timezone = None
-        self.updateSrc = None
-        self.upgrade = flags.cmdline.has_key("preupgrade")
-        self.upgradeRoot = None
-        self.upgradeSwapInfo = None
-        self._users = None
-        self.mehConfig = None
-
-        # *sigh* we still need to be able to write this out
-        self.xdriver = None
-
-    @property
-    def backend(self):
-        if not self._backend:
-            b = self.instClass.getBackend()
-            self._backend = apply(b, (self, ))
-
-        return self._backend
-
-    @property
-    def bootloader(self):
-        if not self._bootloader:
-            import booty
-            self._bootloader = booty.getBootloader(self)
-
-        return self._bootloader
-
-    @property
-    def firstboot(self):
-        from pykickstart.constants import FIRSTBOOT_SKIP, FIRSTBOOT_DEFAULT
-
-        if self.ksdata:
-            return self.ksdata.firstboot.firstboot
-        elif iutil.isS390():
-            return FIRSTBOOT_SKIP
-        else:
-            return FIRSTBOOT_DEFAULT
-
-    @property
-    def instClass(self):
-        if not self._instClass:
-            from installclass import DefaultInstall
-            self._instClass = DefaultInstall()
-
-        return self._instClass
-
-    @property
-    def instLanguage(self):
-        if not self._instLanguage:
-            import language
-            self._instLanguage = language.Language(self.displayMode)
-
-        return self._instLanguage
-
-    def _getInterface(self):
-        return self._intf
-
-    def _setInterface(self, v):
-        # "lambda cannot contain assignment"
-        self._intf = v
-
-    def _delInterface(self):
-        del self._intf
-
-    intf = property(_getInterface, _setInterface, _delInterface)
-
-    @property
-    def network(self):
-        if not self._network:
-            import network
-            self._network = network.Network()
-
-        return self._network
-
-    @property
-    def platform(self):
-        if not self._platform:
-            import platform
-            self._platform = platform.getPlatform(self)
-
-        return self._platform
-
-    @property
-    def protected(self):
-        import stat
-
-        if os.path.exists("/dev/live") and \
-           stat.S_ISBLK(os.stat("/dev/live")[stat.ST_MODE]):
-            return [os.readlink("/dev/live")]
-        elif self.methodstr and self.methodstr.startswith("hd:"):
-            method = self.methodstr[3:]
-            return [method.split(":", 3)[0]]
-        else:
-            return []
-
-    @property
-    def users(self):
-        if not self._users:
-            import users
-            self._users = users.Users(self)
-
-        return self._users
-
-    @property
-    def storage(self):
-        if not self._storage:
-            import storage
-            self._storage = storage.Storage(self)
-
-        return self._storage
-
-    @property
-    def timezone(self):
-        if not self._timezone:
-            import timezone
-            self._timezone = timezone.Timezone()
-            self._timezone.setTimezoneInfo(self.instLanguage.getDefaultTimeZone(self.rootPath))
-
-        return self._timezone
-
-    def dumpState(self):
-        from meh.dump import ReverseExceptionDump
-        from inspect import stack as _stack
-
-        # Skip the frames for dumpState and the signal handler.
-        stack = _stack()[2:]
-        stack.reverse()
-        exn = ReverseExceptionDump((None, None, stack), self.mehConfig)
-
-        (fd, filename) = mkstemp("", "anaconda-tb-", "/tmp")
-        fo = os.fdopen(fd, "w")
-
-        exn.write(self, fo)
-
-    def initInterface(self):
-        if self._intf:
-            raise RuntimeError, "Second attempt to initialize the InstallInterface"
-
-        # setup links required by graphical mode if installing and verify display mode
-        if self.displayMode == 'g':
-            stdoutLog.info (_("Starting graphical installation."))
-
-            try:
-                from gui import InstallInterface
-            except Exception, e:
-                from flags import flags
-                stdoutLog.error("Exception starting GUI installer: %s" %(e,))
-                # if we're not going to really go into GUI mode, we need to get
-                # back to vc1 where the text install is going to pop up.
-                if not flags.livecdInstall:
-                    isys.vtActivate (1)
-                stdoutLog.warning("GUI installer startup failed, falling back to text mode.")
-                self.displayMode = 't'
-                if 'DISPLAY' in os.environ.keys():
-                    del os.environ['DISPLAY']
-                time.sleep(2)
-
-        if self.displayMode == 't':
-            from text import InstallInterface
-            if not os.environ.has_key("LANG"):
-                os.environ["LANG"] = "en_US.UTF-8"
-
-        if self.displayMode == 'c':
-            from cmdline import InstallInterface
-
-        self._intf = InstallInterface()
-        return self._intf
-
-    def writeXdriver(self, root = None):
-        # this should go away at some point, but until it does, we
-        # need to keep it around.
-        if self.xdriver is None:
-            return
-        if root is None:
-            root = self.rootPath
-        if not os.path.isdir("%s/etc/X11" %(root,)):
-            os.makedirs("%s/etc/X11" %(root,), mode=0755)
-        f = open("%s/etc/X11/xorg.conf" %(root,), 'w')
-        f.write('Section "Device"\n\tIdentifier "Videocard0"\n\tDriver "%s"\nEndSection\n' % self.xdriver)
-        f.close()
-
-    def setMethodstr(self, methodstr):
-        if methodstr.startswith("cdrom://"):
-            (device, tree) = string.split(methodstr[8:], ":", 1)
-
-            if not tree.startswith("/"):
-                tree = "/%s" %(tree,)
-
-            if device.startswith("/dev/"):
-                device = device[5:]
-
-            self.mediaDevice = device
-            self.methodstr = "cdrom://%s" % tree
-        else:
-            self.methodstr = methodstr
-
-    def requiresNetworkInstall(self):
-        fail = False
-        numNetDevs = isys.getNetworkDeviceCount()
-
-        if self.methodstr is not None:
-            if (self.methodstr.startswith("http") or \
-                self.methodstr.startswith("ftp://";) or \
-                self.methodstr.startswith("nfs:")) and \
-               numNetDevs == 0:
-                fail = True
-        elif self.stage2 is not None:
-            if self.stage2.startswith("cdrom://") and \
-               not os.path.isdir("/mnt/stage2/Packages") and \
-               numNetDevs == 0:
-                fail = True
-
-        if fail:
-            log.error("network install required, but no network devices available")
-
-        return fail
-
-    def write(self):
-        self.writeXdriver()
-        self.instLanguage.write(self.rootPath)
-
-        self.timezone.write(self.rootPath)
-        self.network.write(instPath=self.rootPath, anaconda=self)
-        self.desktop.write(self.rootPath)
-        self.users.write(self.rootPath)
-        self.security.write(self.rootPath)
-        self.firewall.write(self.rootPath)
-
-        if self.ksdata:
-            for svc in self.ksdata.services.disabled:
-                iutil.execWithRedirect("/sbin/chkconfig",
-                                       [svc, "off"],
-                                       stdout="/dev/tty5", stderr="/dev/tty5",
-                                       root=self.rootPath)
-
-            for svc in self.ksdata.services.enabled:
-                iutil.execWithRedirect("/sbin/chkconfig",
-                                       [svc, "on"],
-                                       stdout="/dev/tty5", stderr="/dev/tty5",
-                                       root=self.rootPath)
-
-    def writeKS(self, filename):
-        import urllib
-        from pykickstart.version import versionToString, DEVEL
-
-        f = open(filename, "w")
-
-        f.write("# Kickstart file automatically generated by anaconda.\n\n")
-        f.write("#version=%s\n" % versionToString(DEVEL))
-
-        if self.upgrade:
-            f.write("upgrade\n")
-        else:
-            f.write("install\n")
-
-        m = None
-
-        if self.methodstr:
-            m = self.methodstr
-        elif self.stage2:
-            m = self.stage2
-
-        if m:
-            if m.startswith("cdrom:"):
-                f.write("cdrom\n")
-            elif m.startswith("hd:"):
-                if m.count(":") == 3:
-                    (part, fs, dir) = string.split(m[3:], ":")
-                else:
-                    (part, dir) = string.split(m[3:], ":")
-
-                f.write("harddrive --partition=%s --dir=%s\n" % (part, dir))
-            elif m.startswith("nfs:"):
-                if m.count(":") == 3:
-                    (server, opts, dir) = string.split(m[4:], ":")
-                    f.write("nfs --server=%s --opts=%s --dir=%s" % (server, opts, dir))
-                else:
-                    (server, dir) = string.split(m[4:], ":")
-                    f.write("nfs --server=%s --dir=%s\n" % (server, dir))
-            elif m.startswith("ftp://";) or m.startswith("http"):
-                f.write("url --url=%s\n" % urllib.unquote(m))
-
-        # Some kickstart commands do not correspond to any anaconda UI
-        # component.  If this is a kickstart install, we need to make sure
-        # the information from the input file ends up in the output file.
-        if self.ksdata:
-            f.write(self.ksdata.user.__str__())
-            f.write(self.ksdata.services.__str__())
-            f.write(self.ksdata.reboot.__str__())
-
-        self.instLanguage.writeKS(f)
-
-        if not self.isHeadless:
-            self.keyboard.writeKS(f)
-            self.network.writeKS(f)
-
-        self.timezone.writeKS(f)
-        self.users.writeKS(f)
-        self.security.writeKS(f)
-        self.firewall.writeKS(f)
-
-        self.storage.writeKS(f)
-        self.bootloader.writeKS(f)
-
-        if self.backend:
-            self.backend.writeKS(f)
-            self.backend.writePackagesKS(f, self)
-
-        # Also write out any scripts from the input ksfile.
-        if self.ksdata:
-            for s in self.ksdata.scripts:
-                f.write(s.__str__())
-
-        # make it so only root can read, could have password
-        os.chmod(filename, 0600)
diff --git a/anaconda b/anaconda
deleted file mode 100755
index b5532b0..0000000
--- a/anaconda
+++ /dev/null
@@ -1,932 +0,0 @@
-#!/usr/bin/python
-#
-# anaconda: The Red Hat Linux Installation program
-#
-# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-# Red Hat, Inc.  All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author(s): Brent Fox <bfox redhat com>
-#            Mike Fulbright <msf redhat com>
-#            Jakub Jelinek <jakub redhat com>
-#            Jeremy Katz <katzj redhat com>
-#            Chris Lumens <clumens redhat com>
-#            Paul Nasrat <pnasrat redhat com>
-#            Erik Troan <ewt rpath com>
-#            Matt Wilson <msw rpath com>
-#
-
-# This toplevel file is a little messy at the moment...
-
-import sys, os, re, time, subprocess
-from optparse import OptionParser
-from tempfile import mkstemp
-
-# keep up with process ID of the window manager if we start it
-wm_pid = None
-
-# Make sure messages sent through python's warnings module get logged.
-def AnacondaShowWarning(message, category, filename, lineno, file=sys.stderr, line=None):
-    log.warning("%s" % warnings.formatwarning(message, category, filename, lineno, line))
-
-def startMetacityWM():
-    childpid = os.fork()
-    if not childpid:
-        cmd = '/usr/bin/metacity'
-        if not os.access(cmd, os.X_OK):
-            log.error("Unable to find the window manager binary.")
-            sys.exit(1)
-        args = ['--display', ':1',
-                '--sm-disable']
-        rc = iutil.execWithRedirect(cmd, args, 
-                               stdout='/dev/null', stderr='/dev/null')
-        if rc:
-            log.error("Error running window manager.")
-            sys.exit (rc)
-        else:
-            log.info("The window manager has terminated.")
-            sys.exit(0)
-    return childpid
-
-def startAuditDaemon():
-    childpid = os.fork()
-    if not childpid:
-        cmd = '/sbin/auditd'
-        try:
-            os.execl(cmd, cmd)
-        except OSError as e:
-            log.error("Error running the audit daemon: %s" % str(e))
-        sys.exit(0)
-    # auditd will turn into a daemon so catch the immediate child pid now:
-    os.waitpid(childpid, 0)
-
-# function to handle X startup special issues for anaconda
-def doStartupX11Actions(runres="800x600"):
-    global wm_pid
-
-    setupGraphicalLinks()
-
-    # now start up the window manager
-    try:
-        wm_pid = startMetacityWM()
-        log.info("Starting window manager, pid %s." % (wm_pid,))
-    except Exception:
-        wm_pid = None
-        log.error("Unable to start the window manager.")
-
-    if wm_pid is not None:
-        import xutils
-        import gtk
-
-        try:
-            xutils.setRootResource('Xcursor.size', '24')
-            xutils.setRootResource('Xcursor.theme', 'Bluecurve')
-            xutils.setRootResource('Xcursor.theme_core', 'true')
-
-            xutils.setRootResource('Xft.antialias', '1')
-            xutils.setRootResource('Xft.hinting', '1')
-            xutils.setRootResource('Xft.hintstyle', 'hintslight')
-            xutils.setRootResource('Xft.rgba', 'none')
-        except:
-            sys.stderr.write("X SERVER STARTED, THEN FAILED");
-            raise RuntimeError, "X server failed to start"
-
-def doShutdownX11Actions():
-    global wm_pid
-    
-    if wm_pid is not None:
-        try:
-            os.kill(wm_pid, 15)
-            os.waitpid(wm_pid, 0)
-        except:
-            pass
-
-def setupPythonUpdates():
-    from distutils.sysconfig import get_python_lib
-
-    if not os.path.exists("/tmp/updates"):
-        return
-
-    for pkg in os.listdir("/tmp/updates"):
-        d = "/tmp/updates/%s" % pkg
-
-        if not os.path.isdir(d):
-            continue
-
-        # See if the package exists in /usr/lib{64,}/python/?.?/site-packages.
-        # If it does, we can set it up as an update.  If not, the pkg is
-        # likely a completely new directory and should not be looked at.
-        dest = "%s/%s" % (get_python_lib(), pkg)
-        if not os.access(dest, os.R_OK):
-            dest = "%s/%s" % (get_python_lib(1), pkg)
-            if not os.access(dest, os.R_OK):
-                continue
-
-        contents = os.listdir(d)
-
-        # Symlink over everything that's in the python libdir but not in
-        # the updates directory.
-        for f in filter(lambda fn: fn not in contents, os.listdir(dest)):
-            if f.endswith(".pyc") or f.endswith(".pyo"):
-                continue
-
-            os.symlink("%s/%s" % (dest, f), "/tmp/updates/%s/%s" % (pkg, f))
-
-
-    import glob
-    import shutil
-    for rule in glob.glob("/tmp/updates/*.rules"):
-        target = "/etc/udev/rules.d/" + rule.split('/')[-1]
-        shutil.copyfile(rule, target)
-
-def parseOptions(argv = None):
-    def resolution_cb (option, opt_str, value, parser):
-        parser.values.runres = value
-
-    op = OptionParser()
-    # Interface
-    op.add_option("-C", "--cmdline", dest="display_mode", action="store_const", const="c",
-                  default="g")
-    op.add_option("-G", "--graphical", dest="display_mode", action="store_const", const="g")
-    op.add_option("-T", "--text", dest="display_mode", action="store_const", const="t")
-
-    # Network
-    op.add_option("--noipv4", action="store_true", default=False)
-    op.add_option("--noipv6", action="store_true", default=False)
-    op.add_option("--proxy")
-    op.add_option("--proxyAuth")
-
-    # Method of operation
-    op.add_option("--autostep", action="store_true", default=False)
-    op.add_option("-d", "--debug", dest="debug", action="store_true", default=False)
-    op.add_option("--kickstart", dest="ksfile")
-    op.add_option("--rescue", dest="rescue", action="store_true", default=False)
-    op.add_option("--targetarch", dest="targetArch", nargs=1, type="string")
-
-    op.add_option("-m", "--method", dest="method", default=None)
-    op.add_option("--repo", dest="method", default=None)
-    op.add_option("--stage2", dest="stage2", default=None)
-
-    op.add_option("--liveinst", action="store_true", default=False)
-
-    # Display
-    op.add_option("--headless", dest="isHeadless", action="store_true", default=False)
-    op.add_option("--nofb")
-    op.add_option("--resolution", action="callback", callback=resolution_cb, dest="runres",
-                  default="800x600", nargs=1, type="string")
-    op.add_option("--serial", action="store_true", default=False)
-    op.add_option("--usefbx", dest="xdriver", action="store_const", const="fbdev")
-    op.add_option("--virtpconsole")
-    op.add_option("--vnc", action="store_true", default=False)
-    op.add_option("--vncconnect")
-    op.add_option("--xdriver", dest="xdriver", action="store", type="string", default=None)
-
-    # Language
-    op.add_option("--keymap")
-    op.add_option("--kbdtype")
-    op.add_option("--lang")
-
-    # Obvious
-    op.add_option("--loglevel")
-    op.add_option("--syslog")
-
-    op.add_option("--noselinux", dest="selinux", action="store_false", default=True)
-    op.add_option("--selinux", action="store_true")
-
-    op.add_option("--nompath", dest="mpath", action="store_false", default=True)
-    op.add_option("--mpath", action="store_true")
-
-    op.add_option("--nodmraid", dest="dmraid", action="store_false", default=True)
-    op.add_option("--dmraid", action="store_true")
-
-    op.add_option("--noibft", dest="ibft", action="store_false", default=True)
-    op.add_option("--ibft", action="store_true")
-    op.add_option("--noiscsi", dest="iscsi", action="store_false", default=False)
-    op.add_option("--iscsi", action="store_true")
-
-    # Miscellaneous
-    op.add_option("--module", action="append", default=[])
-    op.add_option("--nomount", dest="rescue_nomount", action="store_true", default=False)
-    op.add_option("--updates", dest="updateSrc", action="store", type="string")
-    op.add_option("--dogtail", dest="dogtail",   action="store", type="string")
-    op.add_option("--dlabel", action="store_true", default=False)
-
-    # Deprecated, unloved, unused
-    op.add_option("-r", "--rootPath", dest="unsupportedMode",
-                  action="store_const", const="root path")
-    op.add_option("-t", "--test", dest="unsupportedMode",
-                  action="store_const", const="test")
-
-    return op.parse_args(argv)
-
-def setupPythonPath():
-    haveUpdates = False
-    for ndx in range(len(sys.path)-1, -1, -1):
-        if sys.path[ndx].endswith('updates'):
-            haveUpdates = True
-            break
-
-    # With anaconda being a real module this isn't strictly necessary, but
-    # setting up the path now prevents having to change every import line in
-    # anaconda.
-    from distutils.sysconfig import get_python_lib
-    d = get_python_lib(plat_specific=1)
-
-    if haveUpdates:
-        sys.path.insert(ndx+1, "%s/pyanaconda" % d)
-        sys.path.insert(ndx+2, "%s/pyanaconda/textw" % d)
-        sys.path.insert(ndx+3, "%s/pyanaconda/iw" % d)
-    else:
-        sys.path.insert(0, "%s/pyanaconda" % d)
-        sys.path.insert(1, "%s/pyanaconda/textw" % d)
-        sys.path.insert(2, "%s/pyanaconda/iw" % d)
-
-    sys.path.append('/usr/share/system-config-date')
-
-def addPoPath(dir):
-    """ Looks to see what translations are under a given path and tells
-    the gettext module to use that path as the base dir """
-    for d in os.listdir(dir):
-        if not os.path.isdir("%s/%s" %(dir,d)):
-            continue
-        if not os.path.exists("%s/%s/LC_MESSAGES" %(dir,d)):
-            continue
-        for basename in os.listdir("%s/%s/LC_MESSAGES" %(dir,d)):
-            if not basename.endswith(".mo"):
-                continue
-            log.info("setting %s as translation source for %s" %(dir, basename[:-3]))
-            gettext.bindtextdomain(basename[:-3], dir)
-
-def setupTranslations():
-    if os.path.isdir("/tmp/updates/po"):
-        addPoPath("/tmp/updates/po")
-    gettext.textdomain("anaconda")
-
-def setupEnvironment():
-    # Silly GNOME stuff
-    if os.environ.has_key('HOME') and not os.environ.has_key("XAUTHORITY"):
-        os.environ['XAUTHORITY'] = os.environ['HOME'] + '/.Xauthority'
-    os.environ['HOME'] = '/tmp'
-    os.environ['LC_NUMERIC'] = 'C'
-    os.environ["GCONF_GLOBAL_LOCKS"] = "1"
-
-    # In theory, this gets rid of our LVM file descriptor warnings
-    os.environ["LVM_SUPPRESS_FD_WARNINGS"] = "1"
-
-    # make sure we have /sbin and /usr/sbin in our path
-    os.environ["PATH"] += ":/sbin:/usr/sbin"
-
-    # we can't let the LD_PRELOAD hang around because it will leak into
-    # rpm %post and the like.  ick :/
-    if os.environ.has_key("LD_PRELOAD"):
-        del os.environ["LD_PRELOAD"]
-
-    os.environ["GLADEPATH"] = "/tmp/updates/:/tmp/updates/ui/:ui/:/usr/share/anaconda/ui/:/usr/share/python-meh/"
-    os.environ["PIXMAPPATH"] = "/tmp/updates/pixmaps/:/tmp/updates/:/tmp/product/pixmaps/:/tmp/product/:pixmaps/:/usr/share/anaconda/pixmaps/:/usr/share/pixmaps/:/usr/share/anaconda/:/usr/share/python-meh/"
-
-def setupLoggingFromOpts(opts):
-    if opts.loglevel and anaconda_log.logLevelMap.has_key(opts.loglevel):
-        level = anaconda_log.logLevelMap[opts.loglevel]
-        anaconda_log.logger.tty_loglevel = level
-        anaconda_log.setHandlersLevel(log, level)
-        anaconda_log.setHandlersLevel(storage.storage_log.logger, level)
-
-    if opts.syslog:
-        anaconda_log.logger.remote_syslog = opts.syslog
-        if opts.syslog.find(":") != -1:
-            (host, port) = opts.syslog.split(":")
-            anaconda_log.logger.addSysLogHandler(log, host, port=int(port))
-        else:
-            anaconda_log.logger.addSysLogHandler(log, opts.syslog)
-
-# ftp installs pass the password via a file in /tmp so
-# ps doesn't show it
-def expandFTPMethod(str):
-    ret = None
-
-    try:
-        filename = str[1:]
-        ret = open(filename, "r").readline()
-        ret = ret[:len(ret) - 1]
-        os.unlink(filename)
-        return ret
-    except:
-        return None
-
-def runVNC():
-    global vncS
-    vncS.startServer()
-
-    child = os.fork()
-    if child == 0:
-        for p in ('/tmp/updates/pyrc.py', \
-                '/usr/share/anaconda/pyrc.py'):
-            if os.access(p, os.R_OK|os.X_OK):
-                os.environ['PYTHONSTARTUP'] = p
-                break
-
-        while True:
-            # s390/s390x are the only places we /really/ need a shell on tty1,
-            # and everywhere else this just gets in the way of pdb.  But we
-            # don't want to return, because that'll return try to start X
-            # a second time.
-            if iutil.isConsoleOnVirtualTerminal():
-                    time.sleep(10000)
-            else:
-                    print _("Press <enter> for a shell")
-                    sys.stdin.readline()
-                    iutil.execConsole()
-
-def within_available_memory(needed_ram):
-    # kernel binary code estimate that is
-    # not reported in MemTotal by /proc/meminfo:
-    epsilon = 15360 # 15 MB
-    return needed_ram < (iutil.memInstalled() + epsilon)
-
-def check_memory(anaconda, opts, display_mode=None):
-
-    if not display_mode:
-        display_mode = anaconda.displayMode
-
-    extra_ram = 0
-    reason = ''
-    if opts.stage2.startswith(('http', 'ftp', '@')):
-        extra_ram += isys.URL_INSTALL_EXTRA_RAM
-        reason = " using this install method"
-
-    needed_ram = isys.MIN_RAM + extra_ram
-    if not within_available_memory(needed_ram):
-        from snack import SnackScreen, ButtonChoiceWindow
-        screen = SnackScreen()
-        ButtonChoiceWindow(screen, _('Fatal Error'),
-                            _('You do not have enough RAM to install %s '
-                              'on this machine%s.\n'
-                              '\n'
-                              'Press <return> to reboot your system.\n')
-                           %(product.productName, reason),
-                           buttons = (_("OK"),))
-        screen.finish()
-        sys.exit(0)
-
-    # override display mode if machine cannot nicely run X
-    if display_mode not in ('t', 'c') and not flags.usevnc:
-        needed_ram = isys.MIN_GUI_RAM + extra_ram
-
-        if not within_available_memory(needed_ram):
-            complain = _("You do not have enough RAM to use the graphical "
-                         "installer.")
-            if flags.livecdInstall:
-                stdoutLog.warning(complain)
-                recommendation = _("Try the text mode installer by running:\n\n"
-                                   "'/usr/bin/liveinst -T'\n\n from a root "
-                                   "terminal.")
-                title = _("Not enough RAM")
-                text = "%s %s" %(complain, recommendation)
-                import gtk
-                dialog = gtk.MessageDialog(type = gtk.MESSAGE_ERROR, 
-                                           buttons = gtk.BUTTONS_CLOSE,
-                                           message_format=text)
-                dialog.set_title(title)
-                dialog.run()
-                sys.exit(1)
-            else:
-                resolution = _("Starting text mode.")
-                stdoutLog.warning("%s %s" % (complain, resolution))
-                anaconda.displayMode = 't'
-                time.sleep(2)
-
-def setupGraphicalLinks():
-    for i in ( "imrc", "im_palette.pal", "gtk-2.0", "pango", "fonts",
-               "fb.modes"):
-        try:
-            if os.path.exists("/mnt/runtime/etc/%s" %(i,)):
-                os.symlink ("../mnt/runtime/etc/" + i, "/etc/" + i)
-        except:
-            pass
-
-def handleSshPw(anaconda):
-    if not anaconda.ksdata:
-        return
-
-    import users
-    u = users.Users(anaconda)
-
-    userdata = anaconda.ksdata.sshpw.dataList()
-    for ud in userdata:
-        if u.checkUserExists(ud.username, root="/"):
-            u.setUserPassword(username=ud.username, password=ud.password,
-                              isCrypted=ud.isCrypted, lock=ud.lock)
-        else:
-            u.createUser(name=ud.username, password=ud.password,
-                         isCrypted=ud.isCrypted, lock=ud.lock,
-                         root="/")
-
-    del u
-
-def createSshKey(algorithm, keyfile):
-    path = '/etc/ssh/%s' % (keyfile,)
-    argv = ['-q','-t',algorithm,'-f',path,'-C','','-N','']
-    log.info("running \"%s\"" % (" ".join(['ssh-keygen']+argv),))
-
-    so = "/tmp/ssh-keygen-%s-stdout.log" % (algorithm,)
-    se = "/tmp/ssh-keygen-%s-stderr.log" % (algorithm,)
-    iutil.execWithRedirect('ssh-keygen', argv, stdout=so, stderr=se)
-
-def fork_orphan():
-    """Forks an orphan.
-    
-    Returns 1 in the parent and 0 in the orphaned child.
-    """
-    intermediate = os.fork()
-    if not intermediate:
-        if os.fork():
-            # the intermediate child dies
-            os._exit(0)
-        return 0;
-    # the original process waits for the intermediate child
-    os.waitpid(intermediate, 0)
-    return 1
-
-def startSsh():
-    if iutil.isS390():
-        return
-
-    if not fork_orphan():
-        os.mkdir("/var/log", 0755)
-        os.open("/var/log/lastlog", os.O_RDWR | os.O_CREAT, 0644)
-        ssh_keys = {
-            'rsa1':'ssh_host_key',
-            'rsa':'ssh_host_rsa_key',
-            'dsa':'ssh_host_dsa_key',
-            }
-        for (algorithm, keyfile) in ssh_keys.items():
-            createSshKey(algorithm, keyfile)
-        args = ["/sbin/sshd", "-f", "/etc/ssh/sshd_config.anaconda"]
-        os.execv("/sbin/sshd", args)
-        sys.exit(1)
-
-def startDebugger(signum, frame):
-    import epdb
-    epdb.serve(skip=1)
-
-if __name__ == "__main__":
-    setupPythonPath()
-
-    # Allow a file to be loaded as early as possible
-    try:
-        import updates_disk_hook
-    except ImportError:
-        pass
-
-    # Set up logging as early as possible.
-    import logging
-    import anaconda_log
-    anaconda_log.init()
-
-    log = logging.getLogger("anaconda")
-    stdoutLog = logging.getLogger("anaconda.stdout")
-
-    if os.geteuid() != 0:
-        stdoutLog.error("anaconda must be run as root.")
-        sys.exit(0)
-
-    # pull this in to get product name and versioning
-    import product
-
-    # this handles setting up updates for pypackages to minimize the set needed
-    setupPythonUpdates()
-
-    import isys
-    isys.initLog()
-
-    import signal, string, iutil, time
-    import warnings
-    import vnc
-    import users
-    import kickstart
-    import storage.storage_log
-
-    from flags import flags
-
-    # the following makes me very sad. -- katzj
-    # we have a slightly different set of udev rules in the second 
-    # stage than the first stage.  why this doesn't get picked up
-    # automatically, I don't know.  but we need to trigger so that we
-    # have all the information about netdevs that we care about for 
-    # NetworkManager in the udev database
-    from baseudev import udev_trigger, udev_settle
-    udev_trigger("net")
-    udev_settle()
-    # and for added fun, once doesn't seem to be enough?  so we 
-    # do it twice, it works and we scream at the world "OH WHY?"
-    udev_trigger("net")
-    udev_settle()
-
-    import gettext
-    _ = lambda x: gettext.ldgettext("anaconda", x)
-
-    from pyanaconda import Anaconda
-    anaconda = Anaconda()
-    warnings.showwarning = AnacondaShowWarning
-    setupTranslations()
-
-    # reset python's default SIGINT handler
-    signal.signal(signal.SIGINT, signal.SIG_DFL)
-    signal.signal(signal.SIGSEGV, isys.handleSegv)
-
-    setupEnvironment()
-
-    pidfile = open("/var/run/anaconda.pid", "w")
-    pidfile.write("%s\n" % (os.getpid(),))
-    del pidfile
-    # add our own additional signal handlers
-    signal.signal(signal.SIGHUP, startDebugger)
-
-    # we need to do this really early so we make sure its done before rpm
-    # is imported
-    iutil.writeRpmPlatform()
-
-    graphical_failed = 0
-    vncS = vnc.VncServer()          # The vnc Server object.
-    vncS.anaconda = anaconda
-    xserver_pid = None
-
-    (opts, args) = parseOptions()
-
-    # check memory, just the text mode for now:
-    check_memory(anaconda, opts, 't')
-
-    if opts.unsupportedMode:
-        stdoutLog.error("Running anaconda in %s mode is no longer supported." % opts.unsupportedMode)
-        sys.exit(0)
-
-    # Now that we've got arguments, do some extra processing.
-    setupLoggingFromOpts(opts)
-
-    # Default is to prompt to mount the installed system.
-    anaconda.rescue_mount = not opts.rescue_nomount
-
-    if opts.dlabel: #autodetected driverdisc in use
-        flags.dlabel = True
-
-    anaconda.displayMode = opts.display_mode
-    anaconda.isHeadless = opts.isHeadless
-
-    if opts.noipv4:
-        flags.useIPv4 = False
-
-    if opts.noipv6:
-        flags.useIPv6 = False
-
-    if opts.proxy:
-        anaconda.proxy = opts.proxy
-
-        if opts.proxyAuth:
-            filename = opts.proxyAuth
-            ret = open(filename, "r").readlines()
-            os.unlink(filename)
-
-            anaconda.proxyUsername = ret[0].rstrip()
-            if len(ret) == 2:
-                anaconda.proxyPassword = ret[1].rstrip()
-
-    if opts.updateSrc:
-        anaconda.updateSrc = opts.updateSrc
-
-    if opts.method:
-        if opts.method[0] == '@':
-            opts.method = expandFTPMethod(opts.method)
-
-        anaconda.setMethodstr(opts.method)
-    else:
-        anaconda.methodstr = None
-
-    if opts.stage2:
-        if opts.stage2[0] == '@':
-            opts.stage2 = expandFTPMethod(opts.stage2)
-
-        anaconda.stage2 = opts.stage2
-
-    if opts.liveinst:
-        flags.livecdInstall = True
-
-    if opts.module:
-        for mod in opts.module:
-            (path, name) = string.split(mod, ":")
-            anaconda.extraModules.append((path, name))
-
-    if opts.vnc:
-        flags.usevnc = 1
-        anaconda.displayMode = 'g'
-        vncS.recoverVNCPassword()
-
-        # Only consider vncconnect when vnc is a param
-        if opts.vncconnect:
-            cargs = string.split(opts.vncconnect, ":")
-            vncS.vncconnecthost = cargs[0]
-            if len(cargs) > 1 and len(cargs[1]) > 0:
-                if len(cargs[1]) > 0:
-                    vncS.vncconnectport = cargs[1]
-
-    if opts.ibft:
-        flags.ibft = 1
-
-    if opts.iscsi:
-        flags.iscsi = 1
-
-    if opts.targetArch:
-        flags.targetarch = opts.targetArch
-
-    # set flags 
-    flags.dmraid = opts.dmraid
-    flags.mpath = opts.mpath
-    flags.selinux = opts.selinux
-
-    if opts.serial:
-        flags.serial = True
-    if opts.virtpconsole:
-        flags.virtpconsole = opts.virtpconsole
-
-    if opts.xdriver:
-        anaconda.xdriver = opts.xdriver
-        anaconda.writeXdriver(root="/")
-
-    if not flags.livecdInstall:
-        startAuditDaemon()
-
-    # setup links required for all install types
-    for i in ( "services", "protocols", "nsswitch.conf", "joe", "selinux",
-               "mke2fs.conf" ):
-        try:
-            if os.path.exists("/mnt/runtime/etc/" + i):
-                os.symlink ("../mnt/runtime/etc/" + i, "/etc/" + i)
-        except:
-            pass
-
-    # This is the one place we do all kickstart file parsing.
-    if opts.ksfile:
-        kickstart.preScriptPass(anaconda, opts.ksfile)
-        anaconda.ksdata = kickstart.parseKickstart(anaconda, opts.ksfile)
-        opts.rescue = anaconda.ksdata.rescue.rescue
-
-    if flags.sshd:
-        # we need to have a libuser.conf that points to the installer root for
-        # sshpw, but after that we start sshd, we need one that points to the
-        # install target.
-        luserConf = users.createLuserConf(instPath="")
-        handleSshPw(anaconda)
-        startSsh()
-        del(os.environ["LIBUSER_CONF"])
-
-    users.createLuserConf(anaconda.rootPath)
-
-    if opts.rescue:
-        anaconda.rescue = True
-
-        import rescue
-
-        if anaconda.ksdata:
-            anaconda.instClass.configure(anaconda)
-
-            # We need an interface before running kickstart execute methods for
-            # storage.
-            from snack import *
-            screen = SnackScreen()
-            anaconda.intf = rescue.RescueInterface(screen)
-
-            anaconda.ksdata.execute()
-
-            anaconda.intf = None
-            screen.finish()
-
-            # command line 'nomount' overrides kickstart /same for vnc/
-            anaconda.rescue_mount = not (opts.rescue_nomount or anaconda.ksdata.rescue.nomount)
-
-        rescue.runRescue(anaconda)
-
-        # shouldn't get back here
-        sys.exit(1)
-
-    if anaconda.ksdata:
-        if anaconda.ksdata.vnc.enabled:
-            flags.usevnc = 1
-            anaconda.displayMode = 'g'
-
-            if vncS.password == "":
-                vncS.password = anaconda.ksdata.vnc.password
-
-            if vncS.vncconnecthost == "":
-                vncS.vncconnecthost = anaconda.ksdata.vnc.host
-
-            if vncS.vncconnectport == "":
-                vncS.vncconnectport = anaconda.ksdata.vnc.port
-
-        flags.vncquestion = False
-
-    # disable VNC over text question when not enough memory is available
-    if iutil.memInstalled() < isys.MIN_GUI_RAM:
-        flags.vncquestion = False
-
-    if os.environ.has_key('DISPLAY'):
-        flags.preexisting_x11 = True
-
-    if anaconda.displayMode == 't' and flags.vncquestion: #we prefer vnc over text mode, so ask about that
-        title = _("Would you like to use VNC?")
-        message = _("Text mode provides a limited set of installation options.  "
-                    "It does not allow you to specify your own partitioning "
-                    "layout or package selections.  Would you like to use VNC "
-                    "mode instead?")
-
-        ret = vnc.askVncWindow(title, message)
-        if ret != -1:
-            anaconda.displayMode = 'g'
-            flags.usevnc = 1
-            if ret is not None:
-                vncS.password = ret
-
-    if opts.debug:
-        flags.debug = True
-
-    log.info("anaconda called with cmdline = %s" %(sys.argv,))
-    log.info("Display mode = %s" % anaconda.displayMode)
-    log.info("Default encoding = %s " % sys.getdefaultencoding())
-
-    check_memory(anaconda, opts)
-
-    #
-    # now determine if we're going to run in GUI or TUI mode
-    #
-    # if no X server, we have to use text mode
-    if not flags.livecdInstall and not iutil.isS390() and not os.access("/usr/bin/Xorg", os.X_OK):
-         stdoutLog.warning(_("Graphical installation is not available. "
-                             "Starting text mode."))
-         time.sleep(2)
-         anaconda.displayMode = 't'
-
-    # s390/iSeries checks
-    if anaconda.isHeadless and anaconda.displayMode == "g" and not \
-       (flags.preexisting_x11 or flags.usevnc):
-        stdoutLog.warning(_("DISPLAY variable not set. Starting text mode."))
-        anaconda.displayMode = 't'
-        graphical_failed = 1
-        time.sleep(2)
-
-    # if DISPLAY not set either vnc server failed to start or we're not
-    # running on a redirected X display, so start local X server
-    if anaconda.displayMode == 'g' and not flags.preexisting_x11 and not flags.usevnc:
-        try:
-            # The following code depends on no SIGCHLD being delivered, possibly
-            # only except the one from a failing X.org. Thus make sure before
-            # entering this section that all the other children of anaconda have
-            # terminated or were forked into an orphan (which won't deliver a
-            # SIGCHLD to mess up the fragile signaling below).
-
-            # start X with its USR1 handler set to ignore.  this will make it send
-            # us SIGUSR1 if it succeeds.  if it fails, catch SIGCHLD and bomb out.
-
-            def sigchld_handler(num, frame):
-                raise OSError
-
-            def sigusr1_handler(num, frame):
-                pass
-
-            def preexec_fn():
-                signal.signal(signal.SIGUSR1, signal.SIG_IGN)
-
-            old_sigusr1 = signal.signal(signal.SIGUSR1, sigusr1_handler)
-            old_sigchld = signal.signal(signal.SIGCHLD, sigchld_handler)
-            xout = open("/dev/tty5", "w")
-
-            proc = subprocess.Popen(["Xorg", "-br", "-logfile", "/tmp/X.log",
-                                     ":1", "vt6", "-s", "1440", "-ac",
-                                     "-nolisten", "tcp", "-dpi", "96"],
-                                     close_fds=True, stdout=xout, stderr=xout,
-                                     preexec_fn=preexec_fn)
-
-            signal.pause()
-
-            os.environ["DISPLAY"] = ":1"
-            doStartupX11Actions(opts.runres)
-            xserver_pid = proc.pid
-        except (OSError, RuntimeError):
-            stdoutLog.warning(" X startup failed, falling back to text mode")
-            anaconda.displayMode = 't'
-            graphical_failed = 1
-            time.sleep(2)
-        finally:
-            signal.signal(signal.SIGUSR1, old_sigusr1)
-            signal.signal(signal.SIGCHLD, old_sigchld)
-
-    if anaconda.displayMode == 't' and graphical_failed and not anaconda.ksdata:
-        ret = vnc.askVncWindow()
-        if ret != -1:
-            anaconda.displayMode = 'g'
-            flags.usevnc = 1
-            if ret is not None:
-                vncS.password = ret
-
-    # if they want us to use VNC do that now
-    if anaconda.displayMode == 'g' and flags.usevnc:
-        runVNC()
-        doStartupX11Actions(opts.runres)
-
-    # with X running we can initialize the UI interface
-    anaconda.initInterface()
-    anaconda.instClass.configure(anaconda)
-
-    # comment out the next line to make exceptions non-fatal
-    from exception import initExceptionHandling
-    anaconda.mehConfig = initExceptionHandling(anaconda)
-
-    # add our own additional signal handlers
-    signal.signal(signal.SIGUSR2, lambda signum, frame: anaconda.dumpState())
-
-    # download and run Dogtail script
-    if opts.dogtail:
-       try:
-           import urlgrabber
-
-           try:
-               fr = urlgrabber.urlopen(opts.dogtail)
-           except urlgrabber.grabber.URLGrabError, e:
-               log.error("Could not retrieve Dogtail script from %s.\nError was\n%s" % (opts.dogtail, e))
-               fr = None
-                           
-           if fr:
-               (fw, testcase) = mkstemp(prefix='testcase.py.', dir='/tmp')
-               os.write(fw, fr.read())
-               fr.close()
-               os.close(fw)
-               
-               # download completed, run the test
-               if not os.fork():
-                   # we are in the child
-                   os.chmod(testcase, 0755)
-                   os.execv(testcase, [testcase])
-                   sys.exit(0)
-               else:
-                   # we are in the parent, sleep to give time for the testcase to initialize
-                   # todo: is this needed, how to avoid possible race conditions
-                   time.sleep(1)
-       except Exception, e:
-           log.error("Exception %s while running Dogtail testcase" % e)
-
-    if opts.lang:
-        # this is lame, but make things match what we expect (#443408)
-        opts.lang = opts.lang.replace(".utf8", ".UTF-8")
-        anaconda.dispatch.skipStep("language", permanent = 1)
-        anaconda.instLanguage.instLang = opts.lang
-        anaconda.instLanguage.systemLang = opts.lang
-        anaconda.timezone.setTimezoneInfo(anaconda.instLanguage.getDefaultTimeZone(anaconda.rootPath))
-
-    if opts.keymap:
-        anaconda.dispatch.skipStep("keyboard", permanent = 1)
-        anaconda.keyboard.set(opts.keymap)
-        anaconda.keyboard.activate()
-
-    if anaconda.ksdata:
-        import storage
-        storage.storageInitialize(anaconda)
-
-        # Now having initialized storage, we can apply all the other kickstart
-        # commands.  This gives us the ability to check that storage commands
-        # are correctly formed and refer to actual devices.
-        anaconda.ksdata.execute()
-
-    # set up the headless case
-    if anaconda.isHeadless:
-        anaconda.dispatch.skipStep("keyboard", permanent = 1)
-
-    if not anaconda.ksdata:
-        anaconda.instClass.setSteps(anaconda)
-    else:
-        kickstart.setSteps(anaconda)
-
-    try:
-        anaconda.intf.run(anaconda)
-    except SystemExit, code:
-        anaconda.intf.shutdown()
-
-    if anaconda.ksdata and anaconda.ksdata.reboot.eject:
-        for drive in anaconda.storage.devicetree.devices:
-            if drive.type != "cdrom":
-                continue
-
-            log.info("attempting to eject %s" % drive.path)
-            drive.eject()
-
-    del anaconda.intf
-
-# vim:tw=78:ts=4:et:sw=4
diff --git a/anaconda.py b/anaconda.py
new file mode 100755
index 0000000..b5532b0
--- /dev/null
+++ b/anaconda.py
@@ -0,0 +1,932 @@
+#!/usr/bin/python
+#
+# anaconda: The Red Hat Linux Installation program
+#
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+# Red Hat, Inc.  All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author(s): Brent Fox <bfox redhat com>
+#            Mike Fulbright <msf redhat com>
+#            Jakub Jelinek <jakub redhat com>
+#            Jeremy Katz <katzj redhat com>
+#            Chris Lumens <clumens redhat com>
+#            Paul Nasrat <pnasrat redhat com>
+#            Erik Troan <ewt rpath com>
+#            Matt Wilson <msw rpath com>
+#
+
+# This toplevel file is a little messy at the moment...
+
+import sys, os, re, time, subprocess
+from optparse import OptionParser
+from tempfile import mkstemp
+
+# keep up with process ID of the window manager if we start it
+wm_pid = None
+
+# Make sure messages sent through python's warnings module get logged.
+def AnacondaShowWarning(message, category, filename, lineno, file=sys.stderr, line=None):
+    log.warning("%s" % warnings.formatwarning(message, category, filename, lineno, line))
+
+def startMetacityWM():
+    childpid = os.fork()
+    if not childpid:
+        cmd = '/usr/bin/metacity'
+        if not os.access(cmd, os.X_OK):
+            log.error("Unable to find the window manager binary.")
+            sys.exit(1)
+        args = ['--display', ':1',
+                '--sm-disable']
+        rc = iutil.execWithRedirect(cmd, args, 
+                               stdout='/dev/null', stderr='/dev/null')
+        if rc:
+            log.error("Error running window manager.")
+            sys.exit (rc)
+        else:
+            log.info("The window manager has terminated.")
+            sys.exit(0)
+    return childpid
+
+def startAuditDaemon():
+    childpid = os.fork()
+    if not childpid:
+        cmd = '/sbin/auditd'
+        try:
+            os.execl(cmd, cmd)
+        except OSError as e:
+            log.error("Error running the audit daemon: %s" % str(e))
+        sys.exit(0)
+    # auditd will turn into a daemon so catch the immediate child pid now:
+    os.waitpid(childpid, 0)
+
+# function to handle X startup special issues for anaconda
+def doStartupX11Actions(runres="800x600"):
+    global wm_pid
+
+    setupGraphicalLinks()
+
+    # now start up the window manager
+    try:
+        wm_pid = startMetacityWM()
+        log.info("Starting window manager, pid %s." % (wm_pid,))
+    except Exception:
+        wm_pid = None
+        log.error("Unable to start the window manager.")
+
+    if wm_pid is not None:
+        import xutils
+        import gtk
+
+        try:
+            xutils.setRootResource('Xcursor.size', '24')
+            xutils.setRootResource('Xcursor.theme', 'Bluecurve')
+            xutils.setRootResource('Xcursor.theme_core', 'true')
+
+            xutils.setRootResource('Xft.antialias', '1')
+            xutils.setRootResource('Xft.hinting', '1')
+            xutils.setRootResource('Xft.hintstyle', 'hintslight')
+            xutils.setRootResource('Xft.rgba', 'none')
+        except:
+            sys.stderr.write("X SERVER STARTED, THEN FAILED");
+            raise RuntimeError, "X server failed to start"
+
+def doShutdownX11Actions():
+    global wm_pid
+    
+    if wm_pid is not None:
+        try:
+            os.kill(wm_pid, 15)
+            os.waitpid(wm_pid, 0)
+        except:
+            pass
+
+def setupPythonUpdates():
+    from distutils.sysconfig import get_python_lib
+
+    if not os.path.exists("/tmp/updates"):
+        return
+
+    for pkg in os.listdir("/tmp/updates"):
+        d = "/tmp/updates/%s" % pkg
+
+        if not os.path.isdir(d):
+            continue
+
+        # See if the package exists in /usr/lib{64,}/python/?.?/site-packages.
+        # If it does, we can set it up as an update.  If not, the pkg is
+        # likely a completely new directory and should not be looked at.
+        dest = "%s/%s" % (get_python_lib(), pkg)
+        if not os.access(dest, os.R_OK):
+            dest = "%s/%s" % (get_python_lib(1), pkg)
+            if not os.access(dest, os.R_OK):
+                continue
+
+        contents = os.listdir(d)
+
+        # Symlink over everything that's in the python libdir but not in
+        # the updates directory.
+        for f in filter(lambda fn: fn not in contents, os.listdir(dest)):
+            if f.endswith(".pyc") or f.endswith(".pyo"):
+                continue
+
+            os.symlink("%s/%s" % (dest, f), "/tmp/updates/%s/%s" % (pkg, f))
+
+
+    import glob
+    import shutil
+    for rule in glob.glob("/tmp/updates/*.rules"):
+        target = "/etc/udev/rules.d/" + rule.split('/')[-1]
+        shutil.copyfile(rule, target)
+
+def parseOptions(argv = None):
+    def resolution_cb (option, opt_str, value, parser):
+        parser.values.runres = value
+
+    op = OptionParser()
+    # Interface
+    op.add_option("-C", "--cmdline", dest="display_mode", action="store_const", const="c",
+                  default="g")
+    op.add_option("-G", "--graphical", dest="display_mode", action="store_const", const="g")
+    op.add_option("-T", "--text", dest="display_mode", action="store_const", const="t")
+
+    # Network
+    op.add_option("--noipv4", action="store_true", default=False)
+    op.add_option("--noipv6", action="store_true", default=False)
+    op.add_option("--proxy")
+    op.add_option("--proxyAuth")
+
+    # Method of operation
+    op.add_option("--autostep", action="store_true", default=False)
+    op.add_option("-d", "--debug", dest="debug", action="store_true", default=False)
+    op.add_option("--kickstart", dest="ksfile")
+    op.add_option("--rescue", dest="rescue", action="store_true", default=False)
+    op.add_option("--targetarch", dest="targetArch", nargs=1, type="string")
+
+    op.add_option("-m", "--method", dest="method", default=None)
+    op.add_option("--repo", dest="method", default=None)
+    op.add_option("--stage2", dest="stage2", default=None)
+
+    op.add_option("--liveinst", action="store_true", default=False)
+
+    # Display
+    op.add_option("--headless", dest="isHeadless", action="store_true", default=False)
+    op.add_option("--nofb")
+    op.add_option("--resolution", action="callback", callback=resolution_cb, dest="runres",
+                  default="800x600", nargs=1, type="string")
+    op.add_option("--serial", action="store_true", default=False)
+    op.add_option("--usefbx", dest="xdriver", action="store_const", const="fbdev")
+    op.add_option("--virtpconsole")
+    op.add_option("--vnc", action="store_true", default=False)
+    op.add_option("--vncconnect")
+    op.add_option("--xdriver", dest="xdriver", action="store", type="string", default=None)
+
+    # Language
+    op.add_option("--keymap")
+    op.add_option("--kbdtype")
+    op.add_option("--lang")
+
+    # Obvious
+    op.add_option("--loglevel")
+    op.add_option("--syslog")
+
+    op.add_option("--noselinux", dest="selinux", action="store_false", default=True)
+    op.add_option("--selinux", action="store_true")
+
+    op.add_option("--nompath", dest="mpath", action="store_false", default=True)
+    op.add_option("--mpath", action="store_true")
+
+    op.add_option("--nodmraid", dest="dmraid", action="store_false", default=True)
+    op.add_option("--dmraid", action="store_true")
+
+    op.add_option("--noibft", dest="ibft", action="store_false", default=True)
+    op.add_option("--ibft", action="store_true")
+    op.add_option("--noiscsi", dest="iscsi", action="store_false", default=False)
+    op.add_option("--iscsi", action="store_true")
+
+    # Miscellaneous
+    op.add_option("--module", action="append", default=[])
+    op.add_option("--nomount", dest="rescue_nomount", action="store_true", default=False)
+    op.add_option("--updates", dest="updateSrc", action="store", type="string")
+    op.add_option("--dogtail", dest="dogtail",   action="store", type="string")
+    op.add_option("--dlabel", action="store_true", default=False)
+
+    # Deprecated, unloved, unused
+    op.add_option("-r", "--rootPath", dest="unsupportedMode",
+                  action="store_const", const="root path")
+    op.add_option("-t", "--test", dest="unsupportedMode",
+                  action="store_const", const="test")
+
+    return op.parse_args(argv)
+
+def setupPythonPath():
+    haveUpdates = False
+    for ndx in range(len(sys.path)-1, -1, -1):
+        if sys.path[ndx].endswith('updates'):
+            haveUpdates = True
+            break
+
+    # With anaconda being a real module this isn't strictly necessary, but
+    # setting up the path now prevents having to change every import line in
+    # anaconda.
+    from distutils.sysconfig import get_python_lib
+    d = get_python_lib(plat_specific=1)
+
+    if haveUpdates:
+        sys.path.insert(ndx+1, "%s/pyanaconda" % d)
+        sys.path.insert(ndx+2, "%s/pyanaconda/textw" % d)
+        sys.path.insert(ndx+3, "%s/pyanaconda/iw" % d)
+    else:
+        sys.path.insert(0, "%s/pyanaconda" % d)
+        sys.path.insert(1, "%s/pyanaconda/textw" % d)
+        sys.path.insert(2, "%s/pyanaconda/iw" % d)
+
+    sys.path.append('/usr/share/system-config-date')
+
+def addPoPath(dir):
+    """ Looks to see what translations are under a given path and tells
+    the gettext module to use that path as the base dir """
+    for d in os.listdir(dir):
+        if not os.path.isdir("%s/%s" %(dir,d)):
+            continue
+        if not os.path.exists("%s/%s/LC_MESSAGES" %(dir,d)):
+            continue
+        for basename in os.listdir("%s/%s/LC_MESSAGES" %(dir,d)):
+            if not basename.endswith(".mo"):
+                continue
+            log.info("setting %s as translation source for %s" %(dir, basename[:-3]))
+            gettext.bindtextdomain(basename[:-3], dir)
+
+def setupTranslations():
+    if os.path.isdir("/tmp/updates/po"):
+        addPoPath("/tmp/updates/po")
+    gettext.textdomain("anaconda")
+
+def setupEnvironment():
+    # Silly GNOME stuff
+    if os.environ.has_key('HOME') and not os.environ.has_key("XAUTHORITY"):
+        os.environ['XAUTHORITY'] = os.environ['HOME'] + '/.Xauthority'
+    os.environ['HOME'] = '/tmp'
+    os.environ['LC_NUMERIC'] = 'C'
+    os.environ["GCONF_GLOBAL_LOCKS"] = "1"
+
+    # In theory, this gets rid of our LVM file descriptor warnings
+    os.environ["LVM_SUPPRESS_FD_WARNINGS"] = "1"
+
+    # make sure we have /sbin and /usr/sbin in our path
+    os.environ["PATH"] += ":/sbin:/usr/sbin"
+
+    # we can't let the LD_PRELOAD hang around because it will leak into
+    # rpm %post and the like.  ick :/
+    if os.environ.has_key("LD_PRELOAD"):
+        del os.environ["LD_PRELOAD"]
+
+    os.environ["GLADEPATH"] = "/tmp/updates/:/tmp/updates/ui/:ui/:/usr/share/anaconda/ui/:/usr/share/python-meh/"
+    os.environ["PIXMAPPATH"] = "/tmp/updates/pixmaps/:/tmp/updates/:/tmp/product/pixmaps/:/tmp/product/:pixmaps/:/usr/share/anaconda/pixmaps/:/usr/share/pixmaps/:/usr/share/anaconda/:/usr/share/python-meh/"
+
+def setupLoggingFromOpts(opts):
+    if opts.loglevel and anaconda_log.logLevelMap.has_key(opts.loglevel):
+        level = anaconda_log.logLevelMap[opts.loglevel]
+        anaconda_log.logger.tty_loglevel = level
+        anaconda_log.setHandlersLevel(log, level)
+        anaconda_log.setHandlersLevel(storage.storage_log.logger, level)
+
+    if opts.syslog:
+        anaconda_log.logger.remote_syslog = opts.syslog
+        if opts.syslog.find(":") != -1:
+            (host, port) = opts.syslog.split(":")
+            anaconda_log.logger.addSysLogHandler(log, host, port=int(port))
+        else:
+            anaconda_log.logger.addSysLogHandler(log, opts.syslog)
+
+# ftp installs pass the password via a file in /tmp so
+# ps doesn't show it
+def expandFTPMethod(str):
+    ret = None
+
+    try:
+        filename = str[1:]
+        ret = open(filename, "r").readline()
+        ret = ret[:len(ret) - 1]
+        os.unlink(filename)
+        return ret
+    except:
+        return None
+
+def runVNC():
+    global vncS
+    vncS.startServer()
+
+    child = os.fork()
+    if child == 0:
+        for p in ('/tmp/updates/pyrc.py', \
+                '/usr/share/anaconda/pyrc.py'):
+            if os.access(p, os.R_OK|os.X_OK):
+                os.environ['PYTHONSTARTUP'] = p
+                break
+
+        while True:
+            # s390/s390x are the only places we /really/ need a shell on tty1,
+            # and everywhere else this just gets in the way of pdb.  But we
+            # don't want to return, because that'll return try to start X
+            # a second time.
+            if iutil.isConsoleOnVirtualTerminal():
+                    time.sleep(10000)
+            else:
+                    print _("Press <enter> for a shell")
+                    sys.stdin.readline()
+                    iutil.execConsole()
+
+def within_available_memory(needed_ram):
+    # kernel binary code estimate that is
+    # not reported in MemTotal by /proc/meminfo:
+    epsilon = 15360 # 15 MB
+    return needed_ram < (iutil.memInstalled() + epsilon)
+
+def check_memory(anaconda, opts, display_mode=None):
+
+    if not display_mode:
+        display_mode = anaconda.displayMode
+
+    extra_ram = 0
+    reason = ''
+    if opts.stage2.startswith(('http', 'ftp', '@')):
+        extra_ram += isys.URL_INSTALL_EXTRA_RAM
+        reason = " using this install method"
+
+    needed_ram = isys.MIN_RAM + extra_ram
+    if not within_available_memory(needed_ram):
+        from snack import SnackScreen, ButtonChoiceWindow
+        screen = SnackScreen()
+        ButtonChoiceWindow(screen, _('Fatal Error'),
+                            _('You do not have enough RAM to install %s '
+                              'on this machine%s.\n'
+                              '\n'
+                              'Press <return> to reboot your system.\n')
+                           %(product.productName, reason),
+                           buttons = (_("OK"),))
+        screen.finish()
+        sys.exit(0)
+
+    # override display mode if machine cannot nicely run X
+    if display_mode not in ('t', 'c') and not flags.usevnc:
+        needed_ram = isys.MIN_GUI_RAM + extra_ram
+
+        if not within_available_memory(needed_ram):
+            complain = _("You do not have enough RAM to use the graphical "
+                         "installer.")
+            if flags.livecdInstall:
+                stdoutLog.warning(complain)
+                recommendation = _("Try the text mode installer by running:\n\n"
+                                   "'/usr/bin/liveinst -T'\n\n from a root "
+                                   "terminal.")
+                title = _("Not enough RAM")
+                text = "%s %s" %(complain, recommendation)
+                import gtk
+                dialog = gtk.MessageDialog(type = gtk.MESSAGE_ERROR, 
+                                           buttons = gtk.BUTTONS_CLOSE,
+                                           message_format=text)
+                dialog.set_title(title)
+                dialog.run()
+                sys.exit(1)
+            else:
+                resolution = _("Starting text mode.")
+                stdoutLog.warning("%s %s" % (complain, resolution))
+                anaconda.displayMode = 't'
+                time.sleep(2)
+
+def setupGraphicalLinks():
+    for i in ( "imrc", "im_palette.pal", "gtk-2.0", "pango", "fonts",
+               "fb.modes"):
+        try:
+            if os.path.exists("/mnt/runtime/etc/%s" %(i,)):
+                os.symlink ("../mnt/runtime/etc/" + i, "/etc/" + i)
+        except:
+            pass
+
+def handleSshPw(anaconda):
+    if not anaconda.ksdata:
+        return
+
+    import users
+    u = users.Users(anaconda)
+
+    userdata = anaconda.ksdata.sshpw.dataList()
+    for ud in userdata:
+        if u.checkUserExists(ud.username, root="/"):
+            u.setUserPassword(username=ud.username, password=ud.password,
+                              isCrypted=ud.isCrypted, lock=ud.lock)
+        else:
+            u.createUser(name=ud.username, password=ud.password,
+                         isCrypted=ud.isCrypted, lock=ud.lock,
+                         root="/")
+
+    del u
+
+def createSshKey(algorithm, keyfile):
+    path = '/etc/ssh/%s' % (keyfile,)
+    argv = ['-q','-t',algorithm,'-f',path,'-C','','-N','']
+    log.info("running \"%s\"" % (" ".join(['ssh-keygen']+argv),))
+
+    so = "/tmp/ssh-keygen-%s-stdout.log" % (algorithm,)
+    se = "/tmp/ssh-keygen-%s-stderr.log" % (algorithm,)
+    iutil.execWithRedirect('ssh-keygen', argv, stdout=so, stderr=se)
+
+def fork_orphan():
+    """Forks an orphan.
+    
+    Returns 1 in the parent and 0 in the orphaned child.
+    """
+    intermediate = os.fork()
+    if not intermediate:
+        if os.fork():
+            # the intermediate child dies
+            os._exit(0)
+        return 0;
+    # the original process waits for the intermediate child
+    os.waitpid(intermediate, 0)
+    return 1
+
+def startSsh():
+    if iutil.isS390():
+        return
+
+    if not fork_orphan():
+        os.mkdir("/var/log", 0755)
+        os.open("/var/log/lastlog", os.O_RDWR | os.O_CREAT, 0644)
+        ssh_keys = {
+            'rsa1':'ssh_host_key',
+            'rsa':'ssh_host_rsa_key',
+            'dsa':'ssh_host_dsa_key',
+            }
+        for (algorithm, keyfile) in ssh_keys.items():
+            createSshKey(algorithm, keyfile)
+        args = ["/sbin/sshd", "-f", "/etc/ssh/sshd_config.anaconda"]
+        os.execv("/sbin/sshd", args)
+        sys.exit(1)
+
+def startDebugger(signum, frame):
+    import epdb
+    epdb.serve(skip=1)
+
+if __name__ == "__main__":
+    setupPythonPath()
+
+    # Allow a file to be loaded as early as possible
+    try:
+        import updates_disk_hook
+    except ImportError:
+        pass
+
+    # Set up logging as early as possible.
+    import logging
+    import anaconda_log
+    anaconda_log.init()
+
+    log = logging.getLogger("anaconda")
+    stdoutLog = logging.getLogger("anaconda.stdout")
+
+    if os.geteuid() != 0:
+        stdoutLog.error("anaconda must be run as root.")
+        sys.exit(0)
+
+    # pull this in to get product name and versioning
+    import product
+
+    # this handles setting up updates for pypackages to minimize the set needed
+    setupPythonUpdates()
+
+    import isys
+    isys.initLog()
+
+    import signal, string, iutil, time
+    import warnings
+    import vnc
+    import users
+    import kickstart
+    import storage.storage_log
+
+    from flags import flags
+
+    # the following makes me very sad. -- katzj
+    # we have a slightly different set of udev rules in the second 
+    # stage than the first stage.  why this doesn't get picked up
+    # automatically, I don't know.  but we need to trigger so that we
+    # have all the information about netdevs that we care about for 
+    # NetworkManager in the udev database
+    from baseudev import udev_trigger, udev_settle
+    udev_trigger("net")
+    udev_settle()
+    # and for added fun, once doesn't seem to be enough?  so we 
+    # do it twice, it works and we scream at the world "OH WHY?"
+    udev_trigger("net")
+    udev_settle()
+
+    import gettext
+    _ = lambda x: gettext.ldgettext("anaconda", x)
+
+    from pyanaconda import Anaconda
+    anaconda = Anaconda()
+    warnings.showwarning = AnacondaShowWarning
+    setupTranslations()
+
+    # reset python's default SIGINT handler
+    signal.signal(signal.SIGINT, signal.SIG_DFL)
+    signal.signal(signal.SIGSEGV, isys.handleSegv)
+
+    setupEnvironment()
+
+    pidfile = open("/var/run/anaconda.pid", "w")
+    pidfile.write("%s\n" % (os.getpid(),))
+    del pidfile
+    # add our own additional signal handlers
+    signal.signal(signal.SIGHUP, startDebugger)
+
+    # we need to do this really early so we make sure its done before rpm
+    # is imported
+    iutil.writeRpmPlatform()
+
+    graphical_failed = 0
+    vncS = vnc.VncServer()          # The vnc Server object.
+    vncS.anaconda = anaconda
+    xserver_pid = None
+
+    (opts, args) = parseOptions()
+
+    # check memory, just the text mode for now:
+    check_memory(anaconda, opts, 't')
+
+    if opts.unsupportedMode:
+        stdoutLog.error("Running anaconda in %s mode is no longer supported." % opts.unsupportedMode)
+        sys.exit(0)
+
+    # Now that we've got arguments, do some extra processing.
+    setupLoggingFromOpts(opts)
+
+    # Default is to prompt to mount the installed system.
+    anaconda.rescue_mount = not opts.rescue_nomount
+
+    if opts.dlabel: #autodetected driverdisc in use
+        flags.dlabel = True
+
+    anaconda.displayMode = opts.display_mode
+    anaconda.isHeadless = opts.isHeadless
+
+    if opts.noipv4:
+        flags.useIPv4 = False
+
+    if opts.noipv6:
+        flags.useIPv6 = False
+
+    if opts.proxy:
+        anaconda.proxy = opts.proxy
+
+        if opts.proxyAuth:
+            filename = opts.proxyAuth
+            ret = open(filename, "r").readlines()
+            os.unlink(filename)
+
+            anaconda.proxyUsername = ret[0].rstrip()
+            if len(ret) == 2:
+                anaconda.proxyPassword = ret[1].rstrip()
+
+    if opts.updateSrc:
+        anaconda.updateSrc = opts.updateSrc
+
+    if opts.method:
+        if opts.method[0] == '@':
+            opts.method = expandFTPMethod(opts.method)
+
+        anaconda.setMethodstr(opts.method)
+    else:
+        anaconda.methodstr = None
+
+    if opts.stage2:
+        if opts.stage2[0] == '@':
+            opts.stage2 = expandFTPMethod(opts.stage2)
+
+        anaconda.stage2 = opts.stage2
+
+    if opts.liveinst:
+        flags.livecdInstall = True
+
+    if opts.module:
+        for mod in opts.module:
+            (path, name) = string.split(mod, ":")
+            anaconda.extraModules.append((path, name))
+
+    if opts.vnc:
+        flags.usevnc = 1
+        anaconda.displayMode = 'g'
+        vncS.recoverVNCPassword()
+
+        # Only consider vncconnect when vnc is a param
+        if opts.vncconnect:
+            cargs = string.split(opts.vncconnect, ":")
+            vncS.vncconnecthost = cargs[0]
+            if len(cargs) > 1 and len(cargs[1]) > 0:
+                if len(cargs[1]) > 0:
+                    vncS.vncconnectport = cargs[1]
+
+    if opts.ibft:
+        flags.ibft = 1
+
+    if opts.iscsi:
+        flags.iscsi = 1
+
+    if opts.targetArch:
+        flags.targetarch = opts.targetArch
+
+    # set flags 
+    flags.dmraid = opts.dmraid
+    flags.mpath = opts.mpath
+    flags.selinux = opts.selinux
+
+    if opts.serial:
+        flags.serial = True
+    if opts.virtpconsole:
+        flags.virtpconsole = opts.virtpconsole
+
+    if opts.xdriver:
+        anaconda.xdriver = opts.xdriver
+        anaconda.writeXdriver(root="/")
+
+    if not flags.livecdInstall:
+        startAuditDaemon()
+
+    # setup links required for all install types
+    for i in ( "services", "protocols", "nsswitch.conf", "joe", "selinux",
+               "mke2fs.conf" ):
+        try:
+            if os.path.exists("/mnt/runtime/etc/" + i):
+                os.symlink ("../mnt/runtime/etc/" + i, "/etc/" + i)
+        except:
+            pass
+
+    # This is the one place we do all kickstart file parsing.
+    if opts.ksfile:
+        kickstart.preScriptPass(anaconda, opts.ksfile)
+        anaconda.ksdata = kickstart.parseKickstart(anaconda, opts.ksfile)
+        opts.rescue = anaconda.ksdata.rescue.rescue
+
+    if flags.sshd:
+        # we need to have a libuser.conf that points to the installer root for
+        # sshpw, but after that we start sshd, we need one that points to the
+        # install target.
+        luserConf = users.createLuserConf(instPath="")
+        handleSshPw(anaconda)
+        startSsh()
+        del(os.environ["LIBUSER_CONF"])
+
+    users.createLuserConf(anaconda.rootPath)
+
+    if opts.rescue:
+        anaconda.rescue = True
+
+        import rescue
+
+        if anaconda.ksdata:
+            anaconda.instClass.configure(anaconda)
+
+            # We need an interface before running kickstart execute methods for
+            # storage.
+            from snack import *
+            screen = SnackScreen()
+            anaconda.intf = rescue.RescueInterface(screen)
+
+            anaconda.ksdata.execute()
+
+            anaconda.intf = None
+            screen.finish()
+
+            # command line 'nomount' overrides kickstart /same for vnc/
+            anaconda.rescue_mount = not (opts.rescue_nomount or anaconda.ksdata.rescue.nomount)
+
+        rescue.runRescue(anaconda)
+
+        # shouldn't get back here
+        sys.exit(1)
+
+    if anaconda.ksdata:
+        if anaconda.ksdata.vnc.enabled:
+            flags.usevnc = 1
+            anaconda.displayMode = 'g'
+
+            if vncS.password == "":
+                vncS.password = anaconda.ksdata.vnc.password
+
+            if vncS.vncconnecthost == "":
+                vncS.vncconnecthost = anaconda.ksdata.vnc.host
+
+            if vncS.vncconnectport == "":
+                vncS.vncconnectport = anaconda.ksdata.vnc.port
+
+        flags.vncquestion = False
+
+    # disable VNC over text question when not enough memory is available
+    if iutil.memInstalled() < isys.MIN_GUI_RAM:
+        flags.vncquestion = False
+
+    if os.environ.has_key('DISPLAY'):
+        flags.preexisting_x11 = True
+
+    if anaconda.displayMode == 't' and flags.vncquestion: #we prefer vnc over text mode, so ask about that
+        title = _("Would you like to use VNC?")
+        message = _("Text mode provides a limited set of installation options.  "
+                    "It does not allow you to specify your own partitioning "
+                    "layout or package selections.  Would you like to use VNC "
+                    "mode instead?")
+
+        ret = vnc.askVncWindow(title, message)
+        if ret != -1:
+            anaconda.displayMode = 'g'
+            flags.usevnc = 1
+            if ret is not None:
+                vncS.password = ret
+
+    if opts.debug:
+        flags.debug = True
+
+    log.info("anaconda called with cmdline = %s" %(sys.argv,))
+    log.info("Display mode = %s" % anaconda.displayMode)
+    log.info("Default encoding = %s " % sys.getdefaultencoding())
+
+    check_memory(anaconda, opts)
+
+    #
+    # now determine if we're going to run in GUI or TUI mode
+    #
+    # if no X server, we have to use text mode
+    if not flags.livecdInstall and not iutil.isS390() and not os.access("/usr/bin/Xorg", os.X_OK):
+         stdoutLog.warning(_("Graphical installation is not available. "
+                             "Starting text mode."))
+         time.sleep(2)
+         anaconda.displayMode = 't'
+
+    # s390/iSeries checks
+    if anaconda.isHeadless and anaconda.displayMode == "g" and not \
+       (flags.preexisting_x11 or flags.usevnc):
+        stdoutLog.warning(_("DISPLAY variable not set. Starting text mode."))
+        anaconda.displayMode = 't'
+        graphical_failed = 1
+        time.sleep(2)
+
+    # if DISPLAY not set either vnc server failed to start or we're not
+    # running on a redirected X display, so start local X server
+    if anaconda.displayMode == 'g' and not flags.preexisting_x11 and not flags.usevnc:
+        try:
+            # The following code depends on no SIGCHLD being delivered, possibly
+            # only except the one from a failing X.org. Thus make sure before
+            # entering this section that all the other children of anaconda have
+            # terminated or were forked into an orphan (which won't deliver a
+            # SIGCHLD to mess up the fragile signaling below).
+
+            # start X with its USR1 handler set to ignore.  this will make it send
+            # us SIGUSR1 if it succeeds.  if it fails, catch SIGCHLD and bomb out.
+
+            def sigchld_handler(num, frame):
+                raise OSError
+
+            def sigusr1_handler(num, frame):
+                pass
+
+            def preexec_fn():
+                signal.signal(signal.SIGUSR1, signal.SIG_IGN)
+
+            old_sigusr1 = signal.signal(signal.SIGUSR1, sigusr1_handler)
+            old_sigchld = signal.signal(signal.SIGCHLD, sigchld_handler)
+            xout = open("/dev/tty5", "w")
+
+            proc = subprocess.Popen(["Xorg", "-br", "-logfile", "/tmp/X.log",
+                                     ":1", "vt6", "-s", "1440", "-ac",
+                                     "-nolisten", "tcp", "-dpi", "96"],
+                                     close_fds=True, stdout=xout, stderr=xout,
+                                     preexec_fn=preexec_fn)
+
+            signal.pause()
+
+            os.environ["DISPLAY"] = ":1"
+            doStartupX11Actions(opts.runres)
+            xserver_pid = proc.pid
+        except (OSError, RuntimeError):
+            stdoutLog.warning(" X startup failed, falling back to text mode")
+            anaconda.displayMode = 't'
+            graphical_failed = 1
+            time.sleep(2)
+        finally:
+            signal.signal(signal.SIGUSR1, old_sigusr1)
+            signal.signal(signal.SIGCHLD, old_sigchld)
+
+    if anaconda.displayMode == 't' and graphical_failed and not anaconda.ksdata:
+        ret = vnc.askVncWindow()
+        if ret != -1:
+            anaconda.displayMode = 'g'
+            flags.usevnc = 1
+            if ret is not None:
+                vncS.password = ret
+
+    # if they want us to use VNC do that now
+    if anaconda.displayMode == 'g' and flags.usevnc:
+        runVNC()
+        doStartupX11Actions(opts.runres)
+
+    # with X running we can initialize the UI interface
+    anaconda.initInterface()
+    anaconda.instClass.configure(anaconda)
+
+    # comment out the next line to make exceptions non-fatal
+    from exception import initExceptionHandling
+    anaconda.mehConfig = initExceptionHandling(anaconda)
+
+    # add our own additional signal handlers
+    signal.signal(signal.SIGUSR2, lambda signum, frame: anaconda.dumpState())
+
+    # download and run Dogtail script
+    if opts.dogtail:
+       try:
+           import urlgrabber
+
+           try:
+               fr = urlgrabber.urlopen(opts.dogtail)
+           except urlgrabber.grabber.URLGrabError, e:
+               log.error("Could not retrieve Dogtail script from %s.\nError was\n%s" % (opts.dogtail, e))
+               fr = None
+                           
+           if fr:
+               (fw, testcase) = mkstemp(prefix='testcase.py.', dir='/tmp')
+               os.write(fw, fr.read())
+               fr.close()
+               os.close(fw)
+               
+               # download completed, run the test
+               if not os.fork():
+                   # we are in the child
+                   os.chmod(testcase, 0755)
+                   os.execv(testcase, [testcase])
+                   sys.exit(0)
+               else:
+                   # we are in the parent, sleep to give time for the testcase to initialize
+                   # todo: is this needed, how to avoid possible race conditions
+                   time.sleep(1)
+       except Exception, e:
+           log.error("Exception %s while running Dogtail testcase" % e)
+
+    if opts.lang:
+        # this is lame, but make things match what we expect (#443408)
+        opts.lang = opts.lang.replace(".utf8", ".UTF-8")
+        anaconda.dispatch.skipStep("language", permanent = 1)
+        anaconda.instLanguage.instLang = opts.lang
+        anaconda.instLanguage.systemLang = opts.lang
+        anaconda.timezone.setTimezoneInfo(anaconda.instLanguage.getDefaultTimeZone(anaconda.rootPath))
+
+    if opts.keymap:
+        anaconda.dispatch.skipStep("keyboard", permanent = 1)
+        anaconda.keyboard.set(opts.keymap)
+        anaconda.keyboard.activate()
+
+    if anaconda.ksdata:
+        import storage
+        storage.storageInitialize(anaconda)
+
+        # Now having initialized storage, we can apply all the other kickstart
+        # commands.  This gives us the ability to check that storage commands
+        # are correctly formed and refer to actual devices.
+        anaconda.ksdata.execute()
+
+    # set up the headless case
+    if anaconda.isHeadless:
+        anaconda.dispatch.skipStep("keyboard", permanent = 1)
+
+    if not anaconda.ksdata:
+        anaconda.instClass.setSteps(anaconda)
+    else:
+        kickstart.setSteps(anaconda)
+
+    try:
+        anaconda.intf.run(anaconda)
+    except SystemExit, code:
+        anaconda.intf.shutdown()
+
+    if anaconda.ksdata and anaconda.ksdata.reboot.eject:
+        for drive in anaconda.storage.devicetree.devices:
+            if drive.type != "cdrom":
+                continue
+
+            log.info("attempting to eject %s" % drive.path)
+            drive.eject()
+
+    del anaconda.intf
+
+# vim:tw=78:ts=4:et:sw=4
diff --git a/anaconda_log.py b/anaconda_log.py
deleted file mode 100644
index 961cba1..0000000
--- a/anaconda_log.py
+++ /dev/null
@@ -1,170 +0,0 @@
-#
-# anaconda_log.py: Support for logging to multiple destinations with log
-# levels.
-#
-# Copyright (C) 2000, 2001, 2002, 2005  Red Hat, Inc.  All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author(s): Chris Lumens <clumens redhat com>
-#            Matt Wilson <msw redhat com>
-#            Michael Fulbright <msf redhat com>
-#
-
-import os
-import signal
-import sys
-import logging
-from logging.handlers import SysLogHandler, SYSLOG_UDP_PORT
-import types
-
-import iutil
-
-DEFAULT_TTY_LEVEL = logging.INFO
-ENTRY_FORMAT = "%(asctime)s,%(msecs)03d %(levelname)s %(name)s: %(message)s"
-TTY_FORMAT = "%(levelname)s %(name)s: %(message)s"
-STDOUT_FORMAT = "%(asctime)s %(message)s"
-DATE_FORMAT = "%H:%M:%S"
-
-MAIN_LOG_FILE = "/tmp/anaconda.log"
-MAIN_LOG_TTY = "/dev/tty3"
-PROGRAM_LOG_FILE = "/tmp/program.log"
-ANACONDA_SYSLOG_FACILITY = SysLogHandler.LOG_LOCAL1
-
-logLevelMap = {"debug": logging.DEBUG, "info": logging.INFO,
-               "warning": logging.WARNING, "error": logging.ERROR,
-               "critical": logging.CRITICAL}
-
-# sets autoSetLevel for the given handler
-def autoSetLevel(handler, value):
-    handler.autoSetLevel = value
-
-# all handlers of given logger with autoSetLevel == True are set to level
-def setHandlersLevel(logger, level):
-    map(lambda hdlr: hdlr.setLevel(level),
-        filter (lambda hdlr: hasattr(hdlr, "autoSetLevel") and hdlr.autoSetLevel, logger.handlers))
-
-class AnacondaSyslogHandler(SysLogHandler):
-    def __init__(self, 
-                 address=('localhost', SYSLOG_UDP_PORT),
-                 facility=SysLogHandler.LOG_USER, 
-                 tag=''):
-        self.tag = tag
-        SysLogHandler.__init__(self, address, facility)
-
-    def emit(self, record):
-        original_msg = record.msg
-        record.msg = '%s: %s' %(self.tag, original_msg)
-        SysLogHandler.emit(self, record)
-        record.msg = original_msg
-
-class AnacondaLog:
-    def __init__ (self):
-        self.tty_loglevel = DEFAULT_TTY_LEVEL
-        self.remote_syslog = None
-        # Create the base of the logger hierarcy.
-        logger = logging.getLogger("anaconda")
-        logger.setLevel(logging.DEBUG)
-        self.addFileHandler(MAIN_LOG_FILE, logger,
-                            minLevel=logging.DEBUG)
-        self.forwardToSyslog(logger)
-        # Log to tty3.
-        if not iutil.isS390() and os.access(MAIN_LOG_TTY, os.W_OK):
-            self.addFileHandler(MAIN_LOG_TTY, logger,
-                                fmtStr=TTY_FORMAT,
-                                autoLevel=True)
-
-        # External program output log
-        program_logger = logging.getLogger("program")
-        program_logger.setLevel(logging.DEBUG)
-        self.addFileHandler(PROGRAM_LOG_FILE, program_logger,
-                            minLevel=logging.DEBUG)
-        self.forwardToSyslog(program_logger)
-
-        # Create a second logger for just the stuff we want to dup on
-        # stdout.  Anything written here will also get passed up to the
-        # parent loggers for processing and possibly be written to the
-        # log.
-        stdoutLogger = logging.getLogger("anaconda.stdout")
-        stdoutLogger.setLevel(logging.INFO)
-        # Add a handler for the duped stuff.  No fancy formatting, thanks.
-        self.addFileHandler(sys.stdout, stdoutLogger,
-                            fmtStr=STDOUT_FORMAT, minLevel=logging.INFO)
-
-        # Stderr logger
-        stderrLogger = logging.getLogger("anaconda.stderr")
-        stderrLogger.setLevel(logging.INFO)
-        self.addFileHandler(sys.stderr, stderrLogger,
-                            fmtStr=STDOUT_FORMAT, minLevel=logging.INFO)
-
-    # Add a simple handler - file or stream, depending on what we're given.
-    def addFileHandler (self, file, addToLogger, minLevel=DEFAULT_TTY_LEVEL,
-                        fmtStr=ENTRY_FORMAT,
-                        autoLevel=False):
-        if isinstance(file, types.StringTypes):
-            logfileHandler = logging.FileHandler(file)
-        else:
-            logfileHandler = logging.StreamHandler(file)
-
-        logfileHandler.setLevel(minLevel)
-        logfileHandler.setFormatter(logging.Formatter(fmtStr, DATE_FORMAT))
-        autoSetLevel(logfileHandler, autoLevel)
-        addToLogger.addHandler(logfileHandler)
-
-    # Add another logger to the hierarchy.  For best results, make sure
-    # name falls under anaconda in the tree.
-    def addLogger (self, name, minLevel=DEFAULT_TTY_LEVEL):
-        newLogger = logging.getLogger(name)
-        newLogger.setLevel(minLevel)
-
-    # Add a handler for remote syslogs.
-    def addSysLogHandler (self, logger, host, port=SYSLOG_UDP_PORT,
-                          minLevel=DEFAULT_TTY_LEVEL):
-        fmt = logging.Formatter("%(levelname)-8s %(message)s")
-        syslogHandler = SysLogHandler((host, port))
-        syslogHandler.setLevel(minLevel)
-        syslogHandler.setFormatter(fmt)
-        logger.addHandler(syslogHandler)
-
-    def forwardToSyslog(self, logger):
-        """Forward everything that goes in the logger to the syslog daemon.
-        """
-        syslogHandler = AnacondaSyslogHandler(
-            '/dev/log', 
-            ANACONDA_SYSLOG_FACILITY,
-            logger.name)
-        syslogHandler.setLevel(logging.DEBUG)
-        logger.addHandler(syslogHandler)
-
-    def updateRemote(self, remote_syslog):
-        """Updates the location of remote rsyslogd to forward to.
-
-        Requires updating rsyslogd config and sending SIGHUP to the daemon.
-        """
-        PIDFILE  = "/var/run/syslogd.pid"
-        CFGFILE  = "/etc/rsyslog.conf"
-        TEMPLATE = "*.* @@%s\n"
-
-        self.remote_syslog = remote_syslog
-        with open(CFGFILE, 'a') as cfgfile:
-            forward_line = TEMPLATE % remote_syslog
-            cfgfile.write(forward_line)
-        with open(PIDFILE, 'r') as pidfile:
-            pid = int(pidfile.read())
-            os.kill(pid, signal.SIGHUP)
-
-logger = None
-def init():
-    global logger
-    logger = AnacondaLog()
diff --git a/backend.py b/backend.py
deleted file mode 100644
index 217fa55..0000000
--- a/backend.py
+++ /dev/null
@@ -1,301 +0,0 @@
-#
-# backend.py: Interface for installation backends
-#
-# Copyright (C) 2005, 2006, 2007  Red Hat, Inc.  All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author(s): Paul Nasrat <pnasrat redhat com>
-#            Jeremy Katz <katzj redhat com>
-#
-
-import glob
-import shutil
-import iutil
-import os, sys
-import logging
-import backend_log
-from constants import *
-
-import isys
-import kickstart
-import packages
-import storage
-
-from flags import flags
-log = logging.getLogger("anaconda")
-
-import gettext
-_ = lambda x: gettext.ldgettext("anaconda", x)
-
-class AnacondaBackend:
-    def __init__(self, anaconda):
-        """Abstract backend class all backends should inherit from this
-           @param instPath: root path for the installation to occur"""
-        self.anaconda = anaconda
-        self.instPath = anaconda.rootPath
-        self.instLog = None
-        self.modeText = ""
-
-        # some backends may not support upgrading
-        self.supportsUpgrades = True
-        self.supportsPackageSelection = False
-
-        # some backends may have a special case for rootfs formatting
-        # FIXME: we should handle this a little more elegantly
-        self.skipFormatRoot = False
-        self.rootFsType = None
-
-        self._loopbackFile = None
-
-    def postAction(self, anaconda):
-        pass
-
-    def doPreSelection(self, intf, id, instPath):
-        pass
-
-    def doPostSelection(self, anaconda):
-        pass
-
-    def doPreInstall(self, anaconda):
-        self.initLog(anaconda.rootPath)
-
-    def copyFirmware(self, anaconda):
-        # Multiple driver disks may be loaded, so we need to glob for all
-        # the firmware files in the common DD firmware directory
-        for f in glob.glob(DD_EXTRACTED+"/lib/firmware/*"):
-            try:
-                shutil.copyfile(f, "%s/lib/firmware/" % anaconda.rootPath)
-            except IOError, e:
-                log.error("Could not copy firmware file %s: %s" % (f, e.strerror))
-
-    def doPostInstall(self, anaconda):
-        #always copy the firmware files from DD
-        self.copyFirmware(anaconda)
-
-        if anaconda.extraModules:
-            for (n, arch, tag) in self.kernelVersionList(anaconda.rootPath):
-                packages.recreateInitrd(n, anaconda.rootPath)
-
-        #copy RPMS
-        for d in glob.glob(DD_RPMS):
-            shutil.copytree(d, anaconda.rootPath + "/root/" + os.path.basename(d))
-
-        #copy modules and firmware
-        if os.path.exists(DD_EXTRACTED):
-            try:
-                shutil.copytree(DD_EXTRACTED, anaconda.rootPath + "/root/DD")
-            except IOError, e:
-                pass
-
-        storage.writeEscrowPackets(anaconda)
-        sys.stdout.flush()
-        backend_log.log.stop()
-
-    def doInstall(self, anaconda):
-        log.warning("doInstall not implemented for backend!")
-        raise NotImplementedError
-
-    def initLog(self, instPath):
-        if not os.path.isdir(instPath + "/root"):
-            iutil.mkdirChain(instPath + "/root")
-
-        if self.anaconda.upgrade:
-            logname = '/root/upgrade.log'
-        else:
-            logname = '/root/install.log'
-
-        instLogName = instPath + logname
-        try:
-            shutil.rmtree (instLogName)
-        except OSError:
-            pass
-
-        self.instLog = open(instLogName, "w+")
-
-        syslogname = "%s%s.syslog" % (instPath, logname)
-        try:
-            shutil.rmtree (syslogname)
-        except OSError:
-            pass
-        backend_log.log.start(instPath, syslogname)
-
-        if self.anaconda.upgrade:
-            self.modeText = _("Upgrading %s\n")
-        else:
-            self.modeText = _("Installing %s\n")
-
-    def mountInstallImage(self, anaconda, installimg):
-        if self._loopbackFile and os.path.exists(self._loopbackFile):
-            return
-
-        # Copy the install.img to the filesystem and switch loopback devices
-        # to there.  Otherwise we won't be able to unmount and swap media.
-        free = anaconda.storage.fsFreeSpace
-        self._loopbackFile = "%s%s/rhinstall-install.img" % (anaconda.rootPath,
-                                                             free[-1][0])
-        try:
-            log.info("transferring install image to install target")
-            win = anaconda.intf.waitWindow(_("Copying File"),
-                    _("Transferring install image to hard drive"))
-            shutil.copyfile(installimg, self._loopbackFile)
-            win.pop()
-        except Exception, e:
-            if win:
-                win.pop()
-
-            log.critical("error transferring install.img: %s" %(e,))
-
-            if isinstance(e, IOError) and e.errno == 5:
-                msg = _("An error occurred transferring the install image "
-                        "to your hard drive.  This is often cause by "
-                        "damaged or low quality media.")
-            else:
-                msg = _("An error occurred transferring the install image "
-                        "to your hard drive. You are probably out of disk "
-                        "space.")
-
-            anaconda.intf.messageWindow(_("Error"), msg)
-            try:
-                os.unlink(self._loopbackFile)
-            except:
-                pass
-
-            return 1
-
-        isys.lochangefd("/dev/loop0", self._loopbackFile)
-        if os.path.ismount("/mnt/stage2"):
-            isys.umount("/mnt/stage2")
-
-    def removeInstallImage(self):
-        if self._loopbackFile:
-            try:
-                os.unlink(self._loopbackFile)
-            except SystemError:
-                pass
-   
-    def freetmp(self, anaconda):
-    # installs that don't use /mnt/stage2 hold the install.img on
-    # a tmpfs, free this ram if things are tight.
-        stage2img = "/tmp/install.img"
-        if os.path.exists(stage2img):
-            # free up /tmp for more memory before yum is called,
-            if self.mountInstallImage(anaconda, stage2img):
-               	return DISPATCH_BACK
-            try:
-                os.unlink(stage2img)
-            except SystemError:
-                log.info("clearing /tmp failed")
-                return DISPATCH_BACK
-
-    def kernelVersionList(self, rootPath="/"):
-        return []
-
-    def getMinimumSizeMB(self, part):
-        """Return the minimal size for part in megabytes if we can."""
-        return 0
-
-    def doBackendSetup(self, anaconda):
-        log.warning("doBackendSetup not implemented for backend!")
-        raise NotImplementedError
-
-    def groupExists(self, group):
-        log.warning("groupExists not implemented for backend!")
-        raise NotImplementedError
-
-    def selectGroup(self, group, *args):
-        log.warning("selectGroup not implemented for backend!")
-        raise NotImplementedError
-
-    def deselectGroup(self, group, *args):
-        log.warning("deselectGroup not implemented for backend!")
-        raise NotImplementedError
-
-    def packageExists(self, pkg):
-        log.warning("packageExists not implemented for backend!")
-        raise NotImplementedError
-    
-    def selectPackage(self, pkg, *args):
-        log.warning("selectPackage not implemented for backend!")
-        raise NotImplementedError
-
-    def deselectPackage(self, pkg, *args):
-        log.warning("deselectPackage not implemented for backend!")
-        raise NotImplementedError
-
-    def getDefaultGroups(self, anaconda):
-        log.warning("getDefaultGroups not implemented for backend!")
-        raise NotImplementedError
-
-    def resetPackageSelections(self):
-        # we just leave this one unimplemented if it's not needed
-        pass
-
-    # write out the %packages section of anaconda-ks.cfg
-    def writePackagesKS(self, f, anaconda):
-        log.warning("writePackagesKS not implemented for backend!")
-        raise NotImplementedError
-
-    # write out any config files that live on the installed system
-    # (e.g., /etc/yum.repos.d/* files)
-    def writeConfiguration(self):
-        log.warning("writeConfig not implemented for backend!")
-        raise NotImplementedError
-
-    # write out any other kickstart bits the backend requires - no warning
-    # here because this may not be needed
-    def writeKS(self, f):
-        pass
-
-    def getRequiredMedia(self):
-        log.warning("getRequiredMedia not implmented for backend!")
-        raise NotImplementedError
-
-    def complete(self, anaconda):
-        pass
-
-def doBackendSetup(anaconda):
-    if anaconda.backend.doBackendSetup(anaconda) == DISPATCH_BACK:
-        return DISPATCH_BACK
-
-    if anaconda.upgrade:
-        anaconda.backend.checkSupportedUpgrade(anaconda)
-        iutil.writeRpmPlatform(anaconda.rootPath)
-
-def doPostSelection(anaconda):
-    return anaconda.backend.doPostSelection(anaconda)
-
-def doPreInstall(anaconda):
-    anaconda.backend.doPreInstall(anaconda)
-
-def doPostInstall(anaconda):
-    anaconda.backend.doPostInstall(anaconda)
-
-def doInstall(anaconda):
-    return anaconda.backend.doInstall(anaconda)
-
-# does this need to be per-backend?  we'll just leave here until it does :)
-def doBasePackageSelect(anaconda):
-    if anaconda.ksdata:
-        anaconda.backend.resetPackageSelections()
-        kickstart.selectPackages(anaconda)
-    elif anaconda.displayMode != 't':
-        anaconda.backend.resetPackageSelections()
-        anaconda.instClass.setPackageSelection(anaconda)
-        anaconda.instClass.setGroupSelection(anaconda)
-
-def writeConfiguration(anaconda):
-    log.info("Writing main configuration")
-    anaconda.write()
-    anaconda.backend.writeConfiguration()
diff --git a/backend_log.py b/backend_log.py
deleted file mode 100644
index fd11692..0000000
--- a/backend_log.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# backend_log.py
-# Logging infrastructure for Anaconda's backend.
-#
-# Copyright (C) 2009  Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties 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, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-# Red Hat Author(s): Ales Kozumplik <akozumpl redhat com>
-#
-
-import logging
-import os
-import signal
-
-import anaconda_log
-import iutil
-
-SYSLOG_PATH           = '/sbin/rsyslogd'
-SYSLOG_PIDFILE        = '/var/run/rsyslog_backend.pid'
-SYSLOG_CFGFILE        = '/etc/rsyslog_backend.conf'
-
-CFG_TEMPLATE = """
-$ModLoad imuxsock
-$InputUnixListenSocketHostName sysimage
-$AddUnixListenSocket %(socket)s
-+sysimage
-*.* %(logfile)s;RSYSLOG_TraditionalFileFormat
-%(remote_syslog)s
-"""
-
-global_log = logging.getLogger("anaconda")
-class BackendSyslog:
-    def __init__(self):
-        pass
-    
-    def build_cfg(self, root, log):
-        socket = "%s/dev/log" % (root, )
-        remote_syslog = ''
-        if anaconda_log.logger.remote_syslog:
-            remote_syslog = "*.* @@%s" % (anaconda_log.logger.remote_syslog, )
-        
-        cfg = CFG_TEMPLATE % {
-            'socket' : socket,
-            'logfile' : log,
-            'remote_syslog' : remote_syslog
-            }
-        with open(SYSLOG_CFGFILE, 'w') as cfg_file:
-            cfg_file.write(cfg)
-
-    def start(self, root, log):
-        """ Start an rsyslogd instance dedicated for the sysimage.
-
-        Other possibility would be to change configuration and SIGHUP the
-        existing instance, but it could lose some of its internal queues and
-        give us problems with remote logging.
-        """
-        self.build_cfg(root, log)
-        args = ['-c', '4', 
-                '-f', SYSLOG_CFGFILE,
-                '-i', str(SYSLOG_PIDFILE)]
-        status = iutil.execWithRedirect(SYSLOG_PATH, args)
-        if status == 0:
-            global_log.info("Backend logger started.")
-        else:
-            global_log.error("Unable to start backend logger")
-    
-    def stop(self):
-        try:
-            with open(SYSLOG_PIDFILE, 'r') as pidfile:
-                pid = int(pidfile.read())
-            os.kill(pid, signal.SIGKILL)
-        except:
-            return
-        global_log.info("Backend logger stopped.")
-
-log = BackendSyslog()
diff --git a/baseudev.py b/baseudev.py
deleted file mode 100644
index 3d9ee45..0000000
--- a/baseudev.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# udev.py
-# Python module for querying the udev database for device information.
-#
-# Copyright (C) 2009  Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties 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, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-# Red Hat Author(s): Dave Lehman <dlehman redhat com>
-#                    Chris Lumens <clumens redhat com>
-#
-
-import iutil
-import os
-
-import pyudev
-global_udev = pyudev.Udev()
-
-import logging
-log = logging.getLogger("storage")
-
-def udev_enumerate_devices(deviceClass="block"):
-    devices = global_udev.enumerate_devices(subsystem=deviceClass)
-    return [path[4:] for path in devices]
-
-def udev_get_device(sysfs_path):
-    if not os.path.exists("/sys%s" % sysfs_path):
-        log.debug("%s does not exist" % sysfs_path)
-        return None
-
-    # XXX we remove the /sys part when enumerating devices,
-    # so we have to prepend it when creating the device
-    dev = global_udev.create_device("/sys" + sysfs_path)
-
-    if dev:
-        dev["name"] = dev.sysname
-        dev["sysfs_path"] = sysfs_path
-
-        # now add in the contents of the uevent file since they're handy
-        dev = udev_parse_uevent_file(dev)
-
-    return dev
-
-def udev_get_devices(deviceClass="block"):
-    udev_settle()
-    entries = []
-    for path in udev_enumerate_devices(deviceClass):
-        entry = udev_get_device(path)
-        if entry:
-            entries.append(entry)
-    return entries
-
-def udev_parse_uevent_file(dev):
-    path = os.path.normpath("/sys/%s/uevent" % dev['sysfs_path'])
-    if not os.access(path, os.R_OK):
-        return dev
-
-    with open(path) as f:
-        for line in f.readlines():
-            (key, equals, value) = line.strip().partition("=")
-            if not equals:
-                continue
-
-            dev[key] = value
-
-    return dev
-
-def udev_settle():
-    # wait maximal 300 seconds for udev to be done running blkid, lvm,
-    # mdadm etc. This large timeout is needed when running on machines with
-    # lots of disks, or with slow disks
-    argv = ["settle", "--timeout=300"]
-
-    iutil.execWithRedirect("udevadm", argv, stderr="/dev/null")
-
-def udev_trigger(subsystem=None, action="add"):
-    argv = ["trigger", "--action=%s" % action]
-    if subsystem:
-        argv.append("--subsystem-match=%s" % subsystem)
-
-    iutil.execWithRedirect("udevadm", argv, stderr="/dev/null")
diff --git a/bin/Makefile.am b/bin/Makefile.am
new file mode 100644
index 0000000..53a5c44
--- /dev/null
+++ b/bin/Makefile.am
@@ -0,0 +1,23 @@
+# liveinst/Makefile.am for anaconda
+#
+# 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 Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Martin Sivak <msivak redhat com>
+
+SUBDIRS = loader gptsync 
+
+MAINTAINERCLEANFILES = Makefile.in
+
diff --git a/bin/gptsync/.gitignore b/bin/gptsync/.gitignore
new file mode 100644
index 0000000..4971cfa
--- /dev/null
+++ b/bin/gptsync/.gitignore
@@ -0,0 +1,2 @@
+gptsync
+showpart
diff --git a/bin/gptsync/Makefile.am b/bin/gptsync/Makefile.am
new file mode 100644
index 0000000..7f66432
--- /dev/null
+++ b/bin/gptsync/Makefile.am
@@ -0,0 +1,35 @@
+# gptsync/Makefile.am for anaconda
+#
+# 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 Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: David Cantrell <dcantrell redhat com>
+
+COMMON_SRCS      = lib.c os_unix.c
+noinst_HEADERS   = gptsync.h syslinux_mbr.h
+
+if IS_GPTSYNC_ARCH
+sbin_PROGRAMS    = gptsync showpart
+
+gptsync_CFLAGS   = -DPROGNAME=gptsync
+gptsync_SOURCES  = gptsync.c $(COMMON_SRCS)
+
+showpart_CFLAGS  = -DPROGNAME=showpart
+showpart_SOURCES = showpart.c $(COMMON_SRCS)
+endif
+
+EXTRA_DIST       = README
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/bin/gptsync/README b/bin/gptsync/README
new file mode 100644
index 0000000..cb306bd
--- /dev/null
+++ b/bin/gptsync/README
@@ -0,0 +1,41 @@
+gptsync is from refit (refit.sf.net).  It has been modified to
+1) Not prompt if you want to copy
+2) Default to Linux native (0x83) instead of fat32 partition id
+
+The original license follows.
+
+
+ rEFIt License
+===============
+
+Copyright (c) 2006-2007 Christoph Pfisterer
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the
+   distribution.
+
+ * Neither the name of Christoph Pfisterer nor the names of the
+   contributors may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/bin/gptsync/gptsync.c b/bin/gptsync/gptsync.c
new file mode 100644
index 0000000..3ad26bf
--- /dev/null
+++ b/bin/gptsync/gptsync.c
@@ -0,0 +1,470 @@
+/*
+ * gptsync/gptsync.c
+ * Platform-independent code for syncing GPT and MBR
+ *
+ * Copyright (c) 2006-2007 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gptsync.h"
+
+#include "syslinux_mbr.h"
+
+//
+// MBR functions
+//
+
+static UINTN check_mbr(VOID)
+{
+    UINTN       i, k;
+    
+    // check each entry
+    for (i = 0; i < mbr_part_count; i++) {
+        // check for overlap
+        for (k = 0; k < mbr_part_count; k++) {
+            if (k != i && !(mbr_parts[i].start_lba > mbr_parts[k].end_lba || mbr_parts[k].start_lba > mbr_parts[i].end_lba)) {
+                Print(L"Status: MBR partition table is invalid, partitions overlap.\n");
+                return 1;
+            }
+        }
+        
+        // check for extended partitions
+        if (mbr_parts[i].mbr_type == 0x05 || mbr_parts[i].mbr_type == 0x0f || mbr_parts[i].mbr_type == 0x85) {
+            Print(L"Status: Extended partition found in MBR table, will not touch this disk.\n",
+                  gpt_parts[i].gpt_parttype->name);
+            return 1;
+        }
+    }
+    
+    return 0;
+}
+
+static UINTN write_mbr(VOID)
+{
+    UINTN               status;
+    UINTN               i, k;
+    UINT8               active;
+    UINT64              lba;
+    MBR_PARTITION_INFO  *table;
+    BOOLEAN             have_bootcode;
+    
+    Print(L"\nWriting new MBR...\n");
+    
+    // read MBR data
+    status = read_sector(0, sector);
+    if (status != 0)
+        return status;
+    
+    // write partition table
+    *((UINT16 *)(sector + 510)) = 0xaa55;
+    
+    table = (MBR_PARTITION_INFO *)(sector + 446);
+    active = 0x80;
+    for (i = 0; i < 4; i++) {
+        for (k = 0; k < new_mbr_part_count; k++) {
+            if (new_mbr_parts[k].index == i)
+                break;
+        }
+        if (k >= new_mbr_part_count) {
+            // unused entry
+            table[i].flags        = 0;
+            table[i].start_chs[0] = 0;
+            table[i].start_chs[1] = 0;
+            table[i].start_chs[2] = 0;
+            table[i].type         = 0;
+            table[i].end_chs[0]   = 0;
+            table[i].end_chs[1]   = 0;
+            table[i].end_chs[2]   = 0;
+            table[i].start_lba    = 0;
+            table[i].size         = 0;
+        } else {
+            if (new_mbr_parts[k].active) {
+                table[i].flags        = active;
+                active = 0x00;
+            } else
+                table[i].flags        = 0x00;
+            table[i].start_chs[0] = 0xfe;
+            table[i].start_chs[1] = 0xff;
+            table[i].start_chs[2] = 0xff;
+            table[i].type         = new_mbr_parts[k].mbr_type;
+            table[i].end_chs[0]   = 0xfe;
+            table[i].end_chs[1]   = 0xff;
+            table[i].end_chs[2]   = 0xff;
+            
+            lba = new_mbr_parts[k].start_lba;
+            if (lba > 0xffffffffULL) {
+                Print(L"Warning: Partition %d starts beyond 2 TiB limit\n", i+1);
+                lba = 0xffffffffULL;
+            }
+            table[i].start_lba    = (UINT32)lba;
+            
+            lba = new_mbr_parts[k].end_lba + 1 - new_mbr_parts[k].start_lba;
+            if (lba > 0xffffffffULL) {
+                Print(L"Warning: Partition %d extends beyond 2 TiB limit\n", i+1);
+                lba = 0xffffffffULL;
+            }
+            table[i].size         = (UINT32)lba;
+        }
+    }
+    
+    // add boot code if necessary
+    have_bootcode = FALSE;
+    for (i = 0; i < MBR_BOOTCODE_SIZE; i++) {
+        if (sector[i] != 0) {
+            have_bootcode = TRUE;
+            break;
+        }
+    }
+    if (!have_bootcode) {
+        // no boot code found in the MBR, add the syslinux MBR code
+        SetMem(sector, 0, MBR_BOOTCODE_SIZE);
+        CopyMem(sector, syslinux_mbr, SYSLINUX_MBR_SIZE);
+    }
+    
+    // write MBR data
+    status = write_sector(0, sector);
+    if (status != 0)
+        return status;
+    
+    Print(L"MBR updated successfully!\n");
+    
+    return 0;
+}
+
+//
+// GPT functions
+//
+
+static UINTN check_gpt(VOID)
+{
+    UINTN       i, k;
+    BOOLEAN     found_data_parts;
+    
+    if (gpt_part_count == 0) {
+        Print(L"Status: No GPT partition table, no need to sync.\n");
+        return 1;
+    }
+    
+    // check each entry
+    found_data_parts = FALSE;
+    for (i = 0; i < gpt_part_count; i++) {
+        // check sanity
+        if (gpt_parts[i].end_lba < gpt_parts[i].start_lba) {
+            Print(L"Status: GPT partition table is invalid.\n");
+            return 1;
+        }
+        // check for overlap
+        for (k = 0; k < gpt_part_count; k++) {
+            if (k != i && !(gpt_parts[i].start_lba > gpt_parts[k].end_lba || gpt_parts[k].start_lba > gpt_parts[i].end_lba)) {
+                Print(L"Status: GPT partition table is invalid, partitions overlap.\n");
+                return 1;
+            }
+        }
+        
+        // check for partitions kind
+        if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_FATAL) {
+            Print(L"Status: GPT partition of type '%s' found, will not touch this disk.\n",
+                  gpt_parts[i].gpt_parttype->name);
+            return 1;
+        }
+        if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_DATA ||
+            gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA)
+            found_data_parts = TRUE;
+    }
+    
+    if (!found_data_parts) {
+        Print(L"Status: GPT partition table has no data partitions, no need to sync.\n");
+        return 1;
+    }
+    
+    return 0;
+}
+
+//
+// compare GPT and MBR tables
+//
+
+#define ACTION_NONE        (0)
+#define ACTION_NOP         (1)
+#define ACTION_REWRITE     (2)
+
+static UINTN analyze(VOID)
+{
+    UINTN   action;
+    UINTN   i, k, iter, count_active, detected_parttype;
+    CHARN   *fsname;
+    UINT64  min_start_lba;
+    UINTN   status;
+    BOOLEAN have_esp;
+    
+    new_mbr_part_count = 0;
+    
+    // determine correct MBR types for GPT partitions
+    if (gpt_part_count == 0) {
+        Print(L"Status: No GPT partitions defined, nothing to sync.\n");
+        return 0;
+    }
+    have_esp = FALSE;
+    for (i = 0; i < gpt_part_count; i++) {
+        gpt_parts[i].mbr_type = gpt_parts[i].gpt_parttype->mbr_type;
+        if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) {
+            // Basic Data: need to look at data in the partition
+            status = detect_mbrtype_fs(gpt_parts[i].start_lba, &detected_parttype, &fsname);
+            if (detected_parttype)
+                gpt_parts[i].mbr_type = detected_parttype;
+            else
+                gpt_parts[i].mbr_type = 0x0b;  // fallback: FAT32
+        } else if (gpt_parts[i].mbr_type == 0xef) {
+            // EFI System Partition: GNU parted can put this on any partition,
+            // need to detect file systems
+            status = detect_mbrtype_fs(gpt_parts[i].start_lba, &detected_parttype, &fsname);
+            if (!have_esp && (detected_parttype == 0x01 || detected_parttype == 0x0e || detected_parttype == 0x0c))
+                ;  // seems to be a legitimate ESP, don't change
+            else if (detected_parttype)
+                gpt_parts[i].mbr_type = detected_parttype;
+            else if (have_esp)    // make sure there's no more than one ESP per disk
+                gpt_parts[i].mbr_type = 0x83;  // fallback: Linux
+        }
+        // NOTE: mbr_type may still be 0 if content detection fails for exotic GPT types or file systems
+        
+        if (gpt_parts[i].mbr_type == 0xef)
+            have_esp = TRUE;
+    }
+    
+    // check for common scenarios
+    action = ACTION_NONE;
+    if (mbr_part_count == 0) {
+        // current MBR is empty
+        action = ACTION_REWRITE;
+    } else if (mbr_part_count == 1 && mbr_parts[0].mbr_type == 0xee) {
+        // MBR has just the EFI Protective partition (i.e. untouched)
+        action = ACTION_REWRITE;
+    }
+    if (action == ACTION_NONE && mbr_part_count > 0) {
+        if (mbr_parts[0].mbr_type == 0xee &&
+            gpt_parts[0].mbr_type == 0xef &&
+            mbr_parts[0].start_lba == 1 &&
+            mbr_parts[0].end_lba == gpt_parts[0].end_lba) {
+            // The Apple Way, "EFI Protective" covering the tables and the ESP
+            action = ACTION_NOP;
+            if ((mbr_part_count != gpt_part_count && gpt_part_count <= 4) ||
+                (mbr_part_count != 4              && gpt_part_count > 4)) {
+                // number of partitions has changed
+                action = ACTION_REWRITE;
+            } else {
+                // check partition ranges and types
+                for (i = 1; i < mbr_part_count; i++) {
+                    if (mbr_parts[i].start_lba != gpt_parts[i].start_lba ||
+                        mbr_parts[i].end_lba   != gpt_parts[i].end_lba ||
+                        (gpt_parts[i].mbr_type && mbr_parts[i].mbr_type != gpt_parts[i].mbr_type))
+                        // position or type has changed
+                        action = ACTION_REWRITE;
+                }
+            }
+            // check number of active partitions
+            count_active = 0;
+            for (i = 0; i < mbr_part_count; i++)
+                if (mbr_parts[i].active)
+                    count_active++;
+            if (count_active!= 1)
+                action = ACTION_REWRITE;
+        }
+    }
+    if (action == ACTION_NONE && mbr_part_count > 0 && mbr_parts[0].mbr_type == 0xef) {
+        // The XOM Way, all partitions mirrored 1:1
+        action = ACTION_REWRITE;
+        // check partition ranges and types
+        for (i = 0; i < mbr_part_count; i++) {
+            if (mbr_parts[i].start_lba != gpt_parts[i].start_lba ||
+                mbr_parts[i].end_lba   != gpt_parts[i].end_lba ||
+                (gpt_parts[i].mbr_type && mbr_parts[i].mbr_type != gpt_parts[i].mbr_type))
+                // position or type has changed -> better don't touch
+                action = ACTION_NONE;
+        }
+    }
+    
+    if (action == ACTION_NOP) {
+        Print(L"Status: Tables are synchronized, no need to sync.\n");
+        return 0;
+    } else if (action == ACTION_REWRITE) {
+        Print(L"Status: MBR table must be updated.\n");
+    } else {
+        Print(L"Status: Analysis inconclusive, will not touch this disk.\n");
+        return 1;
+    }
+    
+    // generate the new table
+    
+    // first entry: EFI Protective
+    new_mbr_parts[0].index     = 0;
+    new_mbr_parts[0].start_lba = 1;
+    new_mbr_parts[0].mbr_type  = 0xee;
+    new_mbr_part_count = 1;
+    
+    if (gpt_parts[0].mbr_type == 0xef) {
+        new_mbr_parts[0].end_lba = gpt_parts[0].end_lba;
+        i = 1;
+    } else {
+        min_start_lba = gpt_parts[0].start_lba;
+        for (k = 0; k < gpt_part_count; k++) {
+            if (min_start_lba > gpt_parts[k].start_lba)
+                min_start_lba = gpt_parts[k].start_lba;
+        }
+        new_mbr_parts[0].end_lba = min_start_lba - 1;
+        i = 0;
+    }
+    
+    // add other GPT partitions until the table is full
+    // TODO: in the future, prioritize partitions by kind
+    for (; i < gpt_part_count && new_mbr_part_count < 4; i++) {
+        new_mbr_parts[new_mbr_part_count].index     = new_mbr_part_count;
+        new_mbr_parts[new_mbr_part_count].start_lba = gpt_parts[i].start_lba;
+        new_mbr_parts[new_mbr_part_count].end_lba   = gpt_parts[i].end_lba;
+        new_mbr_parts[new_mbr_part_count].mbr_type  = gpt_parts[i].mbr_type;
+        new_mbr_parts[new_mbr_part_count].active    = FALSE;
+        
+        // find matching partition in the old MBR table
+        for (k = 0; k < mbr_part_count; k++) {
+            if (mbr_parts[k].start_lba == gpt_parts[i].start_lba) {
+                // keep type if not detected
+                if (new_mbr_parts[new_mbr_part_count].mbr_type == 0)
+                    new_mbr_parts[new_mbr_part_count].mbr_type = mbr_parts[k].mbr_type;
+                // keep active flag
+                new_mbr_parts[new_mbr_part_count].active = mbr_parts[k].active;
+                break;
+            }
+        }
+        
+        if (new_mbr_parts[new_mbr_part_count].mbr_type == 0)
+            // final fallback: set to a (hopefully) unused type
+            new_mbr_parts[new_mbr_part_count].mbr_type = 0xc0;
+        
+        new_mbr_part_count++;
+    }
+    
+    // make sure there's exactly one active partition
+    for (iter = 0; iter < 3; iter++) {
+        // check
+        count_active = 0;
+        for (i = 0; i < new_mbr_part_count; i++)
+            if (new_mbr_parts[i].active)
+                count_active++;
+        if (count_active == 1)
+            break;
+        
+        // set active on the first matching partition
+        if (count_active == 0) {
+            for (i = 0; i < new_mbr_part_count; i++) {
+                if ((iter >= 0 && (new_mbr_parts[i].mbr_type == 0x07 ||    // NTFS
+                                   new_mbr_parts[i].mbr_type == 0x0b ||    // FAT32
+                                   new_mbr_parts[i].mbr_type == 0x0c)) ||  // FAT32 (LBA)
+                    (iter >= 1 && (new_mbr_parts[i].mbr_type == 0x83)) ||  // Linux
+                    (iter >= 2 && i > 0)) {
+                    new_mbr_parts[i].active = TRUE;
+                    break;
+                }
+            }
+        } else if (count_active > 1 && iter == 0) {
+            // too many active partitions, try deactivating the ESP / EFI Protective entry
+            if ((new_mbr_parts[0].mbr_type == 0xee || new_mbr_parts[0].mbr_type == 0xef) &&
+                new_mbr_parts[0].active) {
+                new_mbr_parts[0].active = FALSE;
+            }
+        } else if (count_active > 1 && iter > 0) {
+            // too many active partitions, deactivate all but the first one
+            count_active = 0;
+            for (i = 0; i < new_mbr_part_count; i++)
+                if (new_mbr_parts[i].active) {
+                    if (count_active > 0)
+                        new_mbr_parts[i].active = FALSE;
+                    count_active++;
+                }
+        }
+    }
+    
+    // dump table
+    Print(L"\nProposed new MBR partition table:\n");
+    Print(L" # A    Start LBA      End LBA  Type\n");
+    for (i = 0; i < new_mbr_part_count; i++) {
+        Print(L" %d %s %12lld %12lld  %02x  %s\n",
+              new_mbr_parts[i].index + 1,
+              new_mbr_parts[i].active ? STR("*") : STR(" "),
+              new_mbr_parts[i].start_lba,
+              new_mbr_parts[i].end_lba,
+              new_mbr_parts[i].mbr_type,
+              mbr_parttype_name(new_mbr_parts[i].mbr_type));
+    }
+    
+    return 0;
+}
+
+//
+// sync algorithm entry point
+//
+
+UINTN gptsync(VOID)
+{
+    UINTN   status = 0;
+    UINTN   status_gpt, status_mbr;
+    // BOOLEAN proceed = FALSE;
+    
+    // get full information from disk
+    status_gpt = read_gpt();
+    status_mbr = read_mbr();
+    if (status_gpt != 0 || status_mbr != 0)
+        return (status_gpt || status_mbr);
+    
+    // cross-check current situation
+    Print(L"\n");
+    status = check_gpt();   // check GPT for consistency
+    if (status != 0)
+        return status;
+    status = check_mbr();   // check MBR for consistency
+    if (status != 0)
+        return status;
+    status = analyze();     // analyze the situation & compose new MBR table
+    if (status != 0)
+        return status;
+    if (new_mbr_part_count == 0)
+        return status;
+    
+    // offer user the choice what to do
+    // status = input_boolean(STR("\nMay I update the MBR as printed above? [y/N] "), &proceed);
+    // if (status != 0 || proceed != TRUE)
+    //    return status;
+    
+    // adjust the MBR and write it back
+    status = write_mbr();
+    if (status != 0)
+        return status;
+    
+    return status;
+}
diff --git a/bin/gptsync/gptsync.h b/bin/gptsync/gptsync.h
new file mode 100644
index 0000000..d1bf3c2
--- /dev/null
+++ b/bin/gptsync/gptsync.h
@@ -0,0 +1,219 @@
+/*
+ * gptsync/gptsync.h
+ * Common header for gptsync and showpart
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//
+// config
+//
+
+#if defined(EFI32) || defined(EFIX64)
+#define CONFIG_EFI
+#endif
+
+//
+// platform-dependent types
+//
+
+#ifdef CONFIG_EFI
+
+#include <efi.h>
+#include <efilib.h>
+
+#define copy_guid(destguid, srcguid) (CopyMem(destguid, srcguid, 16))
+#define guids_are_equal(guid1, guid2) (CompareMem(guid1, guid2, 16) == 0)
+
+typedef CHAR16 CHARN;
+#define STR(x) L##x
+
+#endif
+
+
+#ifndef CONFIG_EFI
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
+typedef int                 INTN;
+typedef unsigned int        UINTN;
+typedef uint8_t             UINT8;
+typedef uint16_t            UINT16;
+typedef uint32_t            UINT32;
+typedef uint64_t            UINT64;
+typedef void                VOID;
+
+typedef int                 BOOLEAN;
+#ifndef FALSE
+#define FALSE (0)
+#endif
+#ifndef TRUE
+#define TRUE  (1)
+#endif
+
+typedef unsigned short      CHAR16;
+typedef char                CHARN;
+#define STR(x) x
+
+void Print(wchar_t *format, ...);
+
+// FUTURE: use STR(),  #define Print printf
+
+#define CopyMem     memcpy
+#define SetMem      memset
+#define CompareMem  memcmp
+
+#define copy_guid(destguid, srcguid) (memcpy(destguid, srcguid, 16))
+#define guids_are_equal(guid1, guid2) (memcmp(guid1, guid2, 16) == 0)
+
+#endif
+
+//
+// platform-independent types
+//
+
+typedef struct {
+    UINT8   flags;
+    UINT8   start_chs[3];
+    UINT8   type;
+    UINT8   end_chs[3];
+    UINT32  start_lba;
+    UINT32  size;
+} MBR_PARTITION_INFO;
+
+typedef struct {
+    UINT8   type;
+    CHARN   *name;
+} MBR_PARTTYPE;
+
+typedef struct {
+    UINT64  signature;
+    UINT32  spec_revision;
+    UINT32  header_size;
+    UINT32  header_crc32;
+    UINT32  reserved;
+    UINT64  header_lba;
+    UINT64  alternate_header_lba;
+    UINT64  first_usable_lba;
+    UINT64  last_usable_lba;
+    UINT8   disk_guid[16];
+    UINT64  entry_lba;
+    UINT32  entry_count;
+    UINT32  entry_size;
+    UINT32  entry_crc32;
+} GPT_HEADER;
+
+typedef struct {
+    UINT8   type_guid[16];
+    UINT8   partition_guid[16];
+    UINT64  start_lba;
+    UINT64  end_lba;
+    UINT64  attributes;
+    CHAR16  name[36];
+} GPT_ENTRY;
+
+#define GPT_KIND_SYSTEM     (0)
+#define GPT_KIND_DATA       (1)
+#define GPT_KIND_BASIC_DATA (2)
+#define GPT_KIND_FATAL      (3)
+
+typedef struct {
+    UINT8   guid[16];
+    UINT8   mbr_type;
+    CHARN   *name;
+    UINTN   kind;
+} GPT_PARTTYPE;
+
+typedef struct {
+    UINTN   index;
+    UINT64  start_lba;
+    UINT64  end_lba;
+    UINTN   mbr_type;
+    UINT8   gpt_type[16];
+    GPT_PARTTYPE *gpt_parttype;
+    BOOLEAN active;
+} PARTITION_INFO;
+
+//
+// functions provided by the OS-specific module
+//
+
+UINTN read_sector(UINT64 lba, UINT8 *buffer);
+UINTN write_sector(UINT64 lba, UINT8 *buffer);
+UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out);
+
+//
+// vars and functions provided by the common lib module
+//
+
+extern UINT8           empty_guid[16];
+
+extern PARTITION_INFO  mbr_parts[4];
+extern UINTN           mbr_part_count;
+extern PARTITION_INFO  gpt_parts[128];
+extern UINTN           gpt_part_count;
+
+extern PARTITION_INFO  new_mbr_parts[4];
+extern UINTN           new_mbr_part_count;
+
+extern UINT8           sector[512];
+
+extern MBR_PARTTYPE    mbr_types[];
+extern GPT_PARTTYPE    gpt_types[];
+extern GPT_PARTTYPE    gpt_dummy_type;
+
+CHARN * mbr_parttype_name(UINT8 type);
+UINTN read_mbr(VOID);
+
+GPT_PARTTYPE * gpt_parttype(UINT8 *type_guid);
+UINTN read_gpt(VOID);
+
+UINTN detect_mbrtype_fs(UINT64 partlba, UINTN *parttype, CHARN **fsname);
+
+//
+// actual platform-independent programs
+//
+
+UINTN gptsync(VOID);
+UINTN showpart(VOID);
+
+/* EOF */
diff --git a/bin/gptsync/lib.c b/bin/gptsync/lib.c
new file mode 100644
index 0000000..f2d71b2
--- /dev/null
+++ b/bin/gptsync/lib.c
@@ -0,0 +1,469 @@
+/*
+ * gptsync/lib.c
+ * Platform-independent code common to gptsync and showpart
+ *
+ * Copyright (c) 2006-2007 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gptsync.h"
+
+// variables
+
+UINT8           empty_guid[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+PARTITION_INFO  mbr_parts[4];
+UINTN           mbr_part_count = 0;
+PARTITION_INFO  gpt_parts[128];
+UINTN           gpt_part_count = 0;
+
+PARTITION_INFO  new_mbr_parts[4];
+UINTN           new_mbr_part_count = 0;
+
+UINT8           sector[512];
+
+MBR_PARTTYPE    mbr_types[] = {
+    { 0x01, STR("FAT12 (CHS)") },
+    { 0x04, STR("FAT16 <32M (CHS)") },
+    { 0x05, STR("Extended (CHS)") },
+    { 0x06, STR("FAT16 (CHS)") },
+    { 0x07, STR("NTFS/HPFS") },
+    { 0x0b, STR("FAT32 (CHS)") },
+    { 0x0c, STR("FAT32 (LBA)") },
+    { 0x0e, STR("FAT16 (LBA)") },
+    { 0x0f, STR("Extended (LBA)") },
+    { 0x11, STR("Hidden FAT12 (CHS)") },
+    { 0x14, STR("Hidden FAT16 <32M (CHS)") },
+    { 0x16, STR("Hidden FAT16 (CHS)") },
+    { 0x17, STR("Hidden NTFS/HPFS") },
+    { 0x1b, STR("Hidden FAT32 (CHS)") },
+    { 0x1c, STR("Hidden FAT32 (LBA)") },
+    { 0x1e, STR("Hidden FAT16 (LBA)") },
+    { 0x82, STR("Linux swap / Solaris") },
+    { 0x83, STR("Linux") },
+    { 0x85, STR("Linux Extended") },
+    { 0x86, STR("NT FAT volume set") },
+    { 0x87, STR("NTFS volume set") },
+    { 0x8e, STR("Linux LVM") },
+    { 0xa5, STR("FreeBSD") },
+    { 0xa6, STR("OpenBSD") },
+    { 0xa7, STR("NeXTSTEP") },
+    { 0xa8, STR("Mac OS X UFS") },
+    { 0xa9, STR("NetBSD") },
+    { 0xab, STR("Mac OS X Boot") },
+    { 0xac, STR("Apple RAID") },
+    { 0xaf, STR("Mac OS X HFS+") },
+    { 0xbe, STR("Solaris Boot") },
+    { 0xbf, STR("Solaris") },
+    { 0xeb, STR("BeOS") },
+    { 0xee, STR("EFI Protective") },
+    { 0xef, STR("EFI System (FAT)") },
+    { 0xfd, STR("Linux RAID") },
+    { 0, NULL },
+};
+
+GPT_PARTTYPE    gpt_types[] = {
+    { "\x28\x73\x2A\xC1\x1F\xF8\xD2\x11\xBA\x4B\x00\xA0\xC9\x3E\xC9\x3B", 0xef, STR("EFI System (FAT)"), GPT_KIND_SYSTEM },
+    { "\x41\xEE\x4D\x02\xE7\x33\xD3\x11\x9D\x69\x00\x08\xC7\x81\xF3\x9F", 0x00, STR("MBR partition scheme"), GPT_KIND_FATAL },
+    { "\x16\xE3\xC9\xE3\x5C\x0B\xB8\x4D\x81\x7D\xF9\x2D\xF0\x02\x15\xAE", 0x00, STR("MS Reserved"), GPT_KIND_SYSTEM },
+    { "\xA2\xA0\xD0\xEB\xE5\xB9\x33\x44\x87\xC0\x68\xB6\xB7\x26\x99\xC7", 0x00, STR("Basic Data"), GPT_KIND_BASIC_DATA },
+    { "\xAA\xC8\x08\x58\x8F\x7E\xE0\x42\x85\xD2\xE1\xE9\x04\x34\xCF\xB3", 0x00, STR("MS LDM Metadata"), GPT_KIND_FATAL },
+    { "\xA0\x60\x9B\xAF\x31\x14\x62\x4F\xBC\x68\x33\x11\x71\x4A\x69\xAD", 0x00, STR("MS LDM Data"), GPT_KIND_FATAL },
+    { "\x1E\x4C\x89\x75\xEB\x3A\xD3\x11\xB7\xC1\x7B\x03\xA0\x00\x00\x00", 0x00, STR("HP/UX Data"), GPT_KIND_DATA },
+    { "\x28\xE7\xA1\xE2\xE3\x32\xD6\x11\xA6\x82\x7B\x03\xA0\x00\x00\x00", 0x00, STR("HP/UX Service"), GPT_KIND_SYSTEM },
+    { "\x0F\x88\x9D\xA1\xFC\x05\x3B\x4D\xA0\x06\x74\x3F\x0F\x84\x91\x1E", 0xfd, STR("Linux RAID"), GPT_KIND_DATA },
+    { "\x6D\xFD\x57\x06\xAB\xA4\xC4\x43\x84\xE5\x09\x33\xC8\x4B\x4F\x4F", 0x82, STR("Linux Swap"), GPT_KIND_SYSTEM },
+    { "\x79\xD3\xD6\xE6\x07\xF5\xC2\x44\xA2\x3C\x23\x8F\x2A\x3D\xF9\x28", 0x8e, STR("Linux LVM"), GPT_KIND_DATA },
+    { "\x39\x33\xA6\x8D\x07\x00\xC0\x60\xC4\x36\x08\x3A\xC8\x23\x09\x08", 0x00, STR("Linux Reserved"), GPT_KIND_SYSTEM },
+    { "\xB4\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD Data"), GPT_KIND_DATA },
+    { "\xB5\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0x00, STR("FreeBSD Swap"), GPT_KIND_SYSTEM },
+    { "\xB6\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD UFS"), GPT_KIND_DATA },
+    { "\xB8\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0x00, STR("FreeBSD Vinum"), GPT_KIND_DATA },
+    { "\x00\x53\x46\x48\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xaf, STR("Mac OS X HFS+"), GPT_KIND_DATA },
+    { "\x00\x53\x46\x55\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xa8, STR("Mac OS X UFS"), GPT_KIND_DATA },
+    { "\x74\x6F\x6F\x42\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xab, STR("Mac OS X Boot"), GPT_KIND_DATA },
+    { "\x44\x49\x41\x52\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xac, STR("Apple RAID"), GPT_KIND_DATA },
+    { "\x44\x49\x41\x52\x4F\x5F\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xac, STR("Apple RAID (Offline)"), GPT_KIND_DATA },
+    { "\x65\x62\x61\x4C\x00\x6C\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("Apple Label"), GPT_KIND_SYSTEM },
+    { "\x6F\x63\x65\x52\x65\x76\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("Apple Recovery"), GPT_KIND_BASIC_DATA },
+    { "\x7f\x23\x96\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved"), GPT_KIND_SYSTEM },
+    { "\x45\xCB\x82\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Boot"), GPT_KIND_DATA },
+    { "\x4D\xCF\x85\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Root"), GPT_KIND_DATA },
+    { "\x6F\xC4\x87\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Swap"), GPT_KIND_SYSTEM },
+    { "\xC3\x8C\x89\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Usr"), GPT_KIND_DATA },
+    { "\x2B\x64\x8B\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Backup"), GPT_KIND_SYSTEM },
+    { "\xC7\x2A\x8D\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Stand"), GPT_KIND_DATA },
+    { "\xE9\xF2\x8E\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Var"), GPT_KIND_DATA },
+    { "\x39\xBA\x90\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Home"), GPT_KIND_DATA },
+    { "\xA5\x83\x92\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris ALTSCTR"), GPT_KIND_DATA },
+    { "\x3B\x5A\x94\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Cache"), GPT_KIND_SYSTEM },
+    { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, NULL, 0 },
+};
+GPT_PARTTYPE    gpt_dummy_type =
+    { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, STR("Unknown"), GPT_KIND_FATAL };
+
+//
+// MBR functions
+//
+
+CHARN * mbr_parttype_name(UINT8 type)
+{
+    int i;
+    
+    for (i = 0; mbr_types[i].name; i++)
+        if (mbr_types[i].type == type)
+            return mbr_types[i].name;
+    return STR("Unknown");
+}
+
+UINTN read_mbr(VOID)
+{
+    UINTN               status;
+    UINTN               i;
+    BOOLEAN             used;
+    MBR_PARTITION_INFO  *table;
+    
+    Print(L"\nCurrent MBR partition table:\n");
+    
+    // read MBR data
+    status = read_sector(0, sector);
+    if (status != 0)
+        return status;
+    
+    // check for validity
+    if (*((UINT16 *)(sector + 510)) != 0xaa55) {
+        Print(L" No MBR partition table present!\n");
+        return 1;
+    }
+    table = (MBR_PARTITION_INFO *)(sector + 446);
+    for (i = 0; i < 4; i++) {
+        if (table[i].flags != 0x00 && table[i].flags != 0x80) {
+            Print(L" MBR partition table is invalid!\n");
+            return 1;
+        }
+    }
+    
+    // check if used
+    used = FALSE;
+    for (i = 0; i < 4; i++) {
+        if (table[i].start_lba > 0 && table[i].size > 0) {
+            used = TRUE;
+            break;
+        }
+    }
+    if (!used) {
+        Print(L" No partitions defined\n");
+        return 0;
+    }
+    
+    // dump current state & fill internal structures
+    Print(L" # A    Start LBA      End LBA  Type\n");
+    for (i = 0; i < 4; i++) {
+        if (table[i].start_lba == 0 || table[i].size == 0)
+            continue;
+        
+        mbr_parts[mbr_part_count].index     = i;
+        mbr_parts[mbr_part_count].start_lba = (UINT64)table[i].start_lba;
+        mbr_parts[mbr_part_count].end_lba   = (UINT64)table[i].start_lba + (UINT64)table[i].size - 1;
+        mbr_parts[mbr_part_count].mbr_type  = table[i].type;
+        mbr_parts[mbr_part_count].active    = (table[i].flags == 0x80) ? TRUE : FALSE;
+        
+        Print(L" %d %s %12lld %12lld  %02x  %s\n",
+              mbr_parts[mbr_part_count].index + 1,
+              mbr_parts[mbr_part_count].active ? STR("*") : STR(" "),
+              mbr_parts[mbr_part_count].start_lba,
+              mbr_parts[mbr_part_count].end_lba,
+              mbr_parts[mbr_part_count].mbr_type,
+              mbr_parttype_name(mbr_parts[mbr_part_count].mbr_type));
+        
+        mbr_part_count++;
+    }
+    
+    return 0;
+}
+
+//
+// GPT functions
+//
+
+GPT_PARTTYPE * gpt_parttype(UINT8 *type_guid)
+{
+    int i;
+    
+    for (i = 0; gpt_types[i].name; i++)
+        if (guids_are_equal(gpt_types[i].guid, type_guid))
+            return &(gpt_types[i]);
+    return &gpt_dummy_type;
+}
+
+UINTN read_gpt(VOID)
+{
+    UINTN       status;
+    GPT_HEADER  *header;
+    GPT_ENTRY   *entry;
+    UINT64      entry_lba;
+    UINTN       entry_count, entry_size, i;
+    
+    Print(L"\nCurrent GPT partition table:\n");
+    
+    // read GPT header
+    status = read_sector(1, sector);
+    if (status != 0)
+        return status;
+    
+    // check signature
+    header = (GPT_HEADER *)sector;
+    if (header->signature != 0x5452415020494645ULL) {
+        Print(L" No GPT partition table present!\n");
+        return 0;
+    }
+    if (header->spec_revision != 0x00010000UL) {
+        Print(L" Warning: Unknown GPT spec revision 0x%08x\n", header->spec_revision);
+    }
+    if ((512 % header->entry_size) > 0 || header->entry_size > 512) {
+        Print(L" Error: Invalid GPT entry size (misaligned or more than 512 bytes)\n");
+        return 0;
+    }
+    
+    // read entries
+    entry_lba   = header->entry_lba;
+    entry_size  = header->entry_size;
+    entry_count = header->entry_count;
+    
+    for (i = 0; i < entry_count; i++) {
+        if (((i * entry_size) % 512) == 0) {
+            status = read_sector(entry_lba, sector);
+            if (status != 0)
+                return status;
+            entry_lba++;
+        }
+        entry = (GPT_ENTRY *)(sector + ((i * entry_size) % 512));
+        
+        if (guids_are_equal(entry->type_guid, empty_guid))
+            continue;
+        if (gpt_part_count == 0) {
+            Print(L" #      Start LBA      End LBA  Type\n");
+        }
+        
+        gpt_parts[gpt_part_count].index     = i;
+        gpt_parts[gpt_part_count].start_lba = entry->start_lba;
+        gpt_parts[gpt_part_count].end_lba   = entry->end_lba;
+        gpt_parts[gpt_part_count].mbr_type  = 0;
+        copy_guid(gpt_parts[gpt_part_count].gpt_type, entry->type_guid);
+        gpt_parts[gpt_part_count].gpt_parttype = gpt_parttype(gpt_parts[gpt_part_count].gpt_type);
+        gpt_parts[gpt_part_count].active    = FALSE;
+        
+        Print(L" %d   %12lld %12lld  %s\n",
+              gpt_parts[gpt_part_count].index + 1,
+              gpt_parts[gpt_part_count].start_lba,
+              gpt_parts[gpt_part_count].end_lba,
+              gpt_parts[gpt_part_count].gpt_parttype->name);
+        
+        gpt_part_count++;
+    }
+    if (gpt_part_count == 0) {
+        Print(L" No partitions defined\n");
+        return 0;
+    }
+    
+    return 0;
+}
+
+//
+// detect file system type
+//
+
+UINTN detect_mbrtype_fs(UINT64 partlba, UINTN *parttype, CHARN **fsname)
+{
+    UINTN   status;
+    UINTN   signature, score;
+    UINTN   sectsize, clustersize, reserved, fatcount, dirsize, sectcount, fatsize, clustercount;
+    
+    *fsname = STR("Unknown");
+    *parttype = 0;
+    
+    // READ sector 0 / offset 0K
+    status = read_sector(partlba, sector);
+    if (status != 0)
+        return status;
+    
+    // detect XFS
+    memcpy(&signature, sector, sizeof(UINT32));
+    if (signature == 0x42534658) {
+        *parttype = 0x83;
+        *fsname = STR("XFS");
+        return 0;
+    }
+    
+    // detect FAT and NTFS
+    sectsize = *((UINT16 *)(sector + 11));
+    clustersize = sector[13];
+    if (sectsize >= 512 && (sectsize & (sectsize - 1)) == 0 &&
+        clustersize > 0 && (clustersize & (clustersize - 1)) == 0) {
+        // preconditions for both FAT and NTFS are now met
+        
+        if (CompareMem(sector + 3, "NTFS    ", 8) == 0) {
+            *parttype = 0x07;
+            *fsname = STR("NTFS");
+            return 0;
+        }
+        
+        score = 0;
+        // boot jump
+        if ((sector[0] == 0xEB && sector[2] == 0x90) || 
+            sector[0] == 0xE9)
+            score++;
+        // boot signature
+        if (sector[510] == 0x55 && sector[511] == 0xAA)
+            score++;
+        // reserved sectors
+        reserved = *((UINT16 *)(sector + 14));
+        if (reserved == 1 || reserved == 32)
+            score++;
+        // number of FATs
+        fatcount = sector[16];
+        if (fatcount == 2)
+            score++;
+        // number of root dir entries
+        dirsize = *((UINT16 *)(sector + 17));
+        // sector count (16-bit and 32-bit versions)
+        sectcount = *((UINT16 *)(sector + 19));
+        if (sectcount == 0)
+            sectcount = *((UINT32 *)(sector + 32));
+        // media byte
+        if (sector[21] == 0xF0 || sector[21] >= 0xF8)
+            score++;
+        // FAT size in sectors
+        fatsize = *((UINT16 *)(sector + 22));
+        if (fatsize == 0)
+            fatsize = *((UINT32 *)(sector + 36));
+        
+        // determine FAT type
+        dirsize = ((dirsize * 32) + (sectsize - 1)) / sectsize;
+        clustercount = sectcount - (reserved + (fatcount * fatsize) + dirsize);
+        clustercount /= clustersize;
+        
+        if (score >= 3) {
+            if (clustercount < 4085) {
+                *parttype = 0x01;
+                *fsname = STR("FAT12");
+            } else if (clustercount < 65525) {
+                *parttype = 0x0e;
+                *fsname = STR("FAT16");
+            } else {
+                *parttype = 0x0c;
+                *fsname = STR("FAT32");
+            }
+            // TODO: check if 0e and 0c are okay to use, maybe we should use 06 and 0b instead...
+            return 0;
+        }
+    }
+    
+    // READ sector 2 / offset 1K
+    status = read_sector(partlba + 2, sector);
+    if (status != 0)
+        return status;
+    
+    // detect HFS+
+    memcpy(&signature, sector, sizeof(UINT16));
+    if (signature == 0x4442) {
+        *parttype = 0xaf;
+        if (*((UINT16 *)(sector + 0x7c)) == 0x2B48)
+            *fsname = STR("HFS Extended (HFS+)");
+        else
+            *fsname = STR("HFS Standard");
+        return 0;
+    } else if (signature == 0x2B48) {
+        *parttype = 0xaf;
+        *fsname = STR("HFS Extended (HFS+)");
+        return 0;
+    }
+    
+    // detect ext2/ext3
+    signature = *((UINT16 *)(sector + 56));
+    if (signature == 0xEF53) {
+        *parttype = 0x83;
+        if (*((UINT16 *)(sector + 92)) & 0x0004)
+            *fsname = STR("ext3");
+        else
+            *fsname = STR("ext2");
+        return 0;
+    }
+    
+    // READ sector 128 / offset 64K
+    status = read_sector(partlba + 128, sector);
+    if (status != 0)
+        return status;
+    
+    // detect ReiserFS
+    if (CompareMem(sector + 52, "ReIsErFs", 8) == 0 ||
+        CompareMem(sector + 52, "ReIsEr2Fs", 9) == 0 ||
+        CompareMem(sector + 52, "ReIsEr3Fs", 9) == 0) {
+        *parttype = 0x83;
+        *fsname = STR("ReiserFS");
+        return 0;
+    }
+    
+    // detect Reiser4
+    if (CompareMem(sector, "ReIsEr4", 7) == 0) {
+        *parttype = 0x83;
+        *fsname = STR("Reiser4");
+        return 0;
+    }
+    
+    // READ sector 64 / offset 32K
+    status = read_sector(partlba + 64, sector);
+    if (status != 0)
+        return status;
+    
+    // detect JFS
+    if (CompareMem(sector, "JFS1", 4) == 0) {
+        *parttype = 0x83;
+        *fsname = STR("JFS");
+        return 0;
+    }
+    
+    // READ sector 16 / offset 8K
+    status = read_sector(partlba + 16, sector);
+    if (status != 0)
+        return status;
+    
+    // detect ReiserFS
+    if (CompareMem(sector + 52, "ReIsErFs", 8) == 0 ||
+        CompareMem(sector + 52, "ReIsEr2Fs", 9) == 0 ||
+        CompareMem(sector + 52, "ReIsEr3Fs", 9) == 0) {
+        *parttype = 0x83;
+        *fsname = STR("ReiserFS");
+        return 0;
+    }
+    
+    return 0;
+}
diff --git a/bin/gptsync/os_unix.c b/bin/gptsync/os_unix.c
new file mode 100644
index 0000000..b43685b
--- /dev/null
+++ b/bin/gptsync/os_unix.c
@@ -0,0 +1,267 @@
+/*
+ * gptsync/os_unix.c
+ * Unix OS glue for gptsync
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gptsync.h"
+
+#include <stdarg.h>
+
+#define STRINGIFY(s) #s
+#define STRINGIFY2(s) STRINGIFY(s)
+#define PROGNAME_S STRINGIFY2(PROGNAME)
+
+// variables
+
+static int      fd;
+
+//
+// error functions
+//
+
+void error(const char *msg, ...)
+{
+    va_list par;
+    char buf[4096];
+    
+    va_start(par, msg);
+    vsnprintf(buf, 4096, msg, par);
+    va_end(par);
+    
+    fprintf(stderr, PROGNAME_S ": %s\n", buf);
+}
+
+void errore(const char *msg, ...)
+{
+    va_list par;
+    char buf[4096];
+    
+    va_start(par, msg);
+    vsnprintf(buf, 4096, msg, par);
+    va_end(par);
+    
+    fprintf(stderr, PROGNAME_S ": %s: %s\n", buf, strerror(errno));
+}
+
+//
+// sector I/O functions
+//
+
+UINTN read_sector(UINT64 lba, UINT8 *buffer)
+{
+    off_t   offset;
+    off_t   result_seek;
+    ssize_t result_read;
+    
+    offset = lba * 512;
+    result_seek = lseek(fd, offset, SEEK_SET);
+    if (result_seek != offset) {
+        errore("Seek to %llu failed", offset);
+        return 1;
+    }
+    
+    result_read = read(fd, buffer, 512);
+    if (result_read < 0) {
+        errore("Data read failed at position %llu", offset);
+        return 1;
+    }
+    if (result_read != 512) {
+        errore("Data read fell short at position %llu", offset);
+        return 1;
+    }
+    return 0;
+}
+
+UINTN write_sector(UINT64 lba, UINT8 *buffer)
+{
+    off_t   offset;
+    off_t   result_seek;
+    ssize_t result_write;
+    
+    offset = lba * 512;
+    result_seek = lseek(fd, offset, SEEK_SET);
+    if (result_seek != offset) {
+        errore("Seek to %llu failed", offset);
+        return 1;
+    }
+    
+    result_write = write(fd, buffer, 512);
+    if (result_write < 0) {
+        errore("Data write failed at position %llu", offset);
+        return 1;
+    }
+    if (result_write != 512) {
+        errore("Data write fell short at position %llu", offset);
+        return 1;
+    }
+    return 0;
+}
+
+//
+// keyboard input
+//
+
+UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out)
+{
+    int c;
+    
+    printf("%s", prompt);
+    fflush(NULL);
+    
+    c = getchar();
+    if (c == EOF)
+        return 1;
+    
+    if (c == 'y' || c == 'Y') {
+        printf("Yes\n");
+        *bool_out = TRUE;
+    } else {
+        printf("No\n");
+        *bool_out = FALSE;
+    }
+    
+    return 0;
+}
+
+//
+// EFI-style print function
+//
+
+void Print(wchar_t *format, ...)
+{
+    va_list par;
+    char formatbuf[256];
+    char buf[4096];
+    int i;
+    
+    for (i = 0; format[i]; i++)
+        formatbuf[i] = (format[i] > 255) ? '?' : (char)(format[i] & 0xff);
+    formatbuf[i] = 0;
+    
+    va_start(par, format);
+    vsnprintf(buf, 4096, formatbuf, par);
+    va_end(par);
+    
+    printf("%s", buf);
+}
+
+//
+// main entry point
+//
+
+int main(int argc, char *argv[])
+{
+    char        *filename;
+    struct stat sb;
+    int         filekind;
+    UINT64      filesize;
+    char        *reason;
+    int         status;
+    
+    // argument check
+    if (argc != 2) {
+        fprintf(stderr, "Usage: " PROGNAME_S " <device>\n");
+        return 1;
+    }
+    filename = argv[1];
+    
+    // set input to unbuffered
+    fflush(NULL);
+    setvbuf(stdin, NULL, _IONBF, 0);
+    
+    // stat check
+    if (stat(filename, &sb) < 0) {
+        errore("Can't stat %.300s", filename);
+        return 1;
+    }
+    
+    filekind = 0;
+    filesize = 0;
+    reason = NULL;
+    if (S_ISREG(sb.st_mode))
+        filesize = sb.st_size;
+    else if (S_ISBLK(sb.st_mode))
+        filekind = 1;
+    else if (S_ISCHR(sb.st_mode))
+        filekind = 2;
+    else if (S_ISDIR(sb.st_mode))
+        reason = "Is a directory";
+    else if (S_ISFIFO(sb.st_mode))
+        reason = "Is a FIFO";
+#ifdef S_ISSOCK
+    else if (S_ISSOCK(sb.st_mode))
+        reason = "Is a socket";
+#endif
+    else
+        reason = "Is an unknown kind of special file";
+    
+    if (reason != NULL) {
+        error("%.300s: %s", filename, reason);
+        return 1;
+    }
+    
+    // open file
+    fd = open(filename, O_RDWR);
+    if (fd < 0 && errno == EBUSY) {
+        fd = open(filename, O_RDONLY);
+#ifndef NOREADONLYWARN
+        if (fd >= 0)
+            printf("Warning: %.300s opened read-only\n", filename);
+#endif
+    }
+    if (fd < 0) {
+        errore("Can't open %.300s", filename);
+        return 1;
+    }
+    
+    // (try to) guard against TTY character devices
+    if (filekind == 2) {
+        if (isatty(fd)) {
+            error("%.300s: Is a TTY device", filename);
+            return 1;
+        }
+    }
+    
+    // run sync algorithm
+    status = PROGNAME();
+    printf("\n");
+    
+    // close file
+    if (close(fd) != 0) {
+        errore("Error while closing %.300s", filename);
+        return 1;
+    }
+    
+    return status;
+}
diff --git a/bin/gptsync/showpart.c b/bin/gptsync/showpart.c
new file mode 100644
index 0000000..3d52ba3
--- /dev/null
+++ b/bin/gptsync/showpart.c
@@ -0,0 +1,257 @@
+/*
+ * gptsync/showpart.c
+ * Platform-independent code for analyzing hard disk partitioning
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the
+ *    distribution.
+ *
+ *  * Neither the name of Christoph Pfisterer nor the names of the
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gptsync.h"
+
+//
+// memory string search
+//
+
+static INTN FindMem(VOID *Buffer, UINTN BufferLength, VOID *SearchString, UINTN SearchStringLength)
+{
+    UINT8 *BufferPtr;
+    UINTN Offset;
+    
+    BufferPtr = Buffer;
+    BufferLength -= SearchStringLength;
+    for (Offset = 0; Offset < BufferLength; Offset++, BufferPtr++) {
+        if (CompareMem(BufferPtr, SearchString, SearchStringLength) == 0)
+            return (INTN)Offset;
+    }
+    
+    return -1;
+}
+
+//
+// detect boot code
+//
+
+static UINTN detect_bootcode(UINT64 partlba, CHARN **bootcodename)
+{
+    UINTN   status;
+    BOOLEAN bootable;
+    
+    // read MBR data
+    status = read_sector(partlba, sector);
+    if (status != 0)
+        return status;
+    
+    // check bootable signature
+    if (*((UINT16 *)(sector + 510)) == 0xaa55 && sector[0] != 0)
+        bootable = TRUE;
+    else
+        bootable = FALSE;
+    *bootcodename = NULL;
+    
+    // detect specific boot codes
+    if (CompareMem(sector + 2, "LILO", 4) == 0 ||
+        CompareMem(sector + 6, "LILO", 4) == 0) {
+        *bootcodename = STR("LILO");
+        
+    } else if (CompareMem(sector + 3, "SYSLINUX", 8) == 0) {
+        *bootcodename = STR("SYSLINUX");
+        
+    } else if (FindMem(sector, 512, "ISOLINUX", 8) >= 0) {
+        *bootcodename = STR("ISOLINUX");
+        
+    } else if (FindMem(sector, 512, "Geom\0Hard Disk\0Read\0 Error\0", 27) >= 0) {
+        *bootcodename = STR("GRUB");
+        
+    } else if ((*((UINT32 *)(sector + 502)) == 0 &&
+                *((UINT32 *)(sector + 506)) == 50000 &&
+                *((UINT16 *)(sector + 510)) == 0xaa55) ||
+               FindMem(sector, 512, "Starting the BTX loader", 23) >= 0) {
+        *bootcodename = STR("FreeBSD");
+        
+    } else if (FindMem(sector, 512, "!Loading", 8) >= 0 ||
+               FindMem(sector, 512, "/cdboot\0/CDBOOT\0", 16) >= 0) {
+        *bootcodename = STR("OpenBSD");
+        
+    } else if (FindMem(sector, 512, "NTLDR", 5) >= 0) {
+        *bootcodename = STR("Windows NTLDR");
+        
+    } else if (FindMem(sector, 512, "BOOTMGR", 7) >= 0) {
+        *bootcodename = STR("Windows BOOTMGR (Vista)");
+        
+    } else if (FindMem(sector, 512, "CPUBOOT SYS", 11) >= 0 ||
+               FindMem(sector, 512, "KERNEL  SYS", 11) >= 0) {
+        *bootcodename = STR("FreeDOS");
+        
+    } else if (FindMem(sector, 512, "OS2LDR", 6) >= 0 ||
+               FindMem(sector, 512, "OS2BOOT", 7) >= 0) {
+        *bootcodename = STR("eComStation");
+        
+    } else if (FindMem(sector, 512, "Be Boot Loader", 14) >= 0) {
+        *bootcodename = STR("BeOS");
+        
+    } else if (FindMem(sector, 512, "yT Boot Loader", 14) >= 0) {
+        *bootcodename = STR("ZETA");
+        
+    } else if (FindMem(sector, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0) {
+        *bootcodename = STR("Haiku");
+        
+    }
+    
+    if (FindMem(sector, 512, "Non-system disk", 15) >= 0)   // dummy FAT boot sector
+        *bootcodename = STR("None (Non-system disk message)");
+    
+    // TODO: Add a note if a specific code was detected, but the sector is not bootable?
+    
+    if (*bootcodename == NULL) {
+        if (bootable)
+            *bootcodename = STR("Unknown, but bootable");
+        else
+            *bootcodename = STR("None");
+    }
+    
+    return 0;
+}
+
+//
+// check one partition
+//
+
+static UINTN analyze_part(UINT64 partlba)
+{
+    UINTN   status;
+    UINTN   i;
+    CHARN   *bootcodename;
+    UINTN   parttype;
+    CHARN   *fsname;
+    
+    if (partlba == 0)
+        Print(L"\nMBR contents:\n");
+    else
+        Print(L"\nPartition at LBA %lld:\n", partlba);
+    
+    // detect boot code
+    status = detect_bootcode(partlba, &bootcodename);
+    if (status)
+        return status;
+    Print(L" Boot Code: %s\n", bootcodename);
+    
+    if (partlba == 0)
+        return 0;   // short-circuit MBR analysis
+    
+    // detect file system
+    status = detect_mbrtype_fs(partlba, &parttype, &fsname);
+    if (status)
+        return status;
+    Print(L" File System: %s\n", fsname);
+    
+    // cross-reference with partition table
+    for (i = 0; i < gpt_part_count; i++) {
+        if (gpt_parts[i].start_lba == partlba) {
+            Print(L" Listed in GPT as partition %d, type %s\n", i+1,
+                  gpt_parts[i].gpt_parttype->name);
+        }
+    }
+    for (i = 0; i < mbr_part_count; i++) {
+        if (mbr_parts[i].start_lba == partlba) {
+            Print(L" Listed in MBR as partition %d, type %02x  %s%s\n", i+1,
+                  mbr_parts[i].mbr_type,
+                  mbr_parttype_name(mbr_parts[i].mbr_type),
+                  mbr_parts[i].active ? STR(", active") : STR(""));
+        }
+    }
+    
+    return 0;
+}
+
+//
+// check all partitions
+//
+
+static UINTN analyze_parts(VOID)
+{
+    UINTN   i, k;
+    UINTN   status;
+    BOOLEAN is_dupe;
+    
+    // check MBR (bootcode only)
+    status = analyze_part(0);
+    if (status)
+        return status;
+    
+    // check partitions listed in GPT
+    for (i = 0; i < gpt_part_count; i++) {
+        status = analyze_part(gpt_parts[i].start_lba);
+        if (status)
+            return status;
+    }
+    
+    // check partitions listed in MBR, but not in GPT
+    for (i = 0; i < mbr_part_count; i++) {
+        if (mbr_parts[i].start_lba == 1 && mbr_parts[i].mbr_type == 0xee)
+            continue;   // skip EFI Protective entry
+        
+        is_dupe = FALSE;
+        for (k = 0; k < gpt_part_count; k++)
+            if (gpt_parts[k].start_lba == mbr_parts[i].start_lba)
+                is_dupe = TRUE;
+        
+        if (!is_dupe) {
+            status = analyze_part(mbr_parts[i].start_lba);
+            if (status)
+                return status;
+        }
+    }
+    
+    return 0;
+}
+
+//
+// display algorithm entry point
+//
+
+UINTN showpart(VOID)
+{
+    UINTN   status = 0;
+    UINTN   status_gpt, status_mbr;
+    
+    // get full information from disk
+    status_gpt = read_gpt();
+    status_mbr = read_mbr();
+    if (status_gpt != 0 || status_mbr != 0)
+        return (status_gpt || status_mbr);
+    
+    // analyze all partitions
+    status = analyze_parts();
+    if (status != 0)
+        return status;
+    
+    return status;
+}
diff --git a/bin/gptsync/syslinux_mbr.h b/bin/gptsync/syslinux_mbr.h
new file mode 100644
index 0000000..1c33e11
--- /dev/null
+++ b/bin/gptsync/syslinux_mbr.h
@@ -0,0 +1,90 @@
+/*
+ * include/syslinux_mbr.h
+ * MBR boot code
+ *
+ * The boot code in this file was taken from syslinux-3.11. It is covered
+ * by the following license:
+ *
+ ; -----------------------------------------------------------------------
+ ;   
+ ;   Copyright 2003-2004 H. Peter Anvin - All Rights Reserved
+ ;
+ ;   Permission is hereby granted, free of charge, to any person
+ ;   obtaining a copy of this software and associated documentation
+ ;   files (the "Software"), to deal in the Software without
+ ;   restriction, including without limitation the rights to use,
+ ;   copy, modify, merge, publish, distribute, sublicense, and/or
+ ;   sell copies of the Software, and to permit persons to whom
+ ;   the Software is furnished to do so, subject to the following
+ ;   conditions:
+ ;   
+ ;   The above copyright notice and this permission notice shall
+ ;   be included in all copies or substantial portions of the Software.
+ ;   
+ ;   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ ;   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ ;   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ ;   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ ;   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ ;   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ ;   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ ;   OTHER DEALINGS IN THE SOFTWARE.
+ ;
+ ; -----------------------------------------------------------------------
+ *
+ */
+
+#ifndef __SYSLINUX_MBR_H__
+#define __SYSLINUX_MBR_H__
+
+
+#define MBR_BOOTCODE_SIZE (440)
+
+
+#define SYSLINUX_MBR_SIZE (304)
+
+static UINT8 syslinux_mbr[SYSLINUX_MBR_SIZE] = {
+    0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0x8e,
+    0xd0, 0xbc, 0x00, 0x7c, 0xfb, 0xfc, 0x89, 0xe6,
+    0xbf, 0x00, 0x06, 0xb9, 0x00, 0x01, 0xf3, 0xa5,
+    0xea, 0x1d, 0x06, 0x00, 0x00, 0x88, 0x16, 0x00,
+    0x08, 0xb4, 0x08, 0xcd, 0x13, 0x31, 0xc0, 0x88,
+    0xf0, 0x40, 0xa3, 0xf0, 0x06, 0x80, 0xe1, 0x3f,
+    0x88, 0x0e, 0xf2, 0x06, 0xbe, 0xbe, 0x07, 0x31,
+    0xc0, 0xb9, 0x04, 0x00, 0xf6, 0x04, 0x80, 0x74,
+    0x03, 0x40, 0x89, 0xf7, 0x83, 0xc6, 0x10, 0xe2,
+    0xf3, 0x83, 0xf8, 0x01, 0x75, 0x73, 0x8a, 0x16,
+    0x00, 0x08, 0xb8, 0x00, 0x41, 0xbb, 0xaa, 0x55,
+    0x31, 0xc9, 0x30, 0xf6, 0xf9, 0xcd, 0x13, 0x72,
+    0x23, 0x81, 0xfb, 0x55, 0xaa, 0x75, 0x1d, 0xf6,
+    0xc1, 0x01, 0x74, 0x18, 0x57, 0xbe, 0xe0, 0x06,
+    0x8b, 0x5d, 0x08, 0x89, 0x5c, 0x08, 0x8b, 0x5d,
+    0x0a, 0x89, 0x5c, 0x0a, 0x8a, 0x16, 0x00, 0x08,
+    0xb4, 0x42, 0xeb, 0x2a, 0x57, 0x8b, 0x45, 0x08,
+    0x8b, 0x55, 0x0a, 0xf7, 0x36, 0xf2, 0x06, 0x42,
+    0x89, 0xd1, 0x31, 0xd2, 0xf7, 0x36, 0xf0, 0x06,
+    0x88, 0xc5, 0xd1, 0xe8, 0xd1, 0xe8, 0x24, 0xc0,
+    0x08, 0xc1, 0x88, 0xd6, 0x8a, 0x16, 0x00, 0x08,
+    0xbb, 0x00, 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13,
+    0x72, 0x16, 0x5e, 0x81, 0x3e, 0xfe, 0x7d, 0x55,
+    0xaa, 0x75, 0x08, 0xfa, 0xea, 0x00, 0x7c, 0x00,
+    0x00, 0x77, 0x05, 0xbe, 0xf4, 0x06, 0xeb, 0x03,
+    0xbe, 0x0f, 0x07, 0xac, 0x20, 0xc0, 0x74, 0x0c,
+    0xb4, 0x0e, 0x8a, 0x3e, 0x62, 0x04, 0xb3, 0x07,
+    0xcd, 0x10, 0xeb, 0xef, 0xeb, 0xfe, 0x00, 0x00,
+    0x10, 0x00, 0x01, 0x00, 0x00, 0x7c, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x4d, 0x69, 0x73, 0x73,
+    0x69, 0x6e, 0x67, 0x20, 0x6f, 0x70, 0x65, 0x72,
+    0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x79,
+    0x73, 0x74, 0x65, 0x6d, 0x0d, 0x0a, 0x00, 0x4f,
+    0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67,
+    0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
+    0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x20,
+    0x65, 0x72, 0x72, 0x6f, 0x72, 0x0d, 0x0a, 0x00
+};
+
+
+#endif /* __SYSLINUX_MBR_H__ */
+
+/* EOF */
diff --git a/bin/loader/.gitignore b/bin/loader/.gitignore
new file mode 100644
index 0000000..021a962
--- /dev/null
+++ b/bin/loader/.gitignore
@@ -0,0 +1,12 @@
+ctype.c
+mkctype
+loader
+init
+debug.log
+loader.tr
+.depend
+font.bgf.gz
+loader.po
+shutdown
+checkisomd5
+tr
diff --git a/bin/loader/Makefile.am b/bin/loader/Makefile.am
new file mode 100644
index 0000000..18f1fbe
--- /dev/null
+++ b/bin/loader/Makefile.am
@@ -0,0 +1,118 @@
+# loader/Makefile.am for anaconda
+#
+# 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 Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: David Cantrell <dcantrell redhat com>
+
+bootdir            = $(libdir)/$(PACKAGE_NAME)
+shareddir          = $(datadir)/$(PACKAGE_NAME)
+
+boot_PROGRAMS      = loader
+shared_DATA        = loader.tr
+dist_shared_DATA   = unicode-linedraw-chars.txt
+noinst_PROGRAMS    = mkctype dirbrowser
+noinst_DATA        = ctype.c
+noinst_HEADERS     = *.h
+
+if IS_S390
+boot_PROGRAMS      += shutdown
+dist_shared_SCRIPTS  = linuxrc.s390
+else
+boot_PROGRAMS       += init
+endif
+
+if IS_KEYMAPS_OVERRIDE_ARCH
+keymapsdir         = $(datadir)/$(PACKAGE_NAME)
+keymaps_DATA       = keymaps-override-$(ARCH)
+endif
+
+COMMON_CFLAGS      = -DUSE_LOGDEV -DVERSION='"$(PACKAGE_VERSION)"'
+
+loader_CFLAGS      = $(COMMON_CFLAGS) $(GLIB_CFLAGS) $(LIBNM_GLIB_CFLAGS) \
+                     $(LIBCURL_CFLAGS) $(IPV6_CFLAGS) $(LIBARCHIVE_CFLAGS) \
+                     $(RPM_CFLAGS) -DINCLUDE_LOCAL -DINCLUDE_NETWORK
+loader_LDADD       = $(NEWT_LIBS) $(GLIB_LIBS) $(LIBNL_LIBS) \
+                     $(LIBNM_GLIB_LIBS) $(CHECKISOMD5_LIBS) \
+                     $(LIBCURL_LIBS) $(LIBARCHIVE_LIBS) $(RPM_LIBS) \
+                     $(ISCSI_LIBS) $(top_srcdir)/isys/libisys.la -lm
+loader_SOURCES     = loader.c copy.c moduleinfo.c loadermisc.c \
+                     modules.c windows.c lang.c kbd.c driverdisk.c \
+                     selinux.c mediacheck.c kickstart.c driverselect.c \
+                     getparts.c dirbrowser.c fwloader.c ibft.c hardware.c \
+                     method.c cdinstall.c hdinstall.c nfsinstall.c \
+                     urlinstall.c net.c urls.c telnet.c telnetd.c \
+                     rpmextract.c
+
+init_CFLAGS        = $(COMMON_CFLAGS) $(GLIB_CFLAGS)
+init_LDADD	   = $(GLIB_LIBS)
+init_SOURCES       = init.c undomounts.c shutdown.c copy.c
+
+shutdown_CFLAGS    = $(COMMON_CFLAGS) -DAS_SHUTDOWN=1
+shutdown_SOURCES   = shutdown.c undomounts.c
+
+mkctype_CFLAGS     = $(COMMON_CFLAGS)
+mkctype_SOURCES    = mkctype.c
+
+dirbrowser_CFLAGS  = $(COMMON_CFLAGS) -DSTANDALONE
+dirbrowser_LDADD   = $(NEWT_LIBS)
+dirbrowser_SOURCES = dirbrowser.c
+
+EXTRA_DIST = simplemot keymaps-*
+
+CLEANFILES = keymaps-override-$(ARCH) ctype.c tr/*.tr
+
+MAINTAINERCLEANFILES = Makefile.in
+
+sed_verbose = $(sed_verbose_$(V))
+sed_verbose_ = $(sed_verbose_$(AM_DEFAULT_VERBOSITY))
+sed_verbose_0 = @echo "  SED    "$@;
+
+cp_verbose = $(cp_verbose_$(V))
+cp_verbose_ = $(cp_verbose_$(AM_DEFAULT_VERBOSITY))
+cp_verbose_0 = @echo "  CP     "$@;
+
+mkctype_verbose = $(mkctype_verbose_$(V))
+mkctype_verbose_ = $(mkctype_verbose_$(AM_DEFAULT_VERBOSITY))
+mkctype_verbose_0 = @echo "  MAKE   "$@;
+
+msgmerge_verbose = $(msgmerge_verbose_$(V))
+msgmerge_verbose_ = $(msgmerge_verbose_$(AM_DEFAULT_VERBOSITY))
+msgmerge_verbose_0 = echo "  MERGE  "$${lang}.po;
+
+xgettext_verbose = $(xgettext_verbose_$(V))
+xgettext_verbose_ = $(xgettext_verbose_$(AM_DEFAULT_VERBOSITY))
+xgettext_verbose_0 = @echo "  GETTXT "$@;
+
+keymaps-override-$(ARCH): keymaps-$(ARCH)
+	$(cp_verbose)cp -p $< $@
+
+ctype.c: mkctype
+	$(mkctype_verbose)./mkctype > ctype.c
+
+loader.tr: $(top_srcdir)/lang-table loader.po
+	@LANGS="`cut -f 2 $(top_srcdir)/lang-table | egrep -v '(^en$$)'`" ; \
+	if [ ! -d tr ]; then \
+		mkdir -p tr ; \
+	fi ; \
+	for lang in $$LANGS ; do \
+		$(msgmerge_verbose)msgmerge -q $(top_srcdir)/po/$$lang.po loader.po | msgconv -t utf-8 | ./simplemot > tr/$$lang.tr ; \
+	done ; \
+	(cd tr ; ls -1 *.tr | cpio --quiet -Hcrc -o | gzip -9) > $@
+
+loader.po:
+	$(xgettext_verbose)xgettext --default-domain=loader --add-comments \
+		--keyword=_ --keyword=N_ *.c
+	$(sed_verbose)sed -i 's/charset=CHARSET/charset=UTF-8/' $@
diff --git a/bin/loader/cdinstall.c b/bin/loader/cdinstall.c
new file mode 100644
index 0000000..9d5cee1
--- /dev/null
+++ b/bin/loader/cdinstall.c
@@ -0,0 +1,509 @@
+/*
+ * cdinstall.c - code to set up cdrom installs
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+/* FIXME Remove hack when: https://bugzilla.redhat.com/show_bug.cgi?id=478663
+   is resolved */
+/* Hack both __BIG_ENDIAN and __LITTLE_ENDIAN get defined by glibc, the
+   kernel headers we need do not like this! */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#undef __BIG_ENDIAN 
+#else
+#undef __LITTLE_ENDIAN
+#endif
+#include <asm/types.h>
+#include <limits.h>
+#include <linux/cdrom.h>
+
+#include "kickstart.h"
+#include "loader.h"
+#include "loadermisc.h"
+#include "lang.h"
+#include "modules.h"
+#include "method.h"
+#include "cdinstall.h"
+#include "mediacheck.h"
+#include "windows.h"
+
+#include "../isys/imount.h"
+#include "../isys/isys.h"
+#include "../isys/log.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+/* ejects the CD device the device node points at */
+static void ejectCdrom(char *device) {
+    int ejectfd;
+
+    if (!device) return;
+    logMessage(INFO, "ejecting %s...",device);
+    if ((ejectfd = open(device, O_RDONLY | O_NONBLOCK, 0)) >= 0) {
+        ioctl(ejectfd, CDROM_LOCKDOOR, 0);
+        if (ioctl(ejectfd, CDROMEJECT, 0))
+            logMessage(ERROR, "eject failed on device %s: %m", device);
+        close(ejectfd);
+    } else {
+        logMessage(ERROR, "could not open device %s: %m", device);
+    }
+}
+
+static char *cdrom_drive_status(int rc) {
+    struct {
+        int code;
+        char *str;
+    } status_codes[] =
+        {
+            { CDS_NO_INFO, "CDS_NO_INFO" },
+            { CDS_NO_DISC, "CDS_NO_DISC" },
+            { CDS_TRAY_OPEN, "CDS_TRAY_OPEN" },
+            { CDS_DRIVE_NOT_READY, "CDS_DRIVE_NOT_READY" },
+            { CDS_DISC_OK, "CDS_DISC_OK" },
+            { CDS_AUDIO, "CDS_AUDIO" },
+            { CDS_DATA_1, "CDS_DATA_1" },
+            { CDS_DATA_2, "CDS_DATA_2" },
+            { CDS_XA_2_1, "CDS_XA_2_1" },
+            { CDS_XA_2_2, "CDS_XA_2_2" },
+            { CDS_MIXED, "CDS_MIXED" },
+            { INT_MAX, NULL },
+        };
+    int i;
+
+    if (rc < 0)
+        return strerror(-rc);
+
+    for (i = 0; status_codes[i].code != INT_MAX; i++) {
+        if (status_codes[i].code == rc)
+            return status_codes[i].str;
+    }
+    return NULL;
+}
+
+static int waitForCdromTrayClose(int fd) {
+    int rc;
+    int prev = INT_MAX;
+
+    do {
+        char *status = NULL;
+        rc = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
+        if (rc < 0)
+            rc = -errno;
+
+        /* only bother to print the status if it changes */
+        if (prev == INT_MAX || prev != rc) {
+            status = cdrom_drive_status(rc);
+            if (status != NULL) {
+                logMessage(INFO, "drive status is %s", status);
+            } else {
+                logMessage(INFO, "drive status is unknown status code %d", rc);
+            }
+        }
+        prev = rc;
+        if (rc == CDS_DRIVE_NOT_READY)
+            usleep(100000);
+    } while (rc == CDS_DRIVE_NOT_READY);
+    return rc;
+}
+
+static void closeCdromTray(char *device) {
+    int fd;
+
+    if (!device || !*device)
+        return;
+
+    logMessage(INFO, "closing CD tray on %s .", device);
+    if ((fd = open(device, O_RDONLY | O_NONBLOCK, 0)) >= 0) {
+        if (ioctl(fd, CDROMCLOSETRAY, 0)) {
+            logMessage(ERROR, "closetray failed on device %s: %m", device);
+        } else {
+            waitForCdromTrayClose(fd);
+            ioctl(fd, CDROM_LOCKDOOR, 1);
+        }
+        close(fd);
+    } else {
+        logMessage(ERROR, "could not open device %s: %m", device);
+    }
+}
+
+/* Given cd device cddriver, this function will attempt to check its internal
+ * checksum.
+ */
+static void mediaCheckCdrom(char *cddriver) {
+    int rc;
+    int first;
+
+    first = 1;
+    do {
+        char *descr;
+        char *tstamp;
+        int ejectcd;
+
+        /* init every pass */
+        ejectcd = 0;
+        descr = NULL;
+
+        closeCdromTray(cddriver);
+
+        /* if first time through, see if they want to eject the CD      */
+        /* currently in the drive (most likely the CD they booted from) */
+        /* and test a different disk.  Otherwise just test the disk in  */
+        /* the drive since it was inserted in the previous pass through */
+        /* this loop, so they want it tested.                           */
+        if (first) {
+            first = 0;
+            rc = newtWinChoice(_("Media Check"), _("Test"), _("Eject Disc"),
+                               _("Choose \"%s\" to test the disc currently in "
+                                 "the drive, or \"%s\" to eject the disc and "
+                                 "insert another for testing."), _("Test"),
+                               _("Eject Disc"));
+
+            if (rc == 2)
+                ejectcd = 1;
+        }
+
+        if (!ejectcd) {
+            /* XXX MSFFIXME: should check return code for error */
+            readStampFileFromIso(cddriver, &tstamp, &descr);
+            doMediaCheck(cddriver, descr);
+
+            if (descr)
+                free(descr);
+        }
+
+        ejectCdrom(cddriver);
+
+        rc = newtWinChoice(_("Media Check"), _("Test"), _("Continue"),
+                       _("If you would like to test additional media, "
+                       "insert the next disc and press \"%s\". "
+                       "Testing each disc is not strictly required, however "
+                       "it is highly recommended.  Minimally, the discs should "
+                       "be tested prior to using them for the first time. "
+                       "After they have been successfully tested, it is not "
+                       "required to retest each disc prior to using it again."),
+                       _("Test"), _("Continue"));
+
+        if (rc == 2) {
+            closeCdromTray(cddriver);
+            return;
+        } else {
+            continue;
+        }
+    } while (1);
+}
+
+/* output an error message when CD in drive is not the correct one */
+/* Used by mountCdromStage2()                                      */
+static void wrongCDMessage(void) {
+    newtWinMessage(_("Error"), _("OK"),
+                   _("The %s disc was not found "
+                     "in any of your drives. Please insert "
+                     "the %s disc and press %s to retry."),
+                   getProductName(), getProductName(), _("OK"));
+}
+
+/* ask about doing media check */
+static void queryCDMediaCheck(char *dev, char *location) {
+    int rc;
+    char *stage2loc;
+
+    /* dont bother to test in automated installs */
+    if (FL_KICKSTART(flags) && !FL_MEDIACHECK(flags))
+        return;
+
+    /* see if we should check image(s) */
+    /* in rescue mode only test if they explicitly asked to */
+    if (!FL_RESCUE(flags) || FL_MEDIACHECK(flags)) {
+        startNewt();
+        rc = newtWinChoice(_("Disc Found"), _("OK"), _("Skip"),
+             _("To begin testing the media before installation press %s.\n\n"
+               "Choose %s to skip the media test and start the installation."),
+             _("OK"), _("Skip"));
+
+        if (rc != 2) {
+            /* We already mounted the CD earlier to verify there's at least a
+             * stage2 image.  Now we need to unmount to perform the check, then
+             * remount to pretend nothing ever happened.
+             */
+            umount(location);
+            mediaCheckCdrom(dev);
+
+            do {
+                if (doPwMount(dev, location, "iso9660", "ro", NULL)) {
+                    ejectCdrom(dev);
+                    wrongCDMessage();
+                    continue;
+                }
+
+                checked_asprintf(&stage2loc, "%s/images/install.img",
+                                 location);
+
+                if (access(stage2loc, R_OK)) {
+                    free(stage2loc);
+                    umount(location);
+                    ejectCdrom(dev);
+                    wrongCDMessage();
+                    continue;
+                }
+
+                free(stage2loc);
+                break;
+            } while (1);
+        }
+    }
+}
+
+/* Set up a CD/DVD drive to mount the stage2 image from.  If successful, the
+ * stage2 image will be left mounted on /mnt/runtime.
+ *
+ * location:     Where to mount the media at (usually /mnt/stage2)
+ * loaderData:   The usual, can be NULL if no info
+ * interactive:  Whether or not to prompt about questions/errors
+ * mediaCheck:   Do we run media check or not?
+ */
+static char *setupCdrom(char *location, struct loaderData_s *loaderData,
+                        int interactive, int mediaCheck) {
+    int i, rc;
+    int stage2inram = 0;
+    char *retbuf = NULL, *stage2loc, *stage2img;
+    struct device ** devices;
+    char *cddev = NULL;
+
+    devices = getDevices(DEVICE_CDROM);
+    if (!devices) {
+        logMessage(ERROR, "got to setupCdrom without a CD device");
+        return NULL;
+    }
+
+    checked_asprintf(&stage2loc, "%s/images/install.img", location);
+
+    /* JKFIXME: ASSERT -- we have a cdrom device when we get here */
+    do {
+        for (i = 0; devices[i]; i++) {
+            char *tmp = NULL;
+            int fd;
+
+            if (!devices[i]->device)
+                continue;
+
+            if (strncmp("/dev/", devices[i]->device, 5)) {
+                checked_asprintf(&tmp, "/dev/%s", devices[i]->device);
+
+                free(devices[i]->device);
+                devices[i]->device = tmp;
+            }
+
+            logMessage(INFO, "trying to mount CD device %s on %s",
+                       devices[i]->device, location);
+
+            if (!FL_CMDLINE(flags))
+                winStatus(60, 3, _("Scanning"), _("Looking for installation images on CD device %s\n"), devices[i]->device);
+            else
+                printf(_("Looking for installation images on CD device %s"), devices[i]->device);
+
+            fd = open(devices[i]->device, O_RDONLY | O_NONBLOCK);
+            if (fd < 0) {
+                logMessage(ERROR, "Couldn't open %s: %m", devices[i]->device);
+                if (!FL_CMDLINE(flags))
+                    newtPopWindow();
+                continue;
+            }
+
+            rc = waitForCdromTrayClose(fd);
+            close(fd);
+            switch (rc) {
+                case CDS_NO_INFO:
+                    logMessage(ERROR, "Drive tray reports CDS_NO_INFO");
+                    break;
+                case CDS_NO_DISC:
+                    if (!FL_CMDLINE(flags))
+                            newtPopWindow();
+                    continue;
+                case CDS_TRAY_OPEN:
+                    logMessage(ERROR, "Drive tray reports open when it should be closed");
+                    break;
+                default:
+                    break;
+            }
+
+            if (!FL_CMDLINE(flags))
+                newtPopWindow();
+
+            if (!(rc=doPwMount(devices[i]->device, location, "iso9660", "ro", NULL))) {
+                cddev = devices[i]->device;
+                if (!access(stage2loc, R_OK)) {
+                    char *updpath;
+
+                    if (mediaCheck)
+                        queryCDMediaCheck(devices[i]->device, location);
+
+                    /* if in rescue mode lets copy stage 2 into RAM so we can */
+                    /* free up the CD drive and user can have it avaiable to  */
+                    /* aid system recovery.                                   */
+                    if (FL_RESCUE(flags) && !FL_TEXT(flags) &&
+                        totalMemory() > MIN_GUI_RAM ) {
+                        rc = copyFile(stage2loc, "/tmp/install.img");
+                        stage2img = strdup("/tmp/install.img");
+                        stage2inram = 1;
+                    } else {
+                        stage2img = strdup(stage2loc);
+                        stage2inram = 0;
+                    }
+
+                    rc = mountStage2(stage2img);
+                    free(stage2img);
+
+                    if (rc) {
+                        logMessage(INFO, "mounting stage2 failed");
+                        umount(location);
+                        continue;
+                    }
+
+                    checked_asprintf(&updpath, "%s/images/updates.img", location);
+
+                    logMessage(INFO, "Looking for updates in %s", updpath);
+                    copyUpdatesImg(updpath);
+                    free(updpath);
+
+                    checked_asprintf(&updpath, "%s/images/product.img", location);
+
+                    logMessage(INFO, "Looking for product in %s", updpath);
+                    copyProductImg(updpath);
+                    free(updpath);
+
+                    /* if in rescue mode and we copied stage2 to RAM */
+                    /* we can now unmount the CD                     */
+                    if (FL_RESCUE(flags) && stage2inram) {
+                        umount(location);
+                    }
+
+                    checked_asprintf(&retbuf, "cdrom://%s:%s",
+                                     devices[i]->device, location);
+                } else {
+                    /* this wasnt the CD we were looking for, clean up and */
+                    /* try the next CD drive                               */
+                    umount(location);
+                }
+            }
+        }
+
+        if (!retbuf) {
+            if (interactive) {
+                char * buf;
+
+                checked_asprintf(&buf, _("The %s disc was not found in any of your "
+                                         "CDROM drives. Please insert the %s disc "
+                                         "and press %s to retry."),
+                                 getProductName(), getProductName(), _("OK"));
+
+                ejectCdrom(cddev);
+                rc = newtWinChoice(_("Disc Not Found"),
+                                   _("OK"), _("Back"), buf, _("OK"));
+                free(buf);
+                if (rc == 2)
+                    goto err;
+            } else {
+                /* we can't ask them about it, so just return not found */
+                goto err;
+            }
+        }
+    } while (!retbuf);
+
+err:
+    free(stage2loc);
+    return retbuf;
+}
+
+/* try to find a install CD non-interactively */
+char * findAnacondaCD(char *location) {
+    return setupCdrom(location, NULL, 0, 1);
+}
+
+/* look for a CD and mount it.  if we have problems, ask */
+char * mountCdromImage(struct installMethod * method,
+                       char * location, struct loaderData_s * loaderData) {
+    return setupCdrom(location, loaderData, 1, 1);
+}
+
+void setKickstartCD(struct loaderData_s * loaderData, int argc, char ** argv) {
+
+    logMessage(INFO, "kickstartFromCD");
+    loaderData->method = METHOD_CDROM;
+}
+
+int kickstartFromCD(char *kssrc) {
+    int rc, i;
+    char *p, *kspath;
+    struct device ** devices;
+
+    logMessage(INFO, "getting kickstart file from first CDROM");
+
+    devices = getDevices(DEVICE_CDROM);
+    /* usb can take some time to settle, even with the various hacks we
+     * have in place.  some systems use portable USB CD-ROM drives, try to
+     * make sure there really isn't one before bailing */
+    for (i = 0; !devices && i < 10; ++i) {
+        logMessage(INFO, "sleeping to wait for a USB CD-ROM");
+        sleep(2);
+        devices = getDevices(DEVICE_CDROM);
+    }
+    if (!devices) {
+        logMessage(ERROR, "No CDROM devices found!");
+        return 1;
+    }
+
+    /* format is cdrom:[/path/to/ks.cfg] */
+    kspath = "";
+    p = strchr(kssrc, ':');
+    if (p)
+        kspath = p + 1;
+
+    if (!p || strlen(kspath) < 1)
+        kspath = "/ks.cfg";
+
+    for (i=0; devices[i]; i++) {
+        if (!devices[i]->device)
+            continue;
+
+        rc = getKickstartFromBlockDevice(devices[i]->device, kspath);
+        if (rc == 0)
+            return 0;
+    }
+
+    startNewt();
+    newtWinMessage(_("Error"), _("OK"),
+                   _("Cannot find kickstart file on CDROM."));
+    return 1;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 et */
diff --git a/bin/loader/cdinstall.h b/bin/loader/cdinstall.h
new file mode 100644
index 0000000..a0ecbc3
--- /dev/null
+++ b/bin/loader/cdinstall.h
@@ -0,0 +1,34 @@
+/*
+ * cdinstall.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef H_CDINSTALL
+#define H_CDINSTALL
+
+#include "method.h"
+
+char * mountCdromImage(struct installMethod * method,
+                       char * location, struct loaderData_s * loaderData);
+
+char * findAnacondaCD(char * location);
+
+void setKickstartCD(struct loaderData_s * loaderData, int argc,
+		    char ** argv);
+
+int kickstartFromCD(char *kssrc);
+#endif
diff --git a/bin/loader/copy.c b/bin/loader/copy.c
new file mode 100644
index 0000000..1c61233
--- /dev/null
+++ b/bin/loader/copy.c
@@ -0,0 +1,141 @@
+/*
+ * copy.c - functions for copying files and directories
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "lang.h"
+
+/* Recursive */
+int copyDirectory(char * from, char * to, void (*warnFn)(char *),
+                  void (*errorFn)(char *)) {
+    char *msg;
+    DIR * dir;
+    struct dirent * ent;
+    int fd, outfd;
+    char buf[4096];
+    int i;
+    struct stat sb;
+    char filespec[256];
+    char filespec2[256];
+    char link[1024];
+
+    mkdir(to, 0755);
+
+    if (!(dir = opendir(from))) {
+        if (errorFn) {
+           if (asprintf(&msg, N_("Failed to read directory %s: %m"), from) == -1) {
+               fprintf(stderr, "%s: %d: %m\n", __func__, __LINE__);
+               fflush(stderr);
+               abort();
+           }
+
+           errorFn(msg);
+           free(msg);
+        }
+
+        return 1;
+    }
+
+    errno = 0;
+    while ((ent = readdir(dir))) {
+        if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
+           continue;
+
+        sprintf(filespec, "%s/%s", from, ent->d_name);
+        sprintf(filespec2, "%s/%s", to, ent->d_name);
+
+        lstat(filespec, &sb);
+
+        if (S_ISDIR(sb.st_mode)) {
+            if (copyDirectory(filespec, filespec2, warnFn, errorFn)) {
+                closedir(dir);
+                return 1;
+            }
+        } else if (S_ISLNK(sb.st_mode)) {
+            i = readlink(filespec, link, sizeof(link) - 1);
+            link[i] = '\0';
+            if (symlink(link, filespec2)) {
+                if (warnFn) {
+                    if (asprintf(&msg, "Failed to symlink %s to %s: %m",
+                                 filespec2, link) == -1) {
+                        fprintf(stderr, "%s: %d: %m\n", __func__, __LINE__);
+                        fflush(stderr);
+                        abort();
+                    }
+
+                    warnFn(msg);
+                    free(msg);
+                }
+            }
+        } else {
+            fd = open(filespec, O_RDONLY);
+            if (fd == -1) {
+                if (errorFn) {
+                    if (asprintf(&msg, "Failed to open %s: %m", filespec) == -1) {
+                        fprintf(stderr, "%s: %d: %m\n", __func__, __LINE__);
+                        fflush(stderr);
+                        abort();
+                    }
+
+                    errorFn(msg);
+                    free(msg);
+                }
+
+                closedir(dir);
+                return 1;
+            } 
+            outfd = open(filespec2, O_RDWR | O_TRUNC | O_CREAT, 0644);
+            if (outfd == -1) {
+                if (warnFn) {
+                    if (asprintf(&msg, "Failed to create %s: %m", filespec2) == -1) {
+                        fprintf(stderr, "%s: %d: %m\n", __func__, __LINE__);
+                        fflush(stderr);
+                        abort();
+                    }
+
+                    warnFn(msg);
+                    free(msg);
+                }
+            } else {
+                fchmod(outfd, sb.st_mode & 07777);
+
+                while ((i = read(fd, buf, sizeof(buf))) > 0)
+                    i = write(outfd, buf, i);
+                close(outfd);
+            }
+
+            close(fd);
+        }
+
+        errno = 0;
+    }
+
+    closedir(dir);
+
+    return 0;
+}
diff --git a/bin/loader/copy.h b/bin/loader/copy.h
new file mode 100644
index 0000000..1153bf8
--- /dev/null
+++ b/bin/loader/copy.h
@@ -0,0 +1,26 @@
+/*
+ * copy.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef H_COPY
+#define H_COPY
+
+int copyDirectory (char *from, char *to, void (*warnFn)(char *),
+                   void (*errorFn)(char *));
+
+#endif
diff --git a/bin/loader/devices.h b/bin/loader/devices.h
new file mode 100644
index 0000000..974e792
--- /dev/null
+++ b/bin/loader/devices.h
@@ -0,0 +1,103 @@
+/*
+ * devices.h: handle declaration of devices to be created under /dev
+ *
+ * Copyright (C) 2004  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LOADER_INIT_DEVICES_H
+#define LOADER_INIT_DEVICES_H
+
+struct devnode {
+    char * devname;
+    int type;
+    int major;
+    int minor;
+    int perms;
+    char * owner;
+    char * group;
+};
+
+#define CHARDEV 0
+#define BLOCKDEV 1
+#define DIRTYPE 2
+
+struct devnode devnodes[] = {
+    /* consoles */
+    {"console", CHARDEV, 5, 1, 0600, "root", "root"},
+    {"ttyS0", CHARDEV, 4, 64, 0600, "root", "root"},
+    {"ttyS1", CHARDEV, 4, 65, 0600, "root", "root"},
+    {"ttyS2", CHARDEV, 4, 66, 0600, "root", "root"},
+    {"ttyS3", CHARDEV, 4, 67, 0600, "root", "root"},
+#ifdef __ia64__
+    {"ttySG0", CHARDEV, 204, 40, 0600, "root", "root"},
+#endif
+#ifdef __powerpc__
+    {"hvsi0", CHARDEV, 229, 128, 0600, "root", "root"},
+    {"hvsi1", CHARDEV, 229, 129, 0600, "root", "root"},
+    {"hvsi2", CHARDEV, 229, 130, 0600, "root", "root"},
+#endif
+    {"hvc0", CHARDEV, 229, 0, 0600, "root", "root"},
+#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
+    {"xvc0", CHARDEV, 204, 191, 0600, "root", "root"},
+#endif
+    /* base unix */
+    {"null", CHARDEV, 1, 3, 0666, "root", "root"},
+    {"zero", CHARDEV, 1, 5, 0666, "root", "root"},
+    {"mem", CHARDEV, 1, 1, 0600, "root", "root"},
+    /* ttys */
+    {"pts", DIRTYPE, 0, 0, 0755, "root", "root"},
+    {"ptmx", CHARDEV, 5, 2, 0666, "root", "root"},
+    {"tty", CHARDEV, 5, 0, 0666, "root", "root"},
+    {"tty0", CHARDEV, 4, 0, 0600, "root", "tty"},
+    {"tty1", CHARDEV, 4, 1, 0600, "root", "tty"},
+    {"tty2", CHARDEV, 4, 2, 0600, "root", "tty"},
+    {"tty3", CHARDEV, 4, 3, 0600, "root", "tty"},
+    {"tty4", CHARDEV, 4, 4, 0600, "root", "tty"},
+    {"tty5", CHARDEV, 4, 5, 0600, "root", "tty"},
+    {"tty6", CHARDEV, 4, 6, 0600, "root", "tty"},
+    {"tty7", CHARDEV, 4, 7, 0600, "root", "tty"},
+    {"tty8", CHARDEV, 4, 8, 0600, "root", "tty"},
+    {"tty9", CHARDEV, 4, 9, 0600, "root", "tty"},
+    /* fb */
+    {"fb0", CHARDEV, 29, 0, 0600, "root", "tty"},
+    /* sparc specific */
+#ifdef __sparc__
+    {"openprom", CHARDEV, 10, 139, 0644, "root", "root"},
+    {"sunmouse", CHARDEV, 10, 6, 0644, "root", "root"},
+    {"kbd", CHARDEV, 11, 0, 0644, "root", "root"},
+#endif
+    /* X */
+    {"agpgart", CHARDEV, 10, 175, 0664, "root", "root"},
+    {"psaux", CHARDEV, 10, 1, 0644, "root", "root"},
+    {"input", DIRTYPE, 0, 0, 0755, "root", "root"},
+    {"input/mice", CHARDEV, 13, 63, 0664, "root", "root"},
+    /* floppies */
+    {"fd0", BLOCKDEV, 2, 0, 0644, "root", "root"},
+    {"fd1", BLOCKDEV, 2, 1, 0644, "root", "root"},
+    /* random */
+    {"random", CHARDEV, 1, 8, 0644, "root", "root"},
+    {"urandom", CHARDEV, 1, 9, 0644, "root", "root"},
+    /* mac stuff */
+#ifdef __powerpc__
+    {"nvram", CHARDEV, 10, 144, 0644, "root", "root"},
+    {"adb", CHARDEV, 56, 0, 0644, "root", "root"},
+    {"iseries", DIRTYPE, 0, 0, 0755, "root", "root" },
+#endif
+    {"rtc", CHARDEV, 10, 135, 0644, "root", "root"},
+    { NULL, 0, 0, 0, 0, NULL, NULL },
+};
+
+#endif
diff --git a/bin/loader/devt.h b/bin/loader/devt.h
new file mode 100644
index 0000000..364a134
--- /dev/null
+++ b/bin/loader/devt.h
@@ -0,0 +1,39 @@
+/*
+ * devt.h: handle declaration of dev_t to be sane for loopback purposes
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DEVT_H
+#define DEVT_H
+
+/* Need to tell loop.h what the actual dev_t type is. */
+#undef dev_t
+#if defined(__alpha) || (defined(__sparc__) && defined(__arch64__))
+#define dev_t unsigned int
+#else
+#if defined(__x86_64__)
+#define dev_t unsigned long
+#else
+#define dev_t unsigned short
+#endif
+#endif
+#include <linux/loop.h>
+#undef dev_t
+#define dev_t dev_t
+
+#endif
diff --git a/bin/loader/dirbrowser.c b/bin/loader/dirbrowser.c
new file mode 100644
index 0000000..9199850
--- /dev/null
+++ b/bin/loader/dirbrowser.c
@@ -0,0 +1,199 @@
+/*
+ * dirbrowser.c - newt-based directory browser to get a file name
+ *
+ * Copyright (C) 2004  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Jeremy Katz <katzj redhat com>
+ */
+
+#include <newt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#ifndef STANDALONE
+#include "../isys/log.h"
+
+#include "loader.h"
+#include "loadermisc.h"
+#include "lang.h"
+#endif
+
+#ifdef STANDALONE
+#define _(x) x
+
+static int simpleStringCmp(const void * a, const void * b) {
+    const char * first = *((const char **) a);
+    const char * second = *((const char **) b);
+
+    return strcmp(first, second);
+}
+#endif
+
+#define FSTEP 10
+
+static char ** get_file_list(char * dirname, 
+                             int (*filterfunc)(char *, struct dirent *)) {
+    DIR * dir;
+    struct dirent *entry;
+    char ** files;
+    int numfiles = FSTEP, i = 0;
+
+    dir = opendir(dirname);
+    if (dir == NULL) {
+        fprintf(stderr, "error opening %s: %m", dirname);
+        return NULL;
+    }
+
+    files = malloc(numfiles * sizeof(char *));
+
+    while ((entry = readdir(dir))) {
+        if ((strlen(entry->d_name) == 1) && !strncmp(entry->d_name, ".", 1))
+            continue;
+        if ((strlen(entry->d_name) == 2) && !strncmp(entry->d_name, "..", 2))
+            continue;
+        if (filterfunc && filterfunc(dirname, entry))
+            continue;
+
+        files[i] = strdup(entry->d_name);
+        if (i++ >= (numfiles - 1)) {
+            numfiles += FSTEP;
+            files = realloc(files, numfiles * sizeof(char *));
+        }
+    }
+    files[i] = NULL;
+    closedir(dir);
+
+    qsort(files, i, sizeof(*files), simpleStringCmp);
+    return files;
+}
+
+/* Browse through a directory structure looking for a file.
+ * Returns the full path to the file.
+ *
+ * Parameters:
+ * title: Title for newt dialog window
+ * dirname: Directory to use for root of browsing.  NOTE: you cannot go
+ *          up above this root.
+ * filterfunc: An (optional)  function to filter out files based on whatever 
+ *             criteria you want.  Returns 1 if it passes, 0 if not.  
+ *             Function should take arguments of the directory name and 
+ *             the dirent for the file.
+ */
+char * newt_select_file(char * title, char * text, char * dirname,
+                        int (*filterfunc)(char *, struct dirent *)) {
+    char ** files;
+    char * fn = NULL;
+    int i, done = 0;
+    char * topdir = dirname;
+    char * dir = malloc(PATH_MAX);
+    char * path = NULL;
+    newtGrid grid, buttons;
+    newtComponent f, tb, listbox, ok, cancel;
+    struct stat sb;
+    struct newtExitStruct es;
+
+    dir = realpath(dirname, dir);
+
+    do {
+        files = get_file_list(dir, filterfunc);
+
+        f = newtForm(NULL, NULL, 0);
+        grid = newtCreateGrid(1, 4);
+
+        tb = newtTextboxReflowed(-1, -1, text, 60, 0, 10, 0);
+
+        listbox = newtListbox(12, 65, 10, 
+                              NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
+
+        newtListboxSetWidth(listbox, 55);
+        buttons = newtButtonBar(_("OK"), &ok, _("Cancel"), &cancel, NULL);
+        newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, tb,
+                         0, 0, 0, 1, 0, 0);
+        newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, listbox,
+                         0, 0, 0, 1, 0, 0);
+        newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, buttons,
+                         0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+        
+        /* if this isn't our topdir, we want to let them go up a dir */
+        if (strcmp(topdir, dir))
+            newtListboxAppendEntry(listbox, "../", "..");
+
+        for (i = 0; (files[i] != NULL); i++) {
+            if ((files[i] == NULL) || (strlen(files[i]) == 0)) continue;
+            path = malloc(strlen(files[i]) + strlen(dir) + 2);
+            sprintf(path, "%s/%s", dir, files[i]);
+            stat(path, &sb);
+            free(path);
+            if (S_ISDIR(sb.st_mode)) {
+                char *dir = malloc(strlen(files[i]) + 2);
+                sprintf(dir, "%s/", files[i]);
+                newtListboxAppendEntry(listbox, dir, files[i]);
+            } else {
+                newtListboxAppendEntry(listbox, files[i], files[i]);
+            }
+        }
+
+        newtGridWrappedWindow(grid, title);
+        newtGridAddComponentsToForm(grid, f, 1);
+        newtFormRun(f, &es);
+
+        if (es.reason  == NEWT_EXIT_COMPONENT && es.u.co == cancel) {
+            fn = NULL;
+            done = -1;
+        } else {
+            fn = (char *) newtListboxGetCurrent(listbox);
+            path = malloc(strlen(fn) + strlen(dir) + 2);
+            sprintf(path, "%s/%s", dir, fn);
+
+            stat(path, &sb);
+            if (!S_ISDIR(sb.st_mode)) {
+                fn = path;
+                done = 1;
+            } else { 
+                dir = realpath(path, dir);
+                free(path);
+            }
+        }
+
+        newtGridFree(grid, 1);
+        newtFormDestroy(f);
+        newtPopWindow();
+    } while (done == 0);
+
+    return fn;
+}
+
+#ifdef STANDALONE
+int main(int argc, char ** argv) {
+    char * foo;
+
+    newtInit();
+    newtCls();
+      
+    foo = newt_select_file("Get File Name", "foo, blah blah blah", 
+                           "/etc", NULL);
+    newtFinished();
+    printf("got %s\n", foo);
+    return 0;
+}
+#endif
diff --git a/bin/loader/dirbrowser.h b/bin/loader/dirbrowser.h
new file mode 100644
index 0000000..7fb22f2
--- /dev/null
+++ b/bin/loader/dirbrowser.h
@@ -0,0 +1,28 @@
+/*
+ * dirbrowser.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DIRBROWSER_H
+#define DIRBROWSER_H
+
+#include <dirent.h>
+
+char * newt_select_file(char * title, char * text, char * dirname,
+                        int (*filterfunc)(char *, struct dirent *));
+
+#endif
diff --git a/bin/loader/driverdisk.c b/bin/loader/driverdisk.c
new file mode 100644
index 0000000..4f4446c
--- /dev/null
+++ b/bin/loader/driverdisk.c
@@ -0,0 +1,861 @@
+/*
+ * driverdisk.c - driver disk functionality
+ *
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Jeremy Katz <katzj redhat com>
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include <blkid/blkid.h>
+
+#include <glob.h>
+#include <rpm/rpmlib.h>
+#include <sys/utsname.h>
+
+#include "copy.h"
+#include "loader.h"
+#include "loadermisc.h"
+#include "lang.h"
+#include "fwloader.h"
+#include "method.h"
+#include "modules.h"
+#include "moduleinfo.h"
+#include "windows.h"
+#include "hardware.h"
+#include "driverdisk.h"
+#include "getparts.h"
+#include "dirbrowser.h"
+
+#include "nfsinstall.h"
+#include "urlinstall.h"
+
+#include "rpmextract.h"
+
+#include "../isys/isys.h"
+#include "../isys/imount.h"
+#include "../isys/eddsupport.h"
+#include "../isys/log.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+/*
+ * check if the RPM in question provides
+ * Provides: userptr
+ * we use it to check kernel-modules-<kernelversion>
+ */
+int dlabelProvides(const char* dep, void *userptr)
+{
+    char *kernelver = (char*)userptr;
+
+    logMessage(DEBUGLVL, "Provides: %s\n", dep);
+
+    return strcmp(dep, kernelver);
+}
+
+/*
+ * during cpio extraction, only extract files we need
+ * eg. module .ko files and firmware directory
+ */
+int dlabelFilter(const char* name, const struct stat *fstat, void *userptr)
+{
+    int l = strlen(name);
+
+    logMessage(DEBUGLVL, "Unpacking %s\n", name);
+
+    /* we want firmware files */
+    if (!strncmp("lib/firmware/", name, 13)) return 0; 
+
+    if (l<3)
+        return 1;
+    l-=3;
+
+    /* and we want only .ko files */
+    if (strcmp(".ko", name+l))
+        return 1;
+
+    /* TODO we are unpacking kernel module, read it's description */
+
+    return 0;
+}
+
+char* moduleDescription(const char* modulePath)
+{
+    char *command = NULL;
+    FILE *f = NULL;
+    char *description = NULL;
+    int size;
+
+    checked_asprintf(&command, "modinfo --description '%s'", modulePath);
+    f = popen(command, "r");
+    free(command);
+
+    if (f==NULL)
+        return NULL;
+
+    description = malloc(sizeof(char)*256);
+    if (!description)
+        return NULL;
+
+    size = fread(description, 1, 255, f);
+    if (size == 0) {
+        free(description);
+        return NULL;
+    }
+
+    description[size-1]=0; /* strip the trailing newline */
+    pclose(f);
+
+    return description;
+}
+
+int globErrFunc(const char *epath, int eerrno)
+{
+    /* TODO check fatal errors */
+
+    return 0;
+}
+
+int dlabelUnpackRPMDir(char* rpmdir, char* destination)
+{
+    char *kernelver;
+    struct utsname unamedata;
+    char *oldcwd;
+    char *globpattern;
+    int rc;
+
+    /* get current working directory */ 
+    oldcwd = getcwd(NULL, 0);
+    if (!oldcwd) {
+        logMessage(ERROR, "getcwd() failed: %m");
+        return 1;
+    }
+
+    /* set the cwd to destination */
+    if (chdir(destination)) {
+        logMessage(ERROR, "We weren't able to CWD to \"%s\": %m", destination);
+        free(oldcwd);
+        return 1;
+    }
+
+    /* get running kernel version */
+    rc = uname(&unamedata);
+    checked_asprintf(&kernelver, "kernel-modules-%s",
+            rc ? "unknown" : unamedata.release);
+    logMessage(DEBUGLVL, "Kernel version: %s\n", kernelver);
+
+    checked_asprintf(&globpattern, "%s/*.rpm", rpmdir);
+    glob_t globres;
+    char** globitem;
+    if (!glob(globpattern, GLOB_NOSORT|GLOB_NOESCAPE, globErrFunc, &globres)) {
+        /* iterate over all rpm files */
+        globitem = globres.gl_pathv;
+        while (globres.gl_pathc>0 && globitem != NULL) {
+            explodeRPM(*globitem, dlabelFilter, dlabelProvides, NULL, kernelver);
+        }
+        globfree(&globres);
+        /* end of iteration */
+    }
+    free(globpattern);
+
+    /* restore CWD */
+    if (chdir(oldcwd)) {
+        logMessage(WARNING, "We weren't able to restore CWD to \"%s\": %m", oldcwd);
+    }
+
+    /* cleanup */
+    free(kernelver);
+    free(oldcwd);
+    return rc;
+}
+
+
+static char * driverDiskFiles[] = { "repodata", NULL };
+
+static int verifyDriverDisk(char *mntpt) {
+    char ** fnPtr;
+    char file[200];
+    struct stat sb;
+
+    /* check for dd descriptor */
+    sprintf(file, "%s/rhdd3", mntpt);
+    if (access(file, R_OK)) {
+        logMessage(ERROR, "can't find driver disk identifier, bad "
+                          "driver disk");
+        return LOADER_BACK;
+    }
+
+    /* side effect: file is still mntpt/ddident */
+    stat(file, &sb);
+    if (!sb.st_size)
+        return LOADER_BACK;
+
+    for (fnPtr = driverDiskFiles; *fnPtr; fnPtr++) {
+        snprintf(file, 200, "%s/rpms/%s/%s", mntpt, getProductArch(), *fnPtr);
+        if (access(file, R_OK)) {
+            logMessage(ERROR, "cannot find %s, bad driver disk", file);
+            return LOADER_BACK;
+        }
+    }
+
+    return LOADER_OK;
+}
+
+static void copyWarnFn (char *msg) {
+   logMessage(WARNING, msg);
+}
+
+static void copyErrorFn (char *msg) {
+   newtWinMessage(_("Error"), _("OK"), _(msg));
+}
+
+/* this copies the contents of the driver disk to a ramdisk and loads
+ * the moduleinfo, etc.  assumes a "valid" driver disk mounted at mntpt */
+static int loadDriverDisk(struct loaderData_s *loaderData, char *mntpt) {
+    /* FIXME moduleInfoSet modInfo = loaderData->modInfo; */
+    char file[200], dest[200], src[200];
+    char *title;
+    char *fwdir = NULL;
+    struct moduleBallLocation * location;
+    struct stat sb;
+    static int disknum = 0;
+    int fd, ret;
+
+    /* check for new version */
+    sprintf(file, "%s/rhdd3", mntpt);
+    if (access(file, R_OK)) {
+      /* this can't happen, we already verified it! */
+      return LOADER_BACK;
+    }
+    stat(file, &sb);
+    title = malloc(sb.st_size + 1);
+
+    fd = open(file, O_RDONLY);
+    ret = read(fd, title, sb.st_size);
+    if (title[sb.st_size - 1] == '\n')
+        sb.st_size--;
+    title[sb.st_size] = '\0';
+    close(fd);
+
+    sprintf(file, DD_RPMDIR_TEMPLATE, disknum);
+    mkdirChain(file);
+    mkdirChain(DD_MODULES);
+    mkdirChain(DD_FIRMWARE);
+
+    if (!FL_CMDLINE(flags)) {
+        startNewt();
+        winStatus(40, 3, _("Loading"), _("Reading driver disk"));
+    }
+
+    location = malloc(sizeof(struct moduleBallLocation));
+    location->title = strdup(title);
+    checked_asprintf(&location->path, DD_MODULES);
+
+    sprintf(dest, DD_RPMDIR_TEMPLATE, disknum);
+    sprintf(src, "%s/rpms/%s", mntpt, getProductArch());
+    copyDirectory(src, dest, copyWarnFn, copyErrorFn);
+
+    /* unpack packages from dest into location->path */
+    if (dlabelUnpackRPMDir(dest, DD_EXTRACTED)) {
+        /* fatal error, log this and jump to exception handler */
+        logMessage(ERROR, "Error unpacking RPMs from driver disc no.%d",
+                disknum);
+        goto loadDriverDiscException;
+    }
+
+    /* run depmod to refresh modules db */
+    if (system("depmod -a")) {
+      /* this is not really fatal error, it might still work, log it */
+      logMessage(ERROR, "Error running depmod -a for driverdisc no.%d", disknum);
+    }
+
+    checked_asprintf(&fwdir, DD_FIRMWARE);
+    if (!access(fwdir, R_OK|X_OK)) {
+        add_fw_search_dir(loaderData, fwdir);
+        stop_fw_loader(loaderData);
+        start_fw_loader(loaderData);
+    }
+    free(fwdir);
+
+    /* TODO generate and read module info
+     *
+     * sprintf(file, "%s/modinfo", mntpt);
+     * readModuleInfo(file, modInfo, location, 1);
+     */
+
+loadDriverDiscException:
+
+    if (!FL_CMDLINE(flags))
+        newtPopWindow();
+
+    disknum++;
+    return 0;
+}
+
+/* Get the list of removable devices (floppy/cdrom) available.  Used to
+ * find suitable devices for update disk / driver disk source.  
+ * Returns the number of devices.  ***devNames will be a NULL-terminated list
+ * of device names
+ */
+int getRemovableDevices(char *** devNames) {
+    struct device **devs;
+    int numDevices = 0;
+    int i = 0;
+
+    devs = getDevices(DEVICE_DISK | DEVICE_CDROM);
+
+    if (!devs)
+        return numDevices;
+
+    for (i = 0; devs[i] ; i++) {
+        logMessage(DEBUGLVL, "Considering device %s (isremovable: %d)", devs[i]->device, devs[i]->priv.removable);
+        if (devs[i]->priv.removable) {
+            *devNames = realloc(*devNames, (numDevices + 2) * sizeof(char *));
+            (*devNames)[numDevices] = strdup(devs[i]->device);
+            (*devNames)[numDevices+1] = NULL;
+            numDevices ++;
+        }
+    }
+    if (!numDevices) {
+        logMessage(ERROR, "no devices found to load drivers from");
+    }
+    return numDevices;
+}
+
+/* Prompt for loading a driver from "media"
+ *
+ * class: type of driver to load.
+ * usecancel: if 1, use cancel instead of back
+ */
+int loadDriverFromMedia(int class, struct loaderData_s *loaderData,
+                        int usecancel, int noprobe, GTree *moduleState) {
+    char * device = NULL, * part = NULL, * ddfile = NULL;
+    char ** devNames = NULL;
+    enum { DEV_DEVICE, DEV_PART, DEV_CHOOSEFILE, DEV_LOADFILE, 
+           DEV_INSERT, DEV_LOAD, DEV_PROBE, 
+           DEV_DONE } stage = DEV_DEVICE;
+    int rc, num = 0;
+    int dir = 1;
+    int found = 0, before = 0;
+
+    while (stage != DEV_DONE) {
+        switch(stage) {
+        case DEV_DEVICE:
+            rc = getRemovableDevices(&devNames);
+            if (rc == 0)
+                return LOADER_BACK;
+
+            /* we don't need to ask which to use if they only have one */
+            if (rc == 1) {
+                device = strdup(devNames[0]);
+                free(devNames);
+                if (dir == -1)
+                    return LOADER_BACK;
+                
+                stage = DEV_PART;
+                break;
+            }
+            dir = 1;
+
+            startNewt();
+            rc = newtWinMenu(_("Driver Disk Source"),
+                             _("You have multiple devices which could serve "
+                               "as sources for a driver disk.  Which would "
+                               "you like to use?"), 40, 10, 10,
+                             rc < 6 ? rc : 6, devNames,
+                             &num, _("OK"), 
+                             (usecancel) ? _("Cancel") : _("Back"), NULL);
+
+            if (rc == 2) {
+                free(devNames);
+                return LOADER_BACK;
+            }
+            device = strdup(devNames[num]);
+            free(devNames);
+
+            stage = DEV_PART;
+        case DEV_PART: {
+            char ** part_list = getPartitionsList(device);
+            int nump = 0, num = 0;
+
+            if (part != NULL)
+                free(part);
+
+            if ((nump = lenPartitionsList(part_list)) == 0) {
+                if (dir == -1)
+                    stage = DEV_DEVICE;
+                else
+                    stage = DEV_INSERT;
+                break;
+            }
+            dir = 1;
+
+            startNewt();
+            rc = newtWinMenu(_("Driver Disk Source"),
+                             _("There are multiple partitions on this device "
+                               "which could contain the driver disk image.  "
+                               "Which would you like to use?"), 40, 10, 10,
+                             nump < 6 ? nump : 6, part_list, &num, _("OK"),
+                             _("Back"), NULL);
+
+            if (rc == 2) {
+                freePartitionsList(part_list);
+                stage = DEV_DEVICE;
+                dir = -1;
+                break;
+            }
+
+            part = strdup(part_list[num]);
+            stage = DEV_CHOOSEFILE;
+
+        }
+
+        case DEV_CHOOSEFILE: {
+            if (part == NULL) {
+                logMessage(ERROR, "somehow got to choosing file with a NULL part, going back");
+                stage = DEV_PART;
+                break;
+            }
+            /* make sure nothing is mounted when we get here */
+            num = umount("/tmp/dpart");
+            if (num == -1) { 
+                logMessage(ERROR, "error unmounting: %m");
+                if ((errno != EINVAL) && (errno != ENOENT))
+                    exit(1);
+            }
+
+            logMessage(INFO, "trying to mount %s as partition", part);
+            if (doPwMount(part, "/tmp/dpart", "auto", "ro", NULL)) {
+                newtWinMessage(_("Error"), _("OK"),
+                               _("Failed to mount partition."));
+                stage = DEV_PART;
+                break;
+            }
+
+            ddfile = newt_select_file(_("Select driver disk image"),
+                                      _("Select the file which is your driver "
+                                        "disk image."),
+                                      "/tmp/dpart", NULL);
+            if (ddfile == NULL) {
+                umount("/tmp/dpart");
+                stage = DEV_PART;
+                dir = -1;
+                break;
+            }
+            dir = 1;
+
+            stage = DEV_LOADFILE;
+        }
+
+        case DEV_LOADFILE: {
+            if (ddfile == NULL) {
+                logMessage(DEBUGLVL, "trying to load dd from NULL");
+                stage = DEV_CHOOSEFILE;
+                break;
+            }
+            if (dir == -1) {
+                umountLoopback("/tmp/drivers", "/dev/loop6");
+                unlink("/tmp/drivers");
+                ddfile = NULL;
+                stage = DEV_CHOOSEFILE;
+                break;
+            }
+            if (mountLoopback(ddfile, "/tmp/drivers", "/dev/loop6")) {
+                newtWinMessage(_("Error"), _("OK"),
+                               _("Failed to load driver disk from file."));
+                stage = DEV_CHOOSEFILE;
+                break;
+            }
+            stage = DEV_LOAD;
+            break;
+        }
+
+        case DEV_INSERT: {
+            char * buf;
+
+            checked_asprintf(&buf,
+                             _("Insert your driver disk into /dev/%s "
+                               "and press \"OK\" to continue."), device);
+
+            rc = newtWinChoice(_("Insert Driver Disk"), _("OK"), _("Back"),
+                               buf);
+            free(buf);
+            if (rc == 2) {
+                stage = DEV_DEVICE;
+                dir = -1;
+                break;
+            }
+            dir = 1;
+
+            logMessage(INFO, "trying to mount %s", device);
+            if (doPwMount(device, "/tmp/drivers", "auto", "ro", NULL)) {
+                newtWinMessage(_("Error"), _("OK"),
+                               _("Failed to mount driver disk."));
+                stage = DEV_INSERT;
+                break;
+            }
+
+            rc = verifyDriverDisk("/tmp/drivers");
+            if (rc == LOADER_BACK) {
+                newtWinMessage(_("Error"), _("OK"),
+                               _("Driver disk is invalid for this "
+                                 "release of %s."), getProductName());
+                umount("/tmp/drivers");
+                stage = DEV_INSERT;
+                break;
+            }
+
+            stage = DEV_LOAD;
+            break;
+        }
+        case DEV_LOAD: {
+            struct device ** devices;
+
+	    before = 0;
+	    found = 0;
+
+            devices = getDevices(class);
+            if (devices)
+                for(; devices[before]; before++);
+
+            rc = loadDriverDisk(loaderData, "/tmp/drivers");
+            umount("/tmp/drivers");
+            if (rc == LOADER_BACK) {
+                dir = -1;
+                if (ddfile != NULL)
+                    stage = DEV_CHOOSEFILE;
+                else
+                    stage = DEV_INSERT;
+                break;
+            }
+            /* fall through to probing */
+            stage = DEV_PROBE;
+
+            if (ddfile != NULL) {
+                umountLoopback("/tmp/drivers", "/dev/loop6");
+                unlink("/tmp/drivers");
+                umount("/tmp/dpart");
+            }
+        }
+
+        case DEV_PROBE: {
+            struct device ** devices;
+
+            /* if they didn't specify that we should probe, then we should
+             * just fall out */
+            if (noprobe) {
+                stage = DEV_DONE;
+                break;
+            }
+
+            /* Unload all devices and load them again to use the updated modules */
+            logMessage(INFO, "Trying to refresh loaded drivers");
+            mlRestoreModuleState(moduleState);
+            busProbe(0);
+
+            devices = getDevices(class);
+            if (devices)
+                for(; devices[found]; found++);
+
+            if (found > before) {
+                stage = DEV_DONE;
+                break;
+            }
+
+            /* we don't have any more modules of the proper class.  ask
+             * them to manually load */
+            rc = newtWinTernary(_("Error"), _("Manually choose"), 
+                                _("Continue"), _("Load another disk"),
+                                _("No devices of the appropriate type were "
+                                  "found on this driver disk.  Would you "
+                                  "like to manually select the driver, "
+                                  "continue anyway, or load another "
+                                  "driver disk?"));
+
+            if (rc == 2) {
+                /* if they choose to continue, just go ahead and continue */
+                stage = DEV_DONE;
+            } else if (rc == 3) {
+                /* if they choose to load another disk, back to the 
+                 * beginning with them */
+                stage = DEV_DEVICE;
+            } else {
+                rc = chooseManualDriver(class, loaderData);
+                /* if they go back from a manual driver, we'll ask again.
+                 * if they load something, assume it's what we need */
+                if (rc == LOADER_OK) {
+                    stage = DEV_DONE;
+                }
+            }
+
+            break;
+        }
+
+        case DEV_DONE:
+            break;
+        }
+    }
+
+    return LOADER_OK;
+}
+
+
+/* looping way to load driver disks */
+int loadDriverDisks(int class, struct loaderData_s *loaderData, GTree *moduleState) {
+    int rc;
+
+    rc = newtWinChoice(_("Driver disk"), _("Yes"), _("No"), 
+                       _("Do you have a driver disk?"));
+    if (rc != 1)
+        return LOADER_OK;
+
+    rc = loadDriverFromMedia(DEVICE_ANY, loaderData, 1, 0, moduleState);
+    if (rc == LOADER_BACK)
+        return LOADER_OK;
+
+    do {
+        rc = newtWinChoice(_("More Driver Disks?"), _("Yes"), _("No"),
+                           _("Do you wish to load any more driver disks?"));
+        if (rc != 1)
+            break;
+        loadDriverFromMedia(DEVICE_ANY, loaderData, 0, 0, moduleState);
+    } while (1);
+
+    return LOADER_OK;
+}
+
+static void loadFromLocation(struct loaderData_s * loaderData, char * dir, GTree *moduleState) {
+    if (verifyDriverDisk(dir) == LOADER_BACK) {
+        logMessage(ERROR, "not a valid driver disk");
+        return;
+    }
+
+    loadDriverDisk(loaderData, dir);
+
+    /* Unload all devices and load them again to use the updated modules */
+    logMessage(INFO, "Trying to refresh loaded drivers");
+    mlRestoreModuleState(moduleState);
+    busProbe(0);
+}
+
+void getDDFromSource(struct loaderData_s * loaderData, char * src, GTree *moduleState) {
+    char *path = "/tmp/dd.img";
+    int unlinkf = 0;
+
+    if (!strncmp(src, "nfs:", 4)) {
+        unlinkf = 1;
+        if (getFileFromNfs(src + 4, "/tmp/dd.img", loaderData)) {
+            logMessage(ERROR, "unable to retrieve driver disk: %s", src);
+            return;
+        }
+    } else if (!strncmp(src, "ftp://";, 6) || !strncmp(src, "http", 4)) {
+        unlinkf = 1;
+        if (getFileFromUrl(src, "/tmp/dd.img", loaderData)) {
+            logMessage(ERROR, "unable to retrieve driver disk: %s", src);
+            return;
+        }
+    /* FIXME: this is a hack so that you can load a driver disk from, eg, 
+     * scsi cdrom drives */
+#if !defined(__s390__) && !defined(__s390x__)
+    } else if (!strncmp(src, "cdrom", 5)) {
+        loadDriverDisks(DEVICE_ANY, loaderData, moduleState);
+        return;
+#endif
+    } else if (!strncmp(src, "path:", 5)) {
+	path = src + 5;
+    } else {
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("Unknown driver disk kickstart source: %s"), src);
+        return;
+    }
+
+    if (!mountLoopback(path, "/tmp/drivers", "/dev/loop6")) {
+        loadFromLocation(loaderData, "/tmp/drivers", moduleState);
+        umountLoopback("/tmp/drivers", "/dev/loop6");
+        unlink("/tmp/drivers");
+        if (unlinkf) unlink(path);
+    }
+
+}
+
+static void getDDFromDev(struct loaderData_s * loaderData, char * dev, GTree *moduleState);
+
+void useKickstartDD(struct loaderData_s * loaderData,
+                    int argc, char ** argv) {
+    char * dev = NULL;
+    char * biospart = NULL, * p = NULL; 
+    gchar *fstype = NULL, *src = NULL;
+    gint usebiosdev = 0;
+    gchar **remaining = NULL;
+    GOptionContext *optCon = g_option_context_new(NULL);
+    GError *optErr = NULL;
+    GOptionEntry ksDDOptions[] = {
+        /* The --type option is deprecated and now has no effect. */
+        { "type", 0, 0, G_OPTION_ARG_STRING, &fstype, NULL, NULL },
+        { "source", 0, 0, G_OPTION_ARG_STRING, &src, NULL, NULL },
+        { "biospart", 0, 0, G_OPTION_ARG_INT, &usebiosdev, NULL, NULL },
+        { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &remaining,
+          NULL, NULL },
+        { NULL },
+    };
+
+    g_option_context_set_help_enabled(optCon, FALSE);
+    g_option_context_add_main_entries(optCon, ksDDOptions, NULL);
+
+    if (!g_option_context_parse(optCon, &argc, &argv, &optErr)) {
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("The following invalid argument was specified for "
+                         "the kickstart driver disk command: %s"),
+                       optErr->message);
+        g_error_free(optErr);
+        g_option_context_free(optCon);
+        g_strfreev(remaining);
+        return;
+    }
+
+    g_option_context_free(optCon);
+
+    if ((remaining != NULL) && (g_strv_length(remaining) == 1)) {
+        dev = remaining[0];
+    }
+
+    if (!dev && !src) {
+        logMessage(ERROR, "bad arguments to kickstart driver disk command");
+        return;
+    }
+
+    if (usebiosdev != 0) {
+        p = strchr(dev,'p');
+        if (!p){
+            logMessage(ERROR, "Bad argument for biospart");
+            return;
+        }
+        *p = '\0';
+        
+        biospart = getBiosDisk(dev);
+        if (biospart == NULL) {
+            logMessage(ERROR, "Unable to locate BIOS dev %s",dev);
+            return;
+        }
+        dev = malloc(strlen(biospart) + strlen(p + 1) + 2);
+        sprintf(dev, "%s%s", biospart, p + 1);
+    }
+
+    if (dev) {
+        getDDFromDev(loaderData, dev, NULL);
+    } else {
+        getDDFromSource(loaderData, src, NULL);
+    }
+
+    g_strfreev(remaining);
+    return;
+}
+
+static void getDDFromDev(struct loaderData_s * loaderData, char * dev, GTree* moduleState) {
+    if (doPwMount(dev, "/tmp/drivers", "auto", "ro", NULL)) {
+        logMessage(ERROR, "unable to mount driver disk %s", dev);
+        return;
+    }
+
+    loadFromLocation(loaderData, "/tmp/drivers", moduleState);
+    umount("/tmp/drivers");
+    unlink("/tmp/drivers");
+}
+
+
+/*
+ * Look for partition with specific label (part of #316481)
+ */
+GSList* findDriverDiskByLabel(void)
+{
+    char *ddLabel = "OEMDRV";
+    GSList *ddDevice = NULL;
+    blkid_cache bCache;
+    
+    int res;
+    blkid_dev_iterate bIter;
+    blkid_dev bDev;
+
+    if (blkid_get_cache(&bCache, NULL)<0) {
+        logMessage(ERROR, "Cannot initialize cache instance for blkid");
+        return NULL;
+    }
+    if ((res = blkid_probe_all(bCache))<0) {
+        logMessage(ERROR, "Cannot probe devices in blkid: %d", res);
+        return NULL;
+    }
+    if ((res = blkid_probe_all_removable(bCache))<0) {
+        logMessage(ERROR, "Cannot probe removable devices in blkid: %d", res);
+    }
+
+    bIter = blkid_dev_iterate_begin(bCache);
+    blkid_dev_set_search(bIter, "LABEL", ddLabel);
+    while ((res = blkid_dev_next(bIter, &bDev)) == 0) {
+        bDev = blkid_verify(bCache, bDev);
+        if (!bDev)
+            continue;
+
+        char *devname = strdup(blkid_dev_devname(bDev));
+        logMessage(DEBUGLVL, "Adding driver disc %s to the list "
+                             "of available DDs.", devname);
+        ddDevice = g_slist_prepend(ddDevice, (gpointer)devname);
+        /* Freeing bDev is taken care of by the put cache call */
+    }
+    blkid_dev_iterate_end(bIter);
+
+    blkid_put_cache(bCache);
+
+    return ddDevice;
+}
+
+int loadDriverDiskFromPartition(struct loaderData_s *loaderData, char* device)
+{
+    int rc;
+
+    logMessage(INFO, "trying to mount %s", device);
+    if (doPwMount(device, "/tmp/drivers", "auto", "ro", NULL)) {
+        logMessage(ERROR, "Failed to mount driver disk.");
+        return -1;
+    }
+
+    rc = verifyDriverDisk("/tmp/drivers");
+    if (rc == LOADER_BACK) {
+        logMessage(ERROR, "Driver disk is invalid for this "
+                "release of %s.", getProductName());
+        umount("/tmp/drivers");
+        return -2;
+    }
+
+    rc = loadDriverDisk(loaderData, "/tmp/drivers");
+    umount("/tmp/drivers");
+    if (rc == LOADER_BACK) {
+        return -3;
+    }
+
+    return 0;
+}
+
diff --git a/bin/loader/driverdisk.h b/bin/loader/driverdisk.h
new file mode 100644
index 0000000..4dc8685
--- /dev/null
+++ b/bin/loader/driverdisk.h
@@ -0,0 +1,51 @@
+/*
+ * driverdisk.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DRIVERDISK_H
+#define DRIVERDISK_H
+
+#include "loader.h"
+#include "modules.h"
+#include "moduleinfo.h"
+
+#define DD_RPMDIR_TEMPLATE "/tmp/DD-%d"
+#define DD_EXTRACTED "/tmp/DD"
+#define DD_MODULES "/tmp/DD/lib/modules"
+#define DD_FIRMWARE "/tmp/DD/lib/firmware"
+
+extern char *ddFsTypes[];
+
+int loadDriverFromMedia(int class, struct loaderData_s *loaderData,
+                        int usecancel, int noprobe, GTree *moduleState);
+
+int loadDriverDisks(int class, struct loaderData_s *loaderData, GTree *moduleState);
+
+int getRemovableDevices(char *** devNames);
+
+int chooseManualDriver(int class, struct loaderData_s *loaderData);
+void useKickstartDD(struct loaderData_s * loaderData, int argc, 
+                    char ** argv);
+
+void getDDFromSource(struct loaderData_s * loaderData, char * src, GTree *moduleState);
+
+int loadDriverDiskFromPartition(struct loaderData_s *loaderData, char* device);
+
+GSList* findDriverDiskByLabel(void);
+
+#endif
diff --git a/bin/loader/driverselect.c b/bin/loader/driverselect.c
new file mode 100644
index 0000000..85b777b
--- /dev/null
+++ b/bin/loader/driverselect.c
@@ -0,0 +1,251 @@
+/*
+ * driverselect.c - functionality for manually selecting drivers
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <ctype.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "../isys/log.h"
+
+#include "modules.h"
+#include "moduleinfo.h"
+#include "loader.h"
+#include "loadermisc.h"
+#include "lang.h"
+#include "driverdisk.h"
+
+struct sortModuleList {
+    int index;
+    moduleInfoSet modInfo;
+};
+
+static int sortDrivers(const void * a, const void * b) {
+    const struct sortModuleList * one = a;
+    const struct sortModuleList * two = b;
+
+    return strcmp(one->modInfo->moduleList[one->index].description,
+                  one->modInfo->moduleList[two->index].description);
+}
+
+static int getManualModuleArgs(struct moduleInfo * mod, gchar *** moduleArgs) {
+    newtGrid grid, buttons;
+    newtComponent text, f, ok, back, entry;
+    struct newtExitStruct es;
+    int done = 0, i;
+    char * buf;
+    char *argsEntry = "";
+
+    if (*moduleArgs) {
+        for (i = 0; (*moduleArgs)[i]; i++)
+            argsEntry = strcat(argsEntry, (*moduleArgs)[i]);
+    }
+
+    f = newtForm(NULL, NULL, 0);
+    checked_asprintf(&buf,
+                     _("Please enter any parameters which you wish to pass "
+                       "to the %s module separated by spaces.  If you don't "
+                       "know what parameters to supply, skip this screen "
+                       "by pressing the \"OK\" button."), mod->moduleName);
+
+    text = newtTextboxReflowed(-1, -1, buf, 60, 0, 10, 0);
+    entry = newtEntry(-1, -1, argsEntry, 50, (const char **) &argsEntry, 
+                      NEWT_ENTRY_SCROLL);
+    
+    newtFormAddHotKey(f, NEWT_KEY_F12);
+    
+    buttons = newtButtonBar(_("OK"), &ok, _("Back"), &back, NULL);
+    
+    grid = newtCreateGrid(1, 3);
+    newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
+                     0, 0, 0, 1, 0, 0);
+    newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, entry, 
+                     0, 0, 0, 1, 0, 0);
+    newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
+                     0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+    
+    newtGridWrappedWindow(grid, _("Enter Module Parameters"));
+    newtGridAddComponentsToForm(grid, f, 1);
+    
+    do {
+        newtFormRun(f, &es);
+
+        if (es.reason  == NEWT_EXIT_COMPONENT && es.u.co == back) {
+            done = -1;
+        } else {
+            done = 1;
+        }
+    } while (done == 0);
+
+    free(buf);
+    newtGridFree(grid, 1);
+
+    if (done == -1) {
+        newtFormDestroy(f);
+        newtPopWindow();
+
+        return LOADER_BACK;
+    }
+    logMessage(INFO, "specified args of %s for %s", argsEntry, mod->moduleName);
+
+    if (strlen(argsEntry) > 0) {
+        *moduleArgs = g_strsplit(argsEntry, " ", 0);
+    }
+
+    newtFormDestroy(f);
+    newtPopWindow();
+
+    return LOADER_OK;
+}
+
+int chooseManualDriver(int class, struct loaderData_s *loaderData) {
+    int i, numSorted, num = 0, done = 0;
+    enum driverMajor type;
+    struct sortModuleList * sortedOrder;
+    char giveArgs = ' ';
+    gchar **moduleArgs = NULL;
+    moduleInfoSet modInfo = loaderData->modInfo;
+
+    newtComponent text, f, ok, back, argcheckbox, listbox;
+    newtGrid grid, buttons;
+    struct newtExitStruct es;
+
+    if (class == DEVICE_NETWORK)
+        type = DRIVER_NET;
+    else if (class == DEVICE_DISK || class == DEVICE_CDROM)
+        type = DRIVER_SCSI;
+    else
+        type = DRIVER_ANY;
+
+    do {
+        sortedOrder = malloc(sizeof(*sortedOrder) * modInfo->numModules);
+        numSorted = 0;
+        
+        for (i = 0; i < modInfo->numModules; i++) {
+            sortedOrder[numSorted].index = i;
+            sortedOrder[numSorted++].modInfo = modInfo;
+        }
+        
+        if (numSorted == 0) {
+            i = newtWinChoice(_("No drivers found"), _("Load driver disk"), 
+                              _("Back"), _("No drivers were found to manually "
+                                           "insert.  Would you like to use "
+                                           "a driver disk?"));
+            if (i != 1)
+                return LOADER_BACK;
+            
+            loadDriverFromMedia(class, loaderData, 1, 1, NULL);
+            continue;
+        } else {
+            break;
+        }
+    } while (1);
+        
+    qsort(sortedOrder, numSorted, sizeof(*sortedOrder), sortDrivers);
+
+    f = newtForm(NULL, NULL, 0);
+
+    text = newtTextboxReflowed(-1, -1,
+                               _("Please select the driver below which you "
+                                 "wish to load.  If it does not appear and "
+                                 "you have a driver disk, press F2."),
+                               60, 0, 10, 0);
+
+    listbox = newtListbox(-1, -1, 6, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
+    newtListboxSetWidth(listbox, 55);
+
+    buttons = newtButtonBar(_("OK"), &ok, _("Back"), &back, NULL);
+    argcheckbox = newtCheckbox(-1, -1, _("Specify optional module arguments"),
+                               giveArgs, NULL, &giveArgs);
+
+    newtFormAddHotKey(f, NEWT_KEY_F2);
+    newtFormAddHotKey(f, NEWT_KEY_F12);
+
+    for (i = 0; i < numSorted; i++) {
+        char *buf = NULL;
+
+        checked_asprintf(&buf, "%s (%s)", 
+                         modInfo->moduleList[sortedOrder[i].index].description,
+                         modInfo->moduleList[sortedOrder[i].index].moduleName);
+
+        newtListboxAppendEntry(listbox, buf, 
+                INT_TO_POINTER(sortedOrder[i].index));
+    }
+
+    grid = newtCreateGrid(1, 4);
+    newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text, 0, 0, 0, 1, 0, 0);
+    newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, listbox, 
+                     0, 0, 0, 1, 0, 0);
+    newtGridSetField(grid, 0, 2, NEWT_GRID_COMPONENT, argcheckbox,
+                     0, 0, 0, 1, 0, 0);
+    newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, buttons, 
+                     0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+    newtGridWrappedWindow(grid, _("Select Device Driver to Load"));
+
+    newtGridAddComponentsToForm(grid, f, 1);
+
+    do { 
+        newtFormRun(f, &es);
+
+        num = POINTER_TO_INT(newtListboxGetCurrent(listbox));
+
+        if (es.reason == NEWT_EXIT_COMPONENT && es.u.co == back) {
+            done = -1;
+        } else if (es.reason == NEWT_EXIT_HOTKEY && es.u.key == NEWT_KEY_F2) {
+            done = -2;
+        } else {
+            if (giveArgs != ' ') {
+                i = getManualModuleArgs(&(modInfo->moduleList[num]),
+                                        &moduleArgs);
+                if (i == LOADER_BACK)
+                    done = 0;
+                else
+                    done = 1;
+            } else {
+                done = 1;
+            }
+        }
+    } while (done == 0);
+
+    newtGridFree(grid, 1);
+    newtFormDestroy(f);
+    newtPopWindow();
+
+    if (done == -1) 
+        return LOADER_BACK;
+    if (done == -2) {
+        loadDriverFromMedia(class, loaderData, 1, 1, NULL);
+        return chooseManualDriver(class, loaderData);
+    }
+
+    mlLoadModule(modInfo->moduleList[num].moduleName, moduleArgs);
+    free(sortedOrder);
+
+    if (moduleArgs) {
+        g_strfreev(moduleArgs);
+    }
+
+    return LOADER_OK;
+}
diff --git a/bin/loader/fwloader.c b/bin/loader/fwloader.c
new file mode 100644
index 0000000..5ad1d8e
--- /dev/null
+++ b/bin/loader/fwloader.c
@@ -0,0 +1,675 @@
+/*
+ * fwloader.c -- a small firmware loader.
+ *
+ * Copyright (C) 2006, 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Peter Jones (pjones redhat com)
+ */
+
+#define _GNU_SOURCE 1
+
+#include <argz.h>
+#include <envz.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <asm/types.h>
+#include <linux/netlink.h>
+
+#include "../isys/log.h"
+
+#include "loader.h"
+#include "fwloader.h"
+#include "udelay.h"
+
+#ifndef FWDEBUG
+#define logMessage(x, ...)
+#endif
+
+struct fw_loader {
+    int netlinkfd;
+    sigset_t sigmask;
+    char *fw_pathz;
+    size_t fw_pathz_len;
+    struct pollfd *fds;
+};
+
+int done = 0;
+
+static inline int set_fd_coe(int fd, int enable)
+{
+    int rc;
+    long flags = 0;
+
+    rc = fcntl(fd, F_GETFD, &flags);
+    if (rc < 0)
+        return rc;
+
+    if (enable)
+        flags |= FD_CLOEXEC;
+    else
+        flags &= ~FD_CLOEXEC;
+
+    rc = fcntl(fd, F_SETFD, flags);
+    return rc;
+}
+
+static int open_uevent_socket(struct fw_loader *fwl)
+{
+    int fd, rc;
+    struct sockaddr_nl sa;
+
+    fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+    if (fd < 0)
+        return -1;
+    set_fd_coe(fd, 1);
+
+    memset(&sa, '\0', sizeof (sa));
+    sa.nl_family = AF_NETLINK;
+    sa.nl_pid = getpid();
+    sa.nl_groups = -1;
+
+    if (bind(fd, (struct sockaddr *)&sa, sizeof (sa)) < 0) {
+        close(fd);
+        return -1;
+    }
+
+    fwl->netlinkfd = fd;
+
+    fd = open("/proc/sys/kernel/hotplug", O_RDWR);
+    if (fd >= 0) {
+        rc = ftruncate(fd, 0);
+        rc = write(fd, "\n", 1);
+        close(fd);
+    }
+
+    fd = open("/sys/class/firmware/timeout", O_RDWR);
+    if (fd >= 0) {
+        rc = write(fd, "10", 2);
+        close(fd);
+    }
+
+    return 0;
+}
+
+extern void loaderSegvHandler(int signum);
+
+static void kill_hotplug_signal(int signum)
+{
+    signal(signum, kill_hotplug_signal);
+    logMessage(DEBUGLVL, "fwloader: got exit signal, quitting");
+    done = 1;
+}
+
+static int daemonize(struct fw_loader *fwl)
+{
+    int fd;
+    int rc;
+
+    signal(SIGTERM, kill_hotplug_signal);
+    signal(SIGSEGV, loaderSegvHandler);
+    signal(SIGTTOU, SIG_IGN);
+    signal(SIGTTIN, SIG_IGN);
+    signal(SIGTSTP, SIG_IGN);
+
+    sigfillset(&fwl->sigmask);
+    sigdelset(&fwl->sigmask, SIGTERM);
+    sigdelset(&fwl->sigmask, SIGSEGV);
+    sigemptyset(&fwl->sigmask);
+
+    prctl(PR_SET_NAME, "hotplug", 0, 0, 0);
+    rc = chdir("/");
+
+    fd = open("/proc/self/oom_adj", O_RDWR);
+    if (fd >= 0) {
+        rc = write(fd, "-17", 3);
+        close(fd);
+    }
+
+    for (fd = 0; fd < getdtablesize(); fd++) {
+        if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
+            continue;
+        if (fd == tty_logfd || fd == file_logfd)
+            continue;
+        close(fd);
+    }
+
+    setsid();
+    fd = open("/dev/null", O_RDONLY);
+    close(STDIN_FILENO);
+    dup2(fd, STDIN_FILENO);
+    set_fd_coe(STDIN_FILENO, 1);
+    close(fd);
+    fd = open("/dev/null", O_WRONLY);
+    close(STDOUT_FILENO);
+    dup2(fd, STDOUT_FILENO);
+    set_fd_coe(STDOUT_FILENO, 1);
+    close(STDERR_FILENO);
+    dup2(fd, STDERR_FILENO);
+    set_fd_coe(STDERR_FILENO, 1);
+    close(fd);
+
+    logMessage(DEBUGLVL, "fwloader: starting up (pid %d)", getpid());
+    return 0;
+}
+
+struct uevent {
+    char *msg;
+    char *path;
+    char *envz;
+    size_t envz_len;
+};
+
+static int get_netlink_msg(struct fw_loader *fwl, struct uevent *uevent)
+{
+    size_t len;
+    ssize_t size;
+    static char buffer[2560];
+    char *pos;
+    char *msg = NULL, *path = NULL, *envz = NULL;
+    char *argv[] = { NULL };
+    size_t envz_len;
+    error_t errnum;
+
+    size = recv(fwl->netlinkfd, &buffer, sizeof (buffer), 0);
+    if (size < 0)
+        return -1;
+
+    if ((size_t)size > sizeof (buffer) - 1)
+        size = sizeof (buffer) - 1;
+    buffer[size] = '\0';
+
+    len = strcspn(buffer, "@");
+    if (!buffer[len])
+        return -1;
+
+    if ((errnum = argz_create(argv, &envz, &envz_len)) > 0)
+        goto err;
+
+    pos = buffer;
+    msg = strndup(pos, len++);
+    pos += len;
+    path = strdup(pos);
+
+    pos += strlen(pos) + 1;
+    if (len < size + 1) {
+        while (pos[0]) {
+            char *value = strchr(pos, '=');
+            if (value)
+                *(value++) = '\0';
+
+            if ((errnum = envz_add(&envz, &envz_len, pos, value)) > 0)
+                goto err;
+            pos += strlen(pos) + 1;
+            if (*pos)
+                pos += strlen(pos) + 1;
+        }
+    }
+
+    uevent->msg = msg;
+    uevent->path = path;
+    uevent->envz = envz;
+    uevent->envz_len = envz_len;
+    return 0;
+err:
+    if (msg)
+        free(msg);
+    if (path)
+        free(path);
+    while(envz)
+        argz_delete(&envz, &envz_len, envz);
+    errno = errnum;
+    return -1;
+}
+
+/* Set the 'loading' attribute for a firmware device.
+ * 1 == currently loading
+ * 0 == done loading
+ * -1 == error
+ */
+static int
+get_loading_fd(const char *device)
+{
+    int fd = -1;
+    char *loading_path = NULL;
+
+    if (asprintf(&loading_path, "%s/loading", device) < 0) {
+        logMessage(ERROR, "fwloader: device %s: asprintf: %m", device);
+        return -1;
+    }
+    logMessage(DEBUGLVL, "fwloader: looking for loading file at %s", loading_path);
+    fd = open(loading_path, O_RDWR | O_SYNC );
+    if (fd < 0)
+        logMessage(ERROR, "fwloader: open %s: %m", loading_path);
+    free(loading_path);
+    return fd;
+}
+
+static int
+set_loading(int fd, int value)
+{
+    int rc = 0;
+
+    if (value == -1)
+        rc = write(fd, "-1", 3);
+    else if (value == 0)
+        rc = write(fd, "0", 2);
+    else if (value == 1)
+        rc = write(fd, "1", 2);
+    fsync(fd);
+    fdatasync(fd);
+
+    return rc < 0 ? rc : 0;
+}
+
+static int
+fd_map(int fd, char **buf, size_t *bufsize)
+{
+    struct stat stats;
+    int en = 0;
+
+    if (fstat(fd, &stats) < 0) {
+        en = errno;
+        close(fd);
+        errno = en;
+        return -1;
+    }
+
+    *buf = mmap(NULL, stats.st_size, PROT_READ, MAP_SHARED, fd, 0);
+    if (*buf == MAP_FAILED) {
+        *buf = NULL;
+        en = errno;
+        close(fd);
+        errno = en;
+        return -1;
+    }
+    *bufsize = stats.st_size;
+    return 0;
+}
+
+static int
+file_map(const char *filename, char **buf, size_t *bufsize, int flags)
+{
+    int fd, en, rc = 0;
+
+    if ((fd = open(filename, flags ? flags : O_RDONLY)) < 0)
+        return -1;
+
+    if (fd_map(fd, buf, bufsize) < 0)
+        rc = -1;
+
+    en = errno;
+    close(fd);
+    errno = en;
+
+    return rc;
+}
+
+static void
+file_unmap(void *buf, size_t bufsize)
+{
+    munmap(buf, bufsize);
+}
+
+static int
+fetcher(char *inpath, int outfd)
+{
+    char *inbuf = NULL;
+    size_t inlen;
+    int count;
+    int en = 0;
+    int rc;
+
+    errno = 0;
+    if (access(inpath, F_OK))
+        goto out;
+
+    if (file_map(inpath, &inbuf, &inlen, O_RDONLY) < 0)
+        goto out;
+
+    lseek(outfd, 0, SEEK_SET);
+    rc = ftruncate(outfd, 0);
+    rc = ftruncate(outfd, inlen);
+
+    count = 0;
+    while (count < inlen) {
+        ssize_t c;
+        c = write(outfd, inbuf + count, inlen - count);
+        if (c <= 0)
+            goto out;
+        count += c;
+    }
+
+out:
+    en = errno;
+    if (inbuf)
+        file_unmap(inbuf, inlen);
+    if (en) {
+        errno = en;
+        return -1;
+    }
+    return 0;
+}
+
+
+static int
+_load_firmware(struct fw_loader *fwl, int fw_fd, char *sysdir, int timeout)
+{
+    int rc = 0;
+    char *fw_buf = NULL, *data = NULL;
+    size_t fw_len = 0;
+    int dfd = -1, lfd = -1;
+    int loading = -2;
+    size_t count;
+
+    logMessage(DEBUGLVL, "fwloader: waiting for firmware dir at %s", sysdir);
+    timeout *= 1000000;
+    while (access(sysdir, F_OK) && timeout) {
+        udelay(100);
+        timeout -= 100;
+    }
+    if (!timeout) {
+        logMessage(ERROR, "fwloader: never found firmware dir at %s", sysdir);
+        return -ENOENT;
+    }
+
+    if ((lfd = get_loading_fd(sysdir)) < 0)
+        return lfd;
+
+    set_loading(lfd, 1);
+    loading = -1;
+
+    if (fd_map(fw_fd, &fw_buf, &fw_len) < 0) {
+        rc = -errno;
+        goto out;
+    }
+
+    if (asprintf(&data, "%s/data", sysdir) < 0) {
+        rc = -errno;
+        goto out;
+    }
+    if ((dfd = open(data, O_RDWR)) < 0) {
+        rc = -errno;
+        goto out;
+    }
+    count = 0;
+    while (count < fw_len) {
+        ssize_t c;
+        if ((c = write(dfd, fw_buf + count, fw_len - count)) <= 0)
+            goto out;
+        count += c;
+    }
+    loading = 0;
+
+out:
+    if (dfd >= 0)
+        close(dfd);
+    if (fw_buf)
+        file_unmap(fw_buf, fw_len);
+    if (loading != -2)
+        set_loading(lfd, loading);
+    if (lfd >= 0)
+        close(lfd);
+    if (data)
+        free(data);
+
+    return rc;
+}
+
+static void load_firmware(struct fw_loader *fwl, struct uevent *uevent)
+{
+    char *devpath = NULL, *firmware = NULL, *timeout;
+    char *fw_file = NULL, *sys_file = NULL;
+    char *entry;
+    int timeout_secs;
+    char *tempfile;
+    int fd = -1;
+
+    tempfile = strdup("/tmp/fw-XXXXXX");
+    fd = mkstemp(tempfile);
+    if (fd < 0) {
+        logMessage(ERROR, "fwloader: mkstemp(\"%s\") failed: %m", tempfile);
+        free(tempfile);
+        return;
+    }
+    unlink(tempfile);
+    free(tempfile);
+
+    devpath = envz_get(uevent->envz, uevent->envz_len, "DEVPATH");
+    firmware = envz_get(uevent->envz, uevent->envz_len, "FIRMWARE");
+    timeout = envz_get(uevent->envz, uevent->envz_len, "TIMEOUT");
+    
+    if (!devpath || !firmware) {
+        argz_stringify(uevent->envz, uevent->envz_len, ' ');
+        logMessage(ERROR, "fwloader: environment: %s", uevent->envz);
+        return;
+    }
+
+    errno = 0;
+    timeout_secs = strtol(timeout, NULL, 10);
+
+    if ((errno == ERANGE && (timeout_secs == LONG_MIN ||
+                             timeout_secs == LONG_MAX)) ||
+        (errno != 0 && timeout_secs == 0)) {
+        logMessage(ERROR, "%s: %d: %m", __func__, __LINE__);
+        abort();
+    }
+
+    /* find the file */
+    for (entry = fwl->fw_pathz; entry;
+            entry = argz_next(fwl->fw_pathz, fwl->fw_pathz_len, entry)) {
+        if (asprintf(&fw_file, "%s/%s", entry, firmware) < 0)
+            return;
+
+        logMessage(INFO, "fwloader: trying to find %s at %s", firmware, fw_file);
+
+        if (fetcher(fw_file, fd) >= 0)
+            break;
+
+        free(fw_file);
+        fw_file = NULL;
+        if (errno == ENOENT || errno == EPERM)
+            continue;
+        break;
+    }
+    if (!fw_file)
+        goto out;
+
+    if (asprintf(&sys_file, "/sys%s/", devpath) < 0)
+        goto out;
+
+    _load_firmware(fwl, fd, sys_file, timeout_secs);
+
+out:
+    if (fw_file)
+        free(fw_file);
+    if (sys_file)
+        free(sys_file);
+    if (fd != -1)
+        close(fd);
+}
+
+static void handle_single_uevent(struct fw_loader *fwl, struct uevent *uevent)
+{
+    char *action = NULL;
+    char *subsystem = NULL;
+
+    action = envz_get(uevent->envz, uevent->envz_len, "ACTION");
+    subsystem = envz_get(uevent->envz, uevent->envz_len, "SUBSYSTEM");
+
+    logMessage(DEBUGLVL, "fwloader: subsystem %s got action %s", subsystem, action);
+    if (!strcmp(action, "add") && !strcmp(subsystem, "firmware"))
+        load_firmware(fwl, uevent);
+}
+
+static void handle_events(struct fw_loader *fwl)
+{
+    int rc;
+    struct uevent uevent;
+    if (fwl->fds == NULL)
+        fwl->fds = calloc(1, sizeof (struct pollfd));
+
+    do {
+        do {
+            if (done)
+                exit(0);
+            fwl->fds[0].events = POLLIN | POLLPRI;
+            fwl->fds[0].revents = 0;
+            fwl->fds[0].fd = fwl->netlinkfd;
+
+            //logMessage(DEBUGLVL, "fwloader: polling on netlink socket");
+            errno = 0;
+            rc = poll(fwl->fds, 1, -1);
+            //logMessage(DEBUGLVL, "fwloader: poll returned %d", rc);
+
+            if (done)
+                exit(0);
+        } while (rc < 1 || (rc < 0 && errno == EINTR));
+
+        memset(&uevent, '\0', sizeof (uevent));
+        if (get_netlink_msg(fwl, &uevent) < 0)
+            continue;
+
+        handle_single_uevent(fwl, &uevent);
+    } while (1);
+
+    if (fwl->fds) {
+        free(fwl->fds);
+        fwl->fds = NULL;
+    }
+}
+
+void set_fw_search_path(struct loaderData_s *loaderData, char *path)
+{
+    char *old = loaderData->fw_search_pathz, *new = NULL;
+    size_t old_len = loaderData->fw_search_pathz_len;
+
+    loaderData->fw_search_pathz = NULL;
+    loaderData->fw_search_pathz_len = -1;
+    if (!path) {
+        if (old)
+            free(old);
+        return;
+    }
+
+    if ((new = strdup(path)) == NULL)
+        goto out;
+
+    loaderData->fw_search_pathz = NULL;
+    loaderData->fw_search_pathz_len = 0;
+    if (argz_create_sep(new, ':', &loaderData->fw_search_pathz,
+                &loaderData->fw_search_pathz_len) != 0)
+        goto out;
+
+    if (old)
+        free(old);
+
+    return;
+out:
+    if (new)
+        free(new);
+    loaderData->fw_search_pathz = old;
+    loaderData->fw_search_pathz_len = old_len;
+
+    return;
+}
+
+void add_fw_search_dir(struct loaderData_s *loaderData, char *dir)
+{
+    argz_add(&loaderData->fw_search_pathz, &loaderData->fw_search_pathz_len,
+            dir);
+}
+
+void do_fw_loader(struct loaderData_s *loaderData)
+{
+    struct fw_loader fwl;
+    int rc;
+
+    memset(&fwl, '\0', sizeof (fwl));
+    fwl.netlinkfd = -1;
+
+    fwl.fw_pathz = loaderData->fw_search_pathz;
+    fwl.fw_pathz_len = loaderData->fw_search_pathz_len;
+
+    logMessage(INFO, "fwloader: starting firmware loader");
+
+    rc = daemonize(&fwl);
+    if (rc < 0) {
+        logMessage(ERROR, "fwloader: daemonize() failed with %d: %m", rc);
+        exit(1);
+    }
+
+    if (open_uevent_socket(&fwl) < 0) {
+        logMessage(ERROR, "fwloader: open_uevent_socket() failed: %m");
+        exit(1);
+    }
+
+    logMessage(DEBUGLVL, "fwloader: entering event loop");
+    handle_events(&fwl);
+
+    exit(1);
+}
+
+
+void start_fw_loader(struct loaderData_s *loaderData) {
+    pid_t loader;
+
+    loader = fork();
+    if (loader > 0)
+        loaderData->fw_loader_pid = loader;
+    if (loader != 0)
+        return;
+    
+    do_fw_loader(loaderData);
+}
+
+void stop_fw_loader(struct loaderData_s *loaderData) {
+    int x = 0, rc;
+    siginfo_t siginfo;
+    if (loaderData->fw_loader_pid > 0)
+        kill(loaderData->fw_loader_pid, SIGTERM);
+    while (x <= 100) {
+        if (x > 90)
+            kill(loaderData->fw_loader_pid, SIGKILL);
+        memset(&siginfo, '\0', sizeof (siginfo));
+        rc = waitid(P_PID, loaderData->fw_loader_pid, &siginfo, WNOHANG|WEXITED);
+        if (rc < 0 && errno == ECHILD)
+            return;
+        else if (rc == 0 && siginfo.si_pid != 0)
+            return;
+        else if (rc == 0)
+            x++;
+        usleep(10000);
+    }
+    return;
+}
+
+
+/*
+ * vim:ts=8:sw=4:sts=4:et
+ */
diff --git a/bin/loader/fwloader.h b/bin/loader/fwloader.h
new file mode 100644
index 0000000..e0b0fe8
--- /dev/null
+++ b/bin/loader/fwloader.h
@@ -0,0 +1,35 @@
+/*
+ * fwloader.h -- a small firmware loader.
+ *
+ * Copyright (C) 2006, 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Peter Jones <pjones redhat com>
+ */
+
+#ifndef FWLOADER_H
+#define FWLOADER_H 1
+
+#include "loader.h"
+
+extern void set_fw_search_path(struct loaderData_s *loaderData, char *path);
+extern void add_fw_search_dir(struct loaderData_s *loaderData, char *dir);
+extern void start_fw_loader(struct loaderData_s *loaderData);
+extern void stop_fw_loader(struct loaderData_s *loaderData);
+
+#endif /* FWLOADER_H */
+/*
+ * vim:ts=8:sw=4:sts=4:et
+ */
diff --git a/bin/loader/getparts.c b/bin/loader/getparts.c
new file mode 100644
index 0000000..c60dc83
--- /dev/null
+++ b/bin/loader/getparts.c
@@ -0,0 +1,180 @@
+/*
+ * getparts.c - functions associated with getting partitions for a disk
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "../isys/log.h"
+
+/* see if this is a partition name or not */
+static int isPartitionName(char *pname) {
+
+    /* if it doesnt start with a alpha its not one */
+    if (!isalpha(*pname) || strstr(pname, "ram"))
+	return 0;
+
+    /* if it has a '/' in it then treat it specially */
+    if (strchr(pname, '/') && !strstr(pname, "iseries") && 
+        !strstr(pname, "i2o")) {
+	/* assume its either a /dev/ida/ or /dev/cciss device */
+	/* these have form of c?d?p? if its a partition */
+	return strchr(pname, 'p') != NULL;
+    } else {
+	/* if it ends with a digit we're ok */
+	return isdigit(pname[strlen(pname)-1]);
+    }
+}
+
+/* return NULL terminated array of pointers to names of partitons in
+ * /proc/partitions
+ */
+char **getPartitionsList(char * disk) {
+    FILE *f;
+    int numfound = 0;
+    char **rc=NULL;
+
+    f = fopen("/proc/partitions", "r");
+    if (!f) {
+	logMessage(ERROR, "getPartitionsList: could not open /proc/partitions");
+	return NULL;
+    }
+
+    /* read through /proc/partitions and parse out partitions */
+    while (1) {
+	char *tmpptr, *pptr;
+	char tmpstr[4096];
+
+	tmpptr = fgets(tmpstr, sizeof(tmpstr), f);
+
+	if (tmpptr) {
+	    char *a, *b;
+	    int toknum = 0;
+
+	    a = tmpstr;
+	    while (1) {
+		b = strsep(&a, " \n");
+
+		/* if no fields left abort */
+		if (!b)
+		    break;
+
+		/* if field was empty means we hit another delimiter */
+		if (!*b)
+		    continue;
+
+		/* make sure this is a valid partition line, should start */
+		/* with a numeral */
+		if (toknum == 0) {
+		    if (!isdigit(*b))
+			break;
+		} else if (toknum == 2) {
+		    /* if size is exactly 1 then ignore it as an extended */
+		    if (!strcmp(b, "1"))
+			break;
+		} else if (toknum == 3) {
+		    /* this should be the partition name */
+		    /* now we need to see if this is the block device or */
+		    /* actually a partition name                         */
+		    if (!isPartitionName(b))
+			break;
+
+                    /* make sure that either we don't care about the disk
+                     * or it's this one */
+                    if ((disk != NULL) && (strncmp(disk, b, strlen(disk))))
+                        break;
+
+		    /* we found a partition! */
+		    pptr = (char *) malloc(strlen(b) + 7);
+		    sprintf(pptr, "/dev/%s", b);
+
+		    if (!rc) {
+			rc = (char **) malloc(2*sizeof(char *));
+		        rc[0] = pptr;
+			rc[1] = NULL;
+		    } else {
+			int idx;
+			
+			rc = (char **) realloc(rc, (numfound+2)*sizeof(char *));
+			idx = 0;
+			while (idx < numfound) {
+			    if (strcmp(pptr, rc[idx]) < 0)
+				break;
+
+			    idx++;
+			}
+
+			/* move existing out of way if necessary */
+			if (idx != numfound)
+			    memmove(rc+idx+1, rc+idx, (numfound-idx)*sizeof(char *));
+
+			rc[idx] = pptr;
+			rc[numfound+1] = NULL;
+		    }
+		    numfound++;
+		    break;
+		}
+		toknum++;
+	    }
+	} else {
+	    break;
+	}
+    }
+
+    fclose(f);
+
+    return rc;
+}
+
+/* returns length of partitionlist */
+int lenPartitionsList(char **list) {
+    char **part;
+    int  rc;
+
+    if (!list) return 0;
+    for (rc = 0, part = list; *part; rc++, part++);
+
+    return rc;
+}
+
+/* frees partition list */
+void freePartitionsList(char **list) {
+    char **part;
+
+    if (!list)
+        return;
+
+    for (part = list; *part; part++) {
+	if (*part) {
+            free(*part);
+            *part = NULL;
+        }
+    }
+
+    free(list);
+    list = NULL;
+}
diff --git a/bin/loader/getparts.h b/bin/loader/getparts.h
new file mode 100644
index 0000000..b672a77
--- /dev/null
+++ b/bin/loader/getparts.h
@@ -0,0 +1,27 @@
+/*
+ * getparts.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GETPARTS_H
+#define GETPARTS_H
+
+char **getPartitionsList(char * disk);
+int lenPartitionsList(char **list);
+void freePartitionsList(char **list);
+
+#endif
diff --git a/bin/loader/hardware.c b/bin/loader/hardware.c
new file mode 100644
index 0000000..ad20ed5
--- /dev/null
+++ b/bin/loader/hardware.c
@@ -0,0 +1,150 @@
+/*
+ * hardware.c - various hardware probing functionality
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/wait.h>
+#include <glib.h>
+
+#include "loader.h"
+#include "hardware.h"
+
+/* FIXME: for turning off dma */
+#include <sys/ioctl.h>
+#include <linux/hdreg.h>
+#include "../isys/isys.h"
+#include "../isys/log.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+static int detectHardware() {
+    int child, rc, status;
+    int timeout = 0; /* FIXME: commandline option for this */
+
+    fprintf(stderr, "detecting hardware...\n");
+    logMessage(DEBUGLVL, "probing buses");
+
+    if (!(child = fork())) {
+        int fd = open("/dev/tty3", O_RDWR);
+
+        dup2(fd, 0);
+        dup2(fd, 1);
+        dup2(fd, 2);
+        close(fd);
+
+        rc = execl("/sbin/udevadm", "udevadm", "trigger", NULL);
+        _exit(1);
+    }
+
+    waitpid(child, &status, 0);
+    if (!WIFEXITED(status) || (WIFEXITED(status) && WEXITSTATUS(status))) {
+        rc = 1;
+    } else {
+        rc = 0;
+    }
+
+    fprintf(stderr, "waiting for hardware to initialize...\n");
+    logMessage(DEBUGLVL, "waiting for hardware to initialize");
+
+    if (!(child = fork())) {
+        char *args[] = { "/sbin/udevadm", "settle", NULL, NULL };
+        int fd = open("/dev/tty3", O_RDWR);
+
+        dup2(fd, 0);
+        dup2(fd, 1);
+        dup2(fd, 2);
+        close(fd);
+
+        if (timeout) {
+            checked_asprintf(&args[2], "--timeout=%d", timeout);
+        }
+
+        rc = execv("/sbin/udevadm", args);
+        _exit(1);
+    }
+
+    waitpid(child, &status, 0);
+    if (!WIFEXITED(status) || (WIFEXITED(status) && WEXITSTATUS(status))) {
+        rc = 1;
+    } else {
+        rc = 0;
+    }
+    if (rc) {
+        return LOADER_ERROR;
+    }
+    return LOADER_OK;
+}
+
+/* this allows us to do an early load of modules specified on the
+ * command line to allow automating the load order of modules so that
+ * eg, certain scsi controllers are definitely first.
+ * FIXME: this syntax is likely to change in a future release
+ *        but is done as a quick hack for the present.
+ */
+int earlyModuleLoad(int justProbe) {
+    int fd, len, i;
+    char buf[1024], *cmdLine;
+    gint argc = 0;
+    gchar **argv = NULL;
+    GError *optErr = NULL;
+
+    /* FIXME: reparsing /proc/cmdline to avoid major loader changes.  
+     * should probably be done in loader.c:parseCmdline() like everything 
+     * else
+     */
+    if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) return 1;
+    len = read(fd, buf, sizeof(buf) - 1);
+    close(fd);
+    if (len <= 0) return 1;
+
+    buf[len] = '\0';
+    cmdLine = buf;
+
+    if (!g_shell_parse_argv(cmdLine, &argc, &argv, &optErr)) {
+        g_error_free(optErr);
+        return 1;
+    }
+
+    for (i=0; i < argc; i++) {
+        if (!strncasecmp(argv[i], "driverload=", 11)) {
+            logMessage(INFO, "loading %s early", argv[i] + 11);
+            mlLoadModuleSet(argv[i] + 11);
+        }
+    }
+    return 0;
+}
+
+int busProbe(int justProbe) {
+    /* autodetect whatever we can */
+    if (justProbe)
+        return 0;
+    return detectHardware();
+}
diff --git a/bin/loader/hardware.h b/bin/loader/hardware.h
new file mode 100644
index 0000000..47c34d2
--- /dev/null
+++ b/bin/loader/hardware.h
@@ -0,0 +1,28 @@
+/*
+ * hardware.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LOADERHW_H
+#define LOADERHW_H
+
+#include "modules.h"
+
+int earlyModuleLoad(int justProbe);
+int busProbe(int justProbe);
+
+#endif
diff --git a/bin/loader/hdinstall.c b/bin/loader/hdinstall.c
new file mode 100644
index 0000000..4bb31a8
--- /dev/null
+++ b/bin/loader/hdinstall.c
@@ -0,0 +1,496 @@
+/*
+ * hdinstall.c - code to set up hard drive installs
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include "driverdisk.h"
+#include "hdinstall.h"
+#include "getparts.h"
+#include "kickstart.h"
+#include "loader.h"
+#include "loadermisc.h"
+#include "lang.h"
+#include "modules.h"
+#include "method.h"
+#include "mediacheck.h"
+#include "cdinstall.h"
+#include "windows.h"
+
+#include "../isys/imount.h"
+#include "../isys/isys.h"
+#include "../isys/eddsupport.h"
+#include "../isys/log.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+/* given a partition device and directory, tries to mount hd install image */
+static char * setupIsoImages(char * device, char * dirName, char * location) {
+    int rc = 0;
+    char *url = NULL, *dirspec, *updpath, *path;
+
+    logMessage(INFO, "mounting device %s for hard drive install", device);
+
+    if (doPwMount(device, "/mnt/isodir", "auto", "ro", NULL))
+        return NULL;
+
+    checked_asprintf(&dirspec, "/mnt/isodir%.*s",
+                     (int) (strrchr(dirName, '/') - dirName), dirName);
+    checked_asprintf(&path, "/mnt/isodir%s", dirName);
+
+    if (path) {
+        logMessage(INFO, "Path to stage2 image is %s", path);
+
+        rc = copyFile(path, "/tmp/install.img");
+        rc = mountStage2("/tmp/install.img");
+
+        free(path);
+
+        if (rc) {
+            umountLoopback("/mnt/runtime", "/dev/loop0");
+            umount("/mnt/isodir");
+            goto err;
+        }
+
+        checked_asprintf(&updpath, "%s/updates.img", dirspec);
+
+        logMessage(INFO, "Looking for updates for HD in %s", updpath);
+        copyUpdatesImg(updpath);
+        free(updpath);
+
+        checked_asprintf(&updpath, "%s/product.img", dirspec);
+
+        logMessage(INFO, "Looking for product for HD in %s", updpath);
+        copyProductImg(updpath);
+
+        free(updpath);
+        free(dirspec);
+        umount("/mnt/isodir");
+
+        checked_asprintf(&url, "hd:%s:/%s", device,
+                         dirName ? dirName : ".");
+
+        return url;
+    } else {
+        free(dirspec);
+        free(path);
+
+        if (rc) {
+            umount("/mnt/isodir");
+            return NULL;
+        }
+    }
+
+err:
+    newtWinMessage(_("Error"), _("OK"),
+                   _("An error occured finding the installation image "
+                     "on your hard drive.  Please check your images and "
+                     "try again."));
+    return NULL;
+}
+
+/* setup hard drive based install from a partition with a filesystem and
+ * ISO images on that filesystem
+ */
+char * mountHardDrive(struct installMethod * method,
+		      char * location, struct loaderData_s * loaderData) {
+    int rc;
+    int i;
+
+    newtComponent listbox, label, dirEntry, form, okay, back, text;
+    struct newtExitStruct es;
+    newtGrid entryGrid, grid, buttons;
+
+    int done = 0;
+    char * dir = g_strdup("");
+    char * tmpDir;
+    char * url = NULL;
+    char * buf;
+    int numPartitions;
+
+    char **partition_list;
+    char *selpart;
+    char *kspartition = NULL, *ksdirectory = NULL;
+    char *imgpath = "/images/install.img";
+
+    /* handle kickstart/stage2= data first if available */
+    if (loaderData->method == METHOD_HD && loaderData->stage2Data) {
+        kspartition = ((struct hdInstallData *)loaderData->stage2Data)->partition;
+        if (kspartition) {
+            kspartition = g_strdup(kspartition);
+        }
+
+        ksdirectory = ((struct hdInstallData *)loaderData->stage2Data)->directory;
+        if (ksdirectory) {
+            if (g_str_has_suffix(ksdirectory, ".img")) {
+                ksdirectory = g_strdup(ksdirectory);
+            } else {
+                ksdirectory = g_strconcat(ksdirectory, imgpath, NULL);
+            }
+        } else {
+            ksdirectory = g_strdup(imgpath);
+        }
+
+        logMessage(INFO, "partition is %s, dir is %s", kspartition, ksdirectory);
+
+        if (!kspartition || !ksdirectory) {
+            logMessage(ERROR, "missing partition or directory specification");
+            loaderData->method = -1;
+
+            if (loaderData->inferredStage2)
+                loaderData->invalidRepoParam = 1;
+        } else {
+            /* if we start with /dev, strip it (#121486) */
+            char *kspart = kspartition;
+            if (!strncmp(kspart, "/dev/", 5))
+                kspart = kspart + 5;
+
+            url = setupIsoImages(kspart, ksdirectory, location);
+            if (!url) {
+                logMessage(ERROR, "unable to find %s installation images on hd",
+                           getProductName());
+                loaderData->method = -1;
+
+                if (loaderData->inferredStage2)
+                    loaderData->invalidRepoParam = 1;
+            } else {
+                g_free(kspartition);
+                g_free(ksdirectory);
+                return url;
+            }
+        }
+    } else {
+        kspartition = NULL;
+        ksdirectory = NULL;
+    }
+
+    /* if we're here its either because this is interactive, or the */
+    /* hd kickstart directive was faulty and we have to prompt for  */
+    /* location of harddrive image                                  */
+
+    partition_list = NULL;
+    while (!done) {
+        /* if we're doing another pass free this up first */
+        if (partition_list)
+            freePartitionsList(partition_list);
+
+        partition_list = getPartitionsList(NULL);
+        numPartitions = lenPartitionsList(partition_list);
+
+        /* no partitions found, try to load a device driver disk for storage */
+        if (!numPartitions) {
+            rc = newtWinChoice(_("Hard Drives"), _("Yes"), _("Back"),
+                               _("You don't seem to have any hard drives on "
+                                 "your system! Would you like to configure "
+                                 "additional devices?"));
+            if (rc == 2) {
+                loaderData->stage2Data = NULL;
+                return NULL;
+            }
+
+            rc = loadDriverFromMedia(DEVICE_DISK, loaderData, 0, 0, NULL);
+            continue;
+        }
+
+        /* now find out which partition has the stage2 image */
+        checked_asprintf(&buf, _("What partition and directory on that "
+                                 "partition holds the installation image "
+                                 "for %s?  If you don't see the disk drive "
+                                 "you're using listed here, press F2 to "
+                                 "configure additional devices."),
+                         getProductName());
+
+        text = newtTextboxReflowed(-1, -1, buf, 62, 5, 5, 0);
+        free(buf);
+
+        listbox = newtListbox(-1, -1, numPartitions > 5 ? 5 : numPartitions,
+                              NEWT_FLAG_RETURNEXIT | 
+                              (numPartitions > 5 ? NEWT_FLAG_SCROLL : 0));
+
+        for (i = 0; i < numPartitions; i++)
+            newtListboxAppendEntry(listbox,partition_list[i],partition_list[i]);
+
+        /* if we had ks data around use it to prime entry, then get rid of it*/
+        if (kspartition) {
+            newtListboxSetCurrentByKey(listbox, kspartition);
+            g_free(kspartition);
+            kspartition = NULL;
+        }
+
+        label = newtLabel(-1, -1, _("Directory holding image:"));
+
+        dirEntry = newtEntry(28, 11, dir, 28, (const char **) &tmpDir,
+                             NEWT_ENTRY_SCROLL);
+
+        /* if we had ks data around use it to prime entry, then get rid of it*/
+        if (ksdirectory) {
+            newtEntrySet(dirEntry, ksdirectory, 1);
+            g_free(ksdirectory);
+            ksdirectory = NULL;
+        }
+
+        entryGrid = newtGridHStacked(NEWT_GRID_COMPONENT, label,
+                                     NEWT_GRID_COMPONENT, dirEntry,
+                                     NEWT_GRID_EMPTY);
+
+        buttons = newtButtonBar(_("OK"), &okay, _("Back"), &back, NULL);
+
+        grid = newtCreateGrid(1, 4);
+        newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
+                         0, 0, 0, 1, 0, 0);
+        newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, listbox,
+                         0, 0, 0, 1, 0, 0);
+        newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, entryGrid,
+                         0, 0, 0, 1, 0, 0);
+        newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, buttons,
+                         0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+        newtGridWrappedWindow(grid, _("Select Partition"));
+
+        form = newtForm(NULL, NULL, 0);
+        newtFormAddHotKey(form, NEWT_KEY_F2);
+        newtFormAddHotKey(form, NEWT_KEY_F12);
+
+        newtGridAddComponentsToForm(grid, form, 1);
+        newtGridFree(grid, 1);
+
+        newtFormRun(form, &es);
+
+        selpart = newtListboxGetCurrent(listbox);
+
+        g_free(dir);
+        if (tmpDir && *tmpDir) {
+            /* Protect from form free. */
+            dir = g_strdup(tmpDir);
+        } else  {
+            dir = g_strdup("");
+        }
+
+        newtFormDestroy(form);
+        newtPopWindow();
+
+        if (es.reason == NEWT_EXIT_COMPONENT && es.u.co == back) {
+            loaderData->stage2Data = NULL;
+            return NULL;
+        } else if (es.reason == NEWT_EXIT_HOTKEY && es.u.key == NEWT_KEY_F2) {
+            rc = loadDriverFromMedia(DEVICE_DISK, loaderData, 0, 0, NULL);
+            continue;
+        }
+
+        logMessage(INFO, "partition %s selected", selpart);
+
+        /* If the user-provided URL points at a repo instead of a stage2
+         * image, fix that up now.
+         */
+        if (!g_str_has_suffix(dir, ".img")) {
+            char *tmp = g_strconcat(dir, imgpath, NULL);
+            g_free(dir);
+            dir = tmp;
+        }
+
+        loaderData->invalidRepoParam = 1;
+
+        url = setupIsoImages(selpart, dir, location);
+        if (!url) {
+            newtWinMessage(_("Error"), _("OK"), 
+                           _("Device %s does not appear to contain "
+                             "an installation image."), selpart, getProductName());
+            continue;
+        }
+
+        done = 1; 
+    }
+
+    g_free(dir);
+
+    return url;
+}
+
+void setKickstartHD(struct loaderData_s * loaderData, int argc,
+                     char ** argv) {
+    char *p;
+    gchar *biospart = NULL, *partition = NULL, *dir = NULL;
+    GOptionContext *optCon = g_option_context_new(NULL);
+    GError *optErr = NULL;
+    GOptionEntry ksHDOptions[] = {
+        { "biospart", 0, 0, G_OPTION_ARG_STRING, &biospart, NULL, NULL },
+        { "partition", 0, 0, G_OPTION_ARG_STRING, &partition, NULL, NULL },
+        { "dir", 0, 0, G_OPTION_ARG_STRING, &dir, NULL, NULL },
+        { NULL },
+    };
+
+    logMessage(INFO, "kickstartFromHD");
+
+    g_option_context_set_help_enabled(optCon, FALSE);
+    g_option_context_add_main_entries(optCon, ksHDOptions, NULL);
+
+    if (!g_option_context_parse(optCon, &argc, &argv, &optErr)) {
+        startNewt();
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("Bad argument to HD kickstart method "
+                         "command: %s"), optErr->message);
+        g_error_free(optErr);
+        g_option_context_free(optCon);
+        return;
+    }
+
+    g_option_context_free(optCon);
+
+    if (biospart) {
+        char * dev;
+
+        p = strchr(biospart,'p');
+        if(!p){
+            logMessage(ERROR, "Bad argument for --biospart");
+            return;
+        }
+        *p = '\0';
+        dev = getBiosDisk(biospart);
+        if (dev == NULL) {
+            logMessage(ERROR, "Unable to location BIOS partition %s", biospart);
+            return;
+        }
+        partition = malloc(strlen(dev) + strlen(p + 1) + 2);
+        sprintf(partition, "%s%s", dev, p + 1);
+    }
+
+    loaderData->method = METHOD_HD;
+    loaderData->stage2Data = calloc(sizeof(struct hdInstallData *), 1);
+    if (partition)
+        ((struct hdInstallData *)loaderData->stage2Data)->partition = partition;
+    if (dir)
+        ((struct hdInstallData *)loaderData->stage2Data)->directory = dir;
+
+    logMessage(INFO, "results of hd ks, partition is %s, dir is %s", partition,
+               dir);
+}
+
+int kickstartFromHD(char *kssrc) {
+    int rc;
+    char *p, *np = NULL, *tmpstr, *ksdev, *kspath;
+
+    logMessage(INFO, "getting kickstart file from harddrive");
+
+    /* format is hd:[device]:/path/to/ks.cfg */
+    /* split up pieces */
+    tmpstr = strdup(kssrc);
+    p = strchr(tmpstr, ':');
+    if (p)
+        np = strchr(p+1, ':');
+    
+    /* no second colon, assume its the old format of                     */
+    /*        hd:[device]/path/to/ks.cfg                                 */
+    /* this format is bad however because some devices have '/' in them! */
+    if (!np)
+        np = strchr(p+1, '/');
+
+    if (!p || !np) {
+        logMessage(WARNING, "Format of command line is ks=hd:[device]:/path/to/ks.cfg");
+        free(tmpstr);
+        return 1;
+    }
+
+    *np = '\0';
+    ksdev = p+1;
+    kspath = np+1;
+
+    logMessage(INFO, "Loading ks from device %s on path %s", ksdev, kspath);
+    if ((rc=getKickstartFromBlockDevice(ksdev, kspath))) {
+        if (rc == 3) {
+            startNewt();
+            newtWinMessage(_("Error"), _("OK"),
+                           _("Cannot find kickstart file on hard drive."));
+        }
+        return 1;
+    }
+
+    return 0;
+}
+
+
+int kickstartFromBD(char *kssrc) {
+    int rc;
+    char *p, *np = NULL, *r = NULL, *tmpstr, *ksdev, *kspath, *biosksdev;
+
+    logMessage(INFO, "getting kickstart file from biosdrive");
+
+    /* format is bd:[device]:/path/to/ks.cfg */
+    /* split of pieces */
+    tmpstr = strdup(kssrc);
+    p = strchr(tmpstr, ':');
+    if (p)
+        np = strchr(p+1, ':');
+    
+    if (!p || !np) {
+        logMessage(WARNING, "Format of command line is ks=bd:device:/path/to/ks.cfg");
+        free(tmpstr);
+        return 1;
+    }
+
+    *np = '\0';
+    kspath = np+1;
+
+    r = strchr(p+1,'p');
+    if(!r){
+        logMessage(INFO, "Format of biosdisk is 80p1");
+        free(tmpstr);
+        return 1;
+    }                                                          
+
+    *r = '\0';
+    biosksdev = getBiosDisk((p + 1));
+    if(!biosksdev){
+        startNewt();
+        newtWinMessage(_("Error"), _("OK"),
+                       _("Cannot find hard drive for BIOS disk %s"),
+                       p + 1);
+        return 1;
+    }
+
+
+    ksdev = malloc(strlen(biosksdev) + 3);
+    sprintf(ksdev, "%s%s", biosksdev, r + 1);
+    logMessage(INFO, "Loading ks from device %s on path %s", ksdev, kspath);
+    if ((rc=getKickstartFromBlockDevice(ksdev, kspath))) {
+        if (rc == 3) {
+            startNewt();
+            newtWinMessage(_("Error"), _("OK"),
+                           _("Cannot find kickstart file on hard drive."));
+        }
+        return 1;
+    }
+
+    return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4: */
diff --git a/bin/loader/hdinstall.h b/bin/loader/hdinstall.h
new file mode 100644
index 0000000..44351a3
--- /dev/null
+++ b/bin/loader/hdinstall.h
@@ -0,0 +1,38 @@
+/*
+ * hdinstall.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef H_HDINSTALL
+#define H_HDINSTALL
+
+#include "method.h"
+
+struct hdInstallData {
+    char * partition;
+    char * directory;
+};
+
+
+void setKickstartHD(struct loaderData_s * loaderData, int argc,
+		    char ** argv);
+char * mountHardDrive(struct installMethod * method,
+                      char * location, struct loaderData_s * loaderData);
+int kickstartFromHD(char *kssrc);
+int kickstartFromBD(char *kssrc);
+
+#endif
diff --git a/bin/loader/ibft.c b/bin/loader/ibft.c
new file mode 100644
index 0000000..b3a3827
--- /dev/null
+++ b/bin/loader/ibft.c
@@ -0,0 +1,105 @@
+/*
+   File name: ibft.c
+   Date:      2008/09/02
+   Author:    Martin Sivak <msivak redhat com>
+
+   Copyright (C) 2008 Red Hat
+
+   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
+   in a file called COPYING along with this program; if not, write to
+   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+   02139, USA.
+*/
+
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libiscsi.h>
+#include "ibft.h"
+
+struct libiscsi_network_config ibft_context;
+int ibft_ispresent = 0;
+int ibft_initialized = 0;
+
+int ibft_init(void)
+{
+  int ret;
+
+  memset(&ibft_context, 0, sizeof(ibft_context));
+
+  ret = libiscsi_get_firmware_network_config(&ibft_context);
+
+  /* ret == 0 -> OK */
+  ibft_ispresent = !ret;
+  ibft_initialized = 1;
+
+  return ibft_initialized;
+}
+
+/* Is iBFT available on this system */
+int ibft_present()
+{
+  if(!ibft_initialized)
+    ibft_init();
+
+  return ibft_ispresent;
+}
+
+/* Is the iBFT network configured to use DHCP */
+int ibft_iface_dhcp()
+{
+  if(!ibft_initialized)
+    ibft_init();
+
+  if(!ibft_present())
+    return -1;
+
+  return ibft_context.dhcp;
+}
+
+#define ibft_iface_charfunc(name, var) char* ibft_iface_##name()\
+{\
+  if(!ibft_initialized)\
+    ibft_init();\
+\
+  if(!ibft_present())\
+    return NULL;\
+\
+  if(!strlen(ibft_context.var))\
+    return NULL;\
+\
+  return ibft_context.var;\
+}
+
+
+/* Get the iBFT MAC address */
+ibft_iface_charfunc(mac, mac_address)
+
+/* Get the iBFT ip address */
+ibft_iface_charfunc(ip, ip_address)
+
+/* Get the iBFT subnet mask */
+ibft_iface_charfunc(mask, netmask)
+
+/* Get the iBFT gateway */
+ibft_iface_charfunc(gw, gateway)
+
+/* Get the iBFT iface name */
+ibft_iface_charfunc(iface, iface_name)
+
+/* Get the iBFT dns servers */
+ibft_iface_charfunc(dns1, primary_dns)
+ibft_iface_charfunc(dns2, secondary_dns)
+
diff --git a/bin/loader/ibft.h b/bin/loader/ibft.h
new file mode 100644
index 0000000..a922c91
--- /dev/null
+++ b/bin/loader/ibft.h
@@ -0,0 +1,45 @@
+/*
+   File name: ibft.h
+   Date:      2008/09/02
+   Author:    Martin Sivak
+
+   Copyright (C) 2008 Red Hat
+
+   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
+   in a file called COPYING along with this program; if not, write to
+   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+   02139, USA.
+*/
+
+
+#ifndef __IBFT_H__
+#define __IBFT_H__
+
+
+int ibft_init();
+int ibft_present();
+
+int ibft_iface_dhcp();
+
+char* ibft_iface_mac();
+char* ibft_iface_ip();
+char* ibft_iface_mask();
+char* ibft_iface_gw();
+char* ibft_iface_iface();
+char* ibft_iface_dns1();
+char* ibft_iface_dns2();
+
+
+#endif
+
+/* end of ibft.h */
diff --git a/bin/loader/init.c b/bin/loader/init.c
new file mode 100644
index 0000000..1a38df3
--- /dev/null
+++ b/bin/loader/init.c
@@ -0,0 +1,798 @@
+/*
+ * init.c: This is the install type init
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ * Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan (ewt redhat com)
+ *            Jeremy Katz (katzj redhat com)
+ */
+
+#if USE_MINILIBC
+#include "minilibc.h"
+#ifndef SOCK_STREAM
+# define SOCK_STREAM 1
+#endif 
+#define klogctl syslog
+#else
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <execinfo.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/klog.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/swap.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/reboot.h>
+#include <linux/vt.h>
+#include <termios.h>
+#include <libgen.h>
+#include <glib.h>
+
+#include "init.h"
+#include "copy.h"
+#include "devt.h"
+#include "devices.h"
+
+#endif
+
+#include <asm/types.h>
+#include <linux/serial.h>
+
+#ifndef MS_REMOUNT
+#define MS_REMOUNT          32
+#endif
+
+#define ENV_PATH            0
+#define ENV_LD_LIBRARY_PATH 1
+#define ENV_HOME            2
+#define ENV_TERM            3
+#define ENV_DEBUG           4
+#define ENV_TERMINFO        5
+#define ENV_PYTHONPATH      6
+#define ENV_MALLOC_CHECK    7
+#define ENV_MALLOC_PERTURB  8
+
+char * env[] = {
+    "PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sysimage/bin:"
+    "/mnt/sysimage/usr/bin:/mnt/sysimage/usr/sbin:/mnt/sysimage/sbin:"
+    "/mnt/sysimage/usr/X11R6/bin",
+
+    /* we set a nicer ld library path specifically for bash -- a full
+       one makes anaconda unhappy */
+#if defined(__x86_64__) || defined(__s390x__) || defined(__powerpc64__) || (defined(__sparc__) && defined(__arch64__))
+    "LD_LIBRARY_PATH=/lib64:/usr/lib64:/lib:/usr/lib",
+#else
+    "LD_LIBRARY_PATH=/lib:/usr/lib",
+#endif
+    "HOME=/",
+    "TERM=linux",
+    "DEBUG=",
+    "TERMINFO=/etc/linux-terminfo",
+    "PYTHONPATH=/tmp/updates",
+    "MALLOC_CHECK_=2",
+    "MALLOC_PERTURB_=204",
+    NULL
+};
+
+/* 
+ * this needs to handle the following cases:
+ *
+ *	1) run from a CD root filesystem
+ *	2) run from a read only nfs rooted filesystem
+ *      3) run from a floppy
+ *	4) run from a floppy that's been loaded into a ramdisk 
+ *
+ */
+
+void shutDown(int doKill, reboot_action rebootAction);
+static int getKillPolicy(void);
+static void getSyslog(char*);
+struct termios ts;
+
+static int expected_exit = 0;
+
+static void doExit(int) __attribute__ ((noreturn));
+static void doExit(int result)
+{
+    expected_exit = 1;
+    exit(result);
+}
+
+static void printstr(char * string) {
+    int ret;
+    ret = write(1, string, strlen(string));
+}
+
+static void fatal_error(int usePerror) {
+    printf("failed.\n");
+
+    printf("\nI can't recover from this.\n");
+#if !defined(__s390__) && !defined(__s390x__)
+    while (1) ;
+#endif
+}
+
+/* sets up and launches syslog */
+static void startSyslog(void) {
+    int conf_fd;
+    int ret;
+    char addr[128];
+    char forwardtcp[] = "*.* @@";
+    
+    /* update the config file with command line arguments first */
+    getSyslog(addr);
+    if (strlen(addr) > 0) {
+        conf_fd = open("/etc/rsyslog.conf", O_WRONLY|O_APPEND);
+        if (conf_fd < 0) {
+            printf("error opening /etc/rsyslog.conf: %d\n", errno);
+            printf("syslog forwarding will not be enabled\n");
+            sleep(5);
+        } else {
+            ret = write(conf_fd, forwardtcp, strlen(forwardtcp));
+            ret = write(conf_fd, addr, strlen(addr));
+            ret = write(conf_fd, "\n", 1);
+            close(conf_fd);
+        }
+    }
+
+    /* rsyslog is going to take care of things, so disable console logging */
+    klogctl(8, NULL, 1);
+    /* now we really start the daemon. */
+    int status;
+    status = system("/sbin/rsyslogd -c 4");
+    if (status < 0 || 
+        !WIFEXITED(status) || 
+        WEXITSTATUS(status)  != 0) {
+        printf("Unable to start syslog daemon.\n");
+        fatal_error(1);
+    }
+}
+
+static int setupTerminal(int fd) {
+    struct winsize winsize;
+    int fdn, len;
+    char buf[65535];
+
+    if (ioctl(fd, TIOCGWINSZ, &winsize)) {
+        printf("failed to get winsize");
+        fatal_error(1);
+    }
+
+    winsize.ws_row = 24;
+    winsize.ws_col = 80;
+
+    if (ioctl(fd, TIOCSWINSZ, &winsize)) {
+        printf("failed to set winsize");
+        fatal_error(1);
+    }
+
+    if (!strcmp(ttyname(fd), "/dev/hvc0")) {
+        /* using an HMC on a POWER system, use vt320 */
+        env[ENV_TERM] = "TERM=vt320";
+    } else {
+        /* use the no-advanced-video vt100 definition */
+        env[ENV_TERM] = "TERM=vt100-nav";
+
+        /* unless the user specifies that they want utf8 */
+        if ((fdn = open("/proc/cmdline", O_RDONLY, 0)) != -1) {
+            len = read(fdn, buf, sizeof(buf) - 1);
+            close(fdn);
+            if (len > 0 && strstr(buf, "utf8"))
+                env[ENV_TERM] = "TERM=vt100";
+        }
+    }
+
+    return 0;
+}
+#if defined(__sparc__)
+static int termcmp(struct termios *a, struct termios *b) {
+    if (a->c_iflag != b->c_iflag || a->c_oflag != b->c_oflag ||
+    a->c_cflag != b->c_cflag || a->c_lflag != b->c_lflag)
+    return 1;
+    return memcmp(a->c_cc, b->c_cc, sizeof(a->c_cc));
+}
+#endif
+
+#if !defined(__s390__) && !defined(__s390x__) && !defined(__sparc__)
+static int termcmp(struct termios *a, struct termios *b) {
+    if (a->c_iflag != b->c_iflag || a->c_oflag != b->c_oflag ||
+        a->c_cflag != b->c_cflag || a->c_lflag != b->c_lflag ||
+        a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
+        return 1;
+    return memcmp(a->c_cc, b->c_cc, sizeof(a->c_cc));
+}
+#endif
+
+static void createDevices(void) {
+    int i;
+
+    /*	unset the umask so devices are created with correct perms
+	and not complemented by the previous umask call */
+
+    mode_t previous_umask = umask(0); 
+
+    for (i = 0; devnodes[i].devname != NULL; i++) {
+        char devname[64];
+        int type = -1;
+
+        snprintf(devname, 63, "/dev/%s", devnodes[i].devname);
+        switch (devnodes[i].type) {
+        case DIRTYPE:
+            if (mkdir(devname, devnodes[i].perms) < 0) {
+                fprintf(stderr, "Unable to create directory %s: %m\n",
+                        devname);
+            }
+            break;
+        case CHARDEV:
+            type = S_IFCHR;
+            break;
+        case BLOCKDEV:
+            type = S_IFBLK;
+            break;
+        }
+        if (type == -1) continue;
+
+        if (mknod(devname, type | devnodes[i].perms, 
+                  makedev(devnodes[i].major, devnodes[i].minor)) < 0)
+            fprintf(stderr, "Unable to create device %s: %m\n", devname);
+    }
+
+    /* Hurray for hacks, this stops /lib/udev/rules.d/65-md-incremental.rules
+       from medling with mdraid sets. */
+    i = creat("/dev/.in_sysinit", 0644);
+    close(i);
+
+    /* Restore umask for minimal side affects */
+    umask(previous_umask); 
+}
+
+static void termReset(void) {
+    /* change to tty1 */
+    ioctl(0, VT_ACTIVATE, 1);
+    /* reset terminal */
+    tcsetattr(0, TCSANOW, &ts);
+    /* Shift in, default color, move down 100 lines */
+    /* ^O        ^[[0m          ^[[100E */
+    printf("\017\033[0m\033[100E\n");
+}
+
+/* reboot handler */
+static void sigintHandler(int signum) {
+    termReset();
+    shutDown(getKillPolicy(), REBOOT);
+}
+
+/* halt handler */
+static void sigUsr1Handler(int signum) {
+    termReset();
+    shutDown(getKillPolicy(), HALT);
+}
+
+/* poweroff handler */
+static void sigUsr2Handler(int signum) {
+    termReset();
+    shutDown(getKillPolicy(), POWEROFF);
+}
+
+static int getKillPolicy(void) {
+    int fd;
+    int len;
+    char buf[1024];
+
+    /* look through /proc/cmdline for special options */
+    if ((fd = open("/proc/cmdline", O_RDONLY,0)) > 0) {
+        len = read(fd, buf, sizeof(buf) - 1);
+        close(fd);
+        if ((len > 0) && strstr(buf, "nokill"))
+            return 0;
+    }
+    return 1;
+}
+
+/* Looks through /proc/cmdline for remote syslog paramters. */
+static void getSyslog(char *addr) {
+    int fd;
+    int len;
+    char buf[1024];
+
+    /* assume nothing gets found */
+    addr[0] = '\0';
+    if ((fd = open("/proc/cmdline", O_RDONLY,0)) <= 0) {
+        return;
+    }
+    len = read(fd, buf, sizeof(buf) - 1);
+    close(fd);
+    buf[len] = '\0';
+    
+    /* Parse the command line into argument vector using glib */
+    int i;
+    int argc;
+    char** argv;
+    GError* err = NULL;
+    if (!g_shell_parse_argv(buf, &argc, &argv, &err )) {
+        g_error_free(err);
+        return;
+    }
+    for (i = 0; i < argc; ++i) {
+        /* find what we are looking for */
+        if (!strncmp(argv[i], "syslog=", 7)) {
+            strncpy(addr, argv[i] + 7, 127);
+            addr[127] = '\0';
+            break;
+        }
+    }
+    g_strfreev(argv);
+
+    /* address can be either a hostname or IPv4 or IPv6, with or without port;
+       thus we only allow the following characters in the address: letters and
+       digits, dots, colons, slashes, dashes and square brackets */
+    if (!g_regex_match_simple("^[\\w.:/\\-\\[\\]]*$", addr, 0, 0)) {
+        /* the parameter is malformed, disable its use */
+        addr[0] = '\0';
+        printf("The syslog= command line parameter is malformed and will be\n");
+        printf("ignored by the installer.\n");
+        sleep(5);
+    }
+
+}
+
+static int getInitPid(void) {
+    int fd = 0, pid = -1, ret;
+    char * buf = calloc(1, 10);
+
+    fd = open("/var/run/init.pid", O_RDONLY);
+    if (fd < 0) {
+        fprintf(stderr, "Unable to find pid of init!!!\n");
+        return -1;
+    }
+    ret = read(fd, buf, 9);
+    close(fd);
+    ret = sscanf(buf, "%d", &pid);
+    return pid;
+}
+
+static void copyErrorFn (char *msg) {
+    printf(msg);
+}
+
+void initSegvHandler(int signum) {
+    void *array[30];
+    size_t i;
+    const char const * const errmsgs[] = {
+        "init received SIG",
+        "!  Backtrace:\n",
+        "init exited unexpectedly!  Backtrace:\n",
+    };
+
+    /* XXX This should really be in a glibc header somewhere... */
+    extern const char *const sys_sigabbrev[NSIG];
+
+    signal(signum, SIG_DFL); /* back to default */
+
+    if (signum == 0) {
+        i = write(STDERR_FILENO, errmsgs[2], strlen(errmsgs[2]));
+    } else {
+        i = write(STDERR_FILENO, errmsgs[0], strlen(errmsgs[0]));
+        i = write(STDERR_FILENO, sys_sigabbrev[signum],
+                strlen(sys_sigabbrev[signum]));
+        i = write(STDERR_FILENO, errmsgs[1], strlen(errmsgs[1]));
+    }
+
+    i = backtrace (array, 30);
+    backtrace_symbols_fd(array, i, STDERR_FILENO);
+    _exit(1);
+}
+
+void initExitHandler(void)
+{
+    if (expected_exit)
+        return;
+
+    initSegvHandler(0);
+}
+
+static void setupBacktrace(void)
+{
+    void *array;
+
+    signal(SIGSEGV, initSegvHandler);
+    signal(SIGABRT, initSegvHandler);
+    atexit(initExitHandler);
+
+    /* Turns out, there's an initializer at the top of backtrace() that
+     * (on some arches) calls dlopen(). dlopen(), unsurprisingly, calls
+     * malloc(). So, call backtrace() early in signal handler setup so
+     * we can later safely call it from the signal handler itself. */
+    backtrace(&array, 1);
+}
+
+int main(int argc, char **argv) {
+    pid_t installpid, childpid;
+    int waitStatus;
+    int fd = -1;
+    int doShutdown =0;
+    reboot_action shutdown_method = HALT;
+    int isSerial = 0;
+    char * console = NULL;
+    int doKill = 1;
+    char * argvc[15];
+    char ** argvp = argvc;
+    char twelve = 12;
+    struct serial_struct si;
+    int i, disable_keys;
+
+    if (!strncmp(basename(argv[0]), "poweroff", 8)) {
+        printf("Running poweroff...\n");
+        fd = getInitPid();
+        if (fd > 0)
+            kill(fd, SIGUSR2);
+        doExit(0);
+    } else if (!strncmp(basename(argv[0]), "halt", 4)) {
+        printf("Running halt...\n");
+        fd = getInitPid();
+        if (fd > 0)
+            kill(fd, SIGUSR1);
+        doExit(0);
+    } else if (!strncmp(basename(argv[0]), "reboot", 6)) {
+        printf("Running reboot...\n");
+        fd = getInitPid();
+        if (fd > 0)
+            kill(fd, SIGINT);
+        doExit(0);
+    }
+
+    /* turn off screen blanking */
+    printstr("\033[9;0]");
+    printstr("\033[8]");
+
+    umask(022);
+
+    /* set up signal handler */
+    setupBacktrace();
+
+    printstr("\nGreetings.\n");
+
+    printf("anaconda installer init version %s starting\n", VERSION);
+
+    printf("mounting /proc filesystem... "); 
+    if (mount("/proc", "/proc", "proc", 0, NULL))
+        fatal_error(1);
+    printf("done\n");
+
+    printf("creating /dev filesystem... "); 
+    if (mount("/dev", "/dev", "tmpfs", 0, NULL))
+        fatal_error(1);
+    createDevices();
+    printf("done\n");
+    printf("starting udev...");
+    if ((childpid = fork()) == 0) {
+        execl("/sbin/udevd", "/sbin/udevd", "--daemon", NULL);
+        exit(1);
+    }
+    
+    /* wait at least until the udevd process that we forked exits */
+    do {
+        pid_t retpid;
+        int waitstatus;
+
+        retpid = wait(&waitstatus);
+        if (retpid == -1) {
+            if (errno == EINTR)
+                continue;
+            /* if the child exited before we called waitpid, we can get
+             * ECHILD without anything really being wrong; we just lost
+             * the race.*/
+            if (errno == ECHILD)
+                break;
+            printf("init: error waiting on udevd: %m\n");
+            exit(1);
+        } else if ((retpid == childpid) && WIFEXITED(waitstatus)) {
+            break;
+        }
+    } while (1);
+    
+    if (fork() == 0) {
+        execl("/sbin/udevadm", "udevadm", "control", "--env=ANACONDA=1", NULL);
+        exit(1);
+    }
+    printf("done\n");
+
+    printf("mounting /dev/pts (unix98 pty) filesystem... "); 
+    if (mount("/dev/pts", "/dev/pts", "devpts", 0, NULL))
+        fatal_error(1);
+    printf("done\n");
+
+    printf("mounting /sys filesystem... "); 
+    if (mount("/sys", "/sys", "sysfs", 0, NULL))
+        fatal_error(1);
+    printf("done\n");
+
+    /* these args are only for testing from commandline */
+    for (i = 1; i < argc; i++) {
+        if (!strcmp (argv[i], "serial")) {
+            isSerial = 1;
+            break;
+        }
+    }
+
+    doKill = getKillPolicy();
+
+#if !defined(__s390__) && !defined(__s390x__)
+    static struct termios orig_cmode;
+    struct termios cmode, mode;
+    int cfd;
+    
+    cfd =  open("/dev/console", O_RDONLY);
+    tcgetattr(cfd,&orig_cmode);
+    close(cfd);
+
+    cmode = orig_cmode;
+    cmode.c_lflag &= (~ECHO);
+
+    cfd = open("/dev/console", O_WRONLY);
+    tcsetattr(cfd,TCSANOW,&cmode);
+    close(cfd);
+
+    /* handle weird consoles */
+#if defined(__powerpc__)
+    char * consoles[] = { "/dev/hvc0", /* hvc for JS20 */
+
+                          "/dev/hvsi0", "/dev/hvsi1",
+                          "/dev/hvsi2", /* hvsi for POWER5 */
+                          NULL };
+#elif defined (__ia64__)
+    char * consoles[] = { "/dev/ttySG0", "/dev/xvc0", "/dev/hvc0", NULL };
+#elif defined (__i386__) || defined (__x86_64__)
+    char * consoles[] = { "/dev/xvc0", "/dev/hvc0", NULL };
+#else
+    char * consoles[] = { NULL };
+#endif
+    for (i = 0; consoles[i] != NULL; i++) {
+        if ((fd = open(consoles[i], O_RDWR)) >= 0 && !tcgetattr(fd, &mode) && !termcmp(&cmode, &mode)) {
+            printf("anaconda installer init version %s using %s as console\n",
+                   VERSION, consoles[i]);
+            isSerial = 3;
+            console = strdup(consoles[i]);
+            break;
+        }
+        close(fd);
+    }
+
+    cfd = open("/dev/console", O_WRONLY);
+    tcsetattr(cfd,TCSANOW,&orig_cmode);
+    close(cfd); 
+
+    if ((fd < 0) && (ioctl (0, TIOCLINUX, &twelve) < 0)) {
+        isSerial = 2;
+
+        if (ioctl(0, TIOCGSERIAL, &si) == -1) {
+            isSerial = 0;
+        }
+    }
+
+    if (isSerial && (isSerial != 3)) {
+        char *device = "/dev/ttyS0";
+
+        printf("anaconda installer init version %s using a serial console\n", 
+               VERSION);
+
+        if (isSerial == 2)
+            device = "/dev/console";
+        fd = open(device, O_RDWR, 0);
+        if (fd < 0)
+            device = "/dev/tts/0";
+
+        if (fd < 0) {
+            printf("failed to open %s\n", device);
+            fatal_error(1);
+        }
+
+        setupTerminal(fd);
+    } else if (isSerial == 3) {
+        setupTerminal(fd);
+    } else if (fd < 0)  {
+        fd = open("/dev/tty1", O_RDWR, 0);
+        if (fd < 0)
+            fd = open("/dev/vc/1", O_RDWR, 0);
+
+        if (fd < 0) {
+            printf("failed to open /dev/tty1 and /dev/vc/1");
+            fatal_error(1);
+        }
+    }
+
+    setsid();
+    if (ioctl(0, TIOCSCTTY, NULL)) {
+        printf("could not set new controlling tty\n");
+    }
+
+    dup2(fd, 0);
+    dup2(fd, 1);
+    dup2(fd, 2);
+    if (fd > 2)
+        close(fd);
+#else
+    dup2(0, 1);
+    dup2(0, 2);
+#endif
+
+    /* disable Ctrl+Z, Ctrl+C, etc ... but not in rescue mode */
+    disable_keys = 1;
+    if (argc > 1)
+        if (strstr(argv[1], "rescue"))
+            disable_keys = 0;
+
+    if (disable_keys) {
+        tcgetattr(0, &ts);
+        ts.c_iflag &= ~BRKINT;
+        ts.c_iflag |= IGNBRK;
+        ts.c_iflag &= ~ISIG;
+        tcsetattr(0, TCSANOW, &ts);
+    }
+
+    int ret;
+    ret = sethostname("localhost.localdomain", 21);
+    /* the default domainname (as of 2.0.35) is "(none)", which confuses 
+     glibc */
+    ret = setdomainname("", 0);
+
+    printf("trying to remount root filesystem read write... ");
+    if (mount("/", "/", "ext2", MS_REMOUNT | MS_MGC_VAL, NULL)) {
+        fatal_error(1);
+    }
+    printf("done\n");
+
+    /* we want our /tmp to be tmpfs, but we also want to let people hack
+     * their initrds to add things like a ks.cfg, so this has to be a little
+     * tricky */
+    rename("/tmp", "/oldtmp");
+    mkdir("/tmp", 0755);
+
+    printf("mounting /tmp as tmpfs... ");
+    if (mount("none", "/tmp", "tmpfs", 0, "size=250m"))
+        fatal_error(1);
+    printf("done\n");
+
+    copyDirectory("/oldtmp", "/tmp", copyErrorFn, copyErrorFn);
+    unlink("/oldtmp");
+
+    /* Now we have some /tmp space set up, and /etc and /dev point to
+       it. We should be in pretty good shape. */
+    startSyslog();
+
+    /* write out a pid file */
+    if ((fd = open("/var/run/init.pid", O_WRONLY|O_CREAT, 0644)) > 0) {
+        char * buf = malloc(10);
+        int ret;
+
+        snprintf(buf, 9, "%d", getpid());
+        ret = write(fd, buf, strlen(buf));
+        close(fd);
+        free(buf);
+    } else {
+        printf("unable to write init.pid (%d): %m\n", errno);
+        sleep(2);
+    }
+
+    /* D-Bus */
+    if (fork() == 0) {
+        execl("/sbin/dbus-uuidgen", "/sbin/dbus-uuidgen", "--ensure", NULL);
+        doExit(1);
+    }
+
+    if (fork() == 0) {
+        execl("/sbin/dbus-daemon", "/sbin/dbus-daemon", "--system", NULL);
+        doExit(1);
+    }
+
+    sleep(2);
+
+    /* Go into normal init mode - keep going, and then do a orderly shutdown
+       when:
+
+       1) /bin/install exits
+       2) we receive a SIGHUP 
+    */
+
+    printf("running install...\n"); 
+
+    setsid();
+
+    if (!(installpid = fork())) {
+        /* child */
+        *argvp++ = "/sbin/loader";
+
+        if (isSerial == 3) {
+            *argvp++ = "--virtpconsole";
+            *argvp++ = console;
+        }
+
+        *argvp++ = NULL;
+
+        printf("running %s\n", argvc[0]);
+        execve(argvc[0], argvc, env);
+
+        shutDown(1, HALT);
+    }
+
+    /* signal handlers for halt/poweroff */
+    signal(SIGUSR1, sigUsr1Handler);
+    signal(SIGUSR2, sigUsr2Handler);
+
+    /* set up the ctrl+alt+delete handler to kill our pid, not pid 1 */
+    signal(SIGINT, sigintHandler);
+    if ((fd = open("/proc/sys/kernel/cad_pid", O_WRONLY)) != -1) {
+        char buf[7];
+        size_t count;
+        sprintf(buf, "%d", getpid());
+        count = write(fd, buf, strlen(buf));
+        close(fd);
+        /* if we succeeded in writing our pid, turn off the hard reboot
+           ctrl-alt-del handler */
+        if (count == strlen(buf) &&
+            (fd = open("/proc/sys/kernel/ctrl-alt-del", O_WRONLY)) != -1) {
+            int ret;
+
+            ret = write(fd, "0", 1);
+            close(fd);
+        }
+    }
+    
+    while (!doShutdown) {
+        pid_t childpid;
+        childpid = wait(&waitStatus);
+
+        if (childpid == installpid) {
+            doShutdown = 1;
+            ioctl(0, VT_ACTIVATE, 1);
+        }
+    }
+
+    if (!WIFEXITED(waitStatus) ||
+        (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus))) {
+        shutdown_method = DELAYED_REBOOT;
+        printf("install exited abnormally [%d/%d] ", WIFEXITED(waitStatus),
+                                                     WEXITSTATUS(waitStatus));
+        if (WIFSIGNALED(waitStatus)) {
+            printf("-- received signal %d", WTERMSIG(waitStatus));
+        }
+        printf("\n");
+    } else {
+        shutdown_method = REBOOT;
+    }
+
+    shutDown(doKill, shutdown_method);
+
+    return 0;
+}
+
+/* vim:tw=78:ts=4:et:sw=4
+ */
diff --git a/bin/loader/init.h b/bin/loader/init.h
new file mode 100644
index 0000000..e1e5b70
--- /dev/null
+++ b/bin/loader/init.h
@@ -0,0 +1,31 @@
+/*
+ * init.h
+ *
+ * Copyright (C) 2009  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INIT_H
+#define INIT_H
+
+typedef enum {
+	REBOOT,
+	POWEROFF,
+	HALT,
+        /* gives user a chance to read the trace before scrolling the text out
+           with disk unmounting and termination info */
+        DELAYED_REBOOT
+} reboot_action;
+
+#endif /* INIT_H */
diff --git a/bin/loader/kbd.c b/bin/loader/kbd.c
new file mode 100644
index 0000000..b94f920
--- /dev/null
+++ b/bin/loader/kbd.c
@@ -0,0 +1,164 @@
+/*
+ * kbd.c - keyboard handling
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <alloca.h>
+#include <errno.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "loader.h"
+#include "loadermisc.h"
+#include "lang.h"
+#include "windows.h"
+
+#include "../isys/stubs.h"
+#include "../isys/lang.h"
+#include "../isys/log.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+int chooseKeyboard(struct loaderData_s * loaderData, char ** kbdtypep) {
+    int num = -1;
+    int rc;
+    gzFile f;
+    struct kmapHeader hdr;
+    struct kmapInfo * infoTable;
+    struct langInfo * languages;
+    int numLanguages;
+    char ** kbds;
+    char buf[16384]; 			/* I hope this is big enough */
+    int i;
+    char * defkbd = loaderData->kbd ? loaderData->kbd : NULL;
+    char *lang;
+
+#if defined(__s390__) || defined(__s390x__)
+    return LOADER_NOOP;
+#endif
+
+    if (FL_SERIAL (flags) || FL_VIRTPCONSOLE(flags)) return LOADER_NOOP;
+
+    numLanguages = getLangInfo(&languages);
+
+    lang = getenv("LANG");
+    if (!lang)
+       lang = loaderData->lang;
+
+    if (!defkbd && lang) {
+	for (i = 0; i < numLanguages; i++) {
+	    if (!strncmp(languages[i].lc_all, lang, 2)) {
+		defkbd = languages[i].keyboard;
+		break;
+	    }
+	}
+    }
+
+    if (!defkbd)
+	defkbd = "us";
+
+    f = gunzip_open("/etc/keymaps.gz");
+    if (!f) {
+	errorWindow("cannot open /etc/keymaps.gz: %s");
+	return LOADER_ERROR;
+    }
+
+    if (gunzip_read(f, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+	errorWindow("failed to read keymaps header: %s");
+	gunzip_close(f);
+	return LOADER_ERROR;
+    }
+
+    logMessage(INFO, "%d keymaps are available", hdr.numEntries);
+
+    i = hdr.numEntries * sizeof(*infoTable);
+    infoTable = alloca(i);
+    if (gunzip_read(f, infoTable, i) != i) {
+	errorWindow("failed to read keymap information: %s");
+	gunzip_close(f);
+	return LOADER_ERROR;
+    }
+
+    if (num == -1 ) {
+	kbds = alloca(sizeof(*kbds) * (hdr.numEntries + 1));
+	for (i = 0; i < hdr.numEntries; i++)  {
+	    kbds[i] = infoTable[i].name;
+	}
+
+	kbds[i] = NULL;
+	qsort(kbds, i, sizeof(*kbds), simpleStringCmp);
+
+	for (i = 0; i < hdr.numEntries; i++) 
+	    if (!strcmp(kbds[i], defkbd)) 
+		num = i;
+
+	rc = newtWinMenu(_("Keyboard Type"), 
+			_("What type of keyboard do you have?"),
+		        40, 5, 5, 8, kbds, &num, _("OK"), _("Back"), NULL);
+	if (rc == 2) return LOADER_BACK;
+
+	/* num needs to index the right keyboard infoTable */
+	for (i = 0; i < hdr.numEntries; i++)
+	    if (!strcmp(kbds[num], infoTable[i].name)) break;
+	num = i;
+    }
+
+    rc = 0;
+
+    for (i = 0; i < num; i++) {
+	if (gunzip_read(f, buf, infoTable[i].size) != infoTable[i].size) {
+	    logMessage(ERROR, "error reading %d bytes from file: %m",
+		       infoTable[i].size);
+	    gunzip_close(f);
+	    rc = LOADER_ERROR;
+	}
+    }
+
+    if (!rc) rc = loadKeymap(f);
+
+    /* normalize the error condition */
+    /* MSWFIXME - do we want to warn the user that setting the
+       keyboard didn't work?
+    */
+    if (rc != 0)
+	rc = LOADER_ERROR;
+    else
+        gunzip_close(f);
+
+    loaderData->kbd = strdup(infoTable[num].name);
+
+    return rc;
+}
+
+void setKickstartKeyboard(struct loaderData_s * loaderData, int argc, 
+                          char ** argv) {
+    if (argc < 2) {
+        logMessage(ERROR, "no argument passed to keyboard kickstart command");
+        return;
+    }
+
+    loaderData->kbd = argv[1];
+    loaderData->kbd_set = 1;
+}
diff --git a/bin/loader/kbd.h b/bin/loader/kbd.h
new file mode 100644
index 0000000..26c7111
--- /dev/null
+++ b/bin/loader/kbd.h
@@ -0,0 +1,27 @@
+/*
+ * kbd.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef H_KBD
+#define H_KBD
+
+int chooseKeyboard(struct loaderData_s * loaderData, char ** kbdtypep);
+void setKickstartKeyboard(struct loaderData_s * loaderData, int argc, 
+                          char ** argv);
+
+#endif
diff --git a/bin/loader/keymaps-i386 b/bin/loader/keymaps-i386
new file mode 100644
index 0000000000000000000000000000000000000000..93f2e58d10c66c2586ad2f42deccdecaec16b177
GIT binary patch
literal 12173
zcmZ{KcTiK$7jMD^LQPPl2q6I#K>-1!6OsT5R=|deR1u|#p?8wdi&8`d1u3F}g`!ju
zNJ2*tkRn)sgf1WiLJ1IZAK%~1n|c4dxifor?>VzOyXSn)`JA1LP7;9pyf1u)2UxHZ
z4BR*Lq~WSvaYJ$8LpedHnJSN<0 aY`+~{6I%~5ArRpI74&XVLqRDtgt5+~u~1rhsJ
zn$GCM7bleLkNb8%2)Ec9+8uOD$yv7Dz2}hqo$T9-p>`v?PpQY>qgRR}N)dZUj#kdS
zFRh*1Ui`Ar;Eemc5|_b4qCu)Wmwp-P)%q?SRW^F?x8mPUR+XphUjvQW2_fCzi=mF~
zEmi&%{|H0$r}YKzX>Mp4NYx_bT2oQsy|_4j^AXQ;+h6=2pyLL;s*N=ID#6}$#&^xa
zossEvwoUcFUxpR;w&_)NzY!_z)&9ZAS+>{jDIc`-*pHp%kpO~g5Fz7B_%L>SCHybj
z3+?~;-#(I q1`R<-?g|qhOxSKp;1ZI-Cpz4;rqvaOmTnARMq#1Ryk!1_idNmf1h>l
zF3%s_0yiv(PJQ>}z3u(^oTL{A7gK&(NaZpXwvz+?{rS}PuWB)6DQergxUOr;dsusN
zB|HlffT*QdFa2yOtv !JQKA?c_@%8XuzhE<?EZ%P(9)Ot1Bz8<B!<GqP EHD=4boP
zu?=I-d2Wc#CzbGWy m12hYKi!n((E7Yi)tIYdq$iGHf4Y4(+|x#>nfO(2#KS3!;3P
zC=;Pm^E!PWt#6Rxw#7ysz^c8*3=Oo# 7xSr3VopU$ZYHcnAaSbin(Sgs(mzQ*4I%m
zJ5I+n?lqGqJBp7WiH&vX<!h4{jPiVN?{1UlW4Sx9VGEt+b<L6Myw6LN*30))J^bgm
zQ4Sl9@|61hZN2P1{RXL-MTj?QuKE<^Dg3+hsVU+E*?%>}PW5Sxz+MB_=WjeTzx9sW
zJbc<~b<Vv=Y3-zlbBA=&{*OT)4qMCi-wIKcjJkgLgBdJbZNU9JFtX(u|2JXldQ^$x
z_?DlV^ *GP?yJvl$P8$CoTzwalVn{u=;2#oU3?~MZ`MurZ-X|9kabfFLC{txgEmFr
zvlUcf?DO2qF1;iBb8R6YK<PI%g6eg<y6omNCqDsB^+&^D{{_Q^FAMzZM(g1L;x~IF
zn|z~L7i+Rcno3*(KY9#*`ygeF*Y&euvclbaWj3*Hmn+?VVeVlWDf)DZ(6K&AJ^I}c
zeq!+=KQWP+Vv1Jf<%Z$IjCjmj0{4R(jp3KL+EEcFps`QD)v?6=shQ8TmfPkhM3-BG
zE{B~Ba}To#3kfp|3%N8 c&PAjq2gUd*+&mM-b^kWI`>0yKE1L-iyI-!&HDT5S(<7J
zaSPo=w$2o0IbuI{6OW_&*xIgSz4I}Ddqqyn1|QV=UggWjJ)$8hQlwBLP)W^$&;12?
zC|Kb;rXqLx()mw=#m<Mp)eHCgCEb%MT7K;<w!8UGt>2)+VtkB1N3TxVWT=6~bSdJ|
zhhyssO+CcJP3jT-k~m`h>J0i7dwx|bqBIvY7~unJgsx4r1PR(FW-z9L`0Nu y!Qt%
zG|!LACo=+&trsy5U<4&N16wDx)D-fHg*GS1E>gFbp<!Zy46i>?|JuF1T20wvUM*2I
zd>i9F3pDK-_yx{s_JoaXO53;@234A%G%jt~+Onpe&~f__Q)!~(`5}hoT*vjjT`Z#7
zkJcN1azOqU6S?ntemq}2Qd`JEzvhTXh~CslzU*zFGa(W(8h;^k3SF2_*3QH?+uXix
zZm!sg>u#0qJ}D=wkxNV+52R5<a9dLpD`0!GFjmI>N)>-qKgsUZjZGs0&hXG6KI)WA
zQQYIzJGC7fO_`^Fe+m*^R~>_7hEw=^_xjCzm|{x_h}H;5HbFMY D-lU)6hVnU3dDD
zq ^(wU$I?zP0Ed~J*jvp+83!~qs0uVk}Qd|7mi3Su!4R0P7PpJ+NeZq$ml)9DNYe%
zsFXj}3dMUkzsL0T!E^uoukvnM3UWge{^^Vp<$^1{#!;)XjALYnHwZ27#bF~ouoKBN
zj{`5EAcEk&OvN>bO&b4Ui6(#Jdn!j}viYaKW)ASz=PX0kIfkJm0vjQNJCwLQ6Dl9d
zO;6{gj8lBr8Nt+JE1rLVe ePaEK<}dR9PH`erF|QXA<d)A|O6fC5HdaLj6Hh?>PBS
z2vrrVfou~Ljy1OEk<OI?8IOR`=odWTy&zrtl<J8WHBcf+cU&z<1w||10SAL%_Hkph
zrEyWV5eGYZ(xO`Q^6oL{jvEE3jm8Yozty0I#;*>~w*nar+=6R}SvbWAR0(6MFM>Lp
znGx_nJ5l}Ph#9B!Ape(y&{|MDaCB2 gDA@#VdM&Mzex*p)2y?TSOjdo<PdHvF`6jU
z{SusN!%z1<MN+Ky0UdPD7RhrWuTUc`_(xJ&{EsHa1c^=}vyBry_Mqt|Cu$Uy2+mD9
zv_J-}Oj{sVMXXvNE}Twh#{f-yH!%dI3huGvUWRi*lb}A_e ycXq6Bb76W>Bfguau`
zON1WfzE1)3oJoSOlJf6~OiEjuiYOyFPHhkgaPTYTgQVHzN)7j-{9B|)(s_6Os3bsh
zUUyzIe3rfKd5dJ^(oB+3s}vitvR6BQS#>Ate5tmFf{&(r6G0r{ortG8Ac3%~zh<%w
zjJr5sJ7Fb!qWGkUt3H7<@lx`QRH8H9-rdQXB!SzYsyCH0kr<&A>SY3NP;|ynV|E!6
z)VjV2+YuB5pKX?0TVWHi<!wK0q(iw=l^PEv5n)1K-^U!8MmG;x_iukmfWC6h3($n1
zEJ 9_S<<HiP`&1A=L=p-PD?+Q0 ~Y_t_VBF;lzQeCS1=0vSb Rn<Y=%LlmndFvfcZ
zA|JOdRZ6z2M;MCQ`f)>(p`?gXQ&exbjwUJRxI0-!O_SuMS}Iv2P2388|8^(EWz1n3
z`iXOn1)1LZ3e;#+;y2kZRv^?n4GzH&?SUdMM4qg-=~Eb_)nu=}$2|-+*m DeOwSJ{
z>C8%^ `kRWNM6#h^)UGt_aBIJ-wR>zh754ON;Qgm^(KN|iE8KtNL-O%`9(-_IxOfs
zn><7psXJDsG70k5K~^xS`-0;m7~~ZrNNLIUu8^SG{+}yLwg{q7<Obx3+*z!rQQli<
z;%1K<HH^#Bg0$UdDZhpu_oj}=^>5}<{GE&l>k7|cd`3mVy|L6SDDOY=`7vw4$?2?8
z-X*9WXm4b7IUZHCx`~E!6BgpE8el>mr~x}%w4;&O%$Nbf#&0LRD=Kk5_nsQ>%ug?r
zR^JeAb91Q^=-X7^AcZhdz2N4O3+nV`l$EIVyH=no3#B{*ZT*B|x~%J$Z$M^-?=C3r
z4K7W0R$e99L8o})CZPQ+{JC~vA6QNDA4hXC>`&$zB&9s?Sv Q$uD-=$Z+Bsb=5-^;
zl3?|byc}2KP^x}vq?8j0LqD=Y%wjANo+IgJg3fpjAttQa!E4Nh7Qn~6eRJl-nH^?Y
zCQJ|R# !~(e9MJk<63-aoh*_<H}Eqg?*|4kFm4S1Ly&KZzQzTU<VlwNGjlhN31v@&
z$5 gGm*<+q8N} riiFQt6wSd6Ra8y|9^RNH<JFB2yjzR|hyjU<h$~y1r9#S`I0svh
zH-h_MqGty8(BUgF8k3sTLt*08_97nVXuemYj;Zb%j(FQB^<CUmQ_(5%(NdJ8t-Jge
z88gaS**eQ{an31eHJ7?niaL%ax* JS$n_vuu#M_OX6PP4a$F%wERGs{%i+Xr4yZ1N
z4&_o5C<iCTeggAwcAF{P!5UE~?PuDG+vr&5RDb_G;M_zkErxX)WownC!<aq9BM9Xz
z*byR1wJzjz`#5Z92IR|uMbWhh$wUgffJzjbp^T5oa=&K5{I)oEF=ZZHZ(~7D0E>jA
z>|h*IeoCSI;zHV$!?_2WaO IT`S?aR_ztq^;Mhr2mt1X58kor?)=R6;V#>@p&!pq8
zabh&ZLb*zgD9oi?Vhkl `Mq?WjC+xE-WTcK%tGm2hEM{OJTKjAW~rGcDzO(h`#Bk!
z5}XJ{m!wJ)zWR#<6%<M{V|SIlq(G~J5~13bwbG7Bh0<26S4q&=9%6+vDLtLIp-I);
zouEl#AK)hi{F*(&Uy*Ne3;$MN8Fx{W$_HH;^Xeq}Ia3#%NoqN_<iDjK<JU`L7l;9u
z*-8f^sw=IYzl*tK`taRXfKzl*gn9GFkpyUX2iB<;nh+!AsdlBnRHXf!TC^R?Q8ruo
zT?~(#2-Eb3LIQN>(az%+2eSYDPv^DdJFSR~`2)8X$sCm>a#}>r--Mz2*rh1b1-(fY
zBBU#IqgnR!kck+WLaJ0kmBxq}E%%1*POinjP%nA*2cq#Un)F+miXkLJANPx^7d5c0
zxg)El%DViwiepyZk!8Y%BH1*YluxCVSeS wq(}ar77`w3_fqm*`AJJmvabUFP2s^=
zX~4%p*hLC(Eijtdk$>t~J)1~LMsDA66M?M4<08cVWuk#uns!*rg)vPCYb%A33!0yd
zo={%TBEGl0B%JY{uY7`1CRy^wMtN6i?~!lo0D4<EYNiIy(xFN<N-tMPyQv^n7BLLx
zV(5_ba74}i$FRr2)P3hI5PFEmuq!C5VEh#H$^Y#PS{2wBIT8gC!?5Fs_8n7~5NZqx
z<A`g=$oK5EyqX7_<jjOpyL#$Fso&gDWr;>~TPqadcn~$hGb4nGeH HmL<fl!tzaB$
z)$0rq!zsJ77`C$3KB{~Je7Gzl$MvoI^U%vh7)SqL{JhnF #ZiEwxIf5oO$`qX&)%g
z*`fSIBk=HQHVm_vD*Sw2kbSsc(W9Wg1?#9JaM#?}l3EmsZ_xR5pnZchQRPvfKNI;z
z8;=EltflR&wp5p-$UTLLR4dsBhc6e<p 5z2d}J`buz@~Ut#e&*omZp>upaw$eGvmu
zM&!lHTwR1(MEwD>qdS(MI=dYayniU^5)1zo*cEG)^--S`lmF$Yh<=Eb87v w-a9T+
zCRY<NVlEW# uK)uY(Tl!sP<LYJcT}U+x_<rN $&RzZ>oUEL=16w2`mfs U5+qgMs+
zPnweU4qZOl1aF7)IfKp1)zBrkV3i||CH|#~+F|1J+P<`s!>7XPty+iDgc{NZ7UewC
ze gj^zP($Lw4 +Wm*cl;=Xp^0PWW)1wnh)nTmdmgMo*DhSp9VdmxZ|3M5H_uZW{E}
z1P 3FaY_)f7RMfkJDe`@)#pYB{WvL<>QOKKmS*trlntQs2s`<;S6)Kz#lWc6)=mZg
z^jz9}<ImOkwO0r4J~|5j-x6iv4(%20J<Qw`Tp{`1au%nP>A-u 23<a|l^4OhtCa_E
z+e0BGtj{o4sjYCdKBQ!=`jPDL1^0*-f1$DMXu{pHhqhGZw>x`Q;BJUs(?#-jWL!Jn
zf&$t*)z&yOT(h$?X6}S<K0iS)Al_5?e<zZV6I(sbpT_c28%@@AQV)3k*{YhpcEEJb
zpbom!oV5)9bI2#Z)mwD* JhiV&4XYx`Y 2u`f2;XR!5A_N31IG+Sbs~(Qs_OPPGL4
z8!Hznwqc;@W9l!77&y(1H#`_++w13J*iXRT=^-+b?xYL9Q$lNt-z<CNL&gWo 8*AZ
z!~h&|ZU#zC9gGU2X-!Df4&}Pgx&f^iEP{FKqEWkSUod23S6J63G9lQwsUsYKlD9=@
z9mB{6>+T$BU*kQ!c^#b s_bK&P#~WRV=j>wv>dOa;ypGuqj54UNPejNTbMuuD(^T3
z|GGHkMl4LZgEF!ezn?p$y?jK~9(^K(=zwy>AQ4tu97GuEBt2yT6K{jI5Y>JRBfNvL
zpYFswSroN9@)<AMFbBonrZ}!NIBFL7_>g5 ea7!J6Aw!%+lhNkfzf}V7Lv<2NH%za
zc}d_ip4JofxDmmFn*sIqtq>bmNhuP$QcW`GhXQGnO(~|mGDQkm!cVwZMBfR#8zP!+
zB;}5hj(q`hZy$^{SC%^3L@|oMeYSd8o?Q&f&U_xE#C2icRAU=wFlNvJhMce d0(20
zGb4y9*o5BCbwSmnhb46ZtTELQsgjXa!2F{UKI*j+WOmaC+Q;4rrYG|tFy2PcKjGZ%
zlMa|K4TNlBZ_=ja1}~&O6(lcUu6N`>xQj$_QZ5To`+(RhyxGI3UP0S&p5+KkuOT+q
z9FMJRS_L0d9y5^yo+&Y_Z+VN{#y<Tmet;d^yRbGU&b_25pTRB&0M#4E+-a5 IKhZo
z aMSH1_d%?ewp3WxU>)8mFn5$-w)>!p<hEInbLH %mqz+u%#FZzyMDqfNTI^YQP_W
zjNtuI2|dn1#}zW}-{3kxJS<atSZwflc&mMspAmhVSu-oV$rp+mZ%tyR&~XU)E ?V4
zXg~XxKnhib$%_Fj8{ZRzMm3i2vcV Y;0KsIckJ5)2&_wn+R?|_8(s!Zawtl-NS3se
z3tSM&aVNEzBtXBi<dZksqr{dU_i2{Jw?K9#jk|!QU =x_J0IdQAT`}MbIY+iSRQ>f
z2zC0c^mYAU`E&(->tU&W8DKxPLmZg+OkdZO4;C5ttUjGtq5g)*VKkE_Jzn{86b67@
zn>OT6$}H2ya~;+<(S2(m4-2ivIm-VsR%W-kC6D1Zk<mz%ZcjLa2K1YbYo?~_Xr_uE
z;Ai$7N+#DmodPv?3A+sVSL~L&!jy55^yxg!R4s5&7D!`U(@dR<C&zC)NVMVmW{A6O
zS*^4D^jfLAv;1++lRZFM3kJUywR`eM=VAG>pVo|f$g2E4C g=3sO=Sn`KUKWj!G5A
zux$T!praVErKXy?8pYm=RRBd2%vElO_u8rrm qEqM0)!yj-&22Kj1X<Iv?9MW`>S@
z=iv%_(B{V1mScmQ>yBU*vD#QQtP%Dgc29V|EM_&vYk2_i^7DZ$6J6d0Y*AQvm+}u2
z8ecQIrD0eUwdM36crMPn=D^l1-Jsc|k#RRv#jfrxmH+a SD+n3g|uVvCF-9% 1>qy
zg=FY`5H0`yNLZBx(dRswfgam)R<YkV&u%sTGAb_wLsb;Z=C|kF6*RV%V(=A4r089E
zlh~yM1mr7Fly5c|L{cQ=Tp<{~9XqCHZnLHurs}6LM2&j2Bjl^# 0`|)-%iq^qt-<+
zDn3xe4K2D4T_(twciW`Ui1Y$xaH^X$L3v(5bUOCR33HS=W<3f0QQpD>vIx~J!0IDl
zPLg%-;=J&S?<7s<{PxI0Fvry>uhnPs6C|%T+-%!xP89b;rf~I2?oMcf5&p94=Tr+6
z{ _2QPQL6*ub}e^6VN+1v>XqY9}5Z3e=!4H*p2(Ca$FIxg{^WKKs;K1GS&D`y^k9D
zNrs(z3Md4v_idXPw$Zfv8a~-(9yukG`Q9#_n8aVjz<rXr{w8Mdm$G}2W`eecVb8DY
zhBv>~4(nGXyl_F6yLif}<ddIW0m H^h|8&30_CWxST%a7sheoFb)MZD)IY7kzi0bW
z^W7b*p4)XDbISPCIXtx>6rgys!{VbwtdD5dE1ArCGrioq!7`b}jw1`a^;o-sCcIkP
z#iFRfG=2*Y>i#$U+0O<^oeEtc^50IAuL20X8KA__WgbB)U0c;<t8mbqJzNoWd{<Dk
zR!R<Ai7mt3pF{4U`?3-2YwXWOAA<L4EN2(J3r6O|rqGWB0i$uHbf=JT>qkRPu9dH~
znV#ZA7GEzF2_`X51PNL+oe2^dC8L{uGsW44b;p=Qp8JhUvrimo#Kvl-68llz_#Jj}
zFBKPqpgYh7gM>$85R5T;22*JFzT^pk+phB_)(^}WiaI}FYL7U{{+<HEC&2Liz-;Bk
z7060R-rHsh8bR8NAT`W8y ~w`rFH|V;;1~cjcI6~H{o#*L>$-ZelC=B>~tu}LSPIa
za5Ef*e!KQ$Bo3<SG9c FOh)(X9Wm0?13%?DnQ%i+;=rmDg9z?66R*6Cm;PMobj6Za
zd%y~HI#_;+ys%qC;$%=o-X<8awxuE9=UPnjagTAOJoQ(15zS-odjS_8GAC4iP|D{(
z$N>Ukwov`h*^mQQUcy%U#i5EudpM!gR>5Ubn^hIo^>0I}^4|oj#Wl;d7?FQl>TA 9
zEuNRJ4r4Kh4_hYh8d7QNC#^oG?vhp?g{#MIS5BHt-;&Rw86ZCVH-7asM&z*6aZBKx
zZM)FCpvE&_h4*q4nX|xeH|nv=!0$D)jG^d__#1m`VZ*CtOUar1C1-jIbVg)f3^l7q
zw!Gp##mCJGm30hI1M0u0q+%<U1j}OUP9_qPrB=-xgs&}II7d_7=p6m;Vys^rvU<wo
z{q j-nGN1Dcly4^i-NSFxb!t%G4{bc@(E6-wnk*-;kuufElE%Dp*+#~<YJELMb(-b
zC6n^PhU V9k4CM~ER%R(ni2S2O4W+9hY9&PpWB%OS)8G{yKmo{roFUAJeeRu*BK_Z
z(MjHU%7?vl5dpj 1|L#%>@^Tok}XJU-X7vc_;;QxSp4Z w`0M+twI=A7VF|rhAXF(
z`7U6##kVo<i4otpap8>(x51X~Pq<HGpT;!5&1$ao++9#v*WQlZiQOUZMDVPou+~Z|
zxHkax#;gUSb>DU2b@(>8UJ`xAYg`ED*7j^&r{&UHp~uTIQTm5RTcr2;{JayWvJvi3
zHS{Gb3yEYr`1kYYSmeJ({%l8$js0B`r{xcmF4Tzdmc0;qtPs6 I`Ev#!&hE!75zP4
zJzIRc_S~+tGsW^?{Zjo>_!5>ASoh x_=k*c4P+RxEyC0z#Kuy<M2|`dFRm|QGzr}V
zHh*CP?E7h)xWcGM9mGcyh#8#E2KaI%H$e1pIw=3!BAy~>-fiff^K>TnC8w>VV+zNa
z$LWK680y``+Y`E*mie2OU)lBB#9wSgx#A+xC=FyU!&vD3oNay3Z7qnKzK<y5aJ_Q?
z|4p;d(w$m55hzI6Ge`pC##$ps#Mn0)gY&rXA0N>y#Sex2e Kea%Sdy*UY|yeGVm)Z
z_YlYI3J|dmm%ORHoA~9TS@<16<OgVq%5qFNWWEThe(1x$kVdW!4PNtHV;Dh~sgbCn
zi9QfLZz7K5&>F;WkbR)8V`(QDPV;Jg*4?a5v#4_RMKgM=#!U3amZL2#AX7>21=3Lm
z{~Qk$y}lrvP2pF~i4pV8^VBE&408(Sw3Lf=-&Kkz!<k?sm#bOT^fB5C*s<TLC&M`1
z5vON-FL9Fahq><tN#<$Sg%LWrKtcu6J<Q3ug0AmQ6~35sL08Y=h4Bj;S0B*yf^LKl
zco1#R=~jj8$hkz{t;L<15wvjGhPDa3H%K6;e9f l<E0mC=Ho%Tb|jaNG`thvzLVTU
zZeO#+Mk19tN-ibfrv-B WINKg>r4|_=d_RfbAS>xw1I #9PA($O>Ya<)hg-rhB5WU
zS{!15?|1D|ffq5?9+g_B0sh^<xg|3QH=^RGk9?bWM+#0Bc60_)BLaJlz{0-D5(o8r
z`Om;738b~`VCI~6-e&s UMpfhe3CxaLGC_)jQ;~3Z6{A3%mu!W$p6%{(hqDdoWYw3
z-%r-xIU&q6us v5rxz{Dqc)H<{O-Hl&w}h5q>Ya`J0w8p4)ke_jUEw4M`6^m`Gzm(
ziRJ<$QH6Qd1uUw^fo*7RYsfkPpPa Iba*KJG0E(?NB3ZG1qQ_L btMep7Vmw#JB?r
zsy(XsY^7n64xE?A^40iV=(t|*?qHJL_|#ZfvW?7NL6HBptTKrQZ1lv2J8x~_MfZ)t
zWTsphD_uZa Ga5FalAK@v=!OkVP9#ZF^F`;AAxCnx!9%IMu6NkXA_Zdh*Xn09a97O
z(G<h<(1Ufy02*_XBm$O$j1Z(mp4iP{H`#J^LOs1_61Q%aLAelIR1&?App(t#k_)qM
zbZ67#7~RRMOVkv)Fw>5W{Sb?$UZdY+-qRB}2#1lDXfuo?rXu zm_!4=L)--o(|Z5;
zA({+ZGYlRfkQ;NqQCEH`nJ~hleu!;5{-pAQ 5f{dZNc0JqnInJhJGbQd|_(T<H{2l
z!Xs4n#xDW2_}>rZ^ZAaFQCQ}q;k40yR_|K}{pF><!H#o+SBirj3*)?B&Wjj!VlDGm
z+5MlNAMRV qD_B|f~Oq7*Uw;2*Z8#m^QNt*z^OSp%m}{kZB!sZ{<Te6iBH~X^dzZ`
zT$6M9LbB4OP5s_w`qYNU 0>jN`;KuzvBjvO<&)!6q(n bXB^P`hj^@++vh`aq7Tv#
zrK+%5OUu02PAJu)6MA?L5q0}Uhdybx<@ZAdT|FlOW~e9buqA{4vo_YBgO3F=os$`m
zk4REMj6tvE|6a<IkZmW}1mvbl8`R)Er S|Ee~{qG2FF_tw!dKcJ+;;ETcHQSN&4&C
z1K|)cZwL|f(gsOoN4{Y|#61&hpChS%0abIf%NJ-p7DB|?BVmLs2xBKmaS6zaah2Xo
zXO5P>4gYAhY _UtgxvCpXo7ZW7E<)6$8}-TQzY>+>l# nzK+zq28#(V-nPp1>jZ3F
zC>{S5>AIKA5)*BO+C=kJL?a#fb%gY&%1$sX?hS lGzaNupc8Qe-WyHDkZ!^@_GwVp
z dv*ryNb<_{3XEyz1Lvq>1LdW+cKK}^RwAieWpqLM$4tkuqX9gmpdk#`pm}~upIdt
zWkv9Y$lI4EcXH1NJD;1PrmGehNa~}FIa9v$Gm|~M=(wjfqh(4TFML0DG3ho<O%kUL
z%Q2Sa8!anvjc&npF2~CCXo~-N23Y!zTc%Jb_w^$V>(%Qnm|QstM>e8GU2_C=^vm?8
zS8u{?f9yDNki%b}08-WH^Vi^>E?wjoNJ8YlwqYLHj`RVJ%Z9Tj&qcZHjpirMVDa25
zm*i{ !1i_XCi&1kL)a}g`lKf*0Aa)V_5|e2XibP7-kLM$oA+*^?esX_<pqrHn^zG|
zl83EqIA ={F5+U`U!s1cc1K!8Aj@5W8zEAUZ2#IuZjbASU4JnBrzcr`UoN0#GLn-3
z_mzJSfgjqs 4IUmsY-mcuzu=QaW}F(`Qdrt6Ynnyzls7*g{QSL_A0>M4W6{gixY^d
zNmw&pbtC%`@@6|H NP5EH;#sfdVt##__~Y(@aCSg6_eE0llVk^>Pu<(by2uhb{c>J
z>S<(|_P+o#Jk2bo;k4|}^Gwyg!k9i9nS)I&jFAb{hd2mpANaGU=IJJ`*wjgFK&bKE
z*LJc^B)0dJEXXSbO8V4!7qCz8-3UJ%O{8y`Pd$fS9D%);gn70!;|dkIK8&%Y<)pCh
zePO$vuKxyMV~c(qh=>+p$y>kpqc6M^WfNsEO_p!Mq>2+&px|nQ-U+0GmOkfSG&@U%
zd0&$w=b(oMf9i1mPRwjJb}(|Yfuc5Cx0EQ^z cI#_&^Xl^w*Fp`uac26~l-xUb(l_
zsx2xl%CUFC{}_yHMX#NizkG>J{I&I9WgZud67f{$G9$9jYirz$# %kExG!hGh;rcs
zkFp>K3 +kl@a|gO*dS pFPwn5YmcrICyru1h;aX70`?z=D6ZxuMf}YTy3#puA`YON
zhrIcrg}Au~I3uoi=_)JrOpfwYBd%l5DO1rdYaC*KGT0R0BYJ*?TdK&Ns{=*3^$&@c
zM0>kTGMz1mKOh-Ra3|5;e%eV7Qi0>(VSypL*Qa0=7H^fT?uzyfK`)dGIRdTD)8v0P
zm#u(0p**v|lPTVQ_`8!opv70`1Sf~61{($U?tIx(1b4On)&?3dnZ$HDZmJsqd6%MQ
zRht8>fdbj bvNQYI&vx4GW5eZ;wSj*rPp8faM%-m8crPaL3Xu1o)?6}#i+Osz(qTt
zD{yC<MUN2Guz*!+1fY<-4Mp$#tloK$j5$)KUUK^m&6BPSkp>*VraWKCL-#~`Cm;tn
z<w4`kL)52V45TAOZ=bXRWKW6C314;C-A(20Zm!6JB)I$Yzj-pQm^-MPck$yM^3F)P
zf&FsJcPH>3Y4N~RE%^2aG=JPE|I;jqjTF0um4&<Rrq(8?xznX~=v`wi;a<PH#xjZe
z^i+O_>sZ+8UE 2^NP^sXK|T7R4=&3o$~k=d`{=^Ip8*CeCT&Dav|R =#(N)yy(4)@
z5r*6q$<pzBT}|`9(u$t~Q MO@Ch7!|&$lRq8#6}q2PB$Z*iE+MoTJDpG$451AZ{h=
zn+e~m=zWgKcSSNV*Uf}qAc^b9AP;$14)0UoU?NB{WP<n2;k()F7zyl7MzRCKgd@@z
z;8}C{pJ~V+gX^CpYlGATT0kzGgI=7CvW-+1rBgl^Abb= lb4*>xP5a`8fx+5!OE%G
zapU#3^dQB6kRIe4wA>fM-Nt=J9H`~W!3hoiPyO #OZ=1l$^KRTY5qBD+gJvqcLJHG
zr}p82(v=9c+kZ#FMG7-Bz>*Yfay1qp-`j#r?}F_te1N19jf_9qz(%^_8WR4+$re2!
z;%qOW>30-hGSH%B{oZ<l{yZ>Txv~@|?34FRY#M*d;g3ym8a?TE-zRi(8+oe$K{y$+
z1*y;HdnW^H{|;-XCmc_wCmF=Ndl!?C6<2m1?)e|8t-fNZ42gN*u?ozKtOpB$FC82+
zO1b UADAJ?b+QyggX@;HHkqBj*be0Tt^2^0DXN+jXrU(7LhRcie(G#NdnSTWBE(X}
zI7e_7g6sm8*hF3_yy&iOY`gd?m_8nwqiirw4GD0bO`=rmTj^qqSH78Eanp^3fV72%
z%)*Z&(@JHO Pnp-k{4RLo8rTrHgn|na89(04SYIiTPJ&RK`_-rH{Q+#?pd=N{iWfy
zSa`M(th<|BO!IMNe4ur+zbpx#&Gk>u&NWoj<z5hFSN{s9KH&u=cwftN$Jx%9%DK8-
zIuOW5+z$_v;nmk A%0Av!~^MceWa_R72H!aR$n6=>`5z~>2ECVizZTh9V^*AuGC!$
z*+1b>jLjR7P?P *Cg^E|bG`M-HaIChj!T>9PO +~x6_+G+Tt+1GlpZcD)YQI5vBa}
z7IZO`y?MWkU#x?8O1tdUb}ldX?;^1nm4Xut|G86SChW0`kvB1w9yFQu*Z|Q<yCT7g
zveG8jmCHA9&>z=M3mcx*V+t%F+??_yKafAT4dLNpKe~pX$mqL{ums-|A4(obKK&u-
zD%!rR<=J>RZeoz%y-W5*6s3mWY<u?c{I^)<(m>;JcxH!`_g=rCTk(NWy!y=VZ 1{e
zNBd!xqoR9~9p3Pl;cL*9p4z0B<A?$L j*y4EA`YWP50F}X<ns(@9CNu&ftmeR-{OH
z 1`P?R})D^`ij5^denXKdiYRWG68i~8zy~}1Z3yXlV*G&Wv7tT6r#UN*z)Ys5t!bH
zua={OTa6IIhd|25&Ol802&8^vJ9rpR(bRtf$jGuR+{(g%%F8+74T&V4(kJ~)^Geo_
z1y)Pc9cPRv8PiagaA?7DwKS|&(kmJuocP1PL Q_RMIM^HslA7Lzlp`eafm9mdT+cl
zcz$$tEASO-V#W?sstwmbaUUzKEIXK#C}uTNw4%Y9eXxO#2aR6Qk^8y;pN)fWS9y=L
zCHrByEg_MReV-2+3WAHxW5sfRU1*e>4WvICM8u}aVQ>5~u3ctaR~6b_<n>0&lOQnt
zbiuWj{U2GWj;!S+CeU7n7TL?Z|MHMSyE6CqGOGj>A7KZx)s?OZph3k+o0rS#q70lx
z$%DUtSb4RhV0USg>mCFCU{;=Y&S~MaAXG*2Y($w;vQi&%u0d%pxRX07esm~#;Syu)
zHCvb!qvpnWO~XBeQ f0_oGoyFA!acKB-v$!u2QHRRefAmpyRV>X(=b7Zcjd(e!NbW
z<$)*CHt6>bb>kR=62DT0BIlii{;M=)?$Ci6ey^B&ctXWY(;+Q|2cT?ObpiirmBxMG
zi?U~&X6zeaczh0Wc(`?~IL{1bwHi^!z>CsnuNZ!kTBSx{5-BJ(!Y`R&t7$pL4Wo~-
z#{QhEtY#UBImoyN<b<cW-&H znIVcYSI@G l@n}~_G^Rk*Z|^YiC^BP;MM$|Z5)(=
z-`;im!YKTcUSliE?6B?plLi7;5_aNg?1^pq_iHM#KtFq|@&1JQ@(H$nofIgHi_LA_
z7U;L 93Oj_+mb?`S#DzUaSlfyapaAOz+D{guS>+qhq2LY1<t;RM+^#V{=4yH6Gftl
z?8eDpbT040I7q4iHI{InTFv+^*zaEg%CX^Lq7A}J&4Cm5*oVVTG)Os+k8u0T1Rc(>
znS<=3VJZzV-t>9GUT&%z&T(|!!CJVaPwK{0M01{!bqL30M&b3u5M6L;id1J1gyhDZ
zaYT>7W_F^7U?~x8OHpy0UafUn6T5BAxPKz|o4Dob+6N>(UK;*ta>v1s^ZGMa6n4A~
z*+dqB9Y?kk<o}<})-#~RjX@>I`*!`6g= *2Ky30zZrytHAam=Mj-%<B3c_(4h!V_V
zrDavWcO>X6mAsz%pDdaB{E;hTvI6gCju}CGmb)F$9J;NrnRB{2vKoE4?jSZxvg8>}
zT&X9bePtoOrzEDc9DVU0hCbfCK}^7SC+5U;?Iqg6rAzr9{Y<&W4Q^ksslnK2r0GU9
z1WSL^ZGfv?zr?w*0m$HXOZdO{;2I`A>#lG%suPM}1oE*omeN(d1%rR&BF7=66Fcn3
zB|#IN-jF#S1DSD1zlmk`2>T2T)78&D5|-Nh`FJyQogTWJ_ B}gKI;aWbbBcv6F5(8
z2 =+0Q=%MNOZRZ9$xYClBs%dS3sc-fvVjw#b>OLwfq?PdUopgRjbRsGARRM$r6d;Q
zxxv2p KI*!Q5gTtLZw8wCGrL*h2gndg%dwBcY{F^^%?A_C8xzVZ%<?7OQgWUWN Bh
z^n5mQ9Pf#9zZL+r|BLg;JEE0naZ*W>lJYtld|2St9idnDRw+J?I3V8K6ztM29v$J&
z_ce4UMIn3$x7M7Wt9v}wFv(RZ#R#lnS6gu~10pbRmnH%|l=JNL83$f45exEYLwrD$
z*Gi|?w;i OrGoFPnT3p(QdudS(73c?oK6XfCwf?DjU4)xo33LoPDvP>i;}VOuP8&`
zvdP?Xw6To8t>&p6mKL?#8T!)Cop!k0pTH9;8SsM?`Q_s6ZEA`7folFqw|sU(YKP7B
z9QE7woE94^-nojrtuQjKxq _KBCwK_EfjxU_<1qEMn;pkVz-nYntP+7Oy9#Xv6AGy
z+!k!oJcxg4-7cjYw$mB%lFc>`_on3pjNBUB9G|A)k^$w<;F*QE^Zl y&6jg4Cp!Xn
zs%yoGZp{0Nlf=K3y`oRSgv#D=j{0xa(_FTkoc!S2cZ{~4 DnW8`zhGcR_dc3IXZ*J
zf#-fb%v1x<B|C(3hmI<P{nb)=iOU&Bz|J>O6C03~DcsLHPAd}*9DCAnBk&UjY-wPI
ztf1 JfeI1nU?!(+5_cHX+)U{pp65ERp#MLg3dK0(?(*L>+p<T8 ZByy@Tk&Lfc{%Q
zb=zLyyX6N&CwV=UysIi)<+ILiH1gFGf In~?e#7Qsv}XbN6(@j`s6KyG9J|vBr{rt
z+Y*S<R~BRXC;8H6<AOijf<Io`8JoA)`>B;0Tu(?IdP&Z{QY+OxLv7nLZMH}}t4HVU
zH>j#0Q18U*TkYp`lrBz6WkvYn`Vrr~7Oumi{k}or1$AE-{{z48s*n78v%W}^8S1Q&
zn2(SAeRx;N)D*t*7ruD-g#eAceIKr>&K=1FE`Ju6SBD*Sho8SDw`;q>Tp%e42U<k0
z^pImp!7yJ(#!}$~9 TxSo80061_z>xHcSUU%F22+k#{eMvR78giPQKvm2v#l)kdo!
z*e{-=TX-z&7w_OA OC7jOuCi<JNgsG R6?!Pu=A}c@cjBi5~LG8u?v5A5x_Tp_NgL
V7~sRTFNEiTfZ~fQc(x<}`9D*L!)E{h

literal 0
HcmV?d00001

diff --git a/bin/loader/keymaps-ppc b/bin/loader/keymaps-ppc
new file mode 100644
index 0000000000000000000000000000000000000000..914f4bfd6a36a0b42c8fb5f61284a4c15ee26b8d
GIT binary patch
literal 12871
zcmZX)dpy(c8$Z5zWlO`9a<(Z-DUm}CZ8jp6au!Lfa*E2SoY{tjltZP6j8Y+|R49kd
z9E%*vvC=lDIh*q^+i&mB_xJdH|M>lP-RJvp-`D-Tp4WBV$fTX1jSkUsLcr|R#1MOj
z9A2GcS%KU5q4XUlN+(1lo?%S}&DM4_C^nTiXda5Yn07FAN2&}B+0AcC_+;#H%l y~
zR>xHTd}fg6N_J+y!RV(>g)6vATiK_MYX`4$=Sv*7Y8=W=E~(w~YjZApusQucd^L(*
zN1<;|{dUV1CS-v#K6~L=Odd1V{Q2p(HePdKul%~|^ExFPq5ahcYlBaKJIN)V)<lEX
z77Pq)4~$+Vq<&rpRVz63|7#%ft~s{$Uyd+u8ZD>IeNeq`m_q)I(MLU=;>`zbb6OPt
zgx$r_dAz9jH8R2$IkOf} M%pkFajx~IKx{U4hh7S^HXcK%JFS;bN!dM;)fAed=>R4
zrLy$<w{HaF%Kh43mfrbo)ZaI!W!OKrUGe}?(=S$OTs1frrC&MF_hGePGIpK}x5{y<
zzx8G2#&A%8f16-ncc1TI{V=mLHX^wi-M>A$)%#(*{ZdV&g1A_9-LTw KV>UuHSP4s
z-<gTv)BQb-^B)uy{rQpl!J(v?Kj RQQdd6f>N9v;&5Y*dTazMH>&6N*yvUPx4|6>O
zemCDZc{h|X#(TYW6<vQi_GN s&DixeqvzG(3YK4^6y7>F#<pHH5>G0Y+`dD8;?SRX
z>|gxkk81n^?{y<^`cCq_koOodUlrwf$)AzX=7sRdJo7|xNyZ^3&_Le4-?;s?-~pVt
z3rXYJ?z^<hJ1e43($+p2pX{*wC^ Snk83?9IgxpW>fSme uyY1Ty^lt?2+IEMNe}E
zG*lPFHayjw;~6n t}<Sc)Lf3}Z)gE=)BvN5+YnJr(MFxf`yQM}N6t{O%HFSJSA-)c
zVVfCUOB+#kk^77qy*49_*nJsxlR0-Z)kHl_xbYf$HKQCn592bTU*CDqm0{4Faa~UP
zEujZ L2vrenb$uHwC-rVcqr#q(vux}Tl*p2pqP+e{^0M3PqlDA)!7O1JlAT3-Vyxa
z&mb_nzw*g;+;DSn`PMPm?}NOpq1anTYhDgF%)5ttj2JvwsW{Q-8^<?T+Zpln_BHs&
zD? eN!WOtAcbk~f>qp$}<#o LoaoE&{3P>nCq)C`U2M5^!!n$ED2btW)MXS&x|4Af
zKcDVKCTcI$#Nb0k5sr&~vWIq1V?ue2{FHGRw%q6;-EFFDDW2QMlf#$bi|{Wfofx!}
z*NcYVj9$hk#zWj;C&glsPSFaSN4c8Qwb6yefh{kUe_OcIR8h;W6ue!n#GRN!-uI<4
zguTYyyhw|`YOX4CuBr7J0~g-W-{;*=zAeSclX|<m_s9;JJRuo-lYKjOM1P$Z% 8pv
zc!xZ_#t-VBKql}n-6%cLmEm_x^Y=qi%YoO!lS;gj6>b*p*h#~eocOodizy=9PNW)l
z$yPWzAX7VfalLJszQ{jq@|x;*>Hgxo=zRS4uhl)t!6QgN+IY2)<A_?VtmCM9HDq8!
z%O&n*s8sA=igGm)8X#jeDuPM?LPe2{tsm5IBLNDus8A4 s=9at6&Js_vr;6xTHcEJ
zt6JJ>1c7>x6o4*0y~T|m*?>nk`fWx<w=b+)Eke1I&sh|lQi3rJ`6-5{#DxF6d14aw
zn>z} lgI|ke)o4o2Nj+8ReZwtV;JxCV|*f=dS+$RzPJ&RZAo#w f2U&eAAn`S5)b`
zuvT%?VZJ`#^$I I)1<=N{gk7<R7Oj=sK(P~hICWEL{8_$Bi<AfU+UmgZ#|Wp)Gw4x
zhfG`bWApF*!Rg(kB5W;f#7w`3ey}Ds|Dt~J27NtKKuhJYc8cv>K1*49jPzF3C{Nhy
zAK!$>6b`9~9n*bPeKhNduI7>LOESvb*ZJA6<uaZwLI!tS4d6_D|7JLt4hg2ZU27T*
zDI<=uPc2hSeR7*4VU)}=X2?<v$FM%LY ~|)=h{mK*>Cg|N2 -uY~tufNu;t{gC6^o
z3Lmyn7pYFk ?%}uxLunRvb-AkMRf!Dgd4K^Pe~L1%ys`GD^a%akcLJf3?;s6{MW{X
z`c#dPN0H)XquQJpzZPMB<O#R$zM-%(*00c`eiL?Kl73IP8Y32=fFJ8+B!b-KwK&8*
z<T~TPOGkhb`OdZ<)!;Z4U))!5VwvV-rQ8iUC$&+D>^Bi|i=a-f*BZ!-N$KWHxvB9?
z;bR?m|3Jn7_qhaL4L+DC{|0JkdB<`byk&=Cgx -C$iD$MXw874Opg1D9RD#1{^5eg
z)j|Vjz{* np26Uwpa4W?tE&rPt~yo09~pd>yFRKMDsM!9GcCCy|466UMv;)Nv)rsj
z<G&B8MioO<|2<k~oDBS0a+ZZxXuirhe5WCP lvgH)hOg|+|^99e>g9|t`gCGFxrdv
z+`Wr(w^N*}8j90cqMO~S+QXMmY<M$h&L6nibhV#r!4>D$G+}mg+eLRYU(OZD`XKC;
zhvM&l$(Inpt9NoZ*RMlNT2ESV&jdpDG PsIlWE7&z9l4ys)Q<Qr^ g%*{WVxJp_J?
z>y|x$snfgX%WHpve+d>SSSRQnq(B?Hj~ wjYw(*G=3a`{qtgc17i%rXh+2TlA?=2e
z$b*zeW#cm(xdseH8N_vshS6L6SnoFi>(l($n*1A68!U?rd!v_K6D74TyT-M{VB~{K
z*i3ML+Xa6FxrMb1`Pb&Pix(!(bfbB(n<K$xtk1QXdSO|DEli18FPCX!1$z+)Zl2sz
zo&<6)>jk){>w)Nwu4ktq_6pqQPLM8t{5$ Iv&`uM+T?$meyN3RC$wg3V}tvajOD{}
zTNSmat6}cgKBn_dCJ}ct`m<)e+}78QV$IWuvbi2#zJb&UUMjq&qN!2tnce3(UHa~X
z8LeL01v Wnxzh-8-)GJ4^cP?cI~ZVL%ch8x(R|qo*|ACNhi600)I}e*a^jzlZoF%E
zy*q)?q6;rHEyK&qd5A)i4ZEzARG1uwtA6UHenE{NY-VjYxK;BFH0vx8FNz%#iK7_k
z0*U=GW416m#rGr;I_0l6L4}*?b4`J5?t3j;D^;pS>d-+Tv5aKnu9UhP5B6a`NWwV7
zo+2pA%M=FZrH=p7GG<GZP`d1N{~k8wlsjl<xj?um*#lIqLvhZv=LU~k**R_9SXq6u
z1nO~CS~Vn0WcP#rraI Ea*y|e35}7IHBk7ZO(%l-iCc6Jl%K+S4Edcp4IW&rWf9%f
zUO>G`Zvqk3?decW_4XlvYDmMJ=ja^_Bb=o1vubCU^m|L7q5ekI2+(Hx(J^8ipl^j>
zgiS&J#U5qXS0Bs72SWVvFGID?AYPe==k9=mq7FHo83ZyOgkhyu+0P#^z%BN>G`Y+s
zyeW{sg#1NF<hJ^Ph?qa&?6cw-x6#!$<Sz)+?3HYm zh7_<=i}zRp9U^=&n(#FjLPV
zI&2<%p{)Vv+uH a!Skd=@Xrv3UlHq=#0Mwg(?v)VB3fb*iGjcPDQSEHu7*y%p&qw_
z6<^MEHR2ay0+$JQ(QlwSNeplhp66u%clU-D#3MXLz<+MR_b!8!cf;HMdD0J05KBLl
zF-t(@>)%eObOHCIJk|ZvP`FTaw$M x4SYvMZ!l*J9Abt7MG&KkGoYKgTN1}5c+bC`
zXo|r0NS2mqqI-7DfkpT-wIX$6V2w2XA2Iy>_A!tK^ =U9M)lU>vlS!dM&0yH8YtQ4
zrimJ3sO}9-{+PPJOluyWC~tCRb5Xd(3F2Nv!4YFX 9QtBL_byR=0Hq%8&JqHer2Sj
z9v!xWnR3NrPcwP4sCJ5&y%_H$JjcQsv!7=}r_U~7l|O_jeZBNMOldRRuo<`){_DR3
zy8(|fWIRV;N1mJS=9%&uIS$;2Z-7Vi_8&w+&k!)A?Rl;XA9!JmXwN~<5$~dl5#io&
z`|GRaf%nQ_Vk-UoQ!8ejg^2zzM283ZR)yeNx(X3myYb=hd 3Ex2m3YZauEOGF*FJl
zPrEnhEqk8FmzFxh;e%V!1t3iIgm7P*G4K}_xnwK9c{ScQ)uSB0H>{uGP+pA!+J9F0
zmvg}dgpvl&0b#8Rw<Uy?zv?^vLZTUdXM^%#8D}jjCb}`QzJpH+<@xeHHo6IJG}D#8
z8$SCCe;HobvY-P$%X!HH3rGI}-j>9#{G6em=AJHH#VvAz82B*o26?m%?|9t`<yXfW
zA4t~|C^}=y<gfq|l{&d}PME)-UYEDjEI=XjO1EroyQsIyd(p|eiSAg2A Doh0rKhN
zT`i^Ovh1^$WZ6 Dz7bkoyr?x5-w7elEFrU6fKP`S;FEDz7I)*4taW34J1D7(Ql(A(
z_KmV7>i r~L_7%dTDey*dtgslr~q=y5`4*YaOV*v{_SLLgdPw~2A}jyC+b}ID(Ww^
z7;ymj#ZleQJLZ!odKLCYpsJt5*|2+%w&*x<Gxgr8*`w_$aQ!OkXX`#$tz7H1C}YWf
za3w7?Q2nX!cjtnxysI{_)hlZj)ux<3yIf!n0?;|1Lf@|6DU#Cgp8aC`$*?3me3o7_
zbVQ%rMiF^tB`8ODV0MlmJDb;=BtJ{MlG^3PvW7X7d?$P?BiXLTwhh9mx7F<}CPbCU
zIiaNKBxDb^bZh uCb4P2#G`~*6jUPoO&Fuo+Gk>%r=6QvN(y`q?xAbE_suImeHC_a
zYk!Bjzq<Xsx1w!P>Q8S#y3bb~-!wi(eN%CicV?D0TqH_JzTMRgf2Do|a7vje*GLgn
zdWg4MB=b2BFNAjHM)6wju$-%%)H5Xc-#+_q^qUNE%s-Zp0wZ|l)&>o;Xr;>hb%Nxu
zq)o(sSJ?On8dv!jrL<xx4&Pbx8EPMfmC4FRSl?akM_5N-=fIz#z5kzZIz?-hfcAm!
z99DxL-adUZocd)Rt%N?g3x4<%C^<bBs=|{*<5nKeq8WG4aHo2NHAi(0Y(WRE!#8C5
zoEdl0p-*{vReRC7!_xoKq4}+6nBeiwp&M m3dv7IXl~B>uMqU#qH#lER8Af`7ZH9T
z7(SRcFVYt6w;=Y+5YExvLX 6`>(~Y&*pc ?=l0|fW*wguW<a^AQIOF%3c64=cL1F`
zD1Y1a6*SJ~U0sh>negXzhy?=^jUUV29BG|Pxq1xlG?o*(vD&;I13kw0=cLyOc+SFH
zgCk<o-L0r2VbqF0^6j6YpgHhL_v>sl$mLQ5s9JLajs1?Y&V~~HEv<p3CWxP)-3Y8N
zu7qge3Y^+5)h$PaKTU#2olnqF`XsV_{_FauUc-oUVv2`eR`>K{f&7#>t>5Nq-Wk1}
z5_j)!U8jZHTA4_rFRD%MoGN&7D?cIX#Bv|CFzQ5e(IFzmVday`aE+bMuzLResx+hd
za$UCg&sGyzzk~a 5{1LiJdMB7lKpAnQeQbXwhe#InPWPF_j%$6O?+`f(&br3PjuNC
zRHV_NG=5t|t}-9ZT*nsX*m0!gWIS14F}DKxO^$4uJnl^Aws$<c>lfP_Ze$yqzLZc7
zDLxc+_-US*T6uEsKb^1jy;NKDuB-Y_N?pwiD-d$9kC<C|y5&J`ZRI{GY;pp|5;(<3
zVV5;w{ 88ZcsqpDk>>6e%Rt~oLP2 UB&he3&21S2P~PhLV|o3D7T=I Xewv}V2ZA#
z!DJ47#+d%wKMU E5+PB~xETmGZ!^zsO1r+++!3U1UsWenBrT1raS=OsNmqnhQt^%%
zRc%)q_B#g7I5|rbk5KOwuf15B`ujo1$mviGqlBnH_1?p!ja%cJ1?G#F{wAj|8mo`e
z>l3~dlfKttik*bxMrvHP<3D!)!^>p}M{lv 0<p9iPMerROIWVYk~vNG@>tAt+uVi5
z$r<wBCu}qAZ^8~~DMhU<d#=EC{064-%w;2TPljI7h2w}7s#N4L;GYPn#+eaDc=4(W
zsLiy6FA;qZRIPM0*yzKt&@?vQUeNX`Tq*Dt4M^_klD>fk(-4Piwux`zr}xAC&!FL{
zHPFDH1hZxA$0pUnD}Eio-XWk6jorQ0nq9&I*N%aIE-!q-T(<|_`;N5QuD3p9Va(y0
z&Z6*CFus9hjH_&A8L#mC1%UuGb~BuS9OAoAid|LnC7KxY0g;_N<6-HCaV}HE!n+Fl
zg^W`?O#6j~beRF%#_At k~=TYaS2bVbBOzlC6S>bqyd`#2)t`Tf**%T#LM$N*CMs}
zadg#1w`3MYbB3A6mOD(to34I}^CH}W#~Bopd_EjAhwpvR8yDfDZXbs?=L*hxPgO3P
z Db$%&ugLYZM1UR$C=t=&Ru#T>;jV-r*tFyW7rW1_;l!euEk!2lOby*iuqdsRW2PN
z6n7mBo?Md*7aHUQEmP;tAwp^4Le&x5H>xI+ScB5ZoOfkMxbYD}-3QNcZ}{Cs9J^>m
zP*_Z{1VxXK>(w~#EFN=G8j-D(_{Bfy-LnhoOOf5jCQkSH8jtT5u;cL!c$TfUM0UEL
zRl<Re*fX52UHGq}ZHm!lb^KEdzX!~BWxKd{6P2UGewfUsyj_$Qp(Ke)xNuA31 GDp
zQZO%aU=1QeUXjiHs+uq;&p3b6gAm6b `s#Bp>~a|LlW3lczove5gMj8ty^*|YX^_w
z<<=O%499Zzx~6jZVAm=x`w-UyF#~##0p7!_YW}y=U;H0Ynz=7j;1OA{iJ5Kuh3j1N
zffyJMW69uaukEkZSX_u%U}TT+CDXt(GtQSEe7CV|u#uZU0X!9(hGqwh6aJhh6T{Sj
z4iCj0pWG?p2Oi)ns{|a_nd1bRxUSeHeXw3!<s#(SfMM#nRN|YJ=7;Ur {lEWT%daO
z4M=_`_UcNrf{h0*jDb|QgcKJGOL1WJ;w^T*%+phA2^z<EXCZNjQ+&EV&ud216#k#h
zPZ-dW*eukPZR5CiVF%N_A%PA10omuW)GJT)fNKk88~A_w0g+LP3r93xe 5vp#CA|r
zr31g=siej=1dgPLnzG$GWzTXp-0Ed_J`00fUv{gMP1uG1=B +^_mlZ=iL+TAYU|Lt
zx8DV%BJzkfA?#oU##<klBwX^2e=n<*I>^h#&=i_^xpbPNe<B;>cwj5G#iwE7`-1ef
zy`72VV~tA(S4oI~0k}y&E&JRU=8IIv|388gWwL1!Uoi<A&Tzma+<!a?Q&d~w<xX#(
zKwpLl>xolTx2_AC<4-(xz&!kQut)mTQ!}^Omf{Ix`SY(dD*tm5^3a4LRhP2wK+~$(
zrCBlC#|WIm{km(x&HX~}QCJ1u<7H6!d7itMz g7r1C5V?X<X?uKx6ICWl(cV8JbXq
zCTR1&gn=^jL{K1ac<%q0wiNZAZNu&S=u=F&l?Dfn?KCcrxOHyp;5zB#wVYl;t6jed
zf{0`|e34??UjQBh5^|x*&@Gerr-;ct1^^MSeUm>{-z|kwU8IvMqykTE>?HE<1&Z6i
zvC-E>!jb~uYotm#ppFa!eb^P)d*IDQZgBj1>wY+ciWz>gtj3$Fa2$80>hqNOR}hHY
zx8A<{wZlNMpU6JyxZ4$wxS|4R#_nH)wDfz3S=h k1Qm?8|DP2gKcJZE`eSao^*L9M
z9+BgmwFk%#ZsM+74F8~UcS7N>(%gGzm|a#e x*t`5mo`ja-9B4&gl(l_21#}$rI;v
zHLp-hKVIr k*cr^ezf}G{j5c0!kZrIg+k&GeD*x(aty>XX(+rh`G<(or*{L?N};(=
ztKRV?md_g=U-!XPW|!cO4ygreU- z8n(v@<<- Dj6<0b-yZ<*q<Qjr$)lDr<Qom*~
z6bg#HCxj<OYFPC*Oz8ab }*8yLW)zou}&@>;Y#g<520eBb-TqbykNO8*Zp%`ddLDB
zhiAJ{nPRpbtlSu#ZnuVY_5gcVq!^uwX`s{S?cZNKPhbtWJN$sLwIadNOn|euKGsWw
zFKPp~yXM|a)xOOY)58Ku;kkNDJ+_p~eHa_Xm5UZfHfS)q*!4~PecWBVm%OD 952pp
zo_zhmvTAwWMIY*aApkx0fykZ6Mix7SeI+!0Te;SPgP+J(6<Rq?ev5FAG3s5#=DWuj
zgn{fsL81|aUB4_4*sE}NOA^i!0osQE1(n8UI-}sAP6W0$E?f7V`xKaFps$7k-A7|d
z8g)=YXE~IREYAQZ;9Uqe2G6fY<_!+-*(#T=5xEv0x_y)^-$a?#YQW#D<LyJHOLTk#
z@@POFYwdmydiP5A=?JAc0T&8f!B!mlEsrP&KY&VYBEN<P&cYHm`kLsR`qZHar6I}v
z-vF}#q49a*UAH!o$wVbI?s(LGn;yx$y#fin+qy?`e+b+Oy&EBsz7^{^2}^vCvokD*
zFX(;!CI43_!(~%wgkKeMkY}UdxVh?0II~YVk_g_vKVYW{to)J2agj*mhtVG*JI XM
z8oJtQKH^Ti#*wbTn-JU{0yPZ~`Bs^T(Lsj$fNNM(i*)6UAop15F=={Y)z`1A$;=|7
z_nu$9idH1|{M;EDiT*`jPhJr597(^4n}Zcb?SB(-VAAz$)JjiX>R0KCBjNik3?zyc
z+NY^srES+urd`h()TNFqSg)JB?Uu|<i`buqj*fcq5?I#9Q5uN`|0YK={lDLfAp8Sx
z38RndRW2)p{%krYc}3Om-(>#<F6z5md?8}eqZFhp4xI>nZC6?Cz<^a|`y`?sVH}x{
z>i1k~B<#b_H0Ap<Ot_V*peV1f?m)klT~>rZ $B`rxbn5eL=@Nwp$S$P+=rovdw%t#
zdBrX5$T-p`i3LN0N4owjItI{vtm0(zB0r$&KAdKO-+k`_p0y&|q%U0Op6dpYW-#Td
z0<d+OF)ae0v{>C?oeMtC$+|j`YcP=Q)me42*3lbeso3%N`kmFGlxOb?VoN^xI3?Ed
zVz*wMD*{yBNLLUjdi=bHp4qilof0be1FCK3mhfYD)A+TgjZ_xWQrZ^21uTI#fDL-F
zG170Dd}Hj!lE}u>S_{iGOn(ZWL*a!jBfoo#r s5PJZ84EC+t4=K37ln=n~m2O}fo)
z%wx$nFb-uNZNbyddXrMM(RFQUS6DhX8Fen_Am5=G9~xzC%t`U%rgK#XXYeH)tHn(g
z8!3lxQRV%OyD9nheKr5v2xjO4me)w(ZEvK2 F(~pa+C?o=P}H+QH $&{3FcrK0Zf2
zmj84lWSOkQ(bMIB(>uvuOv2=A6z2uyZchFZHNX}5)+- *t>54!MjjeW341*K%I*mv
zvh+IUkinb7(7(X2{o-94u}^Vom?A<!X;^Hn(%+PgJz*Eik;{7a(rAlOeBA*kN~ux$
z8S4E3=!Ma)MsN|Yve7kE;tbPb5FU?{MqMui%e)FtW?J!i5zNb%0FI37hsF3`nw~cg
z1)j=|iMrJ~VdHdOmugwGF=2}~ SZX&0y%cm*IU}auqfgvi-7jre<4#r|7Lyp8wEnB
z6m6qz<Q=l>-9jlRDdp}(kkttPrbrfvolO4+pNd>bB)jT?N35=jS6lssS>dOPHS5 c
zk=L3P^ex3RTF73%#7?r1>I<Y!Cq;FGQ_-6nbt}V(^c-PaO2uC0T&GpX>jjI;-1mh=
z&e+fU`Yi0hCApM^M`&2NEm5OlAlj5wRH-YmeYOl=1u2SjPo2RW+1mXX^3xm{WpXq3
zM}tmkGqDizyVqaNJ4#c`eKpcf>{ID(9f@(SnV35hX$pL>O|SrLxQ^WvRgzqrE?mK1
zPbgun r^YwlymkC=k?88_s&>o4|eZD a4sKuE1^aw?qZ8@<eTTj-i<8sD_WyQJ#`q
zTMuDeZc_Y7J 1VTkom+yuI;zjo{PZ2AoEBSvHS?;YR|iKp5Qj~ZjEB#<$VMZV)#sV
zFnP9q+E8L6>D4wteUB&j>r2<_k!b9a*2A4M*c+Nk-PrhR`dJ>!)S08}z~idDbI Cf
zCB$Q Wl?My2cwkd;Y<eon3ar-=pPu=K#uP%%&TGIiZ6pStjeVv<PtUxsNRsGS^%F5
zeqt*%ZXF0`*6LU%?GnpB8C t>U`B$xa$8tun %s50yf+B4$ud>@Y(UizC9K|m^Y|h
zI{V_<_tmDf60oz1FQ`u53>ozaQXU+~Pa6j>+($Oj8_?|2gFDt~>kP|km?aij1C5rB
z2H|0NI3HBih oK`Fpc`PVyB-1QM<C3ZVW$$xxlDJo#mnY_1c*=A#ooSr~Kt3<x7c_
z7(c2Z=g?nJ6>Wf_vQohrpbjv7s-;R}XP9TIMef|6)BLW_ZY)RC1C9+<IQ73miy?7G
zbD*A)tvT^S)UQ=1X$4U2z==G4`iF JOEIpwJkw5qrF=_r@Vc)O^Ue;sYp%*lW6gnG
z70Pu)R-STgGmY|rMa)#SE}9_D$=x g2i*6#gX{Zvg2(yz<wbT8iz4Lqchc`eDSxa3
zh-VA;$(=<;y|4uWP-&LG<q}2{?R&A0S=Xiui26BaRd0! uuZ=U+V+$Yad*<_euqP2
zeit2jpo;ZSG)-3BlLCBSH2tnGM;+mjj--x+(0mBNcMy^1oprHK!i81`<p|N3Vu;M1
zj T8|E5J@)aQ3i_r6N{e(hC1wSCYJ<K=9&<&57je5{x#z#TakE)%69cFU$e|C>yI?
zy3~Ndb{%Te&0nC>WBf~Pjfb=MY{Z0dM#P<+V_Nu^zv_VAiI M_MBP#ZHOb}bz|+*k
za-)n--vs$~IiJ hT!m^r&w!N-6G(<2JSOKkq<jXHzP0#RP+#&sw ydIjiXzv@$7Pn
z>)}i}5K5oY4-z2N1-V>0lZq18-zgtgv-?@&vF~8LqCbytHT^#^q&jIg;0i53smPwQ
zEP=iNj1}%`gXvNa-`ed>Fq-sO^xHRgCZP<BYdXryl_RL7SA-Ev5VeEg8+9S}9j4Fq
z%c0PG@|DG|OV6QRf3l8_yi?FW#+z&KeAO6)I~r}}cI-%4ckTc_HPadlMMwoQjK9a2
zg|WvEJt7B=9j?>NR8kmp 4|1sD-Y4*H5il|*q aA>k)kFUpZ{>?WCD!jv4`#L}rPd
z^0~td!hP(T73`>F?Y=JbddH6E0l1)iLmr#+d`&%~Ye)S0eO<4<7 %fUPq+(TsNL`a
zn0aj#6u^j^hf4b6l%=4hL(!TZ3WEu4L|N#k^&3>n^=Q%EJY#_rY=g)SX%*9gQ#X!~
zQPmje3ft`Wp?im_?Fu29Bi<lh^h0ks>VUlCBS^vn%3ZOi&$eai<qqd9gCfQDR*GBa
z5g%-wDA+aaq2}GRNZR!o8LLLUquoVM$#Vi^19Vc;DOEEd&v$mv$-9wx)pBjwR~IrT
z)x_L;O YMdvJ|6D9aoKR$phlqx^Z<_ufy 3A5hg5u1W{x3cgE=Kp5{1h&}zWD}tEw
zZr6y-C8$k5EZ+nO;E-PvX`O)ezAvqKgwhMh2=D1$F%<^&?H=)LteDCbz<(OMSbNR4
zl=$FZ`To)PWJnJdZK+6DNa|HxGJCbD)H<#7Jv{HJcdo5s+Z0I)svt(4BWXpL)mcwK
zCSadGR7gK4dYvZ7WuhqJ?%Nt4InXa0)@?r*abDvwo{b*wxY*P3Fo~gi<#%slck|5r
z+&30gVf;fW^hRm*jvAxQ$=5Tvx<#>pZoqyTDlRSar%&%! !vj&Godj%m$AXzFh6d9
zVri>IfW*Lv-lAHqkmD%GHN~xJr1ecT<T<l1RKzuw-XO?Lmo H(;cG=TT6fn<X|yEy
z?<*Be_|KYW3vo+0H7$lMzprxq)EOyHKJ4pi6{H*`{g1m66bBPwA4tuZeKl-Uc06k&
zQYYY0Ck? UK*CryP7MlZw*pGu>qZ2Y8)ZNc;-VvaOi!68_Yt445*ZA)$*7W2p#5dM
zS`+!hh}*4WC!Wbk%Sy{XmuY`! u>Y_JHW(~0^ZEd(D4XS%B2LPUP~9zqlt6cp1ZFV
z-puKGycZwHcC?22>G~`rIX=L!Q7*grONOE8;-U^vjquo X~sBbdE#0u19R<n+|=hf
zp4q8DGXtfWM^_za3f6~A#Pek+-U#s##)2&Wb_LpI&wUD6`N4|9*)z>3cQbBgkkA-4
zhFNxqw}Rs9^28qD2 1J6q;7MvX9xH=v5sbxYl6IRPrO{im&#Bfq Uj;oIJm}L#+$^
zY?E-t2~rM)G%ZtyM8|d*P xsLxrF<D*+#hzAGQc5&kDMYQ ^jjp2Nvn67pu__VC#L
zyZKgaS2b_Zfo~zq!(N!*h_}R$#s=E49Vk;gKDQR05RWHZP9UEXjBQ!ygW8e! AC`5
zMT;6)!U0UT kHfQP??!cjV$QG;dQfpov~d *-#b>`?hU5_VG*L?x<Vac5?<4K9Z<%
z3aYZbnerRDuUk^hUA%l!<luMknZ>5XPNI6iCWsSdT^FO^L>{{FbBp}N_8hYJOks|-
zIB#E+wQ 1Ms8vCttMTLU0}Bd+K9<Pdq6&`kO{Jh%Yv5wy6CfQ0cY|6LoQ=XB5Zj4B
zeunf4POFCyrKvIt45_^kCS+^FekxxEDvz*9<G$3N$Jz?Y;qJ-~#*t$BJLH|Xb&tJ_
zfA8hco&{hd5dZ4rW2PBrm)WUDI~tR`j7 y0Cxz?FJ>&`wEwhV)-7WgCdr%(&#qz+9
zb>aWsQl<OT0SP8D2l&HzhtrF3Q`~V^(G(eVSL4$>>C%XZ*=WI712H =YBZ&RxNww3
zefq;r{MK&{KTnhoZ`Wr7W7nj4TLRN6Id&rOArpW9ugyL97^ *NBF~o&qp|t7WqBG;
z`;4Q{M^Di3=9d-6q}|~L9c+A#{i?}1a(oPK+1ll;axX{<y7wk1325mCaak0+qN)G(
zDLDqTMX{x><!Z~z7WktDd5qTliTOKw#6V)DV4r Ne3PVFw1)f79KPrNWx7o<`0m^D
z0I?L9e4S!st7{FPmGa50FK!sXj_IR(=HlBc^KqDLH$_ISHL&U_T!;1F5q)PEsL0$q
z8y|F2Y0##S*i>IVbZmt)o6z}w5Z?L=d(jq} gm0%8@nR(<^o_^2AD3Io-nUt?JszC
z)=%T%04grepj?0_hFGB)ke%%%=-Iu{`&>@iug1}`WXeh2=2Xuj{pCLlZ({1IxPaOu
zC(rF)f7o MgU8OJqUcVoGNS}9=N7MQgPJ&g=I8lgi7}oK&t1>Jn PrsXICwTtO{M`
zzzyyZRBv-zy|lRGk8F)z<4*S$4Sns;f+4!D%M!xe^f7SyY>Px#j7|=ufTa51C#wAM
zu*~#`-z_nFxK(P#vc!?!j~ZGjy7x5>HPe6J?sVnfye0MZN>Y7!Nc=KsJR-(^1bKp&
zt>)&$yCd;I6`MV*l=(@JHz2L{nENu~ZZc#P^eZ55`A<z(XrJZA7cJI>>-Lm2zxOwA
zeej;WrxxKyZC{kDP20Hc`bdx2T)h|SFX1 4%jN!arsLvC0YvUAYt*gYQ%3z9s_hzA
zMI9OBu=X;@8vS5LYwq(#f;>K(2=hPQ*|Z#RGA9WZu-meAW6+nGvRn DYA75`3@Qh_
zm|^;2TRr9M)`NqwR|k`&aeA%^UZdBm%Ml!C4|Om8ImD9_@|%;Sqxoq`M`9b3-%ur&
zE|-DkSM}g;7Q5;n?8282Jw`EVNPHF$--_|LN4<a!2OAd<FKZ~61Jd*SKDlat{`ybq
z=Q=*LmnxQoPi5hk8C?s)t0S0N1?&l4kpec6|1}7d&UJhWEJtj^V(@JPl*k*c3-Qqj
z+XY{xF9`@<k U%|!ZzZq;}h8WHcw%L)D#AK0;ZpG>%5J|Eo2|H&j0T)EURRt`HEWy
zF`IDQ7)d=BD!=xV6OwxG<`n63AncNO+nP>3*{{l|U2aI~5|qW%=pbIccefu_)AtA;
zrf~~$VC#T*A-hRp0a7T4+nnxe XCK9K2MQ<rNzS<5M*C%7o2Mc_o_uZDxz$~u_*ZE
zCx)B}YdL>A=Wrqr w!WN{E?BeiQ?VB11RH9kZyBi3Ai|{`dS*~aQJ})R-U^rp;FG9
z;9*oBY9 xozis~`pVdM+u3jJdaLVZ(!(+{~sxc~DiL4~n-9ILmd$A5uzWBV6crC|W
ztoyAiP>}5AOK{&53LiyY1gN!p1<YUh>VM4N+uDt~G{C+80xCKQYfHp*>2#lFTj+zK
z%m9vdE%1(^Qv6-cgo}w?- #G-`~1gGPOEa*tHboP;|b)D?XHk%9Ew|LxtBo~yE-KL
z2yY|I1Bg1gF^W_3=F3Yth^;jD EDcr=7vbVTtrOoUGqu}-fAMn^3=~KG5ESja99`r
z%o1tk7XihcIRTdq!1PWFK0ENb N#%0tH^0w7k-Ws@+=hbxUb>WEEGU;gQDwG`#8`C
z|66>7#iTU39HvtK%wEsICaJNJxsEMo|AtvRbm3VJxx?AFgZEAt*P+rTZ;+OASAvf6
z)~3U(gRX3&(>Psxc8+yGuzS|G a-}S?&oFFMNjUx28=tBkQ3W)PM(+oCM8$Fscw&d
z348|0F&UJWNZV-PG{D#zS$nVvYTI^yNCpmcr8br)weT0Frhsx(0|O-57(57r(+)?9
zY%wKfW6US%`m*<x9Q&Z`6ScN9`uCkzIE_Yw#`uxL?_=jaEyf!kb Mqj-?9J{Y(&=v
zJBs5x3lxX6e^QVs%(8rG{k!7D>eI>Wf*hyr<EMDNVb m^H$k;QpiANjycf mK;#*>
zy_Dyw_V>5}=(Jq}_(3B=ZVmylI8Y&NIP`z~WwPf?tmdz7=(Vtsra$n5vw}i7vPY2;
zqL{t>Y`vR$iA#Rm)n+kvd+B%>iJMb<{@(%fZz6-#5v1}$s`R&rG2tbnjkww~uBxry
zSfc!BEz5e9);4}B>s!{C7!1Eu xmw}gTq4Wl<(tjkFmz~FCoXy1roR~P$qrbl4G*0
zO}a(2+1itLZAMEvLuQDB&~LjdvX~f?$|r8Ajbp}3AOlmxM;*<uL1}zK1yXZ<6<ICq
z@>ZjwX*=PLRWX|b&50M4q3p6M5Q2`4H`KA$*PGbyV}tOt!q}jCyW&{K$g9^BYxm&G
z4823SBtM7-?=ggdM^`{zsP%)ia`>N<F$M#aeyo6F>ZbN%oq?NT`Ttk2e&VZC=BnTQ
zKTpsUSWRT@|F(6&?ZVRT4^bx~R2C9a{=%fa^<sVyw<Av^$t9q~8e?3mpMSIKkpAen
zl+0<X^KS?z4kmNLI;6F!$sAhr*?QGI3TpGMd*>5UCKI2)=rCz7jC)LQlleR;=_Ar+
z9)-)37N1aQmwY#|oEkJ1h+S~aRoYs#)r8A_kv?vzk<liP`G<NKuU8-As!8G8n1%L6
z>kFK-Ho08sO#=mX*99Q^klRijs$1K7ZdPC}Y*-=HCw6qtT4Uia&@-5~n;9a~v;f F
zCNCt$mI{-!{K;{w)&=!J%yD7p+C{*Jpja&K-!`<{?JXFW%9RN=<lrrhl+Mn_Tup|A
zRuzd?(ichc>BZo;YQI263f(0B%$UK_tMR014$bJulGz)%HWJ=Nyr5eiLG#CL>Za!$
z-h~Q?8G$SI$qVgk#;D%h0>3{%zTE{JROK0Z=eicf6zNDred41e>i9N4K7I*Aw79sW
z41>VyjjI`ro 4{M3vMGSBdLHVuW4Si-q?e0Eb&}iE&DB*Ptfj*Ic_B(#b2r(pnP#2
zUiAwbDNnhQK^yilT*m~Z##1uabK<qk-!EEqEz{o+m6=vZM-tv}0Y9$*dUP~1N2$k+
zFL)Sz+g-EvlK7=E{1c<^w*);ZM&LHklWNn{M^E`8@@2_xt$sR@;)l_7<&q_?8U5$3
zq4x`|(B9IdhZOPtR!^5)HD&S_9s<u<1hwGTJBoo*1`>C~3kG2=>!g)A()fl+OS9Ww
z*sixtuGSv)f=AVjFo>4tPxE)DxDF=VW86N0vOz@>Z;T-Gq))nvn}%!TnsZ%qBytQ=
z&88NcO9Ua&@K;aSWoylE+~hwDUmxEXX=$Ka0Bxb$uun)WQ^jmnQqgzGgA=RdGIOp7
z4YTlr&pux(RYn^RJyJ uV29U&HClbye=c!Db)#V#EpPM*vDI>p46RyG3K%WLZ jW-
z=n{K$ahFSy-l$n9jQ3uHpL7zo2NPWb 1E}a7+T~j_>#g9%1+W=jLd$-8ZmK+`xRhh
zd3~{~F)>u!ve_~_R#6|;)p# Gb0}iWUt|p T{$W|_(*zWs9Fa9%2Ole_ZE`O-<Uh|
zu#M040* _IA|G+c6?LG(hZtk7hBH!u0+D#aH_aj?KEltf3#m-;q{n$0Yb3`;eD8?c
z7RRm&f9Ecz>!Jgf_1=URbOl%>yT<cZ92UvZ`}rqy_&r?nW#kY1|0}%Y_iX&%(*LP`
zhv2kM5_<(PLb*C<;FU2%+n4j<O7ZUVr1xyv(EdVbpu}1?XIW4eq_s}_Qs*CvPTgJS
zAINjnM~Urq7q4^%%mmMs3VWx0!c{+*J16K>xEMpk2Bm80T6eJUu OwuS>nSPlD6YH
z_*iO3oxg`%b^GjF{8t4r{Wcw}D+!_##1tfZ7*_O#9B##1`s^^<Q*|pcFjUN4Eep{3
zGdh2N;6JQcv3XCdI3wkA3feLcmaqd1f^b6 Tm-(m?SU)5UhbUdWci67JI=e82|THm
zR4RoO^(kZ&q5Lm!?J&@ZeR%H6o!`j7`&!=U52C~NLflVmv*B4W7PYpFUtI$q+sacL
zdL-ryObK|mND<KI3|vfmP5e1Y+FvHV<CI4)@x0v5%6GNmDj}*SUT7{B80qT6J`Oo>
v>({;9w}n8T3(#B)ym=+9`2gu%Y}j3S_+D-}$M{Scu#Nev7Usv10zm%{dMjH(

literal 0
HcmV?d00001

diff --git a/bin/loader/keymaps-x86_64 b/bin/loader/keymaps-x86_64
new file mode 100644
index 0000000000000000000000000000000000000000..93f2e58d10c66c2586ad2f42deccdecaec16b177
GIT binary patch
literal 12173
zcmZ{KcTiK$7jMD^LQPPl2q6I#K>-1!6OsT5R=|deR1u|#p?8wdi&8`d1u3F}g`!ju
zNJ2*tkRn)sgf1WiLJ1IZAK%~1n|c4dxifor?>VzOyXSn)`JA1LP7;9pyf1u)2UxHZ
z4BR*Lq~WSvaYJ$8LpedHnJSN<0 aY`+~{6I%~5ArRpI74&XVLqRDtgt5+~u~1rhsJ
zn$GCM7bleLkNb8%2)Ec9+8uOD$yv7Dz2}hqo$T9-p>`v?PpQY>qgRR}N)dZUj#kdS
zFRh*1Ui`Ar;Eemc5|_b4qCu)Wmwp-P)%q?SRW^F?x8mPUR+XphUjvQW2_fCzi=mF~
zEmi&%{|H0$r}YKzX>Mp4NYx_bT2oQsy|_4j^AXQ;+h6=2pyLL;s*N=ID#6}$#&^xa
zossEvwoUcFUxpR;w&_)NzY!_z)&9ZAS+>{jDIc`-*pHp%kpO~g5Fz7B_%L>SCHybj
z3+?~;-#(I q1`R<-?g|qhOxSKp;1ZI-Cpz4;rqvaOmTnARMq#1Ryk!1_idNmf1h>l
zF3%s_0yiv(PJQ>}z3u(^oTL{A7gK&(NaZpXwvz+?{rS}PuWB)6DQergxUOr;dsusN
zB|HlffT*QdFa2yOtv !JQKA?c_@%8XuzhE<?EZ%P(9)Ot1Bz8<B!<GqP EHD=4boP
zu?=I-d2Wc#CzbGWy m12hYKi!n((E7Yi)tIYdq$iGHf4Y4(+|x#>nfO(2#KS3!;3P
zC=;Pm^E!PWt#6Rxw#7ysz^c8*3=Oo# 7xSr3VopU$ZYHcnAaSbin(Sgs(mzQ*4I%m
zJ5I+n?lqGqJBp7WiH&vX<!h4{jPiVN?{1UlW4Sx9VGEt+b<L6Myw6LN*30))J^bgm
zQ4Sl9@|61hZN2P1{RXL-MTj?QuKE<^Dg3+hsVU+E*?%>}PW5Sxz+MB_=WjeTzx9sW
zJbc<~b<Vv=Y3-zlbBA=&{*OT)4qMCi-wIKcjJkgLgBdJbZNU9JFtX(u|2JXldQ^$x
z_?DlV^ *GP?yJvl$P8$CoTzwalVn{u=;2#oU3?~MZ`MurZ-X|9kabfFLC{txgEmFr
zvlUcf?DO2qF1;iBb8R6YK<PI%g6eg<y6omNCqDsB^+&^D{{_Q^FAMzZM(g1L;x~IF
zn|z~L7i+Rcno3*(KY9#*`ygeF*Y&euvclbaWj3*Hmn+?VVeVlWDf)DZ(6K&AJ^I}c
zeq!+=KQWP+Vv1Jf<%Z$IjCjmj0{4R(jp3KL+EEcFps`QD)v?6=shQ8TmfPkhM3-BG
zE{B~Ba}To#3kfp|3%N8 c&PAjq2gUd*+&mM-b^kWI`>0yKE1L-iyI-!&HDT5S(<7J
zaSPo=w$2o0IbuI{6OW_&*xIgSz4I}Ddqqyn1|QV=UggWjJ)$8hQlwBLP)W^$&;12?
zC|Kb;rXqLx()mw=#m<Mp)eHCgCEb%MT7K;<w!8UGt>2)+VtkB1N3TxVWT=6~bSdJ|
zhhyssO+CcJP3jT-k~m`h>J0i7dwx|bqBIvY7~unJgsx4r1PR(FW-z9L`0Nu y!Qt%
zG|!LACo=+&trsy5U<4&N16wDx)D-fHg*GS1E>gFbp<!Zy46i>?|JuF1T20wvUM*2I
zd>i9F3pDK-_yx{s_JoaXO53;@234A%G%jt~+Onpe&~f__Q)!~(`5}hoT*vjjT`Z#7
zkJcN1azOqU6S?ntemq}2Qd`JEzvhTXh~CslzU*zFGa(W(8h;^k3SF2_*3QH?+uXix
zZm!sg>u#0qJ}D=wkxNV+52R5<a9dLpD`0!GFjmI>N)>-qKgsUZjZGs0&hXG6KI)WA
zQQYIzJGC7fO_`^Fe+m*^R~>_7hEw=^_xjCzm|{x_h}H;5HbFMY D-lU)6hVnU3dDD
zq ^(wU$I?zP0Ed~J*jvp+83!~qs0uVk}Qd|7mi3Su!4R0P7PpJ+NeZq$ml)9DNYe%
zsFXj}3dMUkzsL0T!E^uoukvnM3UWge{^^Vp<$^1{#!;)XjALYnHwZ27#bF~ouoKBN
zj{`5EAcEk&OvN>bO&b4Ui6(#Jdn!j}viYaKW)ASz=PX0kIfkJm0vjQNJCwLQ6Dl9d
zO;6{gj8lBr8Nt+JE1rLVe ePaEK<}dR9PH`erF|QXA<d)A|O6fC5HdaLj6Hh?>PBS
z2vrrVfou~Ljy1OEk<OI?8IOR`=odWTy&zrtl<J8WHBcf+cU&z<1w||10SAL%_Hkph
zrEyWV5eGYZ(xO`Q^6oL{jvEE3jm8Yozty0I#;*>~w*nar+=6R}SvbWAR0(6MFM>Lp
znGx_nJ5l}Ph#9B!Ape(y&{|MDaCB2 gDA@#VdM&Mzex*p)2y?TSOjdo<PdHvF`6jU
z{SusN!%z1<MN+Ky0UdPD7RhrWuTUc`_(xJ&{EsHa1c^=}vyBry_Mqt|Cu$Uy2+mD9
zv_J-}Oj{sVMXXvNE}Twh#{f-yH!%dI3huGvUWRi*lb}A_e ycXq6Bb76W>Bfguau`
zON1WfzE1)3oJoSOlJf6~OiEjuiYOyFPHhkgaPTYTgQVHzN)7j-{9B|)(s_6Os3bsh
zUUyzIe3rfKd5dJ^(oB+3s}vitvR6BQS#>Ate5tmFf{&(r6G0r{ortG8Ac3%~zh<%w
zjJr5sJ7Fb!qWGkUt3H7<@lx`QRH8H9-rdQXB!SzYsyCH0kr<&A>SY3NP;|ynV|E!6
z)VjV2+YuB5pKX?0TVWHi<!wK0q(iw=l^PEv5n)1K-^U!8MmG;x_iukmfWC6h3($n1
zEJ 9_S<<HiP`&1A=L=p-PD?+Q0 ~Y_t_VBF;lzQeCS1=0vSb Rn<Y=%LlmndFvfcZ
zA|JOdRZ6z2M;MCQ`f)>(p`?gXQ&exbjwUJRxI0-!O_SuMS}Iv2P2388|8^(EWz1n3
z`iXOn1)1LZ3e;#+;y2kZRv^?n4GzH&?SUdMM4qg-=~Eb_)nu=}$2|-+*m DeOwSJ{
z>C8%^ `kRWNM6#h^)UGt_aBIJ-wR>zh754ON;Qgm^(KN|iE8KtNL-O%`9(-_IxOfs
zn><7psXJDsG70k5K~^xS`-0;m7~~ZrNNLIUu8^SG{+}yLwg{q7<Obx3+*z!rQQli<
z;%1K<HH^#Bg0$UdDZhpu_oj}=^>5}<{GE&l>k7|cd`3mVy|L6SDDOY=`7vw4$?2?8
z-X*9WXm4b7IUZHCx`~E!6BgpE8el>mr~x}%w4;&O%$Nbf#&0LRD=Kk5_nsQ>%ug?r
zR^JeAb91Q^=-X7^AcZhdz2N4O3+nV`l$EIVyH=no3#B{*ZT*B|x~%J$Z$M^-?=C3r
z4K7W0R$e99L8o})CZPQ+{JC~vA6QNDA4hXC>`&$zB&9s?Sv Q$uD-=$Z+Bsb=5-^;
zl3?|byc}2KP^x}vq?8j0LqD=Y%wjANo+IgJg3fpjAttQa!E4Nh7Qn~6eRJl-nH^?Y
zCQJ|R# !~(e9MJk<63-aoh*_<H}Eqg?*|4kFm4S1Ly&KZzQzTU<VlwNGjlhN31v@&
z$5 gGm*<+q8N} riiFQt6wSd6Ra8y|9^RNH<JFB2yjzR|hyjU<h$~y1r9#S`I0svh
zH-h_MqGty8(BUgF8k3sTLt*08_97nVXuemYj;Zb%j(FQB^<CUmQ_(5%(NdJ8t-Jge
z88gaS**eQ{an31eHJ7?niaL%ax* JS$n_vuu#M_OX6PP4a$F%wERGs{%i+Xr4yZ1N
z4&_o5C<iCTeggAwcAF{P!5UE~?PuDG+vr&5RDb_G;M_zkErxX)WownC!<aq9BM9Xz
z*byR1wJzjz`#5Z92IR|uMbWhh$wUgffJzjbp^T5oa=&K5{I)oEF=ZZHZ(~7D0E>jA
z>|h*IeoCSI;zHV$!?_2WaO IT`S?aR_ztq^;Mhr2mt1X58kor?)=R6;V#>@p&!pq8
zabh&ZLb*zgD9oi?Vhkl `Mq?WjC+xE-WTcK%tGm2hEM{OJTKjAW~rGcDzO(h`#Bk!
z5}XJ{m!wJ)zWR#<6%<M{V|SIlq(G~J5~13bwbG7Bh0<26S4q&=9%6+vDLtLIp-I);
zouEl#AK)hi{F*(&Uy*Ne3;$MN8Fx{W$_HH;^Xeq}Ia3#%NoqN_<iDjK<JU`L7l;9u
z*-8f^sw=IYzl*tK`taRXfKzl*gn9GFkpyUX2iB<;nh+!AsdlBnRHXf!TC^R?Q8ruo
zT?~(#2-Eb3LIQN>(az%+2eSYDPv^DdJFSR~`2)8X$sCm>a#}>r--Mz2*rh1b1-(fY
zBBU#IqgnR!kck+WLaJ0kmBxq}E%%1*POinjP%nA*2cq#Un)F+miXkLJANPx^7d5c0
zxg)El%DViwiepyZk!8Y%BH1*YluxCVSeS wq(}ar77`w3_fqm*`AJJmvabUFP2s^=
zX~4%p*hLC(Eijtdk$>t~J)1~LMsDA66M?M4<08cVWuk#uns!*rg)vPCYb%A33!0yd
zo={%TBEGl0B%JY{uY7`1CRy^wMtN6i?~!lo0D4<EYNiIy(xFN<N-tMPyQv^n7BLLx
zV(5_ba74}i$FRr2)P3hI5PFEmuq!C5VEh#H$^Y#PS{2wBIT8gC!?5Fs_8n7~5NZqx
z<A`g=$oK5EyqX7_<jjOpyL#$Fso&gDWr;>~TPqadcn~$hGb4nGeH HmL<fl!tzaB$
z)$0rq!zsJ77`C$3KB{~Je7Gzl$MvoI^U%vh7)SqL{JhnF #ZiEwxIf5oO$`qX&)%g
z*`fSIBk=HQHVm_vD*Sw2kbSsc(W9Wg1?#9JaM#?}l3EmsZ_xR5pnZchQRPvfKNI;z
z8;=EltflR&wp5p-$UTLLR4dsBhc6e<p 5z2d}J`buz@~Ut#e&*omZp>upaw$eGvmu
zM&!lHTwR1(MEwD>qdS(MI=dYayniU^5)1zo*cEG)^--S`lmF$Yh<=Eb87v w-a9T+
zCRY<NVlEW# uK)uY(Tl!sP<LYJcT}U+x_<rN $&RzZ>oUEL=16w2`mfs U5+qgMs+
zPnweU4qZOl1aF7)IfKp1)zBrkV3i||CH|#~+F|1J+P<`s!>7XPty+iDgc{NZ7UewC
ze gj^zP($Lw4 +Wm*cl;=Xp^0PWW)1wnh)nTmdmgMo*DhSp9VdmxZ|3M5H_uZW{E}
z1P 3FaY_)f7RMfkJDe`@)#pYB{WvL<>QOKKmS*trlntQs2s`<;S6)Kz#lWc6)=mZg
z^jz9}<ImOkwO0r4J~|5j-x6iv4(%20J<Qw`Tp{`1au%nP>A-u 23<a|l^4OhtCa_E
z+e0BGtj{o4sjYCdKBQ!=`jPDL1^0*-f1$DMXu{pHhqhGZw>x`Q;BJUs(?#-jWL!Jn
zf&$t*)z&yOT(h$?X6}S<K0iS)Al_5?e<zZV6I(sbpT_c28%@@AQV)3k*{YhpcEEJb
zpbom!oV5)9bI2#Z)mwD* JhiV&4XYx`Y 2u`f2;XR!5A_N31IG+Sbs~(Qs_OPPGL4
z8!Hznwqc;@W9l!77&y(1H#`_++w13J*iXRT=^-+b?xYL9Q$lNt-z<CNL&gWo 8*AZ
z!~h&|ZU#zC9gGU2X-!Df4&}Pgx&f^iEP{FKqEWkSUod23S6J63G9lQwsUsYKlD9=@
z9mB{6>+T$BU*kQ!c^#b s_bK&P#~WRV=j>wv>dOa;ypGuqj54UNPejNTbMuuD(^T3
z|GGHkMl4LZgEF!ezn?p$y?jK~9(^K(=zwy>AQ4tu97GuEBt2yT6K{jI5Y>JRBfNvL
zpYFswSroN9@)<AMFbBonrZ}!NIBFL7_>g5 ea7!J6Aw!%+lhNkfzf}V7Lv<2NH%za
zc}d_ip4JofxDmmFn*sIqtq>bmNhuP$QcW`GhXQGnO(~|mGDQkm!cVwZMBfR#8zP!+
zB;}5hj(q`hZy$^{SC%^3L@|oMeYSd8o?Q&f&U_xE#C2icRAU=wFlNvJhMce d0(20
zGb4y9*o5BCbwSmnhb46ZtTELQsgjXa!2F{UKI*j+WOmaC+Q;4rrYG|tFy2PcKjGZ%
zlMa|K4TNlBZ_=ja1}~&O6(lcUu6N`>xQj$_QZ5To`+(RhyxGI3UP0S&p5+KkuOT+q
z9FMJRS_L0d9y5^yo+&Y_Z+VN{#y<Tmet;d^yRbGU&b_25pTRB&0M#4E+-a5 IKhZo
z aMSH1_d%?ewp3WxU>)8mFn5$-w)>!p<hEInbLH %mqz+u%#FZzyMDqfNTI^YQP_W
zjNtuI2|dn1#}zW}-{3kxJS<atSZwflc&mMspAmhVSu-oV$rp+mZ%tyR&~XU)E ?V4
zXg~XxKnhib$%_Fj8{ZRzMm3i2vcV Y;0KsIckJ5)2&_wn+R?|_8(s!Zawtl-NS3se
z3tSM&aVNEzBtXBi<dZksqr{dU_i2{Jw?K9#jk|!QU =x_J0IdQAT`}MbIY+iSRQ>f
z2zC0c^mYAU`E&(->tU&W8DKxPLmZg+OkdZO4;C5ttUjGtq5g)*VKkE_Jzn{86b67@
zn>OT6$}H2ya~;+<(S2(m4-2ivIm-VsR%W-kC6D1Zk<mz%ZcjLa2K1YbYo?~_Xr_uE
z;Ai$7N+#DmodPv?3A+sVSL~L&!jy55^yxg!R4s5&7D!`U(@dR<C&zC)NVMVmW{A6O
zS*^4D^jfLAv;1++lRZFM3kJUywR`eM=VAG>pVo|f$g2E4C g=3sO=Sn`KUKWj!G5A
zux$T!praVErKXy?8pYm=RRBd2%vElO_u8rrm qEqM0)!yj-&22Kj1X<Iv?9MW`>S@
z=iv%_(B{V1mScmQ>yBU*vD#QQtP%Dgc29V|EM_&vYk2_i^7DZ$6J6d0Y*AQvm+}u2
z8ecQIrD0eUwdM36crMPn=D^l1-Jsc|k#RRv#jfrxmH+a SD+n3g|uVvCF-9% 1>qy
zg=FY`5H0`yNLZBx(dRswfgam)R<YkV&u%sTGAb_wLsb;Z=C|kF6*RV%V(=A4r089E
zlh~yM1mr7Fly5c|L{cQ=Tp<{~9XqCHZnLHurs}6LM2&j2Bjl^# 0`|)-%iq^qt-<+
zDn3xe4K2D4T_(twciW`Ui1Y$xaH^X$L3v(5bUOCR33HS=W<3f0QQpD>vIx~J!0IDl
zPLg%-;=J&S?<7s<{PxI0Fvry>uhnPs6C|%T+-%!xP89b;rf~I2?oMcf5&p94=Tr+6
z{ _2QPQL6*ub}e^6VN+1v>XqY9}5Z3e=!4H*p2(Ca$FIxg{^WKKs;K1GS&D`y^k9D
zNrs(z3Md4v_idXPw$Zfv8a~-(9yukG`Q9#_n8aVjz<rXr{w8Mdm$G}2W`eecVb8DY
zhBv>~4(nGXyl_F6yLif}<ddIW0m H^h|8&30_CWxST%a7sheoFb)MZD)IY7kzi0bW
z^W7b*p4)XDbISPCIXtx>6rgys!{VbwtdD5dE1ArCGrioq!7`b}jw1`a^;o-sCcIkP
z#iFRfG=2*Y>i#$U+0O<^oeEtc^50IAuL20X8KA__WgbB)U0c;<t8mbqJzNoWd{<Dk
zR!R<Ai7mt3pF{4U`?3-2YwXWOAA<L4EN2(J3r6O|rqGWB0i$uHbf=JT>qkRPu9dH~
znV#ZA7GEzF2_`X51PNL+oe2^dC8L{uGsW44b;p=Qp8JhUvrimo#Kvl-68llz_#Jj}
zFBKPqpgYh7gM>$85R5T;22*JFzT^pk+phB_)(^}WiaI}FYL7U{{+<HEC&2Liz-;Bk
z7060R-rHsh8bR8NAT`W8y ~w`rFH|V;;1~cjcI6~H{o#*L>$-ZelC=B>~tu}LSPIa
za5Ef*e!KQ$Bo3<SG9c FOh)(X9Wm0?13%?DnQ%i+;=rmDg9z?66R*6Cm;PMobj6Za
zd%y~HI#_;+ys%qC;$%=o-X<8awxuE9=UPnjagTAOJoQ(15zS-odjS_8GAC4iP|D{(
z$N>Ukwov`h*^mQQUcy%U#i5EudpM!gR>5Ubn^hIo^>0I}^4|oj#Wl;d7?FQl>TA 9
zEuNRJ4r4Kh4_hYh8d7QNC#^oG?vhp?g{#MIS5BHt-;&Rw86ZCVH-7asM&z*6aZBKx
zZM)FCpvE&_h4*q4nX|xeH|nv=!0$D)jG^d__#1m`VZ*CtOUar1C1-jIbVg)f3^l7q
zw!Gp##mCJGm30hI1M0u0q+%<U1j}OUP9_qPrB=-xgs&}II7d_7=p6m;Vys^rvU<wo
z{q j-nGN1Dcly4^i-NSFxb!t%G4{bc@(E6-wnk*-;kuufElE%Dp*+#~<YJELMb(-b
zC6n^PhU V9k4CM~ER%R(ni2S2O4W+9hY9&PpWB%OS)8G{yKmo{roFUAJeeRu*BK_Z
z(MjHU%7?vl5dpj 1|L#%>@^Tok}XJU-X7vc_;;QxSp4Z w`0M+twI=A7VF|rhAXF(
z`7U6##kVo<i4otpap8>(x51X~Pq<HGpT;!5&1$ao++9#v*WQlZiQOUZMDVPou+~Z|
zxHkax#;gUSb>DU2b@(>8UJ`xAYg`ED*7j^&r{&UHp~uTIQTm5RTcr2;{JayWvJvi3
zHS{Gb3yEYr`1kYYSmeJ({%l8$js0B`r{xcmF4Tzdmc0;qtPs6 I`Ev#!&hE!75zP4
zJzIRc_S~+tGsW^?{Zjo>_!5>ASoh x_=k*c4P+RxEyC0z#Kuy<M2|`dFRm|QGzr}V
zHh*CP?E7h)xWcGM9mGcyh#8#E2KaI%H$e1pIw=3!BAy~>-fiff^K>TnC8w>VV+zNa
z$LWK680y``+Y`E*mie2OU)lBB#9wSgx#A+xC=FyU!&vD3oNay3Z7qnKzK<y5aJ_Q?
z|4p;d(w$m55hzI6Ge`pC##$ps#Mn0)gY&rXA0N>y#Sex2e Kea%Sdy*UY|yeGVm)Z
z_YlYI3J|dmm%ORHoA~9TS@<16<OgVq%5qFNWWEThe(1x$kVdW!4PNtHV;Dh~sgbCn
zi9QfLZz7K5&>F;WkbR)8V`(QDPV;Jg*4?a5v#4_RMKgM=#!U3amZL2#AX7>21=3Lm
z{~Qk$y}lrvP2pF~i4pV8^VBE&408(Sw3Lf=-&Kkz!<k?sm#bOT^fB5C*s<TLC&M`1
z5vON-FL9Fahq><tN#<$Sg%LWrKtcu6J<Q3ug0AmQ6~35sL08Y=h4Bj;S0B*yf^LKl
zco1#R=~jj8$hkz{t;L<15wvjGhPDa3H%K6;e9f l<E0mC=Ho%Tb|jaNG`thvzLVTU
zZeO#+Mk19tN-ibfrv-B WINKg>r4|_=d_RfbAS>xw1I #9PA($O>Ya<)hg-rhB5WU
zS{!15?|1D|ffq5?9+g_B0sh^<xg|3QH=^RGk9?bWM+#0Bc60_)BLaJlz{0-D5(o8r
z`Om;738b~`VCI~6-e&s UMpfhe3CxaLGC_)jQ;~3Z6{A3%mu!W$p6%{(hqDdoWYw3
z-%r-xIU&q6us v5rxz{Dqc)H<{O-Hl&w}h5q>Ya`J0w8p4)ke_jUEw4M`6^m`Gzm(
ziRJ<$QH6Qd1uUw^fo*7RYsfkPpPa Iba*KJG0E(?NB3ZG1qQ_L btMep7Vmw#JB?r
zsy(XsY^7n64xE?A^40iV=(t|*?qHJL_|#ZfvW?7NL6HBptTKrQZ1lv2J8x~_MfZ)t
zWTsphD_uZa Ga5FalAK@v=!OkVP9#ZF^F`;AAxCnx!9%IMu6NkXA_Zdh*Xn09a97O
z(G<h<(1Ufy02*_XBm$O$j1Z(mp4iP{H`#J^LOs1_61Q%aLAelIR1&?App(t#k_)qM
zbZ67#7~RRMOVkv)Fw>5W{Sb?$UZdY+-qRB}2#1lDXfuo?rXu zm_!4=L)--o(|Z5;
zA({+ZGYlRfkQ;NqQCEH`nJ~hleu!;5{-pAQ 5f{dZNc0JqnInJhJGbQd|_(T<H{2l
z!Xs4n#xDW2_}>rZ^ZAaFQCQ}q;k40yR_|K}{pF><!H#o+SBirj3*)?B&Wjj!VlDGm
z+5MlNAMRV qD_B|f~Oq7*Uw;2*Z8#m^QNt*z^OSp%m}{kZB!sZ{<Te6iBH~X^dzZ`
zT$6M9LbB4OP5s_w`qYNU 0>jN`;KuzvBjvO<&)!6q(n bXB^P`hj^@++vh`aq7Tv#
zrK+%5OUu02PAJu)6MA?L5q0}Uhdybx<@ZAdT|FlOW~e9buqA{4vo_YBgO3F=os$`m
zk4REMj6tvE|6a<IkZmW}1mvbl8`R)Er S|Ee~{qG2FF_tw!dKcJ+;;ETcHQSN&4&C
z1K|)cZwL|f(gsOoN4{Y|#61&hpChS%0abIf%NJ-p7DB|?BVmLs2xBKmaS6zaah2Xo
zXO5P>4gYAhY _UtgxvCpXo7ZW7E<)6$8}-TQzY>+>l# nzK+zq28#(V-nPp1>jZ3F
zC>{S5>AIKA5)*BO+C=kJL?a#fb%gY&%1$sX?hS lGzaNupc8Qe-WyHDkZ!^@_GwVp
z dv*ryNb<_{3XEyz1Lvq>1LdW+cKK}^RwAieWpqLM$4tkuqX9gmpdk#`pm}~upIdt
zWkv9Y$lI4EcXH1NJD;1PrmGehNa~}FIa9v$Gm|~M=(wjfqh(4TFML0DG3ho<O%kUL
z%Q2Sa8!anvjc&npF2~CCXo~-N23Y!zTc%Jb_w^$V>(%Qnm|QstM>e8GU2_C=^vm?8
zS8u{?f9yDNki%b}08-WH^Vi^>E?wjoNJ8YlwqYLHj`RVJ%Z9Tj&qcZHjpirMVDa25
zm*i{ !1i_XCi&1kL)a}g`lKf*0Aa)V_5|e2XibP7-kLM$oA+*^?esX_<pqrHn^zG|
zl83EqIA ={F5+U`U!s1cc1K!8Aj@5W8zEAUZ2#IuZjbASU4JnBrzcr`UoN0#GLn-3
z_mzJSfgjqs 4IUmsY-mcuzu=QaW}F(`Qdrt6Ynnyzls7*g{QSL_A0>M4W6{gixY^d
zNmw&pbtC%`@@6|H NP5EH;#sfdVt##__~Y(@aCSg6_eE0llVk^>Pu<(by2uhb{c>J
z>S<(|_P+o#Jk2bo;k4|}^Gwyg!k9i9nS)I&jFAb{hd2mpANaGU=IJJ`*wjgFK&bKE
z*LJc^B)0dJEXXSbO8V4!7qCz8-3UJ%O{8y`Pd$fS9D%);gn70!;|dkIK8&%Y<)pCh
zePO$vuKxyMV~c(qh=>+p$y>kpqc6M^WfNsEO_p!Mq>2+&px|nQ-U+0GmOkfSG&@U%
zd0&$w=b(oMf9i1mPRwjJb}(|Yfuc5Cx0EQ^z cI#_&^Xl^w*Fp`uac26~l-xUb(l_
zsx2xl%CUFC{}_yHMX#NizkG>J{I&I9WgZud67f{$G9$9jYirz$# %kExG!hGh;rcs
zkFp>K3 +kl@a|gO*dS pFPwn5YmcrICyru1h;aX70`?z=D6ZxuMf}YTy3#puA`YON
zhrIcrg}Au~I3uoi=_)JrOpfwYBd%l5DO1rdYaC*KGT0R0BYJ*?TdK&Ns{=*3^$&@c
zM0>kTGMz1mKOh-Ra3|5;e%eV7Qi0>(VSypL*Qa0=7H^fT?uzyfK`)dGIRdTD)8v0P
zm#u(0p**v|lPTVQ_`8!opv70`1Sf~61{($U?tIx(1b4On)&?3dnZ$HDZmJsqd6%MQ
zRht8>fdbj bvNQYI&vx4GW5eZ;wSj*rPp8faM%-m8crPaL3Xu1o)?6}#i+Osz(qTt
zD{yC<MUN2Guz*!+1fY<-4Mp$#tloK$j5$)KUUK^m&6BPSkp>*VraWKCL-#~`Cm;tn
z<w4`kL)52V45TAOZ=bXRWKW6C314;C-A(20Zm!6JB)I$Yzj-pQm^-MPck$yM^3F)P
zf&FsJcPH>3Y4N~RE%^2aG=JPE|I;jqjTF0um4&<Rrq(8?xznX~=v`wi;a<PH#xjZe
z^i+O_>sZ+8UE 2^NP^sXK|T7R4=&3o$~k=d`{=^Ip8*CeCT&Dav|R =#(N)yy(4)@
z5r*6q$<pzBT}|`9(u$t~Q MO@Ch7!|&$lRq8#6}q2PB$Z*iE+MoTJDpG$451AZ{h=
zn+e~m=zWgKcSSNV*Uf}qAc^b9AP;$14)0UoU?NB{WP<n2;k()F7zyl7MzRCKgd@@z
z;8}C{pJ~V+gX^CpYlGATT0kzGgI=7CvW-+1rBgl^Abb= lb4*>xP5a`8fx+5!OE%G
zapU#3^dQB6kRIe4wA>fM-Nt=J9H`~W!3hoiPyO #OZ=1l$^KRTY5qBD+gJvqcLJHG
zr}p82(v=9c+kZ#FMG7-Bz>*Yfay1qp-`j#r?}F_te1N19jf_9qz(%^_8WR4+$re2!
z;%qOW>30-hGSH%B{oZ<l{yZ>Txv~@|?34FRY#M*d;g3ym8a?TE-zRi(8+oe$K{y$+
z1*y;HdnW^H{|;-XCmc_wCmF=Ndl!?C6<2m1?)e|8t-fNZ42gN*u?ozKtOpB$FC82+
zO1b UADAJ?b+QyggX@;HHkqBj*be0Tt^2^0DXN+jXrU(7LhRcie(G#NdnSTWBE(X}
zI7e_7g6sm8*hF3_yy&iOY`gd?m_8nwqiirw4GD0bO`=rmTj^qqSH78Eanp^3fV72%
z%)*Z&(@JHO Pnp-k{4RLo8rTrHgn|na89(04SYIiTPJ&RK`_-rH{Q+#?pd=N{iWfy
zSa`M(th<|BO!IMNe4ur+zbpx#&Gk>u&NWoj<z5hFSN{s9KH&u=cwftN$Jx%9%DK8-
zIuOW5+z$_v;nmk A%0Av!~^MceWa_R72H!aR$n6=>`5z~>2ECVizZTh9V^*AuGC!$
z*+1b>jLjR7P?P *Cg^E|bG`M-HaIChj!T>9PO +~x6_+G+Tt+1GlpZcD)YQI5vBa}
z7IZO`y?MWkU#x?8O1tdUb}ldX?;^1nm4Xut|G86SChW0`kvB1w9yFQu*Z|Q<yCT7g
zveG8jmCHA9&>z=M3mcx*V+t%F+??_yKafAT4dLNpKe~pX$mqL{ums-|A4(obKK&u-
zD%!rR<=J>RZeoz%y-W5*6s3mWY<u?c{I^)<(m>;JcxH!`_g=rCTk(NWy!y=VZ 1{e
zNBd!xqoR9~9p3Pl;cL*9p4z0B<A?$L j*y4EA`YWP50F}X<ns(@9CNu&ftmeR-{OH
z 1`P?R})D^`ij5^denXKdiYRWG68i~8zy~}1Z3yXlV*G&Wv7tT6r#UN*z)Ys5t!bH
zua={OTa6IIhd|25&Ol802&8^vJ9rpR(bRtf$jGuR+{(g%%F8+74T&V4(kJ~)^Geo_
z1y)Pc9cPRv8PiagaA?7DwKS|&(kmJuocP1PL Q_RMIM^HslA7Lzlp`eafm9mdT+cl
zcz$$tEASO-V#W?sstwmbaUUzKEIXK#C}uTNw4%Y9eXxO#2aR6Qk^8y;pN)fWS9y=L
zCHrByEg_MReV-2+3WAHxW5sfRU1*e>4WvICM8u}aVQ>5~u3ctaR~6b_<n>0&lOQnt
zbiuWj{U2GWj;!S+CeU7n7TL?Z|MHMSyE6CqGOGj>A7KZx)s?OZph3k+o0rS#q70lx
z$%DUtSb4RhV0USg>mCFCU{;=Y&S~MaAXG*2Y($w;vQi&%u0d%pxRX07esm~#;Syu)
zHCvb!qvpnWO~XBeQ f0_oGoyFA!acKB-v$!u2QHRRefAmpyRV>X(=b7Zcjd(e!NbW
z<$)*CHt6>bb>kR=62DT0BIlii{;M=)?$Ci6ey^B&ctXWY(;+Q|2cT?ObpiirmBxMG
zi?U~&X6zeaczh0Wc(`?~IL{1bwHi^!z>CsnuNZ!kTBSx{5-BJ(!Y`R&t7$pL4Wo~-
z#{QhEtY#UBImoyN<b<cW-&H znIVcYSI@G l@n}~_G^Rk*Z|^YiC^BP;MM$|Z5)(=
z-`;im!YKTcUSliE?6B?plLi7;5_aNg?1^pq_iHM#KtFq|@&1JQ@(H$nofIgHi_LA_
z7U;L 93Oj_+mb?`S#DzUaSlfyapaAOz+D{guS>+qhq2LY1<t;RM+^#V{=4yH6Gftl
z?8eDpbT040I7q4iHI{InTFv+^*zaEg%CX^Lq7A}J&4Cm5*oVVTG)Os+k8u0T1Rc(>
znS<=3VJZzV-t>9GUT&%z&T(|!!CJVaPwK{0M01{!bqL30M&b3u5M6L;id1J1gyhDZ
zaYT>7W_F^7U?~x8OHpy0UafUn6T5BAxPKz|o4Dob+6N>(UK;*ta>v1s^ZGMa6n4A~
z*+dqB9Y?kk<o}<})-#~RjX@>I`*!`6g= *2Ky30zZrytHAam=Mj-%<B3c_(4h!V_V
zrDavWcO>X6mAsz%pDdaB{E;hTvI6gCju}CGmb)F$9J;NrnRB{2vKoE4?jSZxvg8>}
zT&X9bePtoOrzEDc9DVU0hCbfCK}^7SC+5U;?Iqg6rAzr9{Y<&W4Q^ksslnK2r0GU9
z1WSL^ZGfv?zr?w*0m$HXOZdO{;2I`A>#lG%suPM}1oE*omeN(d1%rR&BF7=66Fcn3
zB|#IN-jF#S1DSD1zlmk`2>T2T)78&D5|-Nh`FJyQogTWJ_ B}gKI;aWbbBcv6F5(8
z2 =+0Q=%MNOZRZ9$xYClBs%dS3sc-fvVjw#b>OLwfq?PdUopgRjbRsGARRM$r6d;Q
zxxv2p KI*!Q5gTtLZw8wCGrL*h2gndg%dwBcY{F^^%?A_C8xzVZ%<?7OQgWUWN Bh
z^n5mQ9Pf#9zZL+r|BLg;JEE0naZ*W>lJYtld|2St9idnDRw+J?I3V8K6ztM29v$J&
z_ce4UMIn3$x7M7Wt9v}wFv(RZ#R#lnS6gu~10pbRmnH%|l=JNL83$f45exEYLwrD$
z*Gi|?w;i OrGoFPnT3p(QdudS(73c?oK6XfCwf?DjU4)xo33LoPDvP>i;}VOuP8&`
zvdP?Xw6To8t>&p6mKL?#8T!)Cop!k0pTH9;8SsM?`Q_s6ZEA`7folFqw|sU(YKP7B
z9QE7woE94^-nojrtuQjKxq _KBCwK_EfjxU_<1qEMn;pkVz-nYntP+7Oy9#Xv6AGy
z+!k!oJcxg4-7cjYw$mB%lFc>`_on3pjNBUB9G|A)k^$w<;F*QE^Zl y&6jg4Cp!Xn
zs%yoGZp{0Nlf=K3y`oRSgv#D=j{0xa(_FTkoc!S2cZ{~4 DnW8`zhGcR_dc3IXZ*J
zf#-fb%v1x<B|C(3hmI<P{nb)=iOU&Bz|J>O6C03~DcsLHPAd}*9DCAnBk&UjY-wPI
ztf1 JfeI1nU?!(+5_cHX+)U{pp65ERp#MLg3dK0(?(*L>+p<T8 ZByy@Tk&Lfc{%Q
zb=zLyyX6N&CwV=UysIi)<+ILiH1gFGf In~?e#7Qsv}XbN6(@j`s6KyG9J|vBr{rt
z+Y*S<R~BRXC;8H6<AOijf<Io`8JoA)`>B;0Tu(?IdP&Z{QY+OxLv7nLZMH}}t4HVU
zH>j#0Q18U*TkYp`lrBz6WkvYn`Vrr~7Oumi{k}or1$AE-{{z48s*n78v%W}^8S1Q&
zn2(SAeRx;N)D*t*7ruD-g#eAceIKr>&K=1FE`Ju6SBD*Sho8SDw`;q>Tp%e42U<k0
z^pImp!7yJ(#!}$~9 TxSo80061_z>xHcSUU%F22+k#{eMvR78giPQKvm2v#l)kdo!
z*e{-=TX-z&7w_OA OC7jOuCi<JNgsG R6?!Pu=A}c@cjBi5~LG8u?v5A5x_Tp_NgL
V7~sRTFNEiTfZ~fQc(x<}`9D*L!)E{h

literal 0
HcmV?d00001

diff --git a/bin/loader/kickstart.c b/bin/loader/kickstart.c
new file mode 100644
index 0000000..26c4aab
--- /dev/null
+++ b/bin/loader/kickstart.c
@@ -0,0 +1,559 @@
+/*
+ * kickstart.c - kickstart file handling
+ *
+ * Copyright (C) 1999, 2000, 2001, 2002, 2003  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <alloca.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include "loader.h"
+#include "loadermisc.h"
+#include "lang.h"
+#include "kickstart.h"
+#include "modules.h"
+
+#include "kbd.h"
+#include "driverdisk.h"
+#include "net.h"
+#include "method.h"
+
+#include "nfsinstall.h"
+#include "urlinstall.h"
+#include "cdinstall.h"
+#include "hdinstall.h"
+
+#include "../isys/imount.h"
+#include "../isys/isys.h"
+#include "../isys/log.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+struct ksCommandNames {
+    int code;
+    char * name;
+    void (*setupData) (struct loaderData_s *loaderData,
+                       int argc, char ** argv);
+} ;
+
+struct ksCommand {
+    int code, argc;
+    char ** argv;
+};
+
+static void setTextMode(struct loaderData_s * loaderData, int argc, 
+                        char ** argv);
+static void setGraphicalMode(struct loaderData_s * loaderData, int argc, 
+                             char ** argv);
+static void setCmdlineMode(struct loaderData_s * loaderData, int argc, 
+                           char ** argv);
+static void setSELinux(struct loaderData_s * loaderData, int argc, 
+                       char ** argv);
+static void setPowerOff(struct loaderData_s * loaderData, int argc, 
+                        char ** argv);
+static void setHalt(struct loaderData_s * loaderData, int argc, 
+                    char ** argv);
+static void setShutdown(struct loaderData_s * loaderData, int argc, 
+                        char ** argv);
+static void setMediaCheck(struct loaderData_s * loaderData, int argc, 
+                          char ** argv);
+static void setUpdates(struct loaderData_s * loaderData, int argc,
+                       char ** argv);
+static void setVnc(struct loaderData_s * loaderData, int argc,
+                       char ** argv);
+
+struct ksCommandNames ksTable[] = {
+    { KS_CMD_NFS, "nfs", setKickstartNfs },
+    { KS_CMD_CDROM, "cdrom", setKickstartCD },
+    { KS_CMD_HD, "harddrive", setKickstartHD },
+    { KS_CMD_TEXT, "text", setTextMode },
+    { KS_CMD_GRAPHICAL, "graphical", setGraphicalMode },
+    { KS_CMD_URL, "url", setKickstartUrl },
+    { KS_CMD_NETWORK, "network", setKickstartNetwork },
+    { KS_CMD_KEYBOARD, "keyboard", setKickstartKeyboard },
+    { KS_CMD_LANG, "lang", setKickstartLanguage },
+    { KS_CMD_DD, "driverdisk", useKickstartDD },
+    { KS_CMD_DEVICE, "device", loadKickstartModule },
+    { KS_CMD_CMDLINE, "cmdline", setCmdlineMode },
+    { KS_CMD_SELINUX, "selinux", setSELinux },
+    { KS_CMD_POWEROFF, "poweroff", setPowerOff },
+    { KS_CMD_HALT, "halt", setHalt },
+    { KS_CMD_SHUTDOWN, "shutdown", setShutdown },
+    { KS_CMD_MEDIACHECK, "mediacheck", setMediaCheck },
+    { KS_CMD_UPDATES, "updates", setUpdates },
+    { KS_CMD_VNC, "vnc", setVnc },
+    { KS_CMD_NONE, NULL, NULL }
+};
+
+struct ksCommand * commands = NULL;
+int numCommands = 0;
+
+int ksReadCommands(char * cmdFile) {
+    int fd;
+    char * buf;
+    struct stat sb;
+    char * start, * end, * chptr;
+    char oldch;
+    int line = 0;
+    gint argc = 0;
+    gchar **argv = NULL;
+    GError *optErr = NULL;
+    int inSection = 0; /* in a section such as %post, %pre or %packages */
+    struct ksCommandNames * cmd;
+    int commandsAlloced = 5;
+
+    if ((fd = open(cmdFile, O_RDONLY)) < 0) {
+        startNewt();
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("Error opening kickstart file %s: %m"),
+                       cmdFile);
+        return LOADER_ERROR;
+    }
+
+    fstat(fd, &sb);
+    buf = alloca(sb.st_size + 1);
+    if (read(fd, buf, sb.st_size) != sb.st_size) {
+        startNewt();
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("Error reading contents of kickstart file %s: %m"),
+                       cmdFile);
+        close(fd);
+        return LOADER_ERROR;
+    }
+
+    close(fd);
+
+    buf[sb.st_size] = '\0';
+
+    commands = malloc(sizeof(*commands) * commandsAlloced);
+
+    start = buf;
+    while (*start && !inSection) {
+        line++;
+        if (!(end = strchr(start, '\n')))
+            end = start + strlen(start);
+
+        oldch = *end;
+        *end = '\0';
+
+        while (*start && isspace(*start)) start++;
+
+        chptr = end - 1;
+        while (chptr > start && isspace(*chptr)) chptr--;
+        
+        if (isspace(*chptr)) 
+            *chptr = '\0';
+        else
+            *(chptr + 1) = '\0';
+
+        if (!*start || *start == '#' || !strncmp(start, "%include", 8)) {
+            /* keep parsing the file */
+        } else if (*start == '%') {
+            /* assumed - anything starting with %something is a section */
+            inSection = 1;
+        } else if  (*chptr == '\\') {
+            /* JKFIXME: this should be handled better, but at least we 
+             * won't segfault now */
+        } else {
+            if (!g_shell_parse_argv(start, &argc, &argv, &optErr) && argc) {
+                newtWinMessage(_("Kickstart Error"), _("OK"),
+                               _("Error in %s on line %d of kickstart "
+                                 "file %s."), argv[0], line, cmdFile);
+                g_error_free(optErr);
+            } else if (!argc) {
+                newtWinMessage(_("Kickstart Error"), _("OK"),
+                               _("Missing options on line %d of kickstart "
+                                 "file %s."), line, cmdFile);
+            } else {
+                for (cmd = ksTable; cmd->name; cmd++)
+                    if (!strcmp(cmd->name, argv[0])) break;
+                
+                if (cmd->name) {
+                    if (numCommands == commandsAlloced) {
+                        commandsAlloced += 5;
+                        commands = realloc(commands,
+                                           sizeof(*commands) * commandsAlloced);
+                    }
+                    
+                    commands[numCommands].code = cmd->code;
+                    commands[numCommands].argc = argc;
+                    commands[numCommands].argv = argv;
+                    numCommands++;
+                }
+            }
+        }
+        
+        if (oldch)
+            start = end + 1;
+        else
+            start = end;
+    }
+    
+    return 0;
+}
+
+
+int ksHasCommand(int cmd) {
+    int i;
+
+    for(i = 0; i < numCommands; i++)
+	if (commands[i].code == cmd) return 1;
+
+    return 0;
+}
+
+int ksGetCommand(int cmd, char ** last, int * argc, char *** argv) {
+    int i = 0;
+    
+    if (last) {
+        for (i = 0; i < numCommands; i++) {
+            if (commands[i].argv == last) break;
+        }
+        
+        i++;
+    }
+
+    for (; i < numCommands; i++) {    
+        if (commands[i].code == cmd) {
+            if (argv) *argv = commands[i].argv;
+            if (argc) *argc = commands[i].argc;
+            return 0;
+        }
+    }
+    
+    return 1;
+}
+
+int kickstartFromRemovable(char *kssrc) {
+    struct device ** devices;
+    char *p, *kspath;
+    int i, rc;
+
+    logMessage(INFO, "doing kickstart from removable media");
+    devices = getDevices(DEVICE_DISK);
+    /* usb can take some time to settle, even with the various hacks we
+     * have in place. some systems use portable USB CD-ROM drives, try to
+     * make sure there really isn't one before bailing. */
+    for (i = 0; !devices && i < 10; ++i) {
+        logMessage(INFO, "sleeping to wait for a USB disk");
+        sleep(2);
+        devices = getDevices(DEVICE_DISK);
+    }
+    if (!devices) {
+        logMessage(ERROR, "no disks");
+        return 1;
+    }
+
+    for (i = 0; devices[i]; i++) {
+        if (devices[i]->priv.removable == 1) {
+            logMessage(INFO, "first removable media is %s", devices[i]->device);
+            break;
+        }
+    }
+
+    if (!devices[i] || (devices[i]->priv.removable == 0)) {
+        logMessage(ERROR, "no removable devices");
+        return 1;
+    }
+
+    /* format is floppy:[/path/to/ks.cfg] */
+    kspath = "";
+    p = strchr(kssrc, ':');
+    if (p)
+	kspath = p + 1;
+
+    if (!p || strlen(kspath) < 1)
+	kspath = "/ks.cfg";
+
+    if ((rc=getKickstartFromBlockDevice(devices[i]->device, kspath))) {
+	if (rc == 3) {
+	    startNewt();
+	    newtWinMessage(_("Error"), _("OK"),
+			   _("Cannot find ks.cfg on removable media."));
+	}
+	return 1;
+    }
+
+    return 0;
+}
+
+
+/* given a device name (w/o '/dev' on it), try to get ks file */
+/* Error codes: 
+      1 - could not create device node
+      2 - could not mount device as ext2, vfat, or iso9660
+      3 - kickstart file named path not there
+*/
+int getKickstartFromBlockDevice(char *device, char *path) {
+    return getFileFromBlockDevice(device, path, "/tmp/ks.cfg");
+}
+
+static char *newKickstartLocation(const char *origLocation) {
+    const char *location;
+    char *retval = NULL;
+    newtComponent f, okay, cancel, answer, locationEntry;
+    newtGrid grid, buttons;
+
+    startNewt();
+
+    locationEntry = newtEntry(-1, -1, NULL, 60, &location, NEWT_FLAG_SCROLL);
+    newtEntrySet(locationEntry, origLocation, 1);
+
+    /* button bar at the bottom of the window */
+    buttons = newtButtonBar(_("OK"), &okay, _("Cancel"), &cancel, NULL);
+
+    grid = newtCreateGrid(1, 3);
+
+    newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT,
+                     newtTextboxReflowed(-1, -1, _("Unable to download the kickstart file.  Please modify the kickstart parameter below or press Cancel to proceed as an interactive installation."), 60, 0, 0, 0),
+                     0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+    newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, locationEntry,
+                     0, 1, 0, 0, NEWT_ANCHOR_LEFT, 0);
+    newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
+                     0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+    f = newtForm(NULL, NULL, 0);
+    newtGridAddComponentsToForm(grid, f, 1);
+    newtGridWrappedWindow(grid, _("Error downloading kickstart file"));
+    newtGridFree(grid, 1);
+
+    /* run the form */
+    answer = newtRunForm(f);
+
+    if (answer != cancel)
+        retval = strdup(location);
+
+    newtFormDestroy(f);
+    newtPopWindow();
+
+    return retval;
+}
+
+int isKickstartFileRemote(char *ksFile) {
+    char *location = NULL;
+
+    if (ksFile == NULL) {
+        return 0;
+    }
+
+    if (!strcmp(ksFile, "ks")) {
+       return 1;
+    } else if (!strncmp(ksFile, "ks=", 3)) {
+        location = ksFile + 3;
+    }
+
+    if (!strncmp(location, "http", 4) ||
+        !strncmp(location, "ftp://";, 6) ||
+        !strncmp(location, "nfs:", 4)) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+void getKickstartFile(struct loaderData_s *loaderData) {
+    char *c;
+    int rc = 1;
+
+    /* Chop off the parameter name, if given. */
+    if (!strncmp(loaderData->ksFile, "ks=", 3))
+        c = loaderData->ksFile+3;
+    else
+        c = loaderData->ksFile;
+
+    while (rc != 0) {
+        if (!strncmp(c, "ks", 2)) {
+            rc = kickstartFromNfs(NULL, loaderData);
+            loaderData->ksFile = strdup("/tmp/ks.cfg");
+        } else if (!strncmp(c, "http", 4) || !strncmp(c, "ftp://";, 6)) {
+            rc = kickstartFromUrl(c, loaderData);
+            loaderData->ksFile = strdup("/tmp/ks.cfg");
+        } else if (!strncmp(c, "nfs:", 4)) {
+            rc = kickstartFromNfs(c+4, loaderData);
+            loaderData->ksFile = strdup("/tmp/ks.cfg");
+        } else if (!strncmp(c, "floppy", 6)) {
+            rc = kickstartFromRemovable(c);
+            loaderData->ksFile = strdup("/tmp/ks.cfg");
+        } else if (!strncmp(c, "hd:", 3)) {
+            rc = kickstartFromHD(c);
+            loaderData->ksFile = strdup("/tmp/ks.cfg");
+        } else if (!strncmp(c, "bd:", 3)) {
+            rc = kickstartFromBD(c);
+            loaderData->ksFile = strdup("/tmp/ks.cfg");
+        } else if (!strncmp(c, "cdrom", 5)) {
+            rc = kickstartFromCD(c);
+            loaderData->ksFile = strdup("/tmp/ks.cfg");
+        } else if (!strncmp(c, "file:", 5)) {
+            loaderData->ksFile = c+5;
+            break;
+        }
+
+        if (rc != 0) {
+            char *newLocation;
+
+            if (!strcmp(c, "ks"))
+                newLocation = newKickstartLocation("");
+            else
+                newLocation = newKickstartLocation(c);
+
+            if (loaderData->ksFile != NULL)
+                free(loaderData->ksFile);
+
+            if (newLocation != NULL) {
+               loaderData->ksFile = strdup(newLocation);
+               free(newLocation);
+               return getKickstartFile(loaderData);
+            }
+            else
+               return;
+        }
+    }
+
+    flags |= LOADER_FLAGS_KICKSTART;
+    return;
+}
+
+static void setVnc(struct loaderData_s * loaderData, int argc,
+                   char ** argv) {
+    logMessage(INFO, "kickstart forcing graphical mode over vnc");
+    flags |= LOADER_FLAGS_GRAPHICAL | LOADER_FLAGS_EARLY_NETWORKING;
+    return;
+}
+
+static void setUpdates(struct loaderData_s * loaderData, int argc,
+                       char ** argv) {
+   if (argc == 1)
+      flags |= LOADER_FLAGS_UPDATES;
+   else if (argc == 2)
+      loaderData->updatessrc = strdup(argv[1]);
+   else
+      logMessage(WARNING, "updates command given with incorrect arguments");
+}
+
+static void setTextMode(struct loaderData_s * loaderData, int argc, 
+                        char ** argv) {
+    logMessage(INFO, "kickstart forcing text mode");
+    flags |= LOADER_FLAGS_TEXT;
+    return;
+}
+
+static void setGraphicalMode(struct loaderData_s * loaderData, int argc, 
+                        char ** argv) {
+    logMessage(INFO, "kickstart forcing graphical mode");
+    flags |= LOADER_FLAGS_GRAPHICAL;
+    return;
+}
+
+static void setCmdlineMode(struct loaderData_s * loaderData, int argc, 
+                           char ** argv) {
+    logMessage(INFO, "kickstart forcing cmdline mode");
+    flags |= LOADER_FLAGS_CMDLINE;
+    return;
+}
+
+static void setSELinux(struct loaderData_s * loaderData, int argc, 
+                       char ** argv) {
+    flags |= LOADER_FLAGS_SELINUX;
+    return;
+}
+
+static void setPowerOff(struct loaderData_s * loaderData, int argc, 
+                        char ** argv) {
+    if (!FL_NOKILL(flags))
+        flags |= LOADER_FLAGS_POWEROFF;
+    return;
+}
+
+static void setHalt(struct loaderData_s * loaderData, int argc, 
+                    char ** argv) {
+    if (!FL_NOKILL(flags))
+        flags |= LOADER_FLAGS_HALT;
+    return;
+}
+
+static void setShutdown(struct loaderData_s * loaderData, int argc, 
+                    char ** argv) {
+    gint eject = 0, reboot = 0, halt = 0, poweroff = 0;
+    GOptionContext *optCon = g_option_context_new(NULL);
+    GError *optErr = NULL;
+    GOptionEntry ksOptions[] = {
+        { "eject", 'e', 0, G_OPTION_ARG_INT, &eject, NULL, NULL },
+        { "reboot", 'r', 0, G_OPTION_ARG_INT, &reboot, NULL, NULL },
+        { "halt", 'h', 0, G_OPTION_ARG_INT, &halt, NULL, NULL },
+        { "poweroff", 'p', 0, G_OPTION_ARG_INT, &poweroff, NULL, NULL },
+        { NULL },
+    };
+
+    g_option_context_set_help_enabled(optCon, FALSE);
+    g_option_context_add_main_entries(optCon, ksOptions, NULL);
+
+    if (!g_option_context_parse(optCon, &argc, &argv, &optErr)) {
+        startNewt();
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("Bad argument to shutdown kickstart method "
+                         "command: %s"), optErr->message);
+        g_error_free(optErr);
+        g_option_context_free(optCon);
+        return;
+    }
+
+    g_option_context_free(optCon);
+
+    if (FL_NOKILL(flags)) {
+        flags |= LOADER_FLAGS_HALT;
+    } else  {
+        if (poweroff)
+            flags |= LOADER_FLAGS_POWEROFF;
+        if ((!poweroff && !reboot) || (halt))
+            flags |= LOADER_FLAGS_HALT;
+    }
+}
+
+static void setMediaCheck(struct loaderData_s * loaderData, int argc, 
+                          char ** argv) {
+    flags |= LOADER_FLAGS_MEDIACHECK;
+    return;
+}
+
+void runKickstart(struct loaderData_s * loaderData) {
+    struct ksCommandNames * cmd;
+    int argc;
+    char ** argv;
+
+    logMessage(INFO, "setting up kickstart");
+    for (cmd = ksTable; cmd->name; cmd++) {
+        if ((!ksGetCommand(cmd->code, NULL, &argc, &argv)) && cmd->setupData) {
+            cmd->setupData(loaderData, argc, argv);
+        }
+    }
+}
+
+/* vim:set sw=4 sts=4 et: */
diff --git a/bin/loader/kickstart.h b/bin/loader/kickstart.h
new file mode 100644
index 0000000..574026b
--- /dev/null
+++ b/bin/loader/kickstart.h
@@ -0,0 +1,54 @@
+/*
+ * kickstart.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef H_KICKSTART
+
+#include "loader.h"
+
+#define KS_CMD_NONE	    0
+#define KS_CMD_NFS	    1
+#define KS_CMD_CDROM	    2
+#define KS_CMD_HD	    3
+#define KS_CMD_URL	    4
+#define KS_CMD_NETWORK      5
+#define KS_CMD_TEXT         6
+#define KS_CMD_KEYBOARD     7
+#define KS_CMD_LANG         8
+#define KS_CMD_DD           9
+#define KS_CMD_DEVICE      10
+#define KS_CMD_CMDLINE     11
+#define KS_CMD_GRAPHICAL   12
+#define KS_CMD_SELINUX     13
+#define KS_CMD_POWEROFF    14
+#define KS_CMD_HALT        15
+#define KS_CMD_SHUTDOWN    16
+#define KS_CMD_MEDIACHECK  17
+#define KS_CMD_UPDATES     18
+#define KS_CMD_VNC         19
+
+int ksReadCommands(char * cmdFile);
+int ksGetCommand(int cmd, char ** last, int * argc, char *** argv);
+int ksHasCommand(int cmd);
+
+int isKickstartFileRemote(char *ksFile);
+void getKickstartFile(struct loaderData_s * loaderData);
+void runKickstart(struct loaderData_s * loaderData);
+int getKickstartFromBlockDevice(char *device, char *path);
+
+#endif
diff --git a/bin/loader/lang.c b/bin/loader/lang.c
new file mode 100644
index 0000000..31749fc
--- /dev/null
+++ b/bin/loader/lang.c
@@ -0,0 +1,399 @@
+/*
+ * lang.c - determines language, handles translations
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <alloca.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <newt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#include "loader.h"
+#include "lang.h"
+#include "loadermisc.h"
+#include "windows.h"
+
+#include "../isys/stubs.h"
+#include "../isys/cpio.h"
+#include "../isys/lang.h"
+#include "../isys/isys.h"
+#include "../isys/log.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+struct aString {
+    unsigned int hash;
+    short length;
+    char * str;
+} ;
+
+struct aString * strings = NULL;
+int numStrings = 0, allocedStrings = 0;
+
+static int english = 0;
+
+static char * topLineWelcome = N_("Welcome to %s for %s");
+static char * topLineWelcomeRescue = N_("Welcome to %s for %s - Rescue Mode");
+static char * bottomHelpLine = N_("  <Tab>/<Alt-Tab> between elements  | <Space> selects | <F12> next screen ");
+
+static int aStringCmp(const void * a, const void * b) {
+    const struct aString * first = a;
+    const struct aString * second = b;
+
+    if (first->hash < second->hash)
+        return -1;
+    else if (first->hash == second->hash)
+        return 0;
+
+    return 1;
+}
+
+char * translateString(char * str) {
+    unsigned int sum = 0, xor = 0;
+    int len = 0;
+    char * chptr;
+    struct aString * match;
+    struct aString key;
+
+    for (chptr = str; *chptr; chptr++) {
+        sum += *chptr;
+        xor ^= *chptr;
+        len++;
+    }
+
+    key.hash = (sum << 16) | ((xor & 0xFF) << 8) | (len & 0xFF);
+    match = bsearch(&key, strings, numStrings, sizeof(*strings), aStringCmp);
+    if (!match)
+        return str;
+
+    return match->str;
+}
+
+static struct langInfo * languages = NULL;
+static int numLanguages = 0;
+
+static void loadLanguageList(void) {
+    char * file = "/etc/lang-table";
+    FILE * f;
+    char line[256];
+    char name[256], key[256], font[256], code[256],
+        keyboard[256], timezone[256];
+    int lineNum = 0;
+
+    wcwidth(0);
+    f = fopen(file, "r");
+    if (!f) {
+        newtWinMessage(_("Error"), _("OK"), "cannot open %s: %m", file);
+        return;
+    }
+
+    while (fgets(line, sizeof(line), f)) {
+        lineNum++;
+        languages = realloc(languages, sizeof(*languages) * (numLanguages + 1));
+        if (sscanf(line, "%[^\t]\t%[^\t]\t%[^\t]\t%[^\t]\t%[^\t]\t%[^\t]\n",
+                   name, key, font, code, keyboard, timezone) != 6) {
+            printf("bad line %d in lang-table", lineNum);
+            logMessage(WARNING, "bad line %d in lang-table", lineNum);
+        } else {
+            languages[numLanguages].lang = strdup(name);
+            languages[numLanguages].key = strdup(key);
+            languages[numLanguages].font = strdup(font);
+            languages[numLanguages].lc_all = strdup(code);
+            languages[numLanguages++].keyboard = strdup(keyboard);
+        }
+    }
+    fclose(f);
+}
+
+int getLangInfo(struct langInfo ** langs) {
+    if (!languages)
+        loadLanguageList();
+
+    *langs = languages;
+    return numLanguages;
+}
+
+void loadLanguage (char * file) {
+    char filename[200];
+    gzFile stream;
+    int fd, hash, rc;
+    char * key = getenv("LANGKEY");
+
+    if (strings) {
+	free(strings), strings = NULL;
+	numStrings = allocedStrings = 0;
+    }
+    
+    /* english requires no files */
+    if (!strcmp(key, "en"))
+        return;
+
+    if (!file) {
+        file = filename;
+        sprintf(filename, "/etc/loader.tr");
+    }
+
+    stream = gunzip_open(file);
+
+    if (!stream) {
+        newtWinMessage("Error", "OK", "Translation for %s is not available.  "
+                       "The Installation will proceed in English.", key);
+        return ;
+    }
+    
+    sprintf(filename, "%s.tr", key);
+
+    rc = installCpioFile(stream, filename, "/tmp/translation", 1);
+    gunzip_close(stream);
+
+    if (rc || access("/tmp/translation", R_OK)) {
+        newtWinMessage("Error", "OK", "Cannot get translation file %s.\n", 
+                        filename);
+        return;
+    }
+    
+    fd = open("/tmp/translation", O_RDONLY);
+    if (fd < 0) {
+        newtWinMessage("Error", "OK", "Failed to open /tmp/translation: %m\n");
+        return;
+    }
+
+    while (read(fd, &hash, 4) == 4) {
+        if (allocedStrings == numStrings) {
+            allocedStrings += 10;
+            strings = realloc(strings, sizeof(*strings) * allocedStrings);
+        }
+
+        strings[numStrings].hash = ntohl(hash);
+        rc = read(fd, &strings[numStrings].length, 2);
+        strings[numStrings].length = ntohs(strings[numStrings].length);
+        strings[numStrings].str = malloc(strings[numStrings].length + 1);
+        rc = read(fd, strings[numStrings].str, strings[numStrings].length);
+        strings[numStrings].str[strings[numStrings].length] = '\0';
+        numStrings++;
+    }
+
+    close(fd);
+    unlink("/tmp/translation");
+
+    qsort(strings, numStrings, sizeof(*strings), aStringCmp);
+}
+
+
+/* give the index of the language to set to -- sets the appropriate
+ * lang variables if we have a font.
+ *
+ * ASSUMPTION: languages exists
+ */
+static void setLangEnv (int i) {
+    if (i > numLanguages)
+        return;
+
+    if (strcmp(languages[i].font, "latarcyrheb-sun16"))
+        return;
+    logMessage(INFO, "setting language to %s", languages[i].lc_all);
+
+    setenv("LANG", languages[i].lc_all, 1);
+    setenv("LANGKEY", languages[i].key, 1);
+    setenv("LINGUAS", languages[i].lang, 1);
+    loadLanguage (NULL);
+}
+
+/* choice is the index of the chosen language in languages */
+static int setupLanguage(int choice, int forced) {
+    char * buf;
+    int i;
+
+    logMessage(DEBUGLVL, "going to set language to %s", languages[choice].lc_all);
+    /* load the language only if it is displayable.  if they're using
+     * a serial console or iSeries vioconsole, we hope it's smart enough */
+    if ((strcmp(languages[choice].font, "latarcyrheb-sun16") && !FL_SERIAL(flags) && 
+         !FL_VIRTPCONSOLE(flags) && !isVioConsole())) {
+        if (forced == 1) return 0;
+
+	newtWinMessage("Language Unavailable", "OK", 
+		       "%s display is unavailable in text mode.  The "
+		       "installation will continue in English until the "
+		       "display of %s is possible.", languages[choice].lang,
+		       languages[choice].lang);
+        setLangEnv(english);
+	return 0;
+    }
+    
+    setLangEnv (choice);
+    isysLoadFont();
+
+    /* clear out top line */
+    buf = alloca(81); /* reserve one byte for \0 */
+    for (i=0; i < 80; i++)
+	buf[i] = ' ';
+    buf[80] = 0; /* and set the \0 */
+    newtDrawRootText(0, 0, buf);
+
+    char *fmt = FL_RESCUE(flags) ? _(topLineWelcomeRescue) : _(topLineWelcome);
+    checked_asprintf(&buf, fmt, getProductName(), getProductArch());
+
+    newtDrawRootText(0, 0, buf);
+    free(buf);
+    newtPopHelpLine();
+    newtPushHelpLine(_(bottomHelpLine));
+
+    return 0;
+
+}
+
+/* this is pretty simple.  we want to break down the language specifier
+ * into its short form (eg, en_US)
+ */
+static char * getLangShortForm(char * oldLang) {
+    char * lang;
+    char * c;
+    
+    lang = strdup(oldLang);
+
+    c = strchr(lang, '@');
+    if (c) {
+        *c = '\0';
+    }
+
+    c = strchr(lang, '.');
+    if (c) {
+        *c = '\0';
+    }
+
+    return lang;
+}
+
+/* return the nick of a language -- eg en_US -> en */
+static char * getLangNick(char * oldLang) {
+    char * lang;
+    char * c;
+    
+    lang = strdup(oldLang);
+
+    c = strchr(lang, '_');
+    if (c) {
+        *c = '\0';
+    }
+
+    return lang;
+}
+
+int setLanguage (char * key, int forced) {
+    int i;
+
+    if (!languages) loadLanguageList();
+
+    for (i = 0; i < numLanguages; i++) {
+        if (!strcmp(languages[i].lc_all, key)) {
+            return setupLanguage(i, forced | !FL_KICKSTART(flags));
+        }
+    }
+
+    /* we didn't specify anything that's exactly in the lang-table.  check
+     * against short forms and nicks */
+    for (i = 0; i < numLanguages; i++) {
+        if (!strcmp(getLangShortForm(languages[i].lc_all), key)) {
+            return setupLanguage(i, forced | !FL_KICKSTART(flags));
+        }
+    }
+
+    for (i = 0; i < numLanguages; i++) {
+        if (!strcmp(getLangNick(languages[i].lc_all), key)) {
+            return setupLanguage(i, forced | !FL_KICKSTART(flags));
+        }
+    }
+
+    logMessage(ERROR, "unable to set to requested language %s", key);
+    return -1;
+}
+
+int chooseLanguage(char ** lang) {
+    int choice = 0;
+    char ** langs;
+    int i;
+    int current = -1;
+    char * currentLangName = getenv("LANG");
+    int numLangs = 0;
+    char * langPicked;
+
+    if (!languages) loadLanguageList();
+
+    langs = alloca(sizeof(*langs) * (numLanguages + 1)); 
+
+    for (i = 0; i < numLanguages; i++) {
+        if (!strncmp(languages[i].key, "en", 2))
+            english = numLangs;
+        if (currentLangName &&
+            !strcmp(languages[i].lang, currentLangName))
+            current = numLangs;
+
+        langs[numLangs++] = languages[i].lang;
+    }
+
+    langs[numLangs] = NULL;
+
+    if (current >= 0)
+        choice = current;
+    else
+        choice = english;
+
+    if (!FL_CMDLINE(flags))
+        newtWinMenu(_("Choose a Language"),
+                    _("What language would you like to use during the "
+                      "installation process?"), 40, 5, 5, 8,
+                    langs, &choice, _("OK"), NULL);
+
+    langPicked = langs[choice];
+    for (i = 0; i < numLanguages; i++) {
+        if (!strcmp(langPicked, languages[i].lang)) {
+            *lang = languages[i].lc_all;
+            choice = i;
+            break;
+        }
+    }
+
+    /* this can't happen */
+    if (i == numLanguages) abort();
+
+    return setupLanguage(choice, 0);
+}
+
+void setKickstartLanguage(struct loaderData_s * loaderData, int argc, 
+                          char ** argv) {
+    if (argc < 2) {
+        logMessage(ERROR, "no argument passed to lang kickstart command");
+        return;
+    }
+
+    loaderData->lang = argv[1];
+    loaderData->lang_set = 1;
+}
diff --git a/bin/loader/lang.h b/bin/loader/lang.h
new file mode 100644
index 0000000..965f5a0
--- /dev/null
+++ b/bin/loader/lang.h
@@ -0,0 +1,41 @@
+/*
+ * lang.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _LANG_H_
+#define _LANG_H_
+
+#include "loader.h"
+
+#define _(x) translateString (x)
+#define N_(foo) (foo)
+
+struct langInfo {
+    char * lang, * key, * font, * lc_all, * keyboard;
+} ;
+
+
+int chooseLanguage(char ** lang);
+char * translateString(char * str);
+int setLanguage (char * key, int forced);
+int getLangInfo(struct langInfo **langs);
+
+void setKickstartLanguage(struct loaderData_s * loaderData, int argc, 
+                          char ** argv);
+
+#endif /* _LANG_H_ */
diff --git a/bin/loader/linuxrc.s390 b/bin/loader/linuxrc.s390
new file mode 100644
index 0000000..814dd32
--- /dev/null
+++ b/bin/loader/linuxrc.s390
@@ -0,0 +1,3118 @@
+#! /bin/bash
+
+# linuxrc.s390: init process of Red Hat's installer initrd for s390(x)
+# Copyright (C) 2000-2004 by
+#        Bernhard Rosenkraenzer <bero redhat com>
+#        Oliver Paukstadt <opaukstadt millenux com>
+#        Karsten Hopp <karsten redhat de>
+#        Florian La Roche <laroche redhat com>
+#        Nils Philippsen <nils redhat de>
+#        Helge Deller <hdeller redhat de>
+#        David Sainty <dsainty redhat com>
+# Copyright (C) IBM Corp. 2008,2009
+#        Author: Steffen Maier <maier de ibm com>
+#
+#    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, write to the Free Software
+#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+# prerequisites of this script to run inside the installer initrd:
+# - udevadm and udevd need to be there
+# - have /etc/udev/udev.conf with at least one comment line as content
+# - if necessary, have udev rules
+# - lsznet.raw and znetcontrolunits from s390utils-base in /lib/s390-tools
+# - pack kernel modules and module-init-tools (no longer use busybox for that)
+# - "multi on" in /etc/host.conf [RH bugs 486457,486461,483244]
+
+# TODOs:
+# - make sure driver modules get loaded automatically
+# - udev rule for lcs/ctcm vs. cu3088
+
+# debug: set -x
+
+if [ "${0##*/}" = "reboot" ]; then
+    kill -USR2 1
+elif [ "${0##*/}" = "halt" ]; then
+    kill -USR1 1
+fi
+
+VERSION=1.2
+
+export TEXTDOMAIN=s390installer
+export TEXTDOMAINDIR=/usr/lib/locale
+
+# helper function to execute command in arguments and print command on stdout
+function debug() {
+    # uncomment the following echo "$*" to enable debug output
+    #echo "$*"
+    $*
+}
+
+# FIXME: maybe change to "$$" for production use, in case it wouldn't be init
+declare -r INITPID="1"
+
+unset testing
+[ "$$" != "$INITPID" ] && testing="1"
+# uncomment the following test="1" to never execute sensitive commands
+#testing="1"
+
+if [ "$RUNKS" = "0" ]; then
+    RUNKS=""
+fi
+
+# ping command to use to test host availability (for gateway & dns servers)
+PINGOPTS="-c 3 -w 30"
+PING="ping $PINGOPTS"
+PING6="ping6 $PINGOPTS"
+
+# helper function to disable commands while running outside the initrd
+function tv() {
+    if [ -z "$testing" ]; then
+        $*
+    else
+        return 0
+    fi
+}
+
+function checkipv6()
+{
+    local ip=$1
+    [ -z "$ip" ] && return 1
+    /sbin/ipcalc -c -6 "$ip" >/dev/null 2>&1
+    return $?
+}
+
+function checkipv4()
+{
+    local ip=$1
+    [ -z "$ip" ] && return 1
+    /sbin/ipcalc -c -4 "$ip" >/dev/null 2>&1
+    return $?
+}
+
+function doshutdown()
+{
+    echo $"about to exec shutdown"
+    exec /sbin/shutdown
+    exit 0
+}
+
+function doreboot()
+{
+    if [ -e "/sys/firmware/reipl" ]; then
+        read REIPL_TYPE < /sys/firmware/reipl/reipl_type
+        echo "reipl_type=$REIPL_TYPE"
+        pushd /sys/firmware/reipl/$REIPL_TYPE >/dev/null 2>&1
+        for i in *; do
+            echo "$i=`cat $i`"
+        done
+        popd >/dev/null 2>&1
+    fi
+
+    echo $"about to exec shutdown -r"
+    exec /sbin/shutdown -r
+    exit 0
+}
+
+function sysecho () {
+    file=$1
+    shift
+    local i=1
+    while [ $i -le 10 ] ; do
+        if [ ! -f "$file" ]; then
+            sleep 1
+            i=$((i+1))
+        else
+            break
+        fi
+    done
+    [ -f "$file" ] && echo $* > $file
+}
+
+function dasd_settle() {
+    local dasd_status=/sys/bus/ccw/devices/$1/status
+    if [ ! -f $dasd_status ]; then
+        return 1
+    fi
+    local i=1
+    while [ $i -le 30 ] ; do
+        local status
+        read status < $dasd_status
+        case $status in
+            online|unformatted)
+                return 0 ;;
+            *)
+                sleep 0.1
+                i=$((i+1)) ;;
+        esac
+    done
+    return 1
+}
+
+function dasd_settle_all() {
+    for dasdccw in $(cut -d '(' -f 1 /proc/dasd/devices) ; do
+        if ! dasd_settle $dasdccw ; then
+            echo $"Could not access DASD $dasdccw in time"
+            return 1
+        fi
+    done
+    return 0
+}
+
+function startinetd()
+{
+    echo
+    echo $"Starting sshd to allow login over the network."
+    if [ -z "$testing" ]; then
+        echo $"Welcome to the anaconda install environment $VERSION for $S390ARCH" > /etc/issue.net
+        echo $"Welcome to the anaconda install environment $VERSION for $S390ARCH" > /etc/motd
+        echo >> /etc/motd
+    fi # testing
+
+    /sbin/sshd -f /etc/ssh/sshd_config.anaconda
+    if [ -z "$RUNKS" ]; then
+        echo
+        echo $"Connect now to $IPADDR and log in as user install to start the installation."
+        echo $"E.g. using: ssh -x install $IPADDR"
+        echo $"You may log in as the root user to start an interactive shell."
+        read
+        while : ; do
+            /bin/sh --login
+            [ $? = 0 ] || break
+        done
+    fi
+}
+
+# prints a canonocalized device bus ID for a given devno of any format
+function canonicalize_devno()
+{
+    case ${#1} in
+        3) echo "0.0.0${1}" ;;
+        4) echo "0.0.${1}" ;;
+        *) echo "${1}" ;;
+    esac
+    return 0
+}
+
+# read file from CMS and write it to /tmp
+function readcmsfile() # $1=dasdport $2=filename
+{
+    local dev
+    if [ $# -ne 2 ]; then return; fi
+    # precondition: udevd created dasda block device node
+    if ! sysecho /proc/cio_ignore "free $1"; then
+        echo $"DASD $1 could not be cleared from device blacklist"
+        return 1
+    fi
+    # /proc/cio_ignore won't block on freeing devices until resensing
+    # has been completed, so wait until the udev event queue depletes
+    # (without udevadm settle we could wait 2 seconds unconditionally)
+    #debug ls -laF /dev/.udev
+    udevadm settle
+    # even though the device might now be online, some of its
+    # sysfs attributes might not yet be available
+    sleep 1
+    # precondition: dasd_eckd_mod driver incl. dependencies loaded,
+    #               dasd_mod must be loaded without setting any DASD online
+    dev=$(canonicalize_devno $1)
+    if ! sysecho /sys/bus/ccw/devices/$dev/online 1; then
+        echo $"DASD $dev could not be set online"
+        return 1
+    fi
+    udevadm settle
+    if ! dasd_settle $dev ; then
+        echo $"Could not access DASD $dev in time"
+        return 1
+    fi
+    udevadm settle
+    if ! cmsfscat -d /dev/dasda -a $2 > /tmp/$2; then
+        echo $"Could not read conf file $2 on CMS DASD $1."
+    fi
+    if ! sysecho /sys/bus/ccw/devices/$dev/online 0; then
+        echo $"DASD $dev could not be set offline again"
+        return 1
+    fi
+    udevadm settle
+    # consequences of no more module unload: loader can no longer
+    # use DASD module option to online DASDs and set other DASD parameters!
+}
+
+# adaption of the same function in init.c (udevd gets started later)
+function createDevices()
+{
+    awk '{ printf("mknod /dev/%s %s %s %s\n", $1, $2, $3, $4);
+      printf("chmod %s /dev/%s\n", $5, $1);
+      printf("chown %s /dev/%s\n", $6, $1);
+    }' <<EOF | sh
+console c 5 1 600 root:root
+null c 1 3 666 root:root
+zero c 1 5 666 root:root
+mem c 1 1 600 root:root
+ptmx c 5 2 666 root:root
+tty  c 5 0 666 root:root
+tty0 c 4 0 600 root:tty
+tty1 c 4 1 600 root:tty
+random c 1 8 644 root:root
+urandom c 1 9 644 root:root
+rtc c 10 135 644 root:root
+EOF
+    # tty handling is different from init.c since s390 does not have all
+    for i in 2 3 4 5 6 7 8 9 ; do
+        ln -s console /dev/tty$i
+    done
+    mkdir /dev/pts
+    ln -s /proc/self/fd /dev/fd
+}
+
+# approximately the main() function of init.c
+function init_main() {
+    S390ARCH=$(uname -m)
+    if [ "$S390ARCH" = "s390" ]; then
+        export S390ARCH="S/390"
+    else
+        export S390ARCH="zSeries"
+    fi
+
+    echo
+    echo $"Starting the $S390ARCH initrd to configure networking. Version is $VERSION"
+
+    # set up env vars as we do in init.c
+    if [ $(uname -m) = "s390x" ]; then
+        LD_LIBRARY_PATH=/lib64:/usr/lib64:/usr/X11R6/lib64:/usr/kerberos/lib64:/lib:/usr/lib:/usr/X11R6/lib:/usr/kerberos/lib
+    else
+        LD_LIBRARY_PATH=/lib:/usr/lib:/usr/X11R6/lib:/usr/kerberos/lib
+    fi
+    export LD_LIBRARY_PATH
+
+    PATH="$PATH:/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sysimage/bin:/mnt/sysimage/usr/bin:/mnt/sysimage/usr/sbin:/mnt/sysimage/sbin:/mnt/sysimage/usr/X11R6/bin"
+    export PATH
+    HOME=/
+    export HOME
+    PYTHONPATH=/tmp/updates
+    export PYTHONPATH
+
+    if [ -z "$testing" ]; then
+
+        mount -t proc none /proc
+
+        mount -t tmpfs none /dev
+        createDevices
+        # udevd req'd by udevadm settle (/dev/.udev/queue)
+        # in readcmsfile, dialog_network_table, semantic_check_subchannels.
+        # (important: start udevd at the right time, e.g. after setup of /dev)
+        echo $"Starting udev..."
+        udevd --daemon
+        # debug: udevadm control --log-priority=debug
+
+        udevadm control --env=ANACONDA=1
+
+        mount -t devpts /dev/pts /dev/pts
+        mount -t sysfs none /sys
+
+        # remount root fs rw
+        mount /dev/root /  -o remount,rw
+
+        # limit output on 3270 console
+        # (console_loglevel of 4 is just right to not get driver info,
+        #  e.g. from qeth, since that would mix up with the user dialog)
+        echo "4 4 1 7" > /proc/sys/kernel/printk
+
+        # make /tmp/ramfs
+        mount -t ramfs none /tmp
+
+        ifconfig lo 127.0.0.1 netmask 255.0.0.0
+        route add -host 127.0.0.1 dev lo
+
+        echo -e "127.0.0.1\tlocalhost.localdomain localhost localhost4 localhost4.localdomain4" > /etc/hosts
+        echo -e     "::1\t\tlocalhost.localdomain localhost localhost6 localhost6.localdomain6" >> /etc/hosts
+
+        /sbin/dbus-uuidgen --ensure &
+        [ $? != 0 ] && echo "error on calling /sbin/dbus-uuidgen --ensure"
+        /sbin/dbus-daemon --system &
+        [ $? != 0 ] && echo "error on calling /sbin/dbus-daemon --system"
+
+    fi # testing
+}
+
+# trigger udev to automatically load device drivers
+function udev_setup() {
+    if [ -z "$testing" ]; then
+       # debug: udevadm monitor &
+       udevadm trigger
+       udevadm settle
+    fi # testing
+}
+
+# from here on accesses to sysfs try to follow
+# linux/Documentation/sysfs-rules.txt
+
+### lsznet.raw integration
+
+declare -a nettable
+
+function read_lsznet_output() {
+    count=0
+    local line
+    while read line; do
+        nettable[$count]="$line"
+        count=$((count + 1))
+    # using the more sophisticated process substitution instead of temp file
+    # requires the symlink /dev/fd -> /proc/self/fd => createDevices
+    done < <(/lib/s390-tools/lsznet.raw)
+}
+
+function print_nettable() {
+    local fmtstring="%3s %-14s %-7s %-5s %-4s %-6s %-7s %s\n"
+    printf "$fmtstring" \
+        "NUM" "CARD" "CU" "CHPID" "TYPE" "DRIVER" "IF" "DEVICES"
+    local i
+    for ((i=0; i < count; i++)); do
+        local item cutype chp chpidtype devdrv devname chlist cardtype
+        read item cutype chp chpidtype devdrv devname chlist cardtype <<< ${nettable[$i]}
+        printf "$fmtstring" \
+            $item "$cardtype" $cutype $chp "$chpidtype" $devdrv $devname $chlist
+    done
+}
+
+function clear_screen() {
+    # FIXME: find a way to clear screen despite 3215 line mode terminal
+    echo
+}
+
+function dialog_network_table() {
+    while : ; do
+        echo $"Scanning for available network devices..."
+        # This may take a long time so we show "progress":
+        #( while true; do echo -n "."; sleep 1; done ) &
+        #local childpid=$!
+        read_lsznet_output
+        #kill $childpid
+        #echo
+        echo $"Autodetection found ${count} devices."
+        # count==0: there might still be a blacklist the user wants to clear.
+        # do not flood user with long list if there are many devices
+        if [ "$count" -le 15 ]; then
+            # Show list
+            answer=s
+        else # [ $count -gt 15 ]
+            echo
+            while : ; do
+                echo $"s) show all, m) manual config:"
+                local answer
+                read answer
+                case $answer in
+                    s|m) break ;;
+                esac
+            done
+        fi
+        [ "$answer" = "m" ] && break
+        # show network table to select network hardware configuration from
+        if [ "$count" -gt 0 ]; then
+            clear_screen
+            print_nettable
+            echo
+        fi
+        # account for possibly ignored common I/O devices
+        # cio_wc_bytes is NOT local so it can be re-used outside this function
+        cio_wc_bytes=0
+        local cio_wc_filename cio_wc_foo
+        if [ -f /proc/cio_ignore ]; then
+            local cio_wc=$(wc -c /proc/cio_ignore)
+            read cio_wc_bytes cio_wc_filename cio_wc_foo <<< "$cio_wc"
+            if [ "$cio_wc_bytes" != "0" ]; then
+                echo $"Note: There is a device blacklist active! (Clearing might take long)"
+                #cat /proc/cio_ignore | tr '\n' ','
+                #echo
+            else
+                if [ "$count" -eq 0 ]; then
+                    # count==0 AND no device blacklist => manual mode
+                    echo $"Entering manual configuration mode."
+                    break
+                fi
+            fi
+        fi
+        # selection dialog
+        while : ; do
+            [ "$count" -gt 0 ] && echo -n $"<num>) use config, "
+            [ "$cio_wc_bytes" != "0" ] && echo -n $"c) clear blacklist, "
+            echo $"m) manual config, r) rescan, s) shell:"
+            local choice
+            read choice
+            [ -z "$choice" ] && continue
+            if [ "$choice" = "s" ]; then
+                echo $"Enter 'exit' at the shell prompt to get back to the installation dialog."
+                /bin/bash
+                continue 2
+            fi
+            [ "$choice" = "m" ] && break
+            [ "$choice" = "r" ] && continue 2
+            [ "$cio_wc_bytes" != "0" -a "$choice" = "c" ] && break
+            [[ "$choice" =~ ^[[:digit:]]+$ ]]
+            case $? in
+                0)
+                    # string matched the pattern
+                    [ "$choice" -ge 1 -a "$choice" -le "$count"  ] && break
+                    ;;
+                1)
+                    # string did not match the pattern
+                    continue
+                    ;;
+                2)
+                    echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+                    ;;
+                *)
+                    echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+                    ;;
+            esac
+        done
+        if [ "$choice" = "c" ]; then
+            echo $"Clearing device blacklist..."
+            if sysecho /proc/cio_ignore "free all"; then
+                cio_wc_bytes=0
+                # /proc/cio_ignore won't block on freeing devices
+                # until resensing has been completed, so wait until
+                # the udev event queue depletes.
+                # This may take a long time so we show "progress":
+                #( while true; do echo -n "."; sleep 3; done ) &
+                #local childpid=$!
+                #debug ls -laF /dev/.udev
+                udevadm settle
+                # (virtual) CTC/A takes some more time to appear in sysfs
+                # FIXME: how long to wait? 3 seconds seems to be enough.
+                sleep 3
+                #kill $childpid
+                #echo
+                continue
+            else
+                echo $"Device blacklist could not be cleared"
+            fi
+        fi
+        [ "$choice" = "m" ] && break
+        # finally extract config info from selected item
+        # array nettable starts at index zero, user input starts at index one
+        choice=$((choice - 1))
+        local item cutype chp chpidtype devdrv devname chlist cardtype
+        read item cutype chp chpidtype devdrv devname chlist cardtype <<< ${nettable[$choice]}
+        # $NETTYPE happens to be exactly the network driver name
+        if [ "$devdrv" = "ctcm" ]; then
+            NETTYPE="ctc"
+        else
+            NETTYPE=$devdrv
+        fi
+        SUBCHANNELS=$chlist
+        break
+    done
+    echo
+}
+
+declare -r PREFIXFORMAT=[[:xdigit:]]*
+declare -r SSIDFORMAT=[0-3]
+declare -r BUSIDFORMAT=[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]]
+declare -r IDFORMAT=$PREFIXFORMAT.$SSIDFORMAT.$BUSIDFORMAT
+declare -r SUBCHANNEL_TYPE_IO=0
+
+. /lib/s390-tools/znetcontrolunits
+
+function cardtype2cleartext() {
+    local cardtype=$1
+    case $cardtype in
+        OSD_10GIG)        echo "OSA card in OSD mode, 10 Gigabit Ethernet" ;;
+        OSD_1000)         echo "OSA card in OSD mode, Gigabit Ethernet" ;;
+        OSD_100)          echo "OSA card in OSD mode, Fast Ethernet" ;;
+        OSD_GbE_LANE)     echo "OSA card in OSD mode, Gigabit Ethernet, LAN Emulation" ;;
+        OSD_FE_LANE)      echo "OSA card in OSD mode, Fast Ethernet, LAN Emulation" ;;
+        OSD_TR_LANE)      echo "OSA card in OSD mode, Token Ring, LAN Emulation" ;;
+        OSD_ATM_LANE)     echo "OSA card in OSD mode, ATM, LAN Emulation" ;;
+        OSD_Express)      echo "OSA card in OSD mode, unknown link type" ;;
+        HSTR)             echo "OSA card in OSD mode, High Speed Token Ring" ;;
+        OSN)              echo "OSA for NCP, ESCON/CDLC bridge" ;;
+        HiperSockets)     echo "HiperSockets with CHPID type IQD" ;;
+        "GuestLAN QDIO")  echo "GuestLAN based on OSA (QDIO)" ;;
+        "GuestLAN Hiper") echo "GuestLAN based on HiperSockets" ;;
+        unknown)          echo "other" ;;
+        *) echo "unknown"
+            echo "l.$LINENO: found unknown card_type, code needs to be fixed" 1>&2
+            ;;
+    esac
+}
+
+# returns true iff running under z/VM
+function isVM() {
+    local cpu_version=$(cat /proc/cpuinfo |grep "^processor " | head -n1 | sed 's/.*version = \([[:xdigit:]][[:xdigit:]]\).*/\1/' | tr '[:lower:]' '[:upper:]')
+    if [ "$cpu_version" = "FF" ]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+# watch out: potential error message as side effect
+function isLayer2Default() {
+    # Read default from sysfs because according to device
+    # drivers book there are differences in the default between
+    # OSA (l2), hipersockets (l3).
+    # This only works here in installer where nobody has overwritten
+    # the default setting with another custom value already!
+    if [ ! -f /sys/devices/${NETTYPE}/$SCH_R_DEVBUSID/layer2 ]; then
+        echo $"Could not read layer mode from sysfs"
+        return 1
+    fi
+    local layer2
+    read layer2 < /sys/devices/${NETTYPE}/$SCH_R_DEVBUSID/layer2
+    if [ "$layer2" = "1" ]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+# returns true iff either LAYER2 has been set to 1 or is the default
+# watch out: potential error message as side effect
+function isLayer2() {
+    case "x$LAYER2" in
+        x0) return 1 ;; # layer 3
+        x1) return 0 ;; # layer 2
+        x)  # LAYER2 is unset or empty => qeth driver default applies.
+            isLayer2Default
+            return $?
+            ;;
+        *) echo "l.$LINENO: unknown value \"$LAYER2\" for LAYER2, code needs to be fixed" 1>&2
+            return 2 ;;
+    esac
+}
+
+# returns true iff qeth device $SCH_R_DEVBUSID
+# is capable of supporting IPv6
+# watch out: potential error message as side effect
+function ipv6_capable() {
+    [ "$NETTYPE" = "qeth" ] || return 1
+    case $cardtype in
+        OSD_10GIG|OSD_1000|OSD_100|OSD_Express|HiperSockets|"GuestLAN QDIO")
+            return 0 ;;
+        OSD_GbE_LANE|OSD_FE_LANE|OSD_TR_LANE|OSD_ATM_LANE) return 1 ;;
+        HSTR|OSN|unknown) return 1 ;;
+        "GuestLAN Hiper") return 1 ;;
+        *) echo $"Unknown card_type to determine IPv6 support"
+            return 1 ;;
+    esac
+}
+
+# sets device online _and_ retrieves DEVICE at the same time
+function set_device_online() {
+    echo $"Activating network device..."
+    local sysnettype
+    case "${NETTYPE}" in
+        qeth|lcs) sysnettype=${NETTYPE} ;;
+        ctc) sysnettype=ctcm ;;
+    esac
+    if ! [ -f /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/online ]; then
+        echo $"Sysfs path to set device online does not exist."
+        return 1
+    fi
+    if ! sysecho /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/online "1"; then
+        echo $"Could not set device ($SUBCHANNELS) online"
+        return 1
+    fi
+    udevadm settle
+    local i=1
+    while : ; do
+        local online
+        read online < /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/online
+        [ "$online" == "1" ] && break
+        sleep 1
+        i=$((i+1))
+        if [ "$i" -gt 10 ]; then
+            echo $"Could not set device ($SUBCHANNELS) online within timeout"
+            return 1
+        fi
+    done
+    if [ "$NETTYPE" = "lcs" -o "$NETTYPE" = "ctc" ]; then
+        # KH FIXME: Workaround for missing sysfs interface
+        #   DEVICE=$(cat /sys/devices/lcs/${SUBCHANNELS//,*/}/if_name)
+        # replaced with flexible solution:
+        # https://bugzilla.redhat.com/show_bug.cgi?id=204803#c9
+        # "sys/bus/ccwgroup/devices/${SUBCHANNEL}/net\:*
+        # for lcs after setting online"
+        if [ ! -h /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/net:* ]; then
+            echo $"Device $SUBCHANNELS does not have required sysfs attribute 'net:*'"
+            return 1
+        fi
+        DEVICE=$(echo /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/net:*)
+        DEVICE=${DEVICE//*:/}
+        if [ "$DEVICE" = "" ]; then
+            echo $"Could not get device name for $SUBCHANNELS"
+            return 1
+        fi
+    else # qeth
+        if [ ! -f /sys/devices/qeth/$SCH_R_DEVBUSID/if_name ]; then
+            echo $"Device $SUBCHANNELS does not have required sysfs attribute 'if_name'"
+            return 1
+        fi
+        # (device needs to be online to read if_name from sysfs attribute!)
+        read DEVICE < /sys/devices/qeth/$SCH_R_DEVBUSID/if_name
+        if [ "$DEVICE" = "" ]; then
+            echo $"Could not get device name for $SUBCHANNELS"
+            return 1
+        fi
+        if [ -f /sys/devices/qeth/$SCH_R_DEVBUSID/card_type ]; then
+            read cardtype < /sys/devices/qeth/$SCH_R_DEVBUSID/card_type
+            #debug echo "$cardtype"
+            # device is now online and link type will be known
+            echo -n $"Detected: "
+            cardtype2cleartext "$cardtype"
+        else
+            echo $"Could not read qeth network card type from sysfs."
+        fi
+    fi
+}
+
+# sets device up and blocks until device appears to be up
+function set_device_up() {
+    if [ -z "$DEVICE" ]; then
+        echo $"Could not determine interface name to bring up device $SUBCHANNELS"
+        return 1
+    fi
+    # Device does not come up fast enough to use "ip" to configure, so block.
+    # While OSA come up themselves after setting online,
+    # e.g. HiperSockets won't => set them up explicitly for the following check
+    debug ip link set up $DEVICE
+    local i=1
+    while : ; do
+        local tst=$(ip -o link show up dev $DEVICE)
+        [ -n "$tst" ] && break
+        sleep 1
+        i=$((i+1))
+        if [ "$i" -gt 10 ]; then
+            echo $"Could not bring up device $DEVICE within timeout"
+            return 1
+        fi
+    done
+    return 0
+}
+
+function syntax_check_domainname() {
+    # - match against regex adopted from RFC1035,sec.2.3.1 or RFC1034,sec.3.5
+    #   (Internationalized Domain Names in Applications (IDNA) [RFC4690]
+    #    have to be entered after encoding by punycode [RFC3492])
+    [[ "$1" =~ ^[[:alpha:]]([[:alnum:]-]{0,61}[[:alnum:]])?(\.[[:alpha:]]([[:alnum:]-]{0,61}[[:alnum:]])?)*$ ]]
+    case $? in
+        0)
+            # string matched the pattern
+            return 0
+            ;;
+        1)
+            # string did not match the pattern
+            echo "$2"
+            ;;
+        2)
+            echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+            ;;
+        *)
+            echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+            ;;
+    esac
+    return 1
+}
+
+function modprobe_alias() {
+    if [ ":$NETTYPE" = ":ctc" ]; then
+        echo "alias $DEVICE ctcm" >> /tmp/modprobe.conf
+    else
+        echo "alias $DEVICE $NETTYPE" >> /tmp/modprobe.conf
+    fi
+    if [ $? -ne 0 ]; then
+        echo $"Could not append alias for network device $DEVICE to modprobe.conf"
+        return 1
+    fi
+    return 0
+}
+
+function disable_ipv6_autoconf() {
+    sysctl -w net.ipv6.conf.all.accept_ra=0 > /dev/null
+    sysctl -w net.ipv6.conf.all.accept_redirects=0 > /dev/null
+    sysctl -w net.ipv6.conf.all.autoconf=0 > /dev/null
+    sysctl -w net.ipv6.conf.default.accept_ra=0 > /dev/null
+    sysctl -w net.ipv6.conf.default.accept_redirects=0 > /dev/null
+    sysctl -w net.ipv6.conf.default.autoconf=0 > /dev/null
+}
+
+function configure_ipv6_address() {
+    # device needs to be online
+    # arp flag needs to be on for ipv6 over osa because of ndisc.
+    # happens automatically by the driver. do NOT mess with default setting.
+    #NO#debug ip link set dev $DEVICE arp on
+    if ! debug ip -6 address add $IPADDR/$NETMASK dev $DEVICE; then
+        echo $"Could net set IPv6 address $IPADDR/$NETMASK for device $DEVICE"
+        return 1
+    fi
+    # network route has been set by above "ip address add" already
+    # take care of MTU, which is bundled with ifconfig in the other IPv4 cases
+    if [ -n "$MMTU" ]; then
+        if ! debug ip link set $DEVICE $MMTU; then
+            echo $"Could net set maximum transfer unit ($MMTU) for device $DEVICE"
+            return 1
+        fi
+    fi
+    return 0
+}
+
+function configure_ipv4_address() {
+    # it's IPv4 and we can make use of ipcalc for better usability
+    if ipcalc -bmnp $ipcalc_arg > /tmp/ipcalc.$$.out 2> /dev/null; then
+        . /tmp/ipcalc.$$.out
+    else
+        echo $"Could not calculate network address and broadcast address from"
+        echo $" IPv4 address $IPADDR and netmask $NETMASK"
+        return 1
+    fi
+    rm /tmp/ipcalc.$$.out
+    # device needs to be online
+    if ! debug ifconfig $DEVICE $IPADDR $MMTU netmask $NETMASK broadcast $BROADCAST; then
+        echo $"Could not set IPv4 address $IPADDR for device $DEVICE"
+        echo $" with network mask $NETMASK and broadcast address $BROADCAST"
+        [ -n "$MMTU" ] && echo $" and maximum transfer unit: $MMTU"
+        return 1
+    fi
+    # This network route is already there after ifconfig!
+    #if ! debug route add -net $NETWORK netmask $NETMASK dev $DEVICE; then
+    #    echo $"Could not add network route to $NETWORK/$NETMASK on device $DEVICE"
+    #    return 1
+    #fi
+    return 0
+}
+
+function handle_mtu() {
+    # don't ask for MTU, but use it if it has been set in the .parm file
+    # don't overwrite MMTU if it has been set for CTC
+    [ -n "$MTU" -a -z "$MMTU" ] && MMTU="mtu $MTU"
+}
+
+function rollback_config() {
+    # each transaction to roll back may fail, if previous setup has not
+    # made progress that far to reach a certain transation
+    # => error output is misleading and should be avoided
+    [ -n "$DEVICE" ] && tv ip -4 route flush default dev $DEVICE
+    [ -n "$DEVICE" ] && tv ip -6 route flush default dev $DEVICE
+    # address flush seems to be effective for all address families
+    [ -n "$DEVICE" ] && ip address flush dev $DEVICE
+    if [ -n "$NETTYPE" ]; then
+        if [ -n "$SCH_R_DEVBUSID" ]; then
+            local sysnettype
+            case "${NETTYPE}" in
+                qeth|lcs) sysnettype=${NETTYPE} ;;
+                ctcm) sysnettype=ctcm ;;
+            esac
+            [ -f /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/online ] && \
+                sysecho /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/online "0"
+            udevadm settle
+            [ -f /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/ungroup ] && \
+                sysecho /sys/devices/${sysnettype}/$SCH_R_DEVBUSID/ungroup "1"
+            udevadm settle
+        fi
+    fi
+    [ -z "$mtu_was_set" ] && unset MTU
+    [ -z "$mmtu_was_set" ] && unset MMTU
+    [ -z "$vswitch_was_set" ] && unset VSWITCH
+    # prevent possible reuse of an old DEVICE on restarting dialog
+    unset DEVICE
+    # set activated DASDs offline again
+    local dasd
+    while read dasd < /proc/dasd/devices; do
+        dasd=${dasd%%(*}
+        sysecho /sys/bus/ccw/devices/$dasd/online 0
+    done
+    udevadm settle
+}
+
+### workflow helper functions
+
+# workflow ideas:
+# - setting/applying single configuration steps right away save us explicit
+#   syntactical & semantic checks PLUS we get direct feedback on error
+# - check error level of forked external programs and react on errors
+
+unset reenter
+unset redoitem
+unset interaction_happened
+
+function reenter() {
+    [ -z "$reenter" ] && return 1
+    # reenter menu should only be shown if NOT redoing item
+    if [ -n "$redoitem" ]; then
+        # unset redoitem # wrong => do NOT do this here
+        return 1
+    fi
+    return 0
+}
+
+function reenter_menu() {
+    local oldvalue=$1
+    interaction_happened="yes"
+    # unsetting input here is not sufficient, since reenter_menu
+    # is not called for predefined parameters
+    # which then might get assigned a previous old input of another parameter!
+    #unset input
+    reenter || return 0
+    # don't present reenter menu for empty parameters
+    # (currently ignoring parameters that are allowed to be empty!)
+    # this could be improved by checking if variable has been set/defined
+    #[ -z "$1" ] && return 0
+    while : ; do
+        if [ -n "$helptext" ]; then
+            echo $"0) default is previous \"$oldvalue\", 1) new value, ?) help"
+        else
+            echo $"0) default is previous \"$oldvalue\", 1) new value"
+        fi
+        # uncoded alternative: 2) skip parameter
+        local answer
+        read answer
+        [ -z "$answer" ] && return 1
+        case $answer in
+            0) return 1 ;;
+            1)  # Deciding to enter new value gets user out of reenter-mode
+                # temporarily for this parameter.
+                # To put it differently: redoing does NOT present old values.
+                redoitem="yes"
+                echo -n $"new value: "
+                return 0
+                ;;
+            "?") input="?"
+                return 1
+                ;;
+        esac
+    done
+}
+
+function workflow_item_menu() {
+    local noredo=$1
+    # default is to continue if running kickstart to prevent interaction
+    [ -n "$RUNKS" ] && return 0
+    interaction_happened="yes"
+    while : ; do
+        unset redoitem
+        if [ "$noredo" = "noredo" ]; then
+            echo $"1) continue, 2) restart dialog, 3) halt, 4) shell"
+        else
+            echo $"0) redo this parameter, 1) continue, 2) restart dialog, 3) halt, 4) shell"
+        fi
+        local answer
+        read answer
+        case $answer in
+            0) [ "$noredo" = "noredo" ] && continue
+                redoitem="yes"
+                continue 2
+                ;;
+            1) return 0 ;; # can be used to break at caller on ignore
+            2) reenter="yes"
+                rollback_config
+                continue 3
+                ;;
+            3) tv doshutdown
+                exit 0
+                ;;
+            4) echo $"Enter 'exit' at the shell prompt to get back to the installation dialog."
+                /bin/bash
+                if [ "$noredo" != "noredo" ] && [ -n "$question_prefix" ]; then
+                    $question_prefix
+                    echo
+                fi
+                ;; # stay in workflow item menu
+        esac
+    done
+}
+
+# input variables: PARMNAME, question_prefix, question_choices,
+#                  "options" ...
+# output variables: $question_prefix, $helptext
+# modifies: the variable named $PARMNAME, $OPTIND
+function ask() {
+    [ $# -lt 3 ] && echo "l.$LINENO: too few arguments (<3), please fix calling code." 1>&2
+    local PARMNAME=$1
+    shift
+    question_prefix=$1
+    shift
+    local question_choices=$1
+    shift
+    local exception
+    local syntax_check
+    unset helptext
+    local handle
+    local finish
+    local optname
+    OPTIND=1
+    while getopts ":e:s:h:c:f:" optname; do
+        case $optname in
+            e) exception=$OPTARG ;;
+            s) syntax_check=$OPTARG ;;
+            h) helptext=$OPTARG ;;
+            c) handle=$OPTARG ;;
+            f) finish=$OPTARG ;;
+            "?") ;; # ignore invalid option
+            :) echo "l.$LINENO: Missing parameter to option -$OPTARG" 1>&2 ;;
+        esac
+    done
+    while : ; do
+        unset input
+        local input
+        # actually ask question if one of the following is true:
+        # - $PARMNAME parameter has not been set yet, e.g. not in parm file
+        # - on 2nd and further attempts, i.e. redoing the parameter
+        # - on having restarted the whole dialog
+        # describing the same from another viewpoint:
+        # - if $PARMNAME has been set, try to check syntax and apply
+        # - on redo, $PARMNAME has been set and reenter is false,
+        #   but still ask question again
+        # - on reenter, $PARMNAME might have been set, but still ask question
+        if [ -z "${!PARMNAME}" -o -n "$redoitem" -o -n "$reenter" ]; then
+            # one empty line to separate parameter questions from each other
+            echo
+            $question_prefix
+            if reenter; then
+                echo
+            else
+                $question_choices
+            fi
+            # on reenter, give choice between old value and entering new one
+            reenter_menu ${!PARMNAME} && read input \
+                && [ "$input" != "?" ] && eval ${PARMNAME}=\$input
+            # escaping the $ in the RHS of the eval statement makes it safe
+        fi
+        if [ -n "$helptext" ] && [ "$input" = "?" ]; then
+            $helptext
+            continue
+        fi
+        # optional: default or exceptional handling
+        [ -n "$exception" ] && $exception
+        if [ -n "$syntax_check" -a -z "$handle" ]; then
+            # some parameters have only syntax check (and deferred config):
+            if $syntax_check; then
+                break
+            else
+                workflow_item_menu && break
+            fi
+        elif [ -n "$syntax_check" -a -n "$handle" ]; then
+            # most common parameters have syntax and configuration:
+            # user might still continue on syntax error
+            $syntax_check || workflow_item_menu
+            # optional: actual configuration
+            if $handle; then
+                # parmname has been configured successfully
+                break
+            else
+                # user might still continue on configuration failure
+                workflow_item_menu && break
+            fi
+        elif [ -n "$finish" ]; then
+            # few parameters need special handling done by their own function:
+            $finish
+        else
+            echo $"Unsupported calling of ask function, please fix calling code"
+        fi
+    done # PARMNAME
+    # disable potential temporary redoing-mode during reenter-mode
+    unset redoitem
+}
+
+### NETTYPE
+
+function syntax_check_nettype() {
+    # - NETTYPE \in {qeth,lcs,ctc}
+    [[ "$NETTYPE" =~ (^qeth$)|(^lcs$)|(^ctc$) ]]
+    case $? in
+        0)
+            # string matched the pattern
+            return 0
+            ;;
+        1)
+            # string did not match the pattern
+            ;;
+        2)
+            echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+            ;;
+        *)
+            echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+            ;;
+    esac
+    echo $"Incorrect format or value for network type (NETTYPE): $NETTYPE"
+    return 1
+}
+
+function question_prefix_nettype() {
+    echo -n $"Network type"
+}
+
+function question_choices_nettype() {
+    echo $" (qeth, lcs, ctc, ? for help). Default is qeth:"
+}
+
+function helptext_nettype() {
+    echo $" Help text for network type:"
+    echo $"  qeth: OSA-Express Fast Ethernet, Gigabit Ethernet (including 1000Base-T),"
+    echo $"        High Speed Token Ring, Hipersockets, and ATM (running Ethernet LAN emulation)"
+    echo $"        features in QDIO mode."
+    echo $"        [default]"
+    echo $"  lcs:  OSA-2 Ethernet/Token Ring, OSA-Express Fast Ethernet in non-QDIO mode,"
+    echo $"        OSA-Express High Speed Token Ring in non-QDIO mode and Gigabit Ethernet"
+    echo $"        in non-QDIO mode."
+    echo $"  ctc:  Deprecated, useful for migration."
+}
+
+function exception_nettype() {
+    # - default is qeth since it should be common
+    if [ -z "$NETTYPE" ]; then
+        NETTYPE=qeth
+        break
+    fi
+}
+
+function finish_nettype() {
+    if syntax_check_nettype; then
+        break
+    else
+        # necessary parts which would otherwise be done by workflow_item_menu
+        interaction_happened="yes"
+        redoitem="yes"
+    fi
+}
+
+function do_nettype() {
+    ask NETTYPE \
+        question_prefix_nettype question_choices_nettype \
+        -h helptext_nettype -e exception_nettype -f finish_nettype
+}
+
+### CHANDEV
+
+function do_chandev() {
+    echo
+    echo $"The CHANDEV variable isn't used anymore, please update your "
+    echo $".parm or the .conf file to use NETTYPE, SUBCHANNELS, etc. instead."
+    echo
+}
+
+### SUBCHANNELS
+
+function syntax_check_subchannels() {
+    SUBCHANNELS=$(echo $SUBCHANNELS | tr ABCDEF abcdef)
+    # - make subchannel question dependent on NETTYPE (2 vs. 3 subchannels)
+    if [ "$NETTYPE" = "qeth" ]; then
+        # - match against regex, depending on qeth
+        [[ "$SUBCHANNELS" =~ ^[[:xdigit:]]+\.[0-3]\.[[:xdigit:]]{4},[[:xdigit:]]+\.[0-3]\.[[:xdigit:]]{4},[[:xdigit:]]+\.[0-3]\.[[:xdigit:]]{4}$ ]]
+    else
+        # - match against regex, depending on lcs/ctc
+        [[ "$SUBCHANNELS" =~ ^[[:xdigit:]]+\.[0-3]\.[[:xdigit:]]{4},[[:xdigit:]]+\.[0-3]\.[[:xdigit:]]{4}$ ]]
+    fi
+    case $? in
+        0)
+            # string matched the pattern
+            return 0
+            ;;
+        1)
+            # string did not match the pattern
+            echo $"Incorrect format for channels (SUBCHANNELS): $SUBCHANNELS"
+            ;;
+        2)
+            echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+            ;;
+        *)
+            echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+            ;;
+    esac
+    return 1
+}
+
+function semantic_check_subchannels() {
+    local subch_count
+    if [ "$NETTYPE" = "qeth" ]; then
+        subch_count=3
+    else
+        subch_count=2
+    fi
+    # done: make subchannel handling more robust by not relying on REMATCH
+    local -a subch_array
+    IFS=,
+    read -a subch_array <<< "indexzero,$SUBCHANNELS"
+    unset IFS
+    local i
+    local all_subch_good=0
+    for ((i=1; i <= $subch_count; i++)); do
+        local devbusid=${subch_array[$i]}
+        # remember first subchannel for potential undo of ccwgroup
+        # (via /sys/devices/qeth/$SCH_R_DEVBUSID/ungroup)
+        [ "$i" -eq 1 ] && SCH_R_DEVBUSID=$devbusid
+        local prefix ssid devno foo
+        IFS=.
+        read prefix ssid devno foo <<< "$devbusid"
+        unset IFS
+        local dev_p=$(echo /sys/devices/css$prefix/$IDFORMAT/$devbusid)
+        # - check for existence of devnos in sysfs
+        if [ ! -d "$dev_p" -a "$cio_wc_bytes" != "0" ]; then
+            # - try to free from /proc/cio_ignore if they don't exist
+            echo $"Device $devbusid not present, trying to clear from blacklist and resense..."
+            if sysecho /proc/cio_ignore "free $devbusid"; then
+                # /proc/cio_ignore won't block on freeing devices
+                # until resensing has been completed, so wait until
+                # the udev event queue depletes (without udevadm settle we
+                # could wait 2 seconds unconditionally)
+                #debug ls -laF /dev/.udev
+                udevadm settle
+                # even though the device might now be online, some of its
+                # sysfs attributes (e.g. cutype) might not yet be available
+                sleep 1
+            else
+                echo $"Device $devbusid could not be cleared from device blacklist"
+            fi
+        fi
+        # reevaluate since globbing might not have worked before device existed
+        dev_p=$(echo /sys/devices/css$prefix/$IDFORMAT/$devbusid)
+        if [ ! -d "$dev_p" ]; then
+            echo $"Device $devbusid does not exist"
+            all_subch_good=1
+            continue
+        fi
+        # devno does exist now
+        local subch_p=${dev_p%/*}
+        local subch=${subch_p##*/}
+        # filter definitely unusable subchannels ...
+        # - check for subchannel type I/O
+        if [ -f $subch_p/type ]; then
+            local type
+            read type < $subch_p/type
+            if [ "$type" != "$SUBCHANNEL_TYPE_IO" ]; then
+                echo $"Channel $subch (device $devbusid) is not of type I/O"
+                all_subch_good=1
+                continue
+            fi
+        fi
+        # - check for correct CU type/model, depending on qeth/lcs/ctc
+        if [ ! -f $dev_p/cutype ]; then
+            echo $"Device $devbusid does not have required sysfs attribute 'cutype'"
+            all_subch_good=1
+            continue
+        fi
+        local cutype
+        read cutype < $dev_p/cutype
+        if search_cu $cutype; then
+            local driver
+            if [ "$NETTYPE" = "ctc" ]; then
+                driver="ctcm"
+            else
+                driver=$NETTYPE
+            fi
+            if [ "${CU_DEVDRV[$cu_idx]}" != "$driver" ]; then
+                echo $"Device $devbusid has control unit type $cutype,"
+                echo $" which does not match your selected network type $NETTYPE"
+                all_subch_good=1
+                continue
+            fi
+        else
+            echo $"Device $devbusid has control unit type $cutype which is unknown"
+            all_subch_good=1
+            continue
+        fi
+        # read CHPIDs information about subchannels
+        if [ ! -f $subch_p/chpids ]; then
+            echo $"Channel $subch (device $devbusid) does not have required sysfs attribute 'chpids'"
+            all_subch_good=1
+            continue
+        fi
+        local chpid_list
+        read chpid_list < $subch_p/chpids
+        local -a chpids
+        read -a chpids <<< "$chpid_list"
+        if [ ${#chpids[ ]} -ne 8 ]; then
+            echo $"sysfs reported ${#chpids[ ]} CHPIDs instead of expected 8, code needs fix"
+        fi
+        if [ ! -f $subch_p/pimpampom ]; then
+            echo $"Channel $subch (device $devbusid) does not have required sysfs attribute 'pimpampom'"
+            all_subch_good=1
+            continue
+        fi
+        local pim pam pom foo
+        read pim pam pom foo < $subch_p/pimpampom
+        local pimchpidZ=""
+        for ((chp=0; chp < 8; chp++)); do
+            local mask=$((0x80 >> chp))
+            if (( 0x$pim & $mask )); then
+                pimchpidZ=${pimchpidZ}${chpids[chp]}
+            else
+                pimchpidZ=${pimchpidZ}"ZZ"
+            fi
+        done
+        local pimchpids=${pimchpidZ//ZZ/}
+        if [ "x$pimchpids" == "x" ]; then
+            echo $"Channel $subch (device $devbusid) does not have any installed channel path"
+            all_subch_good=1
+            continue
+        fi
+        # compare parts of different subchannels for required matches
+        if [ "$i" -eq 1 ]; then
+            # remember parts of first subchannel for comparison
+            local sch_r_prefix=$prefix
+            local sch_r_ssid=$ssid
+            local sch_r_devno=$devno
+            local sch_r_pimchipidZ=$pimchpidZ
+            local sch_r_cutype=$cutype
+        else
+            local comparison=0
+            # $sch_r_... might be empty if first channel was wrong
+            # => be sure to quote all variable accesses in test statements.
+            # - all subchannels must be of same CU type/model
+            if [ "$cutype" != "$sch_r_cutype" ]; then
+                echo $"Device $devbusid does not have the same control unit type as device $SCH_R_DEVBUSID"
+                comparison=1
+            fi
+            # - all subchannels must have same CHPIDs
+            if [ "$pimchpidZ" != "$sch_r_pimchipidZ" ]; then
+                echo $"Device $devbusid does not have the same CHPIDs as device $SCH_R_DEVBUSID"
+                comparison=1
+            fi
+            # - all subchannels should have same prefix & ssid ?
+            if [ "$prefix" != "$sch_r_prefix" \
+                -o "$ssid" != "$sch_r_ssid" ]; then
+                echo $"Device $devbusid does not have the same prefix and subchannel set ID as device $SCH_R_DEVBUSID"
+                comparison=1
+            fi
+            if [ "$i" -eq 2 ]; then
+                local sch_w_devbusid=$devbusid
+                local sch_w_devno=$devno
+                # TODO: not true for CTCM => relax
+                # - write_devbusid == read_devbusid+1
+                if [ $((0x$devno)) -ne $((0x$sch_r_devno + 1)) ]; then
+                    echo $"Device bus ID of write channel (dev $devbusid) must be one larger than"
+                    echo $" that of read channel (dev $SCH_R_DEVBUSID)"
+                    comparison=1
+                fi
+            elif [ "$i" -eq 3 ]; then
+                # check data subchannel unequal to read/write subchannel
+                # (also seems to be handled by ccwgroup kernel subsystem)
+                if [ "$devbusid" = "$sch_w_devbusid" \
+                    -o "$devbusid" = "$SCH_R_DEVBUSID" ]; then
+                    echo $"Device bus ID of data channel (dev $devbusid) must be different to that of"
+                    echo $" read channel ($SCH_R_DEVBUSID) and write channel ($sch_w_devbusid)"
+                    comparison=1
+                fi
+            fi
+            if [ "$comparison" != 0 ]; then
+                all_subch_good=1
+                continue
+            fi
+        fi
+        # filter potentially good subchannels ...
+        if [ -h $dev_p/group_device ]; then
+            echo $"Device $devbusid is already in a ccwgroup and thus unavailable"
+            all_subch_good=1
+            continue
+        fi
+        if [ ! -f $dev_p/online ]; then
+            echo $"Device $devbusid does not have required sysfs attribute 'online'"
+            all_subch_good=1
+            continue
+        fi
+        local online
+        read online < $dev_p/online
+        if [ "$online" = "1" ]; then
+            echo $"Device $devbusid is already in use and thus unavailable"
+            all_subch_good=1
+            continue
+        fi
+        # - check availability
+        if [ ! -f $dev_p/availability ]; then
+            echo $"Device $devbusid does not have required sysfs attribute 'availability'"
+            all_subch_good=1
+            continue
+        fi
+        local availability
+        read availability < $dev_p/availability
+        if [ "$availability" != "good" ]; then
+            echo $"Device $devbusid is not available but '$availiability'"
+            all_subch_good=1
+            continue
+        fi
+
+    done # for ((i=1; i <= $subch_count; i++))
+    if [ "$all_subch_good" = "0" ]; then
+        return 0
+    fi
+    return 1
+}
+
+function handle_subchannels() {
+    # - try to establish ccwgroup right here and fail out on error
+    local driver
+    if [ "$NETTYPE" = "ctc" ]; then
+        driver="ctcm"
+    else
+        driver=$NETTYPE
+    fi
+    if sysecho /sys/bus/ccwgroup/drivers/${driver}/group "$SUBCHANNELS"; then
+        udevadm settle
+        case "$NETTYPE" in
+            qeth)
+                # Just preliminary card_type info until device goes online!
+                # In fact it seems enough to separate OSA from HiperSockets.
+                if [ -f /sys/devices/qeth/$SCH_R_DEVBUSID/card_type ]; then
+                    read cardtype < /sys/devices/qeth/$SCH_R_DEVBUSID/card_type
+                else
+                    echo $"Could not read qeth network card type from sysfs."
+                fi
+                ;;
+            ctc|lcs)
+                if [ -f /sys/devices/$driver/$SCH_R_DEVBUSID/type ]; then
+                    local type
+                    read type < /sys/devices/$driver/$SCH_R_DEVBUSID/type
+                    [ "$type" = "CTC/A" ] && \
+                        type="channel-to-channel adapter (CTC/A)"
+                    echo $"Detected: $type"
+                else
+                    echo $"Could not read ctc network card type from sysfs."
+                fi
+                ;;
+        esac
+        return 0
+    else
+        echo $"Channels $SUBCHANNELS could not be grouped"
+    fi
+    return 1
+}
+
+function question_prefix_subchannels() {
+    if [ "$NETTYPE" = "qeth" ]; then
+        echo -n $"Read,write,data channel"
+    else
+        echo -n $"Read,write channel"
+    fi
+}
+
+function question_choices_subchannels() {
+    if [ "$NETTYPE" = "qeth" ]; then
+        echo $" (e.g. 0.0.0300,0.0.0301,0.0.0302 or ? for help)."
+    else
+        echo $" (e.g. 0.0.0600,0.0.0601 or ? for help)"
+    fi
+}
+
+function helptext_subchannels() {
+    if [ "$NETTYPE" = "qeth" ]; then
+        echo $" Help text for qeth channels:"
+        echo $"  Enter the device bus ID of your CCW devices."
+        echo $"  QETH needs three channels for read, write, and data,"
+        echo $"  e.g. 0.0.0300,0.0.0301,0.0.0302"
+    else
+        echo $" Help text for lcs/ctc channels:"
+        echo $"  Enter the device bus ID of your CCW devices."
+        echo $"  CTC/ESCON and LCS need two channels for read and write,"
+        echo $"  e.g. 0.0.0600,0.0.0601 will configure the CTC or ESCON interface"
+        echo $"  with the channels 0x600 and 0x601"
+    fi
+}
+
+function finish_subchannels() {
+    syntax_check_subchannels || workflow_item_menu
+    # continuing on syntax error is doomed to fail,
+    # since handle_subchannels relies on the regex-based strict parsing
+    # in syntax_check_subchannels which does not match anything then
+    # news: relaxed by splitting semantic check and actual handling
+    semantic_check_subchannels || workflow_item_menu
+    if handle_subchannels; then
+        break
+    else
+        workflow_item_menu && break
+    fi
+}
+
+function do_subchannels() {
+    ask SUBCHANNELS \
+        question_prefix_subchannels question_choices_subchannels \
+        -h helptext_subchannels -f finish_subchannels
+}
+
+### PORTNAME (qeth)
+
+function syntax_check_portname() {
+    # - 1-8 characters, we convert it to upper case
+    PORTNAME=$(echo $PORTNAME | tr '[:lower:]' '[:upper:]')
+    local portname_len=${#PORTNAME}
+    if [ "$portname_len" -ge 1 -a "$portname_len" -le 8 ]; then
+        return 0
+    fi
+    echo $"Incorrect string length [1..8] for portname (PORTNAME): $PORTNAME"
+    return 1
+}
+
+function handle_portname() {
+    [ -n "$PORTNAME" ] || return 0
+    # - try to set portname right here w/ error handling
+    if sysecho /sys/devices/${NETTYPE}/$SCH_R_DEVBUSID/portname "$PORTNAME"; then
+        return 0
+    else
+        echo $"Portname '$PORTNAME' could not be configured for $SUBCHANNELS"
+    fi
+    return 1
+}
+
+function hint_portname() {
+    if [ -f /sys/devices/${NETTYPE}/$SCH_R_DEVBUSID/portname ]; then
+        local pname_hint
+        read pname_hint < /sys/devices/${NETTYPE}/$SCH_R_DEVBUSID/portname
+        if [ "$pname_hint" = "no portname required" ]; then
+            echo $"  * Your configuration does not require a portname. *"
+        fi
+    fi
+}
+
+function question_prefix_portname(){
+    echo -n $"Portname"
+}
+
+function question_choices_portname(){
+    echo $" (1..8 characters, or ? for help). Default is no portname:"
+}
+
+function helptext_portname(){
+    echo $" Help text for portname:"
+    # updated text describing when portname is obsolete;
+    # taken from:
+    # SA22-7935-09, Open Systems Adapter-Express Customer's
+    #   Guide and Reference, 10th ed. May 2008, IBM, p.17f.
+    # SC33-8411-00, Device Drivers, Features, and Commands,
+    #   1st ed. May 2008, IBM, p.116.
+    echo $"  Portname of the OSA-Express feature in QDIO mode and z/VM Guest LAN."
+    echo $"  This parameter is optional with:"
+    echo $"   - z/VM 4.4.0 or z/VM 4.3.0 with APARs VM63308 and PQ73878"
+    echo $"   - z800, z900 with >= Driver 3G - EC stream J11204, MCL032 (OSA level 3.33)"
+    echo $"   - z890, z990, z9, z10 mainframes"
+    hint_portname
+    echo $"  If portname is used, all operating systems sharing port must use same name."
+    echo $"  Input empty string if you don't want to enter a portname. [default]"
+}
+
+function exception_portname(){
+    [ -z "$PORTNAME" ] && break
+}
+
+function do_portname() {
+    ask PORTNAME \
+        question_prefix_portname question_choices_portname \
+        -h helptext_portname \
+        -e exception_portname -s syntax_check_portname -c handle_portname
+}
+
+### PORTNO (qeth)
+
+function syntax_check_qeth_portno() {
+    case $PORTNO in
+        0|1)
+            return 0
+            ;;
+    esac
+    echo $"Incorrect format or value for relative port number (PORTNO): $PORTNO"
+    return 1
+}
+
+function handle_qeth_portno() {
+    if sysecho /sys/devices/qeth/$SCH_R_DEVBUSID/portno "$PORTNO"; then
+        return 0
+    fi
+    echo $"Could not configure relative port number $PORTNO for $SUBCHANNELS"
+    return 1
+}
+
+function question_prefix_portno() {
+    echo -n $"Relative port number for OSA"
+}
+
+function question_choices_portno() {
+    echo $" (0, 1, or ? for help). Default is 0:"
+}
+
+function helptext_portno() {
+    echo $" Help text for relative port number for OSA with 2 ports per CHPID:"
+    echo $"  This applies to:"
+    echo $"   - OSA-Express3 Gigabit Ethernet on z10 systems"
+    echo $"   - OSA-Express ATM on zSeries 800 and 900 systems"
+    echo $"  0 for relative port number 0 [default]"
+    echo $"  1 for relative port number 1"
+    echo $"  Input empty string to not modify the default configuration."
+}
+
+function exception_portno() {
+    # Writing portno of e.g. hipersockets device fails.
+    # Therefore, do not configure on empty default value.
+    [ -z "$PORTNO" ] && break
+}
+
+function do_portno() {
+    ask PORTNO \
+        question_prefix_portno question_choices_portno \
+        -h helptext_portno -e exception_portno \
+        -s syntax_check_qeth_portno -c handle_qeth_portno
+}
+
+### LAYER2
+
+function syntax_check_layer2() {
+    # - $LAYER2 \in {0,1}
+    case $LAYER2 in
+        0|1)
+            return 0
+            ;;
+    esac
+    echo $"Incorrect format or value for layer2 mode (LAYER2): $LAYER2"
+    return 1
+}
+
+function handle_layer2() {
+    [ "$NETTYPE" == "qeth" ] || return 0
+    [ -n "$LAYER2" ] || return 0
+    # - try to set layer2 mode right here w/ error handling
+    if sysecho /sys/devices/${NETTYPE}/$SCH_R_DEVBUSID/layer2 "$LAYER2"; then
+        return 0
+    else
+        echo $"Layer2 mode '$LAYER2' could not be configured for $SUBCHANNELS"
+    fi
+    return 1
+}
+
+function question_prefix_layer2() {
+    echo -n $"Layer mode"
+}
+
+function question_choices_layer2() {
+    echo -n $" (0 for layer3, 1 for layer2, or ? for help)."
+    if [ "$isLayer2Default" = "yes" ]; then
+        echo $" Default is 1:"
+    else
+        echo $" Default is 0:"
+    fi
+}
+
+function helptext_layer2() {
+    echo $" Help text for OSA mode of operation: layer 2 vs. layer 3"
+    if [ "$isLayer2Default" = "yes" ]; then
+        echo $"  0 for layer 3 mode (may not work with dhcp, tcpdump, etc.)"
+        echo $"  1 for layer 2 mode [default]"
+    else
+        echo $"  0 for layer 3 mode [default] (may not work with dhcp, tcpdump, etc.)"
+        echo $"  1 for layer 2 mode"
+    fi
+}
+
+function exception_layer2() {
+    if [ -z "$LAYER2" ]; then
+        isLayer2Default && LAYER2=1 || LAYER2=0
+        # do not break, always apply, default may differ from online layer mode
+        #break
+    fi
+}
+
+function do_layer2() {
+    isLayer2Default && isLayer2Default=yes || isLayer2Default=no
+    ask LAYER2 \
+        question_prefix_layer2 question_choices_layer2 \
+        -h helptext_layer2 -e exception_layer2 \
+        -s syntax_check_layer2 -c handle_layer2
+}
+
+### MACADDR
+
+function syntax_check_macaddr() {
+    # - match against regex
+    [[ "$MACADDR" =~ ^[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]$ ]]
+    case $? in
+        0)
+            # string matched the pattern
+            return 0
+            ;;
+        1)
+            # string did not match the pattern
+            echo $"Incorrect format for mac address (MACADDR): $MACADDR"
+            ;;
+        2)
+            echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+            ;;
+        *)
+            echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+            ;;
+    esac
+    return 1
+}
+
+function handle_macaddr() {
+    # - try to set macaddr right here w/ error handlg.
+    # device needs to be online
+    if debug ifconfig $DEVICE hw ether $MACADDR; then
+        return 0
+    fi
+    echo $"MAC address $MACADDR could not be configured for"
+    echo $" $SUBCHANNELS (network device $DEVICE)"
+    return 1
+}
+
+function question_prefix_macaddr() {
+    echo -n $"Unique MAC address"
+}
+
+function question_choices_macaddr() {
+    macaddr_default=$(ifconfig $DEVICE | grep 'HWaddr' | sed 's/.*HWaddr \([[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]\).*/\1/')
+    echo $" (e.g. 02:00:00:00:00:00, ? for help). Default is $macaddr_default:"
+}
+
+function helptext_macaddr() {
+    echo $" Help text for MAC address:"
+    if [ -z "${cardtype//OSD_*/}" ]; then
+        echo $"  For real OSA in layer 2 mode, a random MAC address is automatically assigned."
+    else
+        echo $"  If connecting to a layer 2 VSWITCH, a MAC address is automatically assigned."
+    fi
+    echo $"  You may accept the automatic MAC address with an empty input. [default]"
+    echo $"  If the automatic address is not unique, please provide a MAC address."
+    [ -z "${cardtype//OSD_*/}" ] && \
+        echo $"  For real OSA, the provided address must be different from that of the OSA."
+    echo $"  You may override the automatic MAC address with non-empty input."
+    echo $"  An example MAC address would be: 02:00:00:00:00:00"
+}
+
+function exception_macaddr() {
+    if [ -z "$MACADDR" ]; then
+        if [ -z "${cardtype//OSD_*/}" ]; then
+            # keep random default MAC address of real OSA,
+            # so the OSA comes up with the same MAC each time in the future
+            MACADDR=$macaddr_default
+        else
+            # virtual OSA in layer2 is GuestLAN or VSWITCH
+            VSWITCH=1
+        fi
+        break
+    fi
+}
+
+function do_macaddr() {
+    ask MACADDR \
+        question_prefix_macaddr question_choices_macaddr \
+        -h helptext_macaddr -e exception_macaddr \
+        -s syntax_check_macaddr -c handle_macaddr
+}
+
+### CTCPROT
+
+function syntax_check_ctcprot() {
+    case "x$CTCPROT" in
+        x|x0)
+            unset CTCPROT
+            return 0
+            ;;
+        x1|x3)
+            return 0
+            ;;
+        x2)
+            echo $"CTC tty's are not usable for this installation (CTCPROT)"
+            ;;
+        *)
+            echo $"Incorrect format or value for CTC protocol (CTCPROT): $CTCPROT"
+            ;;
+    esac
+    return 1
+}
+
+function handle_ctcprot() {
+    [ -n "$CTCPROT" ] || return 0
+    if sysecho /sys/devices/ctcm/${SCH_R_DEVBUSID}/protocol "$CTCPROT"; then
+        return 0
+    fi
+    echo $"Could not configure CTC protocol $CTCPROT for $SUBCHANNELS"
+    return 1
+}
+
+function question_prefix_ctcprot() {
+    echo -n $"CTC protocol"
+}
+
+function question_choices_ctcprot() {
+    echo $" (0, 1, 3, or ? for help). Default is 0:"
+}
+
+function helptext_ctcprot() {
+    echo $" Help text for CTC protocol:"
+    echo $"  Protocol which should be used for the CTC interface"
+    echo $"  0 for compatibility with p.e. VM TCP service machine [default]"
+    echo $"  1 for enhanced package checking for Linux peers"
+    echo $"  3 for compatibility with OS/390 or z/OS peers"
+}
+
+function do_ctcprot() {
+    ask CTCPROT \
+        question_prefix_ctcprot question_choices_ctcprot \
+        -h helptext_ctcprot -s syntax_check_ctcprot -c handle_ctcprot
+}
+
+### PORTNAME (LCS portno)
+
+function syntax_check_lcs_portno() {
+    [[ "$PORTNAME" =~ ^[[:digit:]]+$ ]]
+    case $? in
+        0)
+            # string matched the pattern
+            return 0
+            ;;
+        1)
+            # string did not match the pattern
+            ;;
+        2)
+            echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+            ;;
+        *)
+            echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+            ;;
+    esac
+    echo $"Incorrect format for LCS port number (PORTNAME): $PORTNAME"
+    return 1
+}
+
+function handle_lcs_portno() {
+    [ -n "$PORTNAME" ] || return 0
+    if sysecho /sys/devices/lcs/$SCH_R_DEVBUSID/portno "$PORTNAME"; then
+        return 0
+    fi
+    echo $"Could not configure relative port number $PORTNAME for $SUBCHANNELS"
+    return 1
+}
+
+function question_prefix_lcs_portno() {
+    echo -n $"Relative port number of your LCS device"
+}
+
+function question_choices_lcs_portno() {
+    echo $" (number or ? for help). Default is 0:"
+}
+
+function helptext_lcs_portno() {
+    echo $" Help text for relative port number of LCS device:"
+    echo $"  Required for OSA-Express ATM cards only."
+}
+
+function exception_lcs_portno() {
+    [ -z "$PORTNAME" ] && break
+}
+
+function do_lcs_portno() {
+    # LCS portno and QETH portname share the parameter variable PORTNAME.
+    # For compatibility with existing parm files we keep this scheme.
+    ask PORTNAME \
+        question_prefix_lcs_portno question_choices_lcs_portno \
+        -e exception_lcs_portno \
+        -h helptext_lcs_portno -s syntax_check_lcs_portno -c handle_lcs_portno
+}
+
+### HOSTNAME
+
+function syntax_check_hostname() {
+    syntax_check_domainname "$HOSTNAME" "Incorrect format for hostname (HOSTNAME): $HOSTNAME"
+}
+
+function handle_hostname() {
+    if ! hostname $HOSTNAME; then
+        echo $"Could not configure hostname $HOSTNAME"
+        return 1
+    fi
+    return 0
+}
+
+function question_prefix_hostname() {
+    echo -n $"Hostname of your new Linux guest"
+}
+
+function question_choices_hostname() {
+    echo $" (FQDN e.g. s390.redhat.com or ? for help):"
+}
+
+function helptext_hostname() {
+    echo $" Help text for hostname:"
+    echo $"  Enter the full qualified domain name of your host."
+}
+
+function do_hostname() {
+    ask HOSTNAME \
+        question_prefix_hostname question_choices_hostname \
+        -h helptext_hostname -s syntax_check_hostname -c handle_hostname
+}
+
+### IPADDR
+
+function syntax_check_ipaddr() {
+    unset ipv4
+    unset ipv6
+    if checkipv4 $IPADDR; then
+        ipv4="yes"
+        return 0
+    elif [ "$ipv6_capable" = "yes" ] && checkipv6 $IPADDR; then
+        ipv6="yes"
+        return 0
+    fi
+    echo $"Incorrect format for IP address (IPADDR): $IPADDR"
+    return 1
+}
+
+function question_prefix_ipaddr() {
+    echo -n $"IPv4 address"
+    [ "$ipv6_capable" = "yes" ] && echo -n $" / IPv6 addr."
+}
+
+function question_choices_ipaddr() {
+    echo -n $" (e.g. 10.0.0.2"
+    [ "$ipv6_capable" = "yes" ] && echo -n $" / 2001:0DB8::"
+    echo $" or ? for help)"
+}
+
+function helptext_ipaddr() {
+    echo $" Help text for IP address:"
+    echo $"  Enter a valid IPv4 address of your new Linux guest (e.g. 10.0.0.2)"
+    if [ "$ipv6_capable" = "yes" ]; then
+        echo $"  or alternatively a valid IPv6 address without CIDR prefix (e.g. 2001:0DB8::)"
+        echo $"  IPv6 is supported on:"
+        echo $"   - Ethernet interfaces of the OSA-Express adapter running in QDIO mode."
+        echo $"   - HiperSockets interfaces"
+        echo $"   - z/VM guest LAN interfaces running in QDIO mode."
+        echo $"  IPv6 is not supported on HiperSockets guest LAN, OSA-Express Token Ring, ATM."
+    fi
+}
+
+function do_ipaddr() {
+    ipv6_capable && ipv6_capable=yes || ipv6_capable=no
+    ask IPADDR \
+        question_prefix_ipaddr question_choices_ipaddr \
+        -h helptext_ipaddr -s syntax_check_ipaddr
+    if [ "$ipv6" ]; then
+       # qeth_l3 would load ipv6 automatically but not qeth_l2
+       modprobe ipv6
+       tv disable_ipv6_autoconf
+    fi
+
+    # no handling/configuring of IPADDR yet, since more parameters needed
+}
+
+### NETMASK (IPv4)
+
+function syntax_check_netmask_v4() {
+    # also support CIDR prefix
+    if [[ "$NETMASK" =~ ^[[:digit:]]+$ ]]; then
+        if [ "$NETMASK" -ge 1 -a "$NETMASK" -le 32 ]; then
+            ipcalc_arg="$IPADDR/$NETMASK"
+            return 0
+        fi
+        echo $"Incorrect value for network prefix [1..32] (NETMASK): $NETMASK"
+        return 1
+    elif checkipv4 $NETMASK; then
+        ipcalc_arg="$IPADDR $NETMASK"
+        return 0
+    fi
+    echo $"Incorrect format or value for network mask (NETMASK): $NETMASK"
+    return 1
+}
+
+function question_prefix_netmask() {
+    echo -n $"IPv4 netmask or CIDR prefix"
+}
+
+function hint_netmask_v4() {
+    # default based on class a/b/c address
+    local a b c d
+    IFS=.
+    read a b c d <<< "$IPADDR"
+    unset IFS
+    local ip=$(( ( a << 24 ) + ( b << 16 ) + ( c << 8 ) + ( d ) ))
+    # <<EOF convince syntax highlighter that above shifts are no here documents
+    if   [ $(( ip & 0x80000000 )) -eq $(( 0x00000000 )) ]; then
+        # class a
+        echo "255.0.0.0"
+    elif [ $(( ip & 0xC0000000 )) -eq $(( 0x80000000 )) ]; then
+        # class b
+        echo "255.255.0.0"
+    elif [ $(( ip & 0xE0000000 )) -eq $(( 0xC0000000 )) ]; then
+        # class c
+        echo "255.255.255.0"
+    else
+        # some other class that should not be used as host address
+        return 1
+    fi
+    return 0
+}
+
+function question_choices_netmask() {
+    echo -n $" (e.g. 255.255.255.0 or 1..32 or ? for help)"
+    local default=$(hint_netmask_v4)
+    if [ -n "$default" ]; then
+        echo $". Default is $default:"
+    else
+        echo $":"
+        echo $"The IP address you entered previously should probably not be used for a host."
+    fi
+}
+
+function helptext_netmask() {
+    echo $" Help text for IPv4 netmask or CIDR prefix:"
+    echo $"  Enter a valid IPv4 netmask or CIDR prefix (e.g. 255.255.255.0 or 1..32)"
+    local default=$(hint_netmask_v4)
+    if [ -n "$default" ]; then
+        echo $"  Default is $default"
+    else
+        echo $"The IP address you entered previously should probably not be used for a host."
+    fi
+}
+
+function exception_netmask() {
+    if [ -z "$NETMASK" ]; then
+        NETMASK=$(hint_netmask_v4)
+    fi
+}
+
+function do_netmask() {
+    ask NETMASK \
+        question_prefix_netmask question_choices_netmask \
+        -h helptext_netmask \
+        -s syntax_check_netmask_v4 -e exception_netmask
+    # no handling/configuring of NETMASK yet, since more parameters needed
+}
+
+### NETWORK
+
+function do_network() {
+    echo
+    echo $"The NETWORK parameter isn't used anymore and will be ignored."
+    echo $" It is sufficient to specify IPADDR and NETMASK."
+    echo
+}
+
+### BROADCAST
+
+function do_broadcast() {
+    echo
+    echo $"The BROADCAST parameter isn't used anymore and will be ignored."
+    echo $" It is sufficient to specify IPADDR and NETMASK."
+    echo
+}
+
+### NETMASK (IPv6)
+
+function syntax_check_prefix_v6() {
+    if [[ "$NETMASK" =~ ^[[:digit:]]+$ ]]; then
+        if [ "$NETMASK" -ge 1 -a "$NETMASK" -le 128 ]; then
+            return 0
+        fi
+    fi
+    echo $"Incorrect value for network prefix [1..128] (NETMASK): $NETMASK"
+    return 1
+}
+
+function question_prefix_netmask_v6() {
+    echo -n $"CIDR prefix for the IPv6 address"
+}
+
+function question_choices_netmask_v6() {
+    echo $" (1..128):"
+}
+
+function do_netmask_v6() {
+    ask NETMASK \
+        question_prefix_netmask_v6 question_choices_netmask_v6 \
+        -s syntax_check_prefix_v6
+    # no handling/configuring of NETMASK yet, since more parameters needed
+}
+
+### GATEWAY (IPv4)
+
+function configure_ipv4_gateway() {
+    # FIXME:
+    # - Strictly speaking we should first check reachability of gateway
+    #   and then configure the gateway route.
+    #   This would require a new intermediate workflow_item step
+    #   so that the user might continue despite unreachable gateway.
+    # done: Only adding default route might add multiple undesired default
+    # routes on redoing the parameter item, so delete default route
+    # before adding a new one.
+    ip -4 route del default dev $DEVICE >& /dev/null
+    [ -z "$GATEWAY" ] && return 0
+    if ! tv route add default gw $GATEWAY dev $DEVICE; then
+        echo $"Could net set default route on device $DEVICE via gateway $GATEWAY"
+        return 1
+    fi
+    # BH FIXME: Workaround for manual MACADDR, need ping to update arp table
+    echo $"Trying to reach gateway $GATEWAY..."
+    if [ "$NETTYPE" = "ctc" ]; then
+        # (virtual) CTC(/A) seems to need some time to get functional
+        local i=1
+        while : ; do
+            $PING $GATEWAY >& /dev/null && break
+            i=$((i+1))
+            if [ "$i" -gt 3 ]; then
+                echo $"Could not reach gateway $GATEWAY within timeout"
+                return 1
+            fi
+        done
+    else
+        if ! $PING $GATEWAY >& /dev/null; then
+            echo $"Could not reach your default gateway $GATEWAY"
+            return 1
+        fi
+    fi
+    return 0
+}
+
+function hint_ipv4_gateway() {
+    # - provide default suggestion based on network,
+    #   for a class C network this would be either .1 or .254 at the end
+    local a b c d
+    IFS=.
+    read a b c d <<< "$NETWORK"
+    unset IFS
+    local ip=$(( ( a << 24 ) + ( b << 16 ) + ( c << 8 ) + ( d ) ))
+    # <<EOF convince syntax highlighter that above shifts are no here documents
+    local lo=$(( ip | 1 ))
+    local lo_a=$(( (lo & 0xFF000000) >> 24 ))
+    local lo_b=$(( (lo & 0x00FF0000) >> 16 ))
+    local lo_c=$(( (lo & 0x0000FF00) >> 8 ))
+    local lo_d=$(( (lo & 0x000000FF) ))
+    local hi=$(( ip | ( (2**(32 - PREFIX)) - 1 ) ))
+    local hi_a=$(( (hi & 0xFF000000) >> 24 ))
+    local hi_b=$(( (hi & 0x00FF0000) >> 16 ))
+    local hi_c=$(( (hi & 0x0000FF00) >> 8 ))
+    local hi_d=$(( (hi & 0x000000FE) ))
+    echo $"  Depending on your network design patterns, the default gateway"
+    echo $"   might be $lo_a.$lo_b.$lo_c.$lo_d or $hi_a.$hi_b.$hi_c.$hi_d"
+}
+
+function question_prefix_gateway() {
+    echo -n $"IPv4 address of your default gateway"
+}
+
+function question_choices_gateway() {
+    echo $" or ? for help:"
+}
+
+function helptext_gateway() {
+    echo $" Help text for IPv4 default gateway:"
+    echo $"  For HiperSockets with internal traffic only you may want to leave this empty"
+    echo $"  and choose continue afterwards to go on without gateway."
+    hint_ipv4_gateway
+}
+
+function finish_gateway() {
+    if ! checkipv4 $GATEWAY; then
+        # above checkipv4 is silent, so make up for syntax error
+        echo $"Incorrect format for IPv4 address of gateway (GATEWAY): $GATEWAY"
+        workflow_item_menu
+    fi
+    if configure_ipv4_gateway; then
+        break
+    else
+        workflow_item_menu && break
+    fi
+}
+
+# FIXME: allow empty/no gateway?
+
+function do_gateway() {
+    ask GATEWAY \
+        question_prefix_gateway question_choices_gateway \
+        -h helptext_gateway -f finish_gateway
+}
+
+### GATEWAY (IPv6)
+
+function configure_ipv6_gateway() {
+    # FIXME:
+    # - Strictly speaking we should first check reachability of gateway
+    #   and then configure the gateway route.
+    #   This would require a new intermediate workflow_item step
+    #   so that the user might continue despite unreachable gateway.
+    # done: Only adding default route might add multiple undesired default
+    # routes on redoing the parameter item, so delete default route
+    # before adding a new one.
+    ip -6 route del default dev $DEVICE >& /dev/null
+    [ -z "$GATEWAY" ] && return 0
+    # IPv6 http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/html_single/Linux+IPv6-HOWTO.html#AEN1147
+    #       ip -6 route add ::/0 dev $DEVICE via $GATEWAY
+    # (Could also be learned by autoconfiguration on the link:
+    #  after IP address setup and device up,
+    #   see if default route has been learned
+    #   ip -6 route show | grep ^default
+    #  However, we currently use manual IPv6 configuration only.)
+    if ! debug ip -6 route add ::/0 dev $DEVICE via $GATEWAY; then
+        echo $"Could net set default route on device $DEVICE"
+        echo $" via gateway $GATEWAY"
+        return 1
+    fi
+    # BH FIXME: Workaround for manual MACADDR, need ping to update arp table
+    echo $"Trying to reach gateway $GATEWAY..."
+    if ! $PING6 $GATEWAY >& /dev/null; then
+        echo $"Could not reach your default gateway $GATEWAY"
+        return 1
+    fi
+    return 0
+}
+
+function question_prefix_gateway_v6() {
+    echo -n $"IPv6 address of your default gateway"
+}
+
+function question_choices_gateway_v6() {
+    echo $":"
+}
+
+function helptext_gateway_v6() {
+    echo $" Help text for IPv6 default gateway:"
+    echo $"  For HiperSockets with internal traffic only you may want to leave this empty"
+    echo $"  and choose continue afterwards to go on without gateway."
+}
+
+function finish_gateway_v6() {
+    if ! checkipv6 $GATEWAY; then
+        # above checkipv6 is silent, so make up for syntax error
+        echo $"Incorrect format for IPv6 address of gateway (GATEWAY): $GATEWAY"
+        workflow_item_menu
+    fi
+    if configure_ipv6_gateway; then
+        break
+    else
+        workflow_item_menu && break
+    fi
+}
+
+# FIXME: allow empty/no gateway?
+
+function do_gateway_v6() {
+    ask GATEWAY \
+        question_prefix_gateway_v6 question_choices_gateway_v6 \
+        -h helptext_gateway_v6 -f finish_gateway_v6
+}
+
+### GATEWAY (IPv4, point-to-point)
+
+function configure_ipv4_ptp() {
+    # device needs to be online
+    if debug ifconfig $DEVICE $IPADDR $MMTU pointopoint $GATEWAY; then
+        configure_ipv4_gateway
+        return $?
+    fi
+    echo $"Could not set IPv4 address $IPADDR for device $DEVICE"
+    echo $" to peer $GATEWAY"
+    [ -n "$MMTU" ] && echo $" and maximum transfer unit: $MMTU"
+    return 1
+}
+
+function question_prefix_ptp_gateway() {
+    echo -n $"IPv4 address of your point-to-point partner"
+}
+
+function question_choices_ptp_gateway() {
+    echo $" or ? for help:"
+    # no hinting possible here
+}
+
+function helptext_ptp_gateway() {
+    echo $" Help text for point-to-point partner:"
+    echo $"  IPv4 address of your CTC or ESCON point-to-point partner."
+}
+
+function finish_ptp_gateway() {
+    if checkipv4 $GATEWAY; then
+        if [ "$GATEWAY" = "$IPADDR" ]; then
+            echo $"IPv4 address of partner should probably be different from the guest's address"
+            workflow_item_menu && break
+        else
+            break
+        fi
+    else
+        # above checkipv4 is silent, so make up for syntax error
+        echo $"Incorrect format for IPv4 address of partner (GATEWAY): $GATEWAY"
+        workflow_item_menu && break
+    fi
+    # too early to actually configure gateway
+}
+
+function do_ptp_gateway() {
+    ask GATEWAY \
+        question_prefix_ptp_gateway question_choices_ptp_gateway \
+        -h helptext_ptp_gateway -f finish_ptp_gateway
+}
+
+### DNS
+
+function syntax_check_dns() {
+    if [ -z "$DNS" ]; then
+        echo $"You might encounter problems without a nameserver, especially with FTP installs"
+        return 1
+    fi
+    local dnsitem
+    local allgood="yes"
+    if [ "$ipv6" ]; then
+        while read dnsitem; do
+            if ! checkipv6 $dnsitem; then
+                echo $"Not a valid IPv6 address for DNS server: $dnsitem"
+                allgood="no"
+            fi
+        done < <(echo $DNS | sed 's/,/\n/g')
+    else
+         while read dnsitem; do
+           if ! checkipv4 $dnsitem; then
+                echo $"Not a valid IPv4 address for DNS server: $dnsitem"
+                allgood="no"
+            fi
+         done < <(echo $DNS | sed 's/:/\n/g')
+    fi
+    if [ "$allgood" = "yes" ]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+function handle_dns() {
+    # - foreach DNS try if server is reachable by one ping
+    [ -z "$DNS" ] && return 0
+    local dnsitem
+    local allgood="yes"
+    echo $"Trying to reach DNS servers..."
+    if [ "$ipv6" ]; then
+        while read dnsitem; do
+            if ! $PING6 $dnsitem >& /dev/null; then
+                echo $"Could not ping DNS server (might still serve DNS requests): $dnsitem"
+                allgood="no"
+                # this should not be a hard failure since some network
+                # environments may prevent pings to DNS servers
+                # => prevent workflow_item_menu in kickstart mode
+            fi
+        done < <(echo $DNS | sed 's/,/\n/g')
+    else
+        while read dnsitem; do
+            # Some network environment may prevent a DNS server from being
+            # reachable by ping, so it would make sense to use nslookup.
+            # However, nslookup fails with "Resolver Error 0 (no error)"
+            # at this stage of the setup progress => not useful
+            if ! $PING $dnsitem >& /dev/null; then
+                echo $"Could not ping DNS server: $dnsitem"
+#                if nslookup $dnsitem $dnsitem >& /dev/null; then
+#                    echo $" but could resolve DNS server with itself: $dnsitem"
+#                else
+#                    echo $"Could not resolve DNS server with itself: $dnsitem"
+#                    allgood="no"
+#                fi
+#            elif ! nslookup $dnsitem $dnsitem >& /dev/null; then
+#                echo $"Could not resolve DNS server with itself: $dnsitem"
+                allgood="no"
+            fi
+        done < <(echo $DNS | sed 's/:/\n/g')
+    fi
+    if [ "$allgood" = "yes" ]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+function question_prefix_dns() {
+    if [ "$ipv6" ]; then
+        echo -n $"IPv6 addresses of DNS servers"
+    else
+        echo -n $"IPv4 addresses of DNS servers"
+    fi
+}
+
+function question_choices_dns() {
+    if [ "$ipv6" ]; then
+        echo $" (separated by commas ',' or ? for help):"
+    else
+        echo $" (separated by colons ':' or ? for help):"
+    fi
+}
+
+function helptext_dns() {
+    echo $" Help text for DNS servers:"
+    if [ "$ipv6" ]; then
+        echo $"  Enter IPv6 addresses of DNS servers separated by commas ','"
+    else
+        echo $"  Enter IPv4 addresses of DNS servers separated by colons ':'"
+    fi
+    echo $"  Default are no DNS servers at all."
+    echo $"  However, you might encounter problems without a nameserver,"
+    echo $"   especially with FTP installs."
+    if [ "$ipv6" ]; then
+        echo $"  An example with 2 servers would be: 2001:0DB8::42,2001:0DB8::BE:AF"
+    else
+        echo $"  An example with 2 servers would be: 10.0.0.250:10.1.1.1"
+    fi
+}
+
+function do_dns() {
+    ask DNS \
+        question_prefix_dns question_choices_dns \
+        -h helptext_dns -s syntax_check_dns -c handle_dns
+}
+
+### SEARCHDNS
+
+function syntax_check_searchdns() {
+    [ -z "$SEARCHDNS" ] && return 0
+    local dnsitem
+    local allgood="yes"
+    while read dnsitem; do
+        syntax_check_domainname "$dnsitem" $"Not a valid DNS search domain: $dnsitem" || allgood="no"
+    done < <(echo $SEARCHDNS | sed 's/:/\n/g')
+    if [ "$allgood" = "yes" ]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+function question_prefix_searchdns() {
+    echo -n $"DNS search domains"
+}
+
+function question_choices_searchdns() {
+    echo $" (separated by colons ':' or ? for help):"
+}
+
+function helptext_searchdns() {
+    echo $" Help text for DNS search domains:"
+    echo $"  Enter search domains according to hostname syntax separated by colons."
+    echo $"  Default are no DNS search domains at all."
+    echo $"  An example would be: subdomain.domain.com:domain.com"
+}
+
+function do_searchdns() {
+    ask SEARCHDNS \
+        question_prefix_searchdns question_choices_searchdns \
+        -h helptext_searchdns -s syntax_check_searchdns
+}
+
+### DASD
+
+function parse_dasd() {
+    local handle
+    [ "$1" = "-h" ] && handle=yes || unset handle
+    local dasditem
+    local allgood="yes"
+    local cio_wc=$(wc -c /proc/cio_ignore)
+    read cio_wc_bytes cio_wc_filename cio_wc_foo <<< "$cio_wc"
+    if [ "$handle" = "yes" -a "$cio_wc_bytes" != "0" ]; then
+        echo $"Trying to clear specified DASDs from device blacklist..."
+        mkdir -p /etc/modprobe.d
+        echo "options dasd_mod dasd=$DASD" > /etc/modprobe.d/dasd_mod.conf
+        if ! dasd_cio_free; then
+            echo $"Not all specified DASDs could be detected within timeout."
+            allgood="no"
+        fi
+    fi
+    while read dasditem; do
+        unset range features range lo hi rangegood \
+            attrs devno lodevno hidevno devbusid sys
+        case $dasditem in
+            autodetect)
+                [ -z "$handle" ] && continue
+                cio_wc=$(wc -c /proc/cio_ignore)
+                read cio_wc_bytes cio_wc_filename cio_wc_foo <<< "$cio_wc"
+                # above we only freed the devices specified in $DASD,
+                # so there might still be other DASDs in the blacklist
+                if [ "$cio_wc_bytes" != "0" ]; then
+                    echo $"Note: There is a device blacklist active! Only activating visible DASDs."
+                fi
+                local sys
+                while read sys; do
+                    if ! sysecho $sys/online 1; then
+                        echo $"Could not set DASD ${sys##*/} online"
+                    fi
+                done < <(find /sys/bus/ccw/drivers/dasd-eckd/ -name "*.?.????" 2>/dev/null;\
+                    find /sys/bus/ccw/drivers/dasd-fba/ -name "*.?.????" 2>/dev/null)
+                ;;
+            probeonly|nopav|nofcx)
+                if [ -z "$handle" ]; then
+                    echo $"DASD option $dasditem not supported by installer"
+                fi
+                ;;
+            "") continue ;; # empty range
+            *)  local range features rangegood="yes"
+                IFS='('
+                read range features <<< "$dasditem"
+                unset IFS
+                # parse: dev OR dev'-'dev
+                local lo=${range%%-*}
+                [[ "$lo" =~ (^[[:xdigit:]]+\.[0-3]\.[[:xdigit:]]{4}$)|(^[[:xdigit:]]{3,4}$) ]]
+                case $? in
+                    0)  # string matched the pattern
+                        lo=$(canonicalize_devno $lo) ;;
+                    1)  # string did not match the pattern
+                        rangegood="no"
+                        if [ -z "$handle" ]; then
+                            echo $"Incorrect format for lower bound of DASD range $range: $lo"
+                            allgood="no"
+                        fi
+                        ;;
+                    2)  echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2 ;;
+                    *)  echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2 ;;
+                esac
+                if [ "${range//*-*/}" = "" ]; then
+                    local hi=${range##*-}
+                    [[ "$hi" =~ (^[[:xdigit:]]+\.[0-3]\.[[:xdigit:]]{4}$)|(^[[:xdigit:]]{3,4}$) ]]
+                    case $? in
+                        0)  # string matched the pattern
+                            hi=$(canonicalize_devno $hi)
+                            if [ "${lo%.*}" != "${hi%.*}" ]; then
+                                echo $"Prefixes of DASD range $range do not match: ${lo%.*} != ${hi%.*}"
+                                rangegood="no"
+                                allgood="no"
+                            fi
+                            ;;
+                        1)  # string did not match the pattern
+                            rangegood="no"
+                            if [ -z "$handle" ]; then
+                                echo $"Incorrect format for upper bound of DASD range $range: $hi"
+                                allgood="no"
+                            fi
+                            ;;
+                        2)  echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2 ;;
+                        *)  echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2 ;;
+                    esac
+                fi
+                if [ "${features//*)/}" != "" ]; then
+                    if [ -z "$handle" ]; then
+                        echo $"Missing closing parenthesis at features of DASD range $range: ($features"
+                        allgood="no"
+                    fi
+                fi
+                local attrs=""
+                if [ -n "$features" ]; then
+                    features="${features%)}"
+                    while read feature; do
+                        case $feature in
+                            ro) attrs=$attrs" readonly" ;;
+                            diag) attrs=$attrs" use_diag" ;;
+                            erplog|failfast) attrs=$attrs" "$feature ;;
+                            *) if [ -z "$handle" ]; then
+                                   echo $"Unknown DASD feature for device range $range: $feature"
+                                   allgood="no"
+                               fi
+                               ;;
+                        esac
+                    done < <(echo $features | sed 's/:/\n/g')
+                fi
+                [ "$rangegood" = "yes" ] || continue
+                [ "$handle" = "yes" ] || continue
+                # now apply $attrs and set DASDs $lo to $hi online
+                [ -z "$hi" ] && hi=$lo
+                local devno lodevno=$((0x${lo##*.})) hidevno=$((0x${hi##*.}))
+                for ((devno=$lodevno; $devno <= $hidevno; ++devno)); do
+                    local devbusid=$(printf "%s.%04x" ${lo%.*} $devno)
+                    local sys="/sys/bus/ccw/devices/"$devbusid
+                    for attr in $attrs; do
+                        if [ "$attr" = "use_diag" ]; then
+                            # diag discipline cannot be auto-loaded
+                            modprobe dasd_diag_mod
+                        fi
+                        if [ ! -f $sys/$attr ]; then
+                            echo $"DASD $devbusid does not provide attribute $attr"
+                            continue
+                        fi
+                        if ! sysecho $sys/$attr 1; then
+                            echo $"Could not set attribute $attr for DASD $devbusid"
+                        fi
+                    done
+                    if [ ! -f $sys/online ]; then
+                        echo $"DASD $devbusid not found"
+                        continue
+                    fi
+                    if ! sysecho $sys/online 1; then
+                        echo $"Could not set DASD $devbusid online"
+                    fi
+                done
+                ;;
+        esac
+    done < <(echo $DASD | sed 's/,/\n/g')
+    if [ "$handle" = "yes" ]; then
+        udevadm settle
+        dasd_settle_all || return 1
+        echo $"Activated DASDs:"
+        cat /proc/dasd/devices | sed -e 's/ at ([^)]*) is//' -e 's/ at/,/'
+    fi
+    if [ "$allgood" = "yes" ]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+function syntax_check_dasd() {
+    parse_dasd
+    return $?
+}
+
+function handle_dasd() {
+    parse_dasd -h
+    return $?
+}
+
+function question_prefix_dasd() {
+    echo -n $"DASD range"
+}
+
+function question_choices_dasd() {
+    echo $" (e.g. 200-203,205 or ? for help). Default is autoprobing:"
+}
+
+function helptext_dasd() {
+    echo $" Help text for DASD range:"
+    echo $"  Comma separated list of ranges of device bus IDs."
+    echo $"  Default is autoprobing (not recommended)."
+    echo $"  Examples would be: 200-203 or 200,201,202,203 or 0.0.0200-0.0.0203,0.0.0205"
+}
+
+function exception_dasd() {
+    [ -z "$DASD" ] && DASD="autodetect"
+}
+
+function do_dasd() {
+    ask DASD \
+        question_prefix_dasd question_choices_dasd \
+        -h helptext_dasd -e exception_dasd -s syntax_check_dasd -c handle_dasd
+}
+
+### FCP
+
+function syntax_check_fcp() {
+    local allgood="yes"
+    local i
+    for i in ${!FCP_*}; do
+        local -a fcp
+        local devno wwpn lun
+        read -a fcp <<< "${!i}"
+        case ${#fcp[ ]} in
+            3)
+                devno=${fcp[0]}
+                wwpn=${fcp[1]}
+                lun=${fcp[2]}
+                ;;
+            5)
+                devno=${fcp[0]}
+                wwpn=${fcp[2]}
+                lun=${fcp[4]}
+                echo $"Deprecated number of FCP arguments (5 instead of 3): "
+                echo $" $i=\"${!i}\""
+                echo $" should instead be: "
+                echo $" $i=\"$devno $wwpn $lun\""
+                ;;
+            *)
+                echo $"Unsupported number of FCP arguments (${#fcp[ ]} instead of 3) in:"
+                echo $" $i=\"${!i}\""
+                allgood="no"
+                continue
+                ;;
+        esac
+        [[ "$devno" =~ (^[[:xdigit:]]+\.[0-3]\.[[:xdigit:]]{4}$)|(^[[:xdigit:]]{3,4}$) ]]
+        case $? in
+            0)  ;; # string matched the pattern
+            1)  # string did not match the pattern
+                echo $"Incorrect format for FCP device $devno in:"
+                echo $" $i=\"${!i}\""
+                allgood="no"
+                ;;
+            2)
+                echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+                ;;
+            *)
+                echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+                ;;
+        esac
+        # zfcp.py:class ZFCPDevice would also accept WWPN without leading 0x
+        [[ "$wwpn" =~ ^0x[[:xdigit:]]{16}$ ]]
+        case $? in
+            0)  ;; # string matched the pattern
+            1)  # string did not match the pattern
+                echo $"Incorrect format for FCP WWPN $wwpn in:"
+                echo $" $i=\"${!i}\""
+                allgood="no"
+                ;;
+            2)  echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2 ;;
+            *)  echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2 ;;
+        esac
+        # zfcp.py:class ZFCPDevice would also accept LUN without leading 0x
+        # zfcp.py:class ZFCPDevice would also accept 16 bit LUN and pads with 0
+        [[ "$lun" =~ ^0x[[:xdigit:]]{8}0{8}$ ]]
+        case $? in
+            0)  ;; # string matched the pattern
+            1)  # string did not match the pattern
+                echo $"Incorrect format for FCP LUN $lun in:"
+                echo $" $i=\"${!i}\""
+                allgood="no"
+                ;;
+            2)
+                echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2
+                ;;
+            *)
+                echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2
+                ;;
+        esac
+    done
+    if [ "$allgood" = "yes" ]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+###
+
+function show_parms() {
+    # The only issue with this stateless approach to showing parameters based
+    # on their content being non-empty is, that parameters with defaults
+    # such as LAYER2, (PORTNAME,) CTCPROT, PORTNO (,MACADDR) won't be shown
+    # if the user just hit enter, so the parm file would be "incomplete".
+    # However this is not easy to fix in here, since it would require the
+    # inter-parameter dependenies coded below in the main part, e.g. an
+    # empty LAYER2 should only be printed with default value if $NETTYPE=qeth.
+    # For the time being, at least the parameters LAYER2, PORTNAME, and CTCPROT
+    # only get asked on being empty if not running in kickstart mode.
+    cat << EOF
+NETTYPE=$NETTYPE
+IPADDR=$IPADDR
+NETMASK=$NETMASK
+GATEWAY=$GATEWAY
+HOSTNAME=$HOSTNAME
+EOF
+    [ "$SUBCHANNELS" ] && echo "SUBCHANNELS=$SUBCHANNELS"
+    [ "$LAYER2" ] && echo "LAYER2=$LAYER2"
+    [ "$VSWITCH" ] && echo "VSWITCH=$VSWITCH"
+    [ "$MACADDR" ] && echo "MACADDR=$MACADDR"
+    [ "$PORTNAME" ] && echo "PORTNAME=$PORTNAME"
+    [ "$PORTNO" ] && echo "PORTNO=$PORTNO"
+    [ "$PEERID" ] && echo "PEERID=$PEERID"
+    [ "$CTCPROT" ] && echo "CTCPROT=$CTCPROT"
+    if [ -n "$mmtu_was_set" ]; then
+        echo "MMTU=\"$MMTU\""
+    elif [ -n "$mtu_was_set" ]; then
+        echo "MTU=$MTU"
+    fi
+    [ "$DNS" ] && echo "DNS=$DNS"
+    [ "$SEARCHDNS" ] && echo "SEARCHDNS=$SEARCHDNS"
+    [ "$DASD" ] && echo "DASD=$DASD"
+}
+
+function final_check() {
+    # final check && break
+    if [ -z "$interaction_happened" ]; then
+        # if parm file was good enough just continue without interaction
+        break
+        return 0
+    fi
+    while : ; do
+        # optionally consider "continue" as default
+        # but then again the user may inadvertently continue
+        echo
+        echo $"c) continue, p) parm file/configuration, n) network state, r) restart, s) shell"
+        local answer
+        read answer
+        case $answer in
+            c) return 0 ;;
+            p) echo
+                show_parms ;;
+            n) # show interfaces and routing table
+                ifconfig -a
+                if [ "$ipv6" ]; then
+                    #route -n -A inet6
+                    # the following produces more compact output for 80 columns
+                    ip -6 route show | grep -v "^unreachable "
+                else
+                    route -n
+                fi
+                ;;
+            d) # show active DASDs with some useful details
+                echo $"Activated DASDs:"
+                cat /proc/dasd/devices|sed -e 's/ at ([^)]*) is//' -e 's/ at/,/'
+                ;;
+            r) break ;;
+            s) echo $"Enter 'exit' at the shell prompt to get back to the installation dialog."
+                /bin/bash
+                ;;
+    esac
+    done
+    return 1
+}
+
+### MAIN ###
+
+init_main
+udev_setup
+
+# Parse configuration
+if [ -n "$CMSDASD" -a -n "$CMSCONFFILE" ]; then
+    readcmsfile $CMSDASD $CMSCONFFILE
+    source /tmp/$CMSCONFFILE #2>/dev/null
+fi
+
+if [ -r /sys/firmware/ipl/ipl_type ]; then
+    #local ipl_type
+    read ipl_type < /sys/firmware/ipl/ipl_type
+    if [ "$ipl_type" = "fcp" ]; then
+        while : ; do
+            echo $"Your IPL device is set to FCP."
+            echo $"Would you like to perform a CD-ROM/DVD-ROM installation? (y/n)"
+            #local do_cd_install
+            read do_cd_install
+            case $do_cd_install in
+                y|Y|[Yy][Ee][Ss])
+                    # precondition: zfcp driver incl. dependencies loaded
+                    #local CD_DEVICE WWPN LUN
+                    read CD_DEVICE < /sys/firmware/ipl/device
+                    read WWPN < /sys/firmware/ipl/wwpn
+                    read LUN < /sys/firmware/ipl/lun
+                    if sysecho /proc/cio_ignore "free $CD_DEVICE"; then
+                        udevadm settle
+                        # even though device might now be online, some of its
+                        # sysfs attributes might not yet be available
+                        sleep 1
+                    else
+                        echo $"Device $CD_DEVICE could not be cleared from device blacklist"
+                    fi
+                    sysecho /sys/bus/ccw/drivers/zfcp/$CD_DEVICE/online 1 \
+                        || echo $"Could not set FCP device $CD_DEVICE online"
+                    udevadm settle
+                    # port (WWPN) appears automatically
+                    sysecho /sys/bus/ccw/drivers/zfcp/$CD_DEVICE/$WWPN/unit_add $LUN \
+                        || echo $"Could not add LUN $LUN at WWPN $WWPN on FCP device $CD_DEVICE"
+                    udevadm settle
+                    break
+                    ;;
+                n|N|[Nn][Oo])
+                    break
+                    ;;
+                *)
+                    echo
+                    echo $"*** INVALID ANSWER: $do_cd_install"
+                    echo
+                    unset do_cd_install
+                    ;;
+            esac
+        done
+    fi
+fi
+
+# Perform a network installation
+
+[ -n "$MTU" ] && mtu_was_set=$MTU
+[ -n "$MMTU" ] && mmtu_was_set=$MMTU
+[ -n "$VSWITCH" ] && vswitch_was_set=$VSWITCH
+
+[ -n "$CHANDEV" ] && do_chandev
+[ -n "$NETWORK" ] && do_network
+[ -n "$BROADCAST" ] && do_broadcast
+
+# [ -z "${cardtype//OSD_*/}" ] can be used to check for real OSA
+
+# Check for missing parameters, prompt for them if necessary
+while : ; do
+
+    # do not show list of possible network device configurations, if:
+    # - running unattended install with kickstart
+    # - relevant parameters have already been specified in parm file
+    #   (a possible optimization would be matching those parms to table entry)
+    # - dialog has not been restarted
+    [ -n "$reenter" \
+        -o -z "$RUNKS" -a \( -z "$NETTYPE" -o -z "$SUBCHANNELS" \) ] && \
+        dialog_network_table
+    if isVM; then
+        echo $"* NOTE: To enter default or empty values press enter twice. *"
+    fi
+    do_nettype
+
+    # precondition: driver (qeth/lcs/ctcm) loaded incl. dependencies
+    do_subchannels
+    if [ "$NETTYPE" = "qeth" ]; then
+        [ -z "$reenter" -a -n "$RUNKS" -a -z "$PORTNAME" ] || \
+            [ -n "${cardtype//OSD_*/}" ] || do_portname
+        # See also https://bugzilla.redhat.com/show_bug.cgi?id=439461
+        #
+        # If running in kickstart mode (unattended), we assume no
+        # interaction and the user won't get asked for PORTNO.
+        # Otherwise the user will be asked for PORTNO.
+        # If the user specified PORTNO in parm/conf file, PORTNO gets
+        # respected (or the user will be asked if it was wrong).
+        if [ -f /sys/devices/qeth/$SCH_R_DEVBUSID/portno ]; then
+            # driver support exists since RHEL5.2
+            [ -z "$reenter" -a -n "$RUNKS" -a -z "$PORTNO" ] || \
+                [ -n "${cardtype//OSD_*/}" ] || do_portno
+        fi
+        do_layer2
+        # set device online to know the device name
+        # and to know if it's OSD/HiperSockets/GuestLAN BUT do not
+        # try to ifconfig the device up since that requires
+        # setting the mac address before (if applicable).
+        set_device_online || workflow_item_menu noredo
+        # MAC address handling is not part of
+        # https://bugzilla.redhat.com/show_bug.cgi?id=233376
+        # Instead the additions come from
+        # https://bugzilla.redhat.com/show_bug.cgi?id=248049
+        # The new parms VSWITCH and MACADDR are described in
+        # the RHEL 5.1 release notes.
+        if isLayer2; then
+            if [ -z "$VSWITCH" -o "$VSWITCH" == 0 ]; then
+                do_macaddr
+            fi
+        fi
+    elif [ "$NETTYPE" = "ctc" ]; then
+        [ -z "$reenter" -a -n "$RUNKS" -a -z "$CTCPROT" ] || do_ctcprot
+        set_device_online || workflow_item_menu noredo
+    elif [ "$NETTYPE" = "lcs" ]; then
+        [ -n "$RUNKS" -a -z "$PORTNAME" ] && PORTNAME=0
+        do_lcs_portno
+        set_device_online || workflow_item_menu noredo
+    fi
+
+    # device needs to be up before configuring with ifconfig/ip in
+    # configure_ipv6_address/configure_ipv4_address/configure_ipv4_address
+    set_device_up || workflow_item_menu noredo
+
+    [ "$HOSTNAME" = "(none)" ] && unset HOSTNAME
+    do_hostname
+
+    # Note: The workflow_item_menu does a rollback_config on restart
+    # dialog, i.e. hardware config has been reset and it is impossible to
+    # only restart halfway at IPADDR.
+    do_ipaddr
+    if [ "$ipv6" ]; then
+        # this branch is all IPv6 and at the same time also NETTYPE==qeth
+        do_netmask_v6
+        handle_mtu
+        configure_ipv6_address || workflow_item_menu noredo
+        do_gateway_v6
+    else
+        # Consider IPv4 as default, even for unknown IP versions
+        # due to invalid input for IPADDR ignored by the user previously
+        # (neither ipv6 nor ipv4 is set).
+        # Otherwise we would skip things like NETMASK or GATEWAY
+        # and jump forward to DNS which is probably not what we want.
+        if [ "$NETTYPE" = "qeth" ] || [ "$NETTYPE" = "lcs" ]; then
+            do_netmask
+            handle_mtu
+            configure_ipv4_address || workflow_item_menu noredo
+            do_gateway
+        else  # ctc0
+            if [ -z "$NETMASK" ]; then
+                # If the user did not supply netmask, we add the right one.
+                # Netmask MUST be present,
+                # or pumpSetupInterface() blows routes.
+                NETMASK="255.255.255.255"
+            fi
+            # don't ask for MTU, but use it if set in the parm file
+            # don't overwrite MMTU if it has been set for CTC
+            [ "$NETTYPE" = "ctc" -a -z "$MTU" -a -z "$MMTU" ] && \
+                MMTU="mtu 1500"
+            do_ptp_gateway
+            configure_ipv4_ptp || workflow_item_menu noredo
+        fi
+    fi
+
+    modprobe_alias
+    do_dns
+    [ -n "$DNS" ] && do_searchdns
+
+    do_dasd
+
+    echo $"Initial configuration completed."
+    final_check && break
+    rollback_config
+    reenter="yes"
+
+done # outer dialog loop
+
+if [ -z "$testing" ]; then
+
+    # convert to space-separated lists
+    if [ -n "$SEARCHDNS" ]; then
+        SEARCHDNS=$(echo $SEARCHDNS |sed -e 's/:/ /g')
+        for i in "$SEARCHDNS"; do echo "search $i"; done >> /etc/resolv.conf
+    fi
+    if [ -n "$DNS" ]; then
+        if [ "$ipv6" ]; then
+            RESOLVDNS=$(echo $DNS |sed -e 's/,/ /g')
+        else
+            RESOLVDNS=$(echo $DNS |sed -e 's/:/ /g')
+        fi
+        for i in $RESOLVDNS; do echo "nameserver $i"; done >> /etc/resolv.conf
+    fi
+
+    # make sure we have an /etc/hosts file (originally required for telnetd)
+    if [ ! -z "$HOSTNAME" -a ! -z "$IPADDR" ]; then
+        echo -e "$IPADDR\t$HOSTNAME $(echo $HOSTNAME | cut -d '.' -f 1)" >> /etc/hosts
+    fi
+
+fi # testing
+
+# syntax check to give user early feedback on parameters provided in parm file
+# (he probably won't notice the logs written by anaconda later on)
+syntax_check_fcp
+# currently we ignore failed syntax checks since FCP parms are non-interactive
+for i in ${!FCP_*}; do
+    echo "${!i}" >> /tmp/fcpconfig
+done
+# cio_ignore handling for FCP should happen when the content of /tmp/fcpconfig
+# will actually be processed which is in anaconda's zfcp.py ZFCP::readConfig()
+
+# TODO/FIXME: also need to pass IPv6 decision to loader/anaconda
+#    [ "$ipv6" ] && echo "IPV6=yes"
+
+# transfer options into install environment
+cat > /tmp/install.cfg << EOF
+LANG="$LANG"
+S390ARCH="$S390ARCH"
+TEXTDOMAIN="$TEXTDOMAIN"
+TEXTDOMAINDIR="$TEXTDOMAINDIR"
+PORTNAME="$PORTNAME"
+HOSTNAME="$HOSTNAME"
+DEVICE="$DEVICE"
+NETTYPE="$NETTYPE"
+IPADDR="$IPADDR"
+GATEWAY="$GATEWAY"
+MTU="$MTU"
+NETWORK="$NETWORK"
+NETMASK="$NETMASK"
+BROADCAST="$BROADCAST"
+SEARCHDNS="$SEARCHDNS"
+PEERID="$PEERID"
+SUBCHANNELS="$SUBCHANNELS"
+ONBOOT="yes"
+CTCPROT="$CTCPROT"
+EOF
+if [ "$ipv6" ]; then
+    DNS1=$(echo $DNS | cut -d ',' -f 1)
+    echo DNS=\"$DNS1\" >> /tmp/install.cfg
+    echo DNS1=\"$DNS1\" >> /tmp/install.cfg
+    echo DNS2=\"$(echo $DNS | cut -d ',' -f 2)\" >> /tmp/install.cfg
+else
+    DNS1=$(echo $DNS | cut -d ':' -f 1)
+    echo DNS=\"$DNS1\" >> /tmp/install.cfg
+    echo DNS1=\"$DNS1\" >> /tmp/install.cfg
+    echo DNS2=\"$(echo $DNS | cut -d ':' -f 2)\" >> /tmp/install.cfg
+fi
+cat >> /tmp/install.cfg << EOF
+export LANG PORTNAME S390ARCH TEXTDOMAIN TEXTDOMAINDIR
+export HOSTNAME DEVICE NETTYPE IPADDR GATEWAY MTU
+export NETWORK NETMASK BROADCAST DNS DNS1 DNS2 SEARCHDNS
+export PEERID ONBOOT SUBCHANNELS CTCPROT
+EOF
+# immediately read it in again to export these into the shell below
+. /tmp/install.cfg
+if [ -z "$testing" ]; then
+    cat /tmp/install.cfg >> /etc/profile
+fi # testing
+
+NETSCRIPTS="/etc/sysconfig/network-scripts"
+IFCFGFILE="$NETSCRIPTS/ifcfg-$DEVICE"
+if [ ! -d "$NETSCRIPTS" ]; then
+    mkdir -p $NETSCRIPTS
+fi
+
+# to please NetworkManager on startup in loader before loader reconfigures net
+cat > /etc/sysconfig/network << EOF
+HOSTNAME=$HOSTNAME
+EOF
+
+cat > $IFCFGFILE << EOF
+DEVICE=$DEVICE
+ONBOOT=yes
+BOOTPROTO=static
+GATEWAY=$GATEWAY
+BROADCAST=$BROADCAST
+MTU=$MTU
+SUBCHANNELS=$SUBCHANNELS
+EOF
+if [ "$ipv6" ]; then
+    cat >> $IFCFGFILE << EOF
+IPV6INIT=yes
+IPV6_AUTOCONF=no
+IPV6ADDR=$IPADDR/$NETMASK
+IPV6_DEFAULTGW=$GATEWAY
+EOF
+    # FIXME: /etc/sysconfig/network:IPV6_DEFAULTGW=$GATEWAY
+    #        /etc/sysconfig/network:NETWORKING_IPV6=yes
+else
+    cat >> $IFCFGFILE << EOF
+IPADDR=$IPADDR
+NETMASK=$NETMASK
+EOF
+fi
+[ "$DNS1" != "" ] && echo "DNS1=$DNS1" >> $IFCFGFILE
+[ "$DNS2" != "" ] && echo "DNS2=$DNS2" >> $IFCFGFILE
+# colons in SEARCHDNS already replaced with spaces above for /etc/resolv.conf
+[ "$SEARCHDNS" != "" ] && echo "DOMAIN=\"$SEARCHDNS\"" >> $IFCFGFILE
+[ "$NETTYPE" != "" ] && echo "NETTYPE=$NETTYPE" >> $IFCFGFILE
+[ "$PEERID" != "" ] && echo "PEERID=$PEERID" >> $IFCFGFILE
+[ "$PORTNAME" != "" ] && echo "PORTNAME=$PORTNAME" >> $IFCFGFILE
+[ "$CTCPROT" != "" ] && echo "CTCPROT=$CTCPROT" >> $IFCFGFILE
+[ "$MACADDR" != "" ] && echo "MACADDR=$MACADDR" >> $IFCFGFILE
+optstr=""
+for option in LAYER2 PORTNO; do
+    [ -z "${!option}" ] && continue
+    [ -n "$optstr" ] && optstr=${optstr}" "
+    optstr=${optstr}$(echo ${option} | tr [[:upper:]] [[:lower:]])"="${!option}
+done
+# write single quotes since network.py removes double quotes but we need quotes
+echo "OPTIONS='$optstr'" >> $IFCFGFILE
+unset option
+unset optstr
+
+if [ -z "$testing" ]; then
+
+    # so that the vars get propagated into the sshd shells
+    mkdir /.ssh
+    cat >> /.ssh/environment <<EOF
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH
+PATH=$PATH
+HOME=$HOME
+PYTHONPATH=$PYTHONPATH
+EOF
+
+    cat >> /etc/profile <<EOF
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH
+PATH=$PATH
+HOME=$HOME
+PYTHONPATH=$PYTHONPATH
+export LD_LIBRARY_PATH PATH HOME PYTHONPATH
+EOF
+
+    if [ -n "$DISPLAY" ]; then
+        echo "export DISPLAY=$DISPLAY" >> /etc/profile
+    fi
+
+    # I'm tired of typing this out...
+    echo "loader" >> /.bash_history
+
+    echo -n $$ > /var/run/init.pid
+
+    # shutdown (halt) on SIGUSR1
+    trap doshutdown SIGUSR1
+    # reboot on SIGUSR2
+    trap doreboot SIGUSR2
+
+    startinetd
+
+    if [ -n "$RUNKS" ]; then
+        /sbin/loader
+    fi
+
+    doshutdown
+
+fi # testing
+
+# ;;; Local Variables: ***
+# ;;; mode: sh ***
+# ;;; end: ***
diff --git a/bin/loader/loader.c b/bin/loader/loader.c
new file mode 100644
index 0000000..84fd116
--- /dev/null
+++ b/bin/loader/loader.c
@@ -0,0 +1,2378 @@
+/*
+ * loader.c
+ *
+ * This is the installer loader.  Its job is to somehow load the rest
+ * of the installer into memory and run it.  This may require setting
+ * up some devices and networking, etc. The main point of this code is
+ * to stay SMALL! Remember that, live by that, and learn to like it.
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ * 2006, 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <execinfo.h>
+#include <fcntl.h>
+#include <newt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <dirent.h>
+#include <arpa/inet.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+
+#include <linux/fb.h>
+#include <linux/serial.h>
+#include <linux/vt.h>
+
+#include <glib.h>
+
+#ifdef USE_MTRACE
+#include <mcheck.h>
+#endif
+
+#include "copy.h"
+#include "getparts.h"
+#include "loader.h"
+#include "loadermisc.h" /* JKFIXME: functions here should be split out */
+#include "lang.h"
+#include "fwloader.h"
+#include "kbd.h"
+#include "kickstart.h"
+#include "windows.h"
+
+/* module stuff */
+#include "modules.h"
+#include "moduleinfo.h"
+
+#include "driverdisk.h"
+
+/* hardware stuff */
+#include "hardware.h"
+
+/* install method stuff */
+#include "method.h"
+#include "cdinstall.h"
+#include "nfsinstall.h"
+#include "hdinstall.h"
+#include "urls.h"
+#include "urlinstall.h"
+
+#include "net.h"
+#include "telnetd.h"
+
+#include <selinux/selinux.h>
+#include "selinux.h"
+
+#include "../isys/imount.h"
+#include "../isys/isys.h"
+#include "../isys/stubs.h"
+#include "../isys/lang.h"
+#include "../isys/eddsupport.h"
+#include "../isys/log.h"
+
+/* maximum number of extra arguments that can be passed to the second stage */
+#define MAX_EXTRA_ARGS 128
+static char * extraArgs[MAX_EXTRA_ARGS];
+static int hasGraphicalOverride();
+
+static int newtRunning = 0;
+
+/* boot flags -- we need these in a lot of places */
+uint64_t flags = LOADER_FLAGS_SELINUX;
+
+#ifdef INCLUDE_LOCAL
+#include "cdinstall.h"
+#include "hdinstall.h"
+#endif
+#ifdef INCLUDE_NETWORK
+#include "nfsinstall.h"
+#include "urlinstall.h"
+#endif
+
+int num_link_checks = 5;
+int post_link_sleep = 0;
+
+static pid_t init_pid = 1;
+static int init_sig = SIGUSR1; /* default to shutdown=halt */
+static const char *LANG_DEFAULT = "en_US.UTF-8";
+
+static struct installMethod installMethods[] = {
+    { N_("Local CD/DVD"), 0, DEVICE_CDROM, mountCdromImage },
+    { N_("Hard drive"), 0, DEVICE_DISK, mountHardDrive },
+    { N_("NFS directory"), 1, DEVICE_NETWORK, mountNfsImage },
+    { "URL", 1, DEVICE_NETWORK, mountUrlImage },
+};
+static int numMethods = sizeof(installMethods) / sizeof(struct installMethod);
+
+static int expected_exit = 0;
+
+void doExit(int result)
+{
+    expected_exit = 1;
+    exit(result);
+}
+
+void doSuspend(void) {
+    newtFinished();
+    doExit(1);
+}
+
+void doShell(void) {
+    pid_t child;
+    int status;
+
+    newtSuspend();
+    child = fork();
+
+    if (child == 0) {
+        if (execl("/sbin/bash", "/sbin/bash", "-i", NULL) == -1) {
+            logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+            _exit(1);
+        }
+    } else if (child == -1) {
+        logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+        newtResume();
+    } else {
+        if (waitpid(child, &status, 0) == -1) {
+            logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+        }
+
+        newtResume();
+    }
+}
+
+void doGdbserver(struct loaderData_s *loaderData) {
+    int child, fd;
+    char *pid;
+    iface_t iface;
+
+    /* If gdbserver is found, go ahead and run it on the loader process now
+     * before anything bad happens.
+     */
+    if (loaderData->gdbServer && !access("/usr/bin/gdbserver", X_OK)) {
+        pid_t loaderPid = getpid();
+        iface_init_iface_t(&iface);
+
+        if (kickstartNetworkUp(loaderData, &iface)) {
+            logMessage(ERROR, "can't run gdbserver due to no network");
+            return;
+        }
+
+        checked_asprintf(&pid, "%d", loaderPid);
+
+        if (!(child = fork())) {
+            logMessage(INFO, "starting gdbserver: %s %s %s %s",
+                       "/usr/bin/gdbserver", "--attach", loaderData->gdbServer,
+                       pid);
+
+            fd = open("/dev/null", O_RDONLY);
+            close(STDIN_FILENO);
+            dup2(fd, STDIN_FILENO);
+            close(fd);
+            fd = open("/dev/null", O_WRONLY);
+            close(STDOUT_FILENO);
+            dup2(fd, STDOUT_FILENO);
+            close(STDERR_FILENO);
+            dup2(fd, STDERR_FILENO);
+            close(fd);
+
+            if (execl("/usr/bin/gdbserver", "/usr/bin/gdbserver", "--attach",
+                      loaderData->gdbServer, pid, NULL) == -1)
+                logMessage(ERROR, "error running gdbserver: %m");
+
+            _exit(1);
+        }
+    }
+}
+
+void startNewt(void) {
+    if (!newtRunning) {
+        char *buf;
+        char *arch = getProductArch();
+        checked_asprintf(&buf, _("Welcome to %s for %s"), getProductName(), arch);
+
+        /*
+         * Because currently initrd.img only has got the default English locale
+         * support, pretend for newtInit() it is actually the used LANG so Newt
+         * knows how to compute character widths etc. 
+         */
+        char *lang = getenv("LANG");
+        if (lang) {
+            lang = strdup(lang);
+        }
+        setenv("LANG", LANG_DEFAULT, 1);
+        newtInit();
+        unsetenv("LANG");
+        /* restore the original LANG value */
+        if (lang) {
+            setenv("LANG", lang, 1);
+            free(lang);
+        }
+
+        newtCls();
+        newtDrawRootText(0, 0, buf);
+        free(buf);
+        
+        newtPushHelpLine(_("  <Tab>/<Alt-Tab> between elements  | <Space> selects | <F12> next screen "));
+        
+        newtRunning = 1;
+        if (!access("/bin/sh",  X_OK)) 
+            newtSetSuspendCallback((void *) doShell, NULL);
+    }
+}
+
+void stopNewt(void) {
+    if (newtRunning) newtFinished();
+    newtRunning = 0;
+}
+
+static gchar *productName = NULL;
+static gchar *productPath = NULL;
+static gchar *productArch = NULL;
+
+static void initProductInfo(void) {
+    gchar *contents = NULL;
+    gchar **lines = NULL, **stamp = NULL;
+    GError *fileErr = NULL;
+
+    if (!g_file_get_contents("/.buildstamp", &contents, NULL, &fileErr)) {
+        logMessage(ERROR, "error reading .buildstamp: %s", fileErr->message);
+        g_error_free(fileErr);
+        productName = g_strdup("anaconda");
+        productArch = g_strdup("unknown architecture");
+        productPath = g_strdup("anaconda");
+        return;
+    }
+
+    /* .buildstamp uses the first 3 lines in this format:
+     *     STAMP.productArch
+     *     productName
+     *     productPath
+     */
+    lines = g_strsplit(contents, "\n", 0);
+    g_free(contents);
+
+    if ((lines != NULL) && (g_strv_length(lines) >= 3)) {
+        /* STAMP.productArch */
+        stamp = g_strsplit(lines[0], ".", 0);
+
+        if ((stamp != NULL) && (g_strv_length(stamp) == 2)) {
+            productArch = g_strdup(stamp[1]);
+        } else {
+            productArch = g_strdup("unknown architecture");
+        }
+
+        if (stamp) {
+            g_strfreev(stamp);
+        }
+
+        productName = g_strdup(lines[1]);
+        productPath = g_strdup(lines[2]);
+    } else {
+        productName = g_strdup("anaconda");
+        productArch = g_strdup("unknown architecture");
+        productPath = g_strdup("anaconda");
+    }
+
+    if (lines) {
+        g_strfreev(lines);
+    }
+
+    return;
+}
+
+char * getProductName(void) {
+    if (!productName) {
+       initProductInfo();
+    }
+    return productName;
+}
+
+char * getProductArch(void) {
+    if (!productArch) {
+       initProductInfo();
+    }
+    return productArch;
+}
+
+char * getProductPath(void) {
+    if (!productPath) {
+       initProductInfo();
+    }
+    return productPath;
+}
+
+void initializeConsole() {
+    /* enable UTF-8 console */
+    setenv("LANG", LANG_DEFAULT, 1);
+    printf("\033%%G");
+    fflush(stdout);
+
+    isysLoadFont();
+    isysSetUnicodeKeymap();
+}
+
+/* fbcon is buggy and resets our color palette if we allocate a terminal
+ * after initializing it, so we initialize 9 of them before we need them.
+ * If it doesn't work, the user gets to suffer through having an ugly palette,
+ * but things are still usable. */
+static void initializeTtys(void) {
+    int fd, n;
+    char dev[] = "/dev/ttyX";
+
+    for (n = 9; n > 0; n--) {
+	sprintf(dev, "/dev/tty%d", n);
+	mknod(dev, 0600 | S_IFCHR, makedev(4, n));
+	fd = open(dev, O_RDWR|O_NOCTTY);
+	if (fd >= 0) {
+	    ioctl(fd, VT_ACTIVATE, n);
+	    if (n == 1)
+		ioctl(fd, VT_WAITACTIVE, n);
+	    close(fd);
+	} else
+	    logMessage(ERROR, "failed to initialize %s", dev);
+    }
+}
+
+static void spawnShell(void) {
+    pid_t pid;
+
+    if (FL_SERIAL(flags) || FL_NOSHELL(flags)) {
+        logMessage(INFO, "not spawning a shell");
+        return;
+    } else if (access("/bin/sh",  X_OK))  {
+        logMessage(ERROR, "cannot open shell - /bin/sh doesn't exist");
+        return;
+    }
+
+    if (!(pid = fork())) {
+	int fd;
+
+    	fd = open("/dev/tty2", O_RDWR|O_NOCTTY);
+    	if (fd < 0) {
+            logMessage(ERROR, "cannot open /dev/tty2 -- no shell will be provided");
+	    return;
+	}
+
+        dup2(fd, 0);
+        dup2(fd, 1);
+        dup2(fd, 2);
+        
+        close(fd);
+        setsid();
+
+	/* enable UTF-8 console */
+	printf("\033%%G");
+	fflush(stdout);
+	isysLoadFont();
+	
+        if (ioctl(0, TIOCSCTTY, NULL)) {
+            logMessage(ERROR, "could not set new controlling tty");
+        }
+        
+        signal(SIGINT, SIG_DFL);
+        signal(SIGTSTP, SIG_DFL);
+
+        if (!access("/tmp/updates/pyrc.py", R_OK|X_OK))
+            setenv("PYTHONSTARTUP", "/tmp/updates/pyrc.py", 1);
+        else if (!access("/usr/share/anaconda/pyrc.py", R_OK|X_OK))
+            setenv("PYTHONSTARTUP", "/usr/share/anaconda/pyrc.py", 1);
+        setenv("LD_LIBRARY_PATH", LIBPATH, 1);
+        setenv("LANG", "C", 1);
+        
+        if (execl("/bin/sh", "-/bin/sh", NULL) == -1) {
+            logMessage(CRITICAL, "exec of /bin/sh failed: %m");
+            exit(1);
+        }
+    }
+
+    return;
+}
+
+
+static void copyWarnFn (char *msg) {
+   logMessage(WARNING, msg);
+}
+
+static void copyErrorFn (char *msg) {
+   newtWinMessage(_("Error"), _("OK"), _(msg));
+}
+
+void loadUpdates(struct loaderData_s *loaderData) {
+    char *device = NULL, *part = NULL, *buf;
+    char **devNames = NULL;
+    enum { UPD_DEVICE, UPD_PART, UPD_PROMPT, UPD_LOAD, UPD_DONE } stage = UPD_DEVICE;
+    int rc, num = 0;
+    int dir = 1;
+
+    while (stage != UPD_DONE) {
+        switch (stage) {
+        case UPD_DEVICE: {
+            rc = getRemovableDevices(&devNames);
+            if (rc == 0)
+                return;
+
+            /* we don't need to ask which to use if they only have one */
+            if (rc == 1) {
+                device = strdup(devNames[0]);
+                free(devNames);
+                devNames = NULL;
+                if (dir == -1)
+                    return;
+
+                stage = UPD_PART;
+                break;
+            }
+            dir = 1;
+
+            startNewt();
+            rc = newtWinMenu(_("Update Disk Source"),
+                             _("You have multiple devices which could serve "
+                               "as sources for an update disk.  Which would "
+                               "you like to use?"), 40, 10, 10,
+                             rc < 6 ? rc : 6, devNames,
+                             &num, _("OK"), _("Cancel"), NULL);
+
+            if (rc == 2) {
+                free(devNames);
+                devNames = NULL;
+                return;
+            }
+
+            device = strdup(devNames[num]);
+            free(devNames);
+            devNames = NULL;
+            stage = UPD_PART;
+        }
+
+        case UPD_PART: {
+            char ** part_list = getPartitionsList(device);
+            int nump = 0, num = 0;
+
+            if (part != NULL) {
+                free(part);
+                part = NULL;
+            }
+
+            if ((nump = lenPartitionsList(part_list)) == 0) {
+                if (dir == -1) {
+                    stage = UPD_DEVICE;
+                } else {
+                    checked_asprintf(&part, "/dev/%s", device);
+                    stage = UPD_PROMPT;
+                }
+
+                break;
+            }
+            dir = 1;
+
+            startNewt();
+            rc = newtWinMenu(_("Update Disk Source"),
+                             _("There are multiple partitions on this device "
+                               "which could contain the update disk image.  "
+                               "Which would you like to use?"), 40, 10, 10,
+                             nump < 6 ? nump : 6, part_list, &num, _("OK"),
+                             _("Back"), NULL);
+
+            if (rc == 2) {
+                freePartitionsList(part_list);
+                stage = UPD_DEVICE;
+                dir = -1;
+                break;
+            }
+
+            part = strdup(part_list[num]);
+            stage = UPD_LOAD;
+        }
+
+        case UPD_PROMPT:
+            checked_asprintf(&buf, _("Insert your updates disk into %s and "
+                                     "press \"OK\" to continue."), part);
+
+            rc = newtWinChoice(_("Updates Disk"), _("OK"), _("Back"), buf);
+            free(buf);
+            buf = NULL;
+
+            if (rc == 2) {
+                stage = UPD_PART;
+                dir = -1;
+                break;
+            }
+
+            stage = UPD_LOAD;
+            break;
+
+        case UPD_LOAD:
+            logMessage(INFO, "UPDATES device is %s", part);
+
+            if (doPwMount(part, "/tmp/update-disk", "auto", "ro", NULL)) {
+                newtWinMessage(_("Error"), _("OK"),
+                               _("Failed to mount updates disk"));
+                stage = UPD_PROMPT;
+                break;
+            } else {
+                /* Copy everything to /tmp/updates so we can unmount the disk  */
+                winStatus(40, 3, _("Updates"), _("Reading anaconda updates"));
+                if (!copyDirectory("/tmp/update-disk", "/tmp/updates", copyWarnFn,
+                                   copyErrorFn)) {
+                    dir = 1;
+                    stage = UPD_DONE;
+                }
+
+                newtPopWindow();
+                umount("/tmp/update-disk");
+            }
+
+        case UPD_DONE:
+            break;
+        }
+    }
+
+    return;
+}
+
+static char *newUpdatesLocation(const char *origLocation) {
+    const char *location;
+    char *retval = NULL;
+    newtComponent f, okay, cancel, answer, locationEntry;
+    newtGrid grid, buttons;
+
+    startNewt();
+
+    locationEntry = newtEntry(-1, -1, NULL, 60, &location, NEWT_FLAG_SCROLL);
+    newtEntrySet(locationEntry, origLocation, 1);
+
+    /* button bar at the bottom of the window */
+    buttons = newtButtonBar(_("OK"), &okay, _("Cancel"), &cancel, NULL);
+
+    grid = newtCreateGrid(1, 3);
+
+    newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT,
+                     newtTextboxReflowed(-1, -1, _("Unable to download the updates image.  Please modify the updates location below or press Cancel to proceed without updates.."), 60, 0, 0, 0),
+                     0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+    newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, locationEntry,
+                     0, 1, 0, 0, NEWT_ANCHOR_LEFT, 0);
+    newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
+                     0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+    f = newtForm(NULL, NULL, 0);
+    newtGridAddComponentsToForm(grid, f, 1);
+    newtGridWrappedWindow(grid, _("Error downloading updates image"));
+    newtGridFree(grid, 1);
+
+    /* run the form */
+    answer = newtRunForm(f);
+
+    if (answer != cancel)
+        retval = strdup(location);
+
+    newtFormDestroy(f);
+    newtPopWindow();
+
+    return retval;
+}
+
+static int loadUpdatesFromRemote(char * url, struct loaderData_s * loaderData) {
+    int rc = getFileFromUrl(url, "/tmp/updates.img", loaderData);
+
+    if (rc != 0) {
+        char *newLocation = newUpdatesLocation(url);
+
+        if (!newLocation)
+           return rc;
+        else
+           return loadUpdatesFromRemote(newLocation, loaderData);
+    }
+
+    copyUpdatesImg("/tmp/updates.img");
+    unlink("/tmp/updates.img");
+    return 0;
+}
+
+static void writeVNCPasswordFile(char *pfile, char *password) {
+    FILE *f;
+
+    f = fopen(pfile, "w+");
+    fprintf(f, "%s\n", password);
+    fclose(f);
+}
+
+/* read information from /etc/sysconfig/network-scripts/ifcfg-$INTERFACE
+ * (written by linuxrc), the linuxrc mess should be firing up NM too
+ */
+static void readNetInfo(struct loaderData_s ** ld) {
+    struct loaderData_s * loaderData = *ld;
+    char *cfgfile = NULL;
+    gchar *contents = NULL;
+    gchar **lines = NULL, **line = NULL;
+    GError *e = NULL;
+
+    /* when this function is called, the DEVICE environment variable
+     * contains the device name whose ifcfg file we want to read
+     */
+    if (!getenv("DEVICE")) {
+        return;
+    }
+
+    checked_asprintf(&cfgfile, "/etc/sysconfig/network-scripts/ifcfg-%s",
+                     getenv("DEVICE"));
+
+    /* make sure everything is NULL before we begin copying info */
+    loaderData->ipv4 = NULL;
+    loaderData->netmask = NULL;
+    loaderData->gateway = NULL;
+    loaderData->dns = NULL;
+    loaderData->peerid = NULL;
+    loaderData->subchannels = NULL;
+    loaderData->portname = NULL;
+    loaderData->nettype = NULL;
+    loaderData->ctcprot = NULL;
+    loaderData->layer2 = NULL;
+    loaderData->portno = NULL;
+    loaderData->macaddr = NULL;
+#ifdef ENABLE_IPV6
+    loaderData->ipv6 = NULL;
+    loaderData->gateway6 = NULL;
+#endif
+
+    /*
+     * The ifcfg file is written out by /sbin/init on s390x (which is
+     * really the linuxrc.s390 script).  It's a shell-sourcable file with
+     * various system settings needing for the system instance.
+     *
+     * The goal of this function is to read in only the network settings
+     * and populate the loaderData structure.
+     */
+    if (!g_file_get_contents(cfgfile, &contents, NULL, &e)) {
+        logMessage(ERROR, "error reading %s: %s", cfgfile, e->message);
+        g_error_free(e);
+        return;
+    }
+
+    line = lines = g_strsplit(contents, "\n", 0);
+    g_free(contents);
+
+    while (*line != NULL) {
+        gchar *tmp = g_strdup(*line);
+        gchar **pair = NULL;
+
+        if (!strstr(tmp, "=")) {
+            g_free(tmp);
+            line++;
+            continue;
+        }
+
+        tmp = g_strstrip(tmp);
+        pair = g_strsplit(tmp, "=", 0);
+
+        if (g_strv_length(pair) == 2) {
+            gchar *val = g_shell_unquote(pair[1], &e);
+
+            if (e != NULL) {
+                logMessage(WARNING,
+                           "error reading %s from %s (line=%s): %s",
+                           pair[0], cfgfile, tmp, e->message);
+                g_error_free(e);
+            } else {
+                if (!g_strcmp0(pair[0], "IPADDR")) {
+                    loaderData->ipv4 = strdup(val);
+                } else if (!g_strcmp0(pair[0], "NETMASK")) {
+                    loaderData->netmask = strdup(val);
+                } else if (!g_strcmp0(pair[0], "GATEWAY")) {
+                    loaderData->gateway = strdup(val);
+                } else if (!g_strcmp0(pair[0], "DNS")) {
+                    loaderData->dns = strdup(val);
+                } else if (!g_strcmp0(pair[0], "MTU")) {
+                    errno = 0;
+                    loaderData->mtu = strtol(val, NULL, 10);
+
+                    if ((errno == ERANGE && (loaderData->mtu == LONG_MIN ||
+                                             loaderData->mtu == LONG_MAX)) ||
+                        (errno != 0 && loaderData->mtu == 0)) {
+                        logMessage(ERROR, "%s: %d: %m", __func__, __LINE__);
+                        abort();
+                    }
+                } else if (!g_strcmp0(pair[0], "PEERID")) {
+                    loaderData->peerid = strdup(val);
+                } else if (!g_strcmp0(pair[0], "SUBCHANNELS")) {
+                    loaderData->subchannels = strdup(val);
+                } else if (!g_strcmp0(pair[0], "PORTNAME")) {
+                    loaderData->portname = strdup(val);
+                } else if (!g_strcmp0(pair[0], "NETTYPE")) {
+                    loaderData->nettype = strdup(val);
+                } else if (!g_strcmp0(pair[0], "CTCPROT")) {
+                    loaderData->ctcprot = strdup(val);
+                } else if (!g_strcmp0(pair[0], "LAYER2")) {
+                    loaderData->layer2 = strdup(val);
+                } else if (!g_strcmp0(pair[0], "PORTNO")) {
+                    loaderData->portno = strdup(val);
+                } else if (!g_strcmp0(pair[0], "MACADDR")) {
+                    loaderData->macaddr = strdup(val);
+                } else if (!g_strcmp0(pair[0], "HOSTNAME")) {
+                    loaderData->hostname = strdup(val);
+                }
+            }
+
+            g_free(val);
+        }
+
+        g_strfreev(pair);
+        g_free(tmp);
+        line++;
+    }
+
+    if (loaderData->ipv4 && loaderData->netmask) {
+        flags |= LOADER_FLAGS_HAVE_CMSCONF;
+    }
+
+    free(cfgfile);
+    g_strfreev(lines);
+    return;
+}
+
+/* parse anaconda or pxelinux-style ip= arguments
+ * pxelinux format: ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask>
+ * anaconda format: ip=<client-ip> netmask=<netmask> gateway=<gw-ip>
+*/
+static void parseCmdLineIp(struct loaderData_s * loaderData, char *argv)
+{
+    /* Detect pxelinux */
+    if (strstr(argv, ":") != NULL) {
+        char *start, *end;
+
+        /* IP */
+        start = argv + 3;
+        end = strstr(start, ":");
+        loaderData->ipv4 = strndup(start, end-start);
+        loaderData->ipinfo_set = 1;
+
+        /* Boot server */
+        if (end + 1 == '\0')
+            return;
+        start = end + 1;
+        end = strstr(start, ":");
+        if (end == NULL)
+            return;
+
+        /* Gateway */
+        if (end + 1 == '\0')
+            return;
+        start = end + 1;
+        end = strstr(start, ":");
+        if (end == NULL) {
+            loaderData->gateway = strdup (start);
+            return;
+        } else {
+            loaderData->gateway = strndup(start, end-start);
+        }
+
+        /* Netmask */
+        if (end + 1 == '\0')
+            return;
+        start = end + 1;
+        loaderData->netmask = strdup(start);
+    } else {
+        loaderData->ipv4 = strdup(argv + 3);
+        loaderData->ipinfo_set = 1;
+    }
+
+    if (loaderData->ipinfo_set)
+        flags |= LOADER_FLAGS_IP_PARAM;
+}
+
+#ifdef ENABLE_IPV6
+/*
+ * parse anaconda ipv6= arguments
+ */
+static void parseCmdLineIpv6(struct loaderData_s * loaderData, char *argv)
+{
+    /* right now we only accept ipv6= arguments equal to:
+     *     dhcp     DHCPv6 call
+     *     auto     RFC 2461 neighbor discovery
+     */
+    loaderData->ipv6 = NULL;
+
+    if (!strncasecmp(argv, "ipv6=dhcp", 9)) {
+        loaderData->ipv6 = strdup("dhcp");
+    } else if (!strncasecmp(argv, "ipv6=auto", 9)) {
+        loaderData->ipv6 = strdup("auto");
+    }
+
+    if (loaderData->ipv6 != NULL) {
+        loaderData->ipv6info_set = 1;
+        flags |= LOADER_FLAGS_IPV6_PARAM;
+    }
+
+    return;
+}
+#endif
+
+static long argToLong(char *arg, int offset) {
+    long retval;
+
+    errno = 0;
+
+    retval = strtol(arg+offset, NULL, 10);
+    if ((errno == ERANGE && (retval == LONG_MIN || retval == LONG_MAX)) ||
+        (errno != 0 && retval == 0)) {
+        logMessage(ERROR, "%s: %d: %m", __func__, __LINE__);
+        abort();
+    }
+
+    return retval;
+}
+
+/* parses /proc/cmdline for any arguments which are important to us.  
+ * NOTE: in test mode, can specify a cmdline with --cmdline
+ */
+static void parseCmdLineFlags(struct loaderData_s * loaderData,
+                              char * cmdLine) {
+    int fd;
+    char buf[1024];
+    int len;
+    gint argc = 0;
+    gchar **argv = NULL;
+    GError *optErr = NULL;
+    int numExtraArgs = 0;
+    int i;
+    char *front;
+
+    /* we want to default to graphical and allow override with 'text' */
+    flags |= LOADER_FLAGS_GRAPHICAL;
+
+    /* if we have any explicit cmdline (probably test mode), we don't want
+     * to parse /proc/cmdline */
+    if (!cmdLine) {
+        if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) return;
+        len = read(fd, buf, sizeof(buf) - 1);
+        close(fd);
+        if (len <= 0) {
+            logMessage(INFO, "kernel command line was empty");
+            return;
+        }
+        
+        buf[len] = '\0';
+        cmdLine = buf;
+    }
+
+    logMessage(INFO, "kernel command line: %s", cmdLine);
+    
+    if (!g_shell_parse_argv(cmdLine, &argc, &argv, &optErr)) {
+        g_error_free(optErr);
+        return;
+    }
+
+    for (i=0; i < argc; i++) {
+        if (!strcasecmp(argv[i], "askmethod"))
+            flags |= LOADER_FLAGS_ASKMETHOD;
+        else if (!strcasecmp(argv[i], "asknetwork"))
+            flags |= LOADER_FLAGS_ASKNETWORK;
+        else if (!strcasecmp(argv[i], "noshell"))
+            flags |= LOADER_FLAGS_NOSHELL;
+        else if (!strcasecmp(argv[i], "nokill"))
+            flags |= LOADER_FLAGS_NOKILL;
+        else if (!strcasecmp(argv[i], "mediacheck"))
+            flags |= LOADER_FLAGS_MEDIACHECK;
+        else if (!strcasecmp(argv[i], "allowwireless"))
+            flags |= LOADER_FLAGS_ALLOW_WIRELESS;
+        else if (!strcasecmp(argv[i], "telnet"))
+            flags |= LOADER_FLAGS_TELNETD;
+        else if (!strcasecmp(argv[i], "noprobe"))
+            flags |= LOADER_FLAGS_NOPROBE;
+        else if (!strcasecmp(argv[i], "text")) {
+            logMessage(INFO, "text mode forced from cmdline");
+            flags |= LOADER_FLAGS_TEXT;
+            flags &= ~LOADER_FLAGS_GRAPHICAL;
+        }
+        else if (!strcasecmp(argv[i], "graphical")) {
+            logMessage(INFO, "graphical mode forced from cmdline");
+            flags |= LOADER_FLAGS_GRAPHICAL;
+        } else if (!strcasecmp(argv[i], "cmdline")) {
+            logMessage(INFO, "cmdline mode forced from cmdline");
+            flags |= LOADER_FLAGS_CMDLINE;
+        } else if (!strncasecmp(argv[i], "updates=", 8))
+            loaderData->updatessrc = strdup(argv[i] + 8);
+        else if (!strncasecmp(argv[i], "updates", 7))
+            flags |= LOADER_FLAGS_UPDATES;
+        else if (!strncasecmp(argv[i], "dogtail=", 8))
+            loaderData->dogtailurl = strdup(argv[i] + 8);
+        else if (!strncasecmp(argv[i], "dd=", 3) || 
+                 !strncasecmp(argv[i], "driverdisk=", 11)) {
+            loaderData->ddsrc = strdup(argv[i] + 
+                                       (argv[i][1] == 'r' ? 11 : 3));
+        }
+        else if (!strcasecmp(argv[i], "dd") || 
+                 !strcasecmp(argv[i], "driverdisk"))
+            flags |= LOADER_FLAGS_MODDISK;
+        else if (!strcasecmp(argv[i], "dlabel=on"))
+            flags |= LOADER_FLAGS_AUTOMODDISK;
+        else if (!strcasecmp(argv[i], "dlabel=off"))
+            flags &= ~LOADER_FLAGS_AUTOMODDISK;
+        else if (!strcasecmp(argv[i], "rescue"))
+            flags |= LOADER_FLAGS_RESCUE;
+        else if (!strcasecmp(argv[i], "nopass"))
+            flags |= LOADER_FLAGS_NOPASS;
+        else if (!strcasecmp(argv[i], "serial")) 
+            flags |= LOADER_FLAGS_SERIAL;
+        else if (!strcasecmp(argv[i], "noipv4"))
+            flags |= LOADER_FLAGS_NOIPV4;
+#ifdef ENABLE_IPV6
+        else if (!strcasecmp(argv[i], "noipv6"))
+            flags |= LOADER_FLAGS_NOIPV6;
+#endif
+        else if (!strcasecmp(argv[i], "kssendmac"))
+            flags |= LOADER_FLAGS_KICKSTART_SEND_MAC;
+        else if (!strcasecmp(argv[i], "kssendsn"))
+            flags |= LOADER_FLAGS_KICKSTART_SEND_SERIAL;
+        /* deprecated hardware bits */
+        else if (!strcasecmp(argv[i], "nousbstorage"))
+            mlAddBlacklist("usb-storage");
+        else if (!strcasecmp(argv[i], "nousb")) {
+            mlAddBlacklist("ehci-hcd");
+            mlAddBlacklist("ohci-hcd");
+            mlAddBlacklist("uhci-hcd");
+        } else if (!strcasecmp(argv[i], "nofirewire"))
+            mlAddBlacklist("firewire-ohci");
+        else if (!strncasecmp(argv[i], "loglevel=", 9)) {
+            if (!strcasecmp(argv[i]+9, "debug")) {
+                loaderData->logLevel = strdup(argv[i]+9);
+                setLogLevel(DEBUGLVL);
+            }
+            else if (!strcasecmp(argv[i]+9, "info")) {
+                loaderData->logLevel = strdup(argv[i]+9);
+                setLogLevel(INFO);
+            }
+            else if (!strcasecmp(argv[i]+9, "warning")) {
+                loaderData->logLevel = strdup(argv[i]+9);
+                setLogLevel(WARNING);
+            }
+            else if (!strcasecmp(argv[i]+9, "error")) {
+                loaderData->logLevel = strdup(argv[i]+9);
+                setLogLevel(ERROR);
+            }
+            else if (!strcasecmp(argv[i]+9, "critical")) {
+                loaderData->logLevel = strdup(argv[i]+9);
+                setLogLevel(CRITICAL);
+            }
+        }
+        else if (!strncasecmp(argv[i], "ksdevice=", 9)) {
+            loaderData->netDev = strdup(argv[i] + 9);
+            loaderData->netDev_set = 1;
+        }
+        else if (!strncmp(argv[i], "BOOTIF=", 7)) {
+            /* +10 so that we skip over the leading 01- */
+            loaderData->bootIf = strdup(argv[i] + 10);
+
+            /* scan the BOOTIF value and replace '-' with ':' */
+            front = loaderData->bootIf;
+            if (front) {
+                while (*front != '\0') {
+                    if (*front == '-')
+                        *front = ':';
+                    front++;
+                }
+            }
+
+            loaderData->bootIf_set = 1;
+        } else if (!strncasecmp(argv[i], "dhcpclass=", 10)) {
+            loaderData->netCls = strdup(argv[i] + 10);
+            loaderData->netCls_set = 1;
+        }
+        else if (!strcasecmp(argv[i], "ks") || !strncasecmp(argv[i], "ks=", 3))
+            loaderData->ksFile = strdup(argv[i]);
+        else if (!strncasecmp(argv[i], "display=", 8))
+            setenv("DISPLAY", argv[i] + 8, 1);
+        else if ((!strncasecmp(argv[i], "lang=", 5)) && 
+                 (strlen(argv[i]) > 5))  {
+            loaderData->lang = strdup(argv[i] + 5);
+            loaderData->lang_set = 1;
+        }
+        else if (!strncasecmp(argv[i], "keymap=", 7) &&
+                   (strlen(argv[i]) > 7)) {
+            loaderData->kbd = strdup(argv[i] + 7);
+            loaderData->kbd_set = 1;
+        }
+        else if (!strncasecmp(argv[i], "method=", 7)) {
+            logMessage(WARNING, "method= is deprecated.  Please use repo= instead.");
+            loaderData->instRepo = strdup(argv[i] + 7);
+        }
+        else if (!strncasecmp(argv[i], "repo=", 5))
+            loaderData->instRepo = strdup(argv[i] + 5);
+        else if (!strncasecmp(argv[i], "stage2=", 7))
+            setStage2LocFromCmdline(argv[i] + 7, loaderData);
+        else if (!strncasecmp(argv[i], "hostname=", 9))
+            loaderData->hostname = strdup(argv[i] + 9);
+        else if (!strncasecmp(argv[i], "ip=", 3))
+            parseCmdLineIp(loaderData, argv[i]);
+#ifdef ENABLE_IPV6
+        else if (!strncasecmp(argv[i], "ipv6=", 5))
+            parseCmdLineIpv6(loaderData, argv[i]);
+#endif
+        else if (!strncasecmp(argv[i], "netmask=", 8))
+            loaderData->netmask = strdup(argv[i] + 8);
+        else if (!strncasecmp(argv[i], "gateway=", 8))
+            loaderData->gateway = strdup(argv[i] + 8);
+        else if (!strncasecmp(argv[i], "dns=", 4))
+            loaderData->dns = strdup(argv[i] + 4);
+        else if (!strncasecmp(argv[i], "ethtool=", 8))
+            loaderData->ethtool = strdup(argv[i] + 8);
+        else if (!strncasecmp(argv[i], "essid=", 6))
+            loaderData->essid = strdup(argv[i] + 6);
+        else if (!strncasecmp(argv[i], "mtu=", 4))
+            loaderData->mtu = argToLong(argv[i], 4);
+        else if (!strncasecmp(argv[i], "wepkey=", 7))
+            loaderData->wepkey = strdup(argv[i] + 7);
+        else if (!strncasecmp(argv[i], "linksleep=", 10))
+            num_link_checks = argToLong(argv[i], 10);
+        else if (!strncasecmp(argv[i], "nicdelay=", 9))
+            post_link_sleep = argToLong(argv[i], 9);
+        else if (!strncasecmp(argv[i], "dhcptimeout=", 12))
+            loaderData->dhcpTimeout = argToLong(argv[i], 12);
+        else if (!strncasecmp(argv[i], "selinux=0", 9))
+            flags &= ~LOADER_FLAGS_SELINUX;
+        else if (!strncasecmp(argv[i], "selinux", 7))
+            flags |= LOADER_FLAGS_SELINUX;
+        else if (!strncasecmp(argv[i], "gdb=", 4))
+            loaderData->gdbServer = strdup(argv[i] + 4);
+        else if (!strncasecmp(argv[i], "proxy=", 6))
+            splitProxyParam(argv[i]+6, &loaderData->proxyUser,
+                            &loaderData->proxyPassword, &loaderData->proxy);
+        else if (numExtraArgs < (MAX_EXTRA_ARGS - 1)) {
+            /* go through and append args we just want to pass on to */
+            /* the anaconda script, but don't want to represent as a */
+            /* LOADER_FLAGS_XXX since loader doesn't care about these */
+            /* particular options.                                   */
+            /* do vncpassword case first */
+            if (!strncasecmp(argv[i], "vncpassword=", 12)) {
+                writeVNCPasswordFile("/tmp/vncpassword.dat", argv[i]+12);
+            }
+            else if (!strncasecmp(argv[i], "resolution=", 11) ||
+                     !strncasecmp(argv[i], "nomount", 7) ||
+                     !strncasecmp(argv[i], "vnc", 3) ||
+                     !strncasecmp(argv[i], "vncconnect=", 11) ||
+                     !strncasecmp(argv[i], "headless", 8) ||
+                     !strncasecmp(argv[i], "usefbx", 6) ||
+                     !strncasecmp(argv[i], "mpath", 6) ||
+                     !strncasecmp(argv[i], "nompath", 8) ||
+                     !strncasecmp(argv[i], "dmraid", 6) ||
+                     !strncasecmp(argv[i], "nodmraid", 8) ||
+                     !strncasecmp(argv[i], "xdriver=", 8) ||
+                     !strncasecmp(argv[i], "vesa", 4) ||
+                     !strncasecmp(argv[i], "syslog=", 7)) { 
+
+                /* vnc implies graphical */
+                if (!strncasecmp(argv[i], "vnc", 3)) {
+                    logMessage(INFO, "vnc forced graphical mode from cmdline");
+                    flags |= LOADER_FLAGS_GRAPHICAL;
+                }
+
+                /* the following things require networking to be configured
+                 * by loader, so an active connection is ready once we get
+                 * to anaconda
+                 */
+                if (!strncasecmp(argv[i], "syslog", 6) ||
+                    !strncasecmp(argv[i], "vnc", 3)) {
+                    logMessage(INFO, "early networking required for %s",
+                               argv[i]);
+                    flags |= LOADER_FLAGS_EARLY_NETWORKING;
+                }
+                if (isKickstartFileRemote(loaderData->ksFile)) {
+                    logMessage(INFO, "early networking required for remote kickstart configuration");
+                    flags |= LOADER_FLAGS_EARLY_NETWORKING;
+                }
+
+                if (!strncasecmp(argv[i], "vesa", 4)) {
+                    checked_asprintf(&extraArgs[numExtraArgs],
+                                     "--xdriver=vesa");
+
+                    logMessage(WARNING, "\"vesa\" command line argument is deprecated.  use \"xdriver=vesa\".");
+                } else {
+                    checked_asprintf(&extraArgs[numExtraArgs],"--%s",
+                                     argv[i]);
+                }
+
+                numExtraArgs += 1;
+
+                if (numExtraArgs > (MAX_EXTRA_ARGS - 2)) {
+                     logMessage(WARNING, "Too many command line arguments (max "
+                                "allowed is %d), rest will be dropped.",
+                                MAX_EXTRA_ARGS);
+                }
+            }
+        }
+    }
+
+    readNetInfo(&loaderData);
+
+    /* NULL terminates the array of extra args */
+    extraArgs[numExtraArgs] = NULL;
+
+    return;
+}
+
+/* make sure they have enough ram */
+static void checkForRam(void) {
+    if (totalMemory() < MIN_RAM) {
+        char *buf;
+
+        checked_asprintf(&buf, _("You do not have enough RAM to install %s "
+                                 "on this machine."), getProductName());
+
+        startNewt();
+        newtWinMessage(_("Error"), _("OK"), buf);
+        free(buf);
+        stopNewt();
+        doExit(0);
+    }
+}
+
+static int haveDeviceOfType(int type) {
+    struct device ** devices;
+
+    devices = getDevices(type);
+    if (devices) {
+        return 1;
+    }
+    return 0;
+}
+
+static char *doLoaderMain(struct loaderData_s *loaderData,
+                          moduleInfoSet modInfo) {
+    enum { STEP_LANG, STEP_KBD, STEP_METHOD, STEP_DRIVER,
+           STEP_DRIVERDISK, STEP_NETWORK, STEP_IFACE,
+           STEP_IP, STEP_STAGE2, STEP_DONE } step;
+
+    char *url = NULL, *ret = NULL, *devName = NULL, *kbdtype = NULL;
+    static iface_t iface;
+    int i, rc = LOADER_NOOP, dir = 1;
+    int needsNetwork = 0, class = -1;
+    int skipMethodDialog = 0, skipLangKbd = 0;
+
+    char *installNames[10];
+    int numValidMethods = 0;
+    int validMethods[10];
+
+    for (i = 0; i < numMethods; i++, numValidMethods++) {
+        installNames[numValidMethods] = installMethods[i].name;
+        validMethods[numValidMethods] = i;
+    }
+    installNames[numValidMethods] = NULL;
+
+    /* Before anything else, see if there's a CD/DVD with a stage2 image on
+     * it.  However if stage2= was given, use that value as an override here.
+     * That will also then bypass any method selection UI in loader.
+     */
+    if (!FL_ASKMETHOD(flags)) {
+        url = findAnacondaCD("/mnt/stage2");
+        if (url) {
+            setStage2LocFromCmdline(url, loaderData);
+            skipMethodDialog = 1;
+
+            logMessage(INFO, "Detected stage 2 image on CD (url: %s)", url);
+            winStatus(50, 3, _("Media Detected"),
+                      _("Found local installation media"), 0);
+            sleep(3);
+            newtPopWindow();
+
+            skipLangKbd = 1;
+            flags |= LOADER_FLAGS_NOPASS;
+        } else if (!loaderData->stage2Data && loaderData->instRepo) {
+            /* If no CD/DVD with a stage2 image was found and we were given a
+             * repo=/method= parameter, try to piece together a valid setting
+             * for the stage2= parameter based on that.
+             */
+            char *tmp;
+
+            checked_asprintf(&tmp, "%s/images/install.img",
+                             loaderData->instRepo);
+
+            logMessage(INFO, "no stage2= given, assuming %s", tmp);
+            setStage2LocFromCmdline(tmp, loaderData);
+            free(tmp);
+
+            /* If we had to infer a stage2= location, but the repo= parameter
+             * we based this guess on was wrong, we need to correct the typo
+             * in both places.  Unfortunately we can't really know what the
+             * user meant, so the best we can do is take the results of
+             * running stage2= through the UI and chop off any /images/whatever
+             * path that's at the end of it.
+             */
+            loaderData->inferredStage2 = 1;
+            if (loaderData->method != -1) {
+                skipMethodDialog = 1;
+            }
+        } else if (loaderData->stage2Data) {
+            skipMethodDialog = 1;
+        }
+    } else {
+        /* Needed because they have already been set when parsing cmdline.
+         * (Leaks a little.)
+         */
+        loaderData->method = -1;
+        loaderData->stage2Data = NULL;
+    }
+
+    i = 0;
+    step = STEP_LANG;
+
+    while (step != STEP_DONE) {
+        switch(step) {
+            case STEP_LANG: {
+                if (loaderData->lang && (loaderData->lang_set == 1))
+                    setLanguage(loaderData->lang, 1);
+                else if (FL_RESCUE(flags) || !skipLangKbd)
+                    chooseLanguage(&loaderData->lang);
+
+                step = STEP_KBD;
+                dir = 1;
+                break;
+            }
+
+            case STEP_KBD: {
+                if (loaderData->kbd && (loaderData->kbd_set == 1)) {
+                    /* JKFIXME: this is broken -- we should tell of the 
+                     * failure; best by pulling code out in kbd.c to use */
+                    if (isysLoadKeymap(loaderData->kbd)) {
+                        logMessage(WARNING, "requested keymap %s is not valid, asking",
+                                   loaderData->kbd);
+                        loaderData->kbd = NULL;
+                        loaderData->kbd_set = 0;
+                        break;
+                    }
+                    rc = LOADER_NOOP;
+                } else if (FL_RESCUE(flags) || !skipLangKbd) {
+                    /* JKFIXME: should handle kbdtype, too probably... but it 
+                     * just matters for sparc */
+                    if (!FL_CMDLINE(flags))
+                        rc = chooseKeyboard(loaderData, &kbdtype);
+                    else
+                       rc = LOADER_NOOP;
+                } else {
+                    step = STEP_METHOD;
+                    dir = 1;
+                }
+
+                if (rc == LOADER_NOOP) {
+                    if (dir == -1)
+                        step = STEP_LANG;
+                    else
+                        step = STEP_METHOD;
+
+                    break;
+                }
+
+                if (rc == LOADER_BACK) {
+                    step = STEP_LANG;
+                    dir = -1;
+                } else {
+                    step = STEP_METHOD;
+                    dir = 1;
+                }
+
+                break;
+            }
+
+            case STEP_METHOD: {
+                if (loaderData->method != -1)
+                    skipMethodDialog = 1;
+                else if (FL_CMDLINE(flags)) {
+                    fprintf(stderr, "No method given for cmdline mode, aborting\n");
+                    doExit(EXIT_FAILURE);
+                }
+
+                /* If we already found a stage2 image, skip the prompt. */
+                if (skipMethodDialog) {
+                    if (dir == 1)
+                        rc = 1;
+                    else
+                        rc = -1;
+                } else {
+                    /* we need to set these each time through so that we get
+                     * updated for language changes (#83672) */
+                    for (i = 0; i < numMethods; i++) {
+                        installNames[i] = _(installMethods[i].name);
+                    }
+                    installNames[i] = NULL;
+
+                    rc = newtWinMenu(FL_RESCUE(flags) ? _("Rescue Method") :
+                                     _("Installation Method"),
+                                     FL_RESCUE(flags) ?
+                                     _("What type of media contains the rescue "
+                                       "image?") :
+                                     _("What type of media contains the installation "
+                                       "image?"),
+                                     30, 10, 20, 6, installNames, &loaderData->method,
+                                     _("OK"), _("Back"), NULL);
+                    if (rc == 2) {
+                        loaderData->method = -1;
+                    }
+                }
+
+                if (rc && (rc != 1)) {
+                    step = STEP_KBD;
+                    dir = -1;
+                } else {
+                    class = installMethods[validMethods[loaderData->method]].type;
+                    step = STEP_DRIVER;
+                    dir = 1;
+                }
+                break;
+            }
+
+            case STEP_DRIVER: {
+                if ((FL_EARLY_NETWORKING(flags) && haveDeviceOfType(DEVICE_NETWORK)) ||
+                    (class == -1 || haveDeviceOfType(class))) {
+                    step = STEP_NETWORK;
+                    dir = 1;
+                    class = -1;
+                    break;
+                }
+
+                if (skipLangKbd) {
+                    skipLangKbd = 0;
+                    step = STEP_KBD;
+                    break;
+                }
+
+                rc = newtWinTernary(_("No driver found"), _("Select driver"),
+                                    _("Use a driver disk"), _("Back"),
+                                    _("Unable to find any devices of the type "
+                                      "needed for this installation type.  "
+                                      "Would you like to manually select your "
+                                      "driver or use a driver disk?"));
+                if (rc == 2) {
+                    step = STEP_DRIVERDISK;
+                    dir = 1;
+                    break;
+                } else if (rc == 3) {
+                    step = STEP_METHOD;
+                    loaderData->method = -1;
+                    dir = -1;
+                    break;
+                }
+
+                chooseManualDriver(installMethods[validMethods[loaderData->method]].type,
+                                   loaderData);
+                /* it doesn't really matter what we return here; we just want
+                 * to reprobe and make sure we have the driver */
+                step = STEP_DRIVER;
+                break;
+            }
+
+            case STEP_DRIVERDISK: {
+                if (skipLangKbd) {
+                    skipLangKbd = 0;
+                    step = STEP_KBD;
+                    break;
+                }
+
+                rc = loadDriverFromMedia(class, loaderData, 0, 0, NULL);
+                if (rc == LOADER_BACK) {
+                    step = STEP_DRIVER;
+                    dir = -1;
+                    break;
+                }
+
+                /* need to come back to driver so that we can ensure that we found
+                 * the right kind of driver after loading the driver disk */
+                step = STEP_DRIVER;
+                break;
+            }
+
+            case STEP_NETWORK: {
+                if (((installMethods[validMethods[loaderData->method]].type !=
+                       DEVICE_NETWORK) && (!hasGraphicalOverride()) &&
+                      !FL_ASKNETWORK(flags) &&
+                      !FL_EARLY_NETWORKING(flags)) ||
+                     (is_nm_connected())) {
+                    needsNetwork = 0;
+                    if (dir == 1) 
+                        step = STEP_STAGE2;
+                    else if (dir == -1)
+                        step = STEP_METHOD;
+                    break;
+                }
+
+                needsNetwork = 1;
+                if (!haveDeviceOfType(DEVICE_NETWORK)) {
+                    class = DEVICE_NETWORK;
+                    step = STEP_DRIVER;
+                    break;
+                }
+                logMessage(INFO, "need to set up networking");
+
+                memset(&iface, 0, sizeof(iface));
+
+                /* fall through to interface selection */
+            }
+
+            case STEP_IFACE: {
+                logMessage(INFO, "going to pick interface");
+
+                /* skip configureTCPIP() screen for kickstart (#260621) */
+                if (loaderData->ksFile)
+                    flags |= LOADER_FLAGS_IS_KICKSTART;
+
+                if (FL_HAVE_CMSCONF(flags)) {
+                    loaderData->ipinfo_set = 1;
+#ifdef ENABLE_IPV6
+                    loaderData->ipv6info_set = 1;
+#endif
+                }
+
+                rc = chooseNetworkInterface(loaderData);
+                if ((rc == LOADER_BACK) || (rc == LOADER_ERROR) ||
+                    ((dir == -1) && (rc == LOADER_NOOP))) {
+                    /* don't skip method dialog iff we don't have url from ks or boot params */
+                    if (!loaderData->stage2Data) {
+                        loaderData->method = -1;
+                    }
+                    step = STEP_METHOD;
+                    dir = -1;
+                    break;
+                }
+
+                devName = loaderData->netDev;
+                strcpy(iface.device, devName);
+
+                /* continue to ip config */
+                step = STEP_IP;
+                dir = 1;
+                break;
+            }
+
+            case STEP_IP: {
+                if (!needsNetwork || dir == -1) {
+                    step = STEP_METHOD; /* only hit going back */
+                    break;
+                }
+
+                if ((ret = malloc(INET6_ADDRSTRLEN+1)) == NULL) {
+                    logMessage(ERROR, "malloc failure for ret in STEP_IP");
+                    doExit(EXIT_FAILURE);
+                }
+
+                logMessage(INFO, "going to do getNetConfig");
+
+                /* s390 provides all config info by way of the CMS conf file */
+                if (FL_HAVE_CMSCONF(flags)) {
+                    loaderData->ipinfo_set = 1;
+#ifdef ENABLE_IPV6
+                    loaderData->ipv6info_set = 1;
+#endif
+                }
+
+                /* populate netDev based on any kickstart data */
+                setupIfaceStruct(&iface, loaderData);
+                rc = readNetConfig(devName, &iface, loaderData->netCls, loaderData->method);
+
+                /* set the hostname if we have that */
+                if (loaderData->hostname) {
+                    if (sethostname(loaderData->hostname,
+                                    strlen(loaderData->hostname))) {
+                        logMessage(ERROR, "error setting hostname to %s",
+                                   loaderData->hostname);
+                    }
+                }
+
+                free(ret);
+                ret = NULL;
+
+                if ((rc == LOADER_BACK) ||
+                    ((dir == -1) && (rc == LOADER_NOOP))) {
+                    needsNetwork = 1;
+                    step = STEP_IFACE;
+                    dir = -1;
+                    break;
+                }
+                /* retry */
+                if (rc == LOADER_ERROR) {
+                    needsNetwork = 1;
+                    break;
+                }
+
+                writeEnabledNetInfo(&iface);
+                step = STEP_STAGE2;
+                dir = 1;
+                break;
+            }
+
+            case STEP_STAGE2: {
+                if (url) {
+                    logMessage(INFO, "stage2 url is %s", url);
+                    return url;
+                }
+
+                logMessage(INFO, "starting STEP_STAGE2");
+                url = installMethods[validMethods[loaderData->method]].mountImage(
+                                          installMethods + validMethods[loaderData->method],
+                                          "/mnt/stage2", loaderData);
+                if (!url) {
+                    step = STEP_IP;
+                    loaderData->ipinfo_set = 0;
+#ifdef ENABLE_IPV6
+                    loaderData->ipv6info_set = 0;
+#endif
+                    loaderData->method = -1;
+                    skipMethodDialog = 0;
+                    dir = -1;
+                } else {
+                    logMessage(INFO, "got stage2 at url %s", url);
+                    step = STEP_DONE;
+                    dir = 1;
+
+                    if (loaderData->invalidRepoParam) {
+                        char *newInstRepo;
+
+                        /* Doesn't contain /images?  Let's not even try. */
+                        if (strstr(url, "/images") == NULL)
+                            break;
+                        
+                        checked_asprintf(&newInstRepo, "%.*s",
+                                         (int) (strstr(url, "/images")-url), url);
+
+                        free(loaderData->instRepo);
+                        loaderData->instRepo = newInstRepo;
+                        logMessage(INFO, "reset repo= parameter to %s",
+                                   loaderData->instRepo);
+                    }
+                }
+
+                break;
+            }
+
+            case STEP_DONE:
+                break;
+        }
+    }
+
+    return url;
+}
+static int manualDeviceCheck(struct loaderData_s *loaderData) {
+    char ** devices;
+    int i, j, rc, num = 0;
+    unsigned int width = 40;
+    char * buf;
+
+    do {
+        /* FIXME */
+        devices = malloc(1 * sizeof(*devices));
+        j = 0;
+        devices[j] = NULL;
+
+        if (width > 70)
+            width = 70;
+
+        if (j > 0) {
+            buf = _("The following devices have been found on your system.");
+        } else {
+            buf = _("No device drivers have been loaded for your system.  "
+                    "Would you like to load any now?");
+        }
+
+        rc = newtWinMenu(_("Devices"), buf, width, 10, 20, 
+                         (j > 6) ? 6 : j, devices, &num, _("Done"), 
+                         _("Add Device"), NULL);
+
+        /* no leaky */
+        for (i = 0; i < j; i++)
+            free(devices[j]);
+        free(devices);
+
+        if (rc != 2)
+            break;
+
+        chooseManualDriver(DEVICE_ANY, loaderData);
+    } while (1);
+    return 0;
+}
+
+/* JKFIXME: I don't really like this, but at least it isolates the ifdefs */
+/* Either move dirname to %s_old or unlink depending on arch (unlink on all
+ * !s390{,x} arches).  symlink to /mnt/runtime/dirname.  dirname *MUST* start
+ * with a '/' */
+static void migrate_runtime_directory(char * dirname) {
+    char * runtimedir;
+    int ret;
+
+    checked_asprintf(&runtimedir, "/mnt/runtime%s", dirname);
+
+    if (!access(runtimedir, X_OK)) {
+        if (unlink(dirname) == -1) {
+            char * olddir;
+            
+            checked_asprintf(&olddir, "%s_old", dirname);
+
+            ret = rename(dirname, olddir);
+            free(olddir);
+        }
+        ret = symlink(runtimedir, dirname);
+    }
+    free(runtimedir);
+}
+
+
+static int hasGraphicalOverride() {
+    int i;
+
+    if (getenv("DISPLAY"))
+        return 1;
+
+    for (i = 0; extraArgs[i] != NULL; i++) {
+        if (!strncasecmp(extraArgs[i], "--vnc", 5))
+            return 1;
+    }
+    return 0;
+}
+
+void loaderSegvHandler(int signum) {
+    void *array[30];
+    size_t i;
+    const char const * const errmsgs[] = {
+        "loader received SIG",
+        "!  Backtrace:\n",
+        "Loader exited unexpectedly!  Backtrace:\n",
+    };
+
+    /* XXX This should really be in a glibc header somewhere... */
+    extern const char *const sys_sigabbrev[NSIG];
+
+    signal(signum, SIG_DFL); /* back to default */
+
+    newtFinished();
+    if (signum == 0) {
+        i = write(STDERR_FILENO, errmsgs[2], strlen(errmsgs[2]));
+    } else {
+        i = write(STDERR_FILENO, errmsgs[0], strlen(errmsgs[0]));
+        i = write(STDERR_FILENO, sys_sigabbrev[signum],
+                strlen(sys_sigabbrev[signum]));
+        i = write(STDERR_FILENO, errmsgs[1], strlen(errmsgs[1]));
+    }
+
+    i = backtrace (array, 30);
+    backtrace_symbols_fd(array, i, STDERR_FILENO);
+    _exit(1);
+}
+
+void loaderExitHandler(void)
+{
+    if (expected_exit)
+        return;
+
+    loaderSegvHandler(0);    
+}
+
+static void setupBacktrace(void)
+{
+    void *array;
+
+    signal(SIGSEGV, loaderSegvHandler);
+    signal(SIGABRT, loaderSegvHandler);
+    atexit(loaderExitHandler);
+
+    /* Turns out, there's an initializer at the top of backtrace() that
+     * (on some arches) calls dlopen(). dlopen(), unsurprisingly, calls
+     * malloc(). So, call backtrace() early in signal handler setup so
+     * we can later safely call it from the signal handler itself. */
+    backtrace(&array, 1);
+}
+
+void loaderUsrXHandler(int signum) {
+    logMessage(INFO, "Remembering signal %d\n", signum);
+    init_sig = signum;
+}
+
+static int anaconda_trace_init(void) {
+#ifdef USE_MTRACE
+    setenv("MALLOC_TRACE","/malloc",1);
+    mtrace();
+#endif
+    /* We have to do this before we init bogl(), which doLoaderMain will do
+     * when setting fonts for different languages.  It's also best if this
+     * is well before we might take a SEGV, so they'll go to tty8 */
+    initializeTtys();
+
+    /* set up signal handler */
+    setupBacktrace();
+
+    return 0;
+}
+
+static void add_to_path_env(const char *env, const char *val)
+{
+    char *oldenv, *newenv;
+
+    oldenv = getenv(env);
+    if (oldenv) {
+        checked_asprintf(&newenv, "%s:%s", val, oldenv);
+
+        oldenv = strdupa(newenv);
+        free(newenv);
+        newenv = oldenv;
+    } else {
+        newenv = strdupa(val);
+    }
+
+    setenv(env, newenv, 1);
+}
+
+static void loadScsiDhModules(void)
+{
+    struct utsname utsname;
+    char *modules = NULL;
+    char *tmp = NULL;
+    struct dirent *ent = NULL;
+
+    uname(&utsname);
+    checked_asprintf(&tmp,
+        "/lib/modules/%s/kernel/drivers/scsi/device_handler", utsname.release);
+
+    DIR *dir = opendir(tmp);
+    free(tmp);
+    if (!dir)
+        return;
+
+    int fd = dirfd(dir);
+    while ((ent = readdir(dir)) != NULL) {
+        struct stat sb;
+
+        if (fstatat(fd, ent->d_name, &sb, 0) < 0)
+            continue;
+
+        size_t len = strlen(ent->d_name) - 3;
+        if (strcmp(ent->d_name+len, ".ko"))
+            continue;
+
+        if (S_ISREG(sb.st_mode)) {
+            char modname[len+1];
+            strncpy(modname, ent->d_name, len);
+	    modname[len] = '\0';
+
+            if (modules && modules[0]) {
+                checked_asprintf(&tmp, "%s:%s", modules, modname);
+            } else {
+                checked_asprintf(&tmp, "%s", modname);
+            }
+
+            free(modules);
+            modules = tmp;
+        }
+    }
+    closedir(dir);
+
+    mlLoadModuleSet(modules);
+    free(modules);
+}
+
+int main(int argc, char ** argv) {
+    int rc, ret, pid, status;
+
+    struct stat sb;
+    struct serial_struct si;
+    char * arg;
+    FILE *f;
+
+    char twelve = 12;
+
+    moduleInfoSet modInfo;
+    iface_t iface;
+
+    char *url = NULL;
+
+    char ** argptr, ** tmparg;
+    char * anacondaArgs[50];
+
+    struct loaderData_s loaderData;
+
+    char *path, *fmt;
+    GSList *dd, *dditer;
+    GTree *moduleState;
+
+    gchar *cmdLine = NULL, *ksFile = NULL, *virtpcon = NULL;
+    gboolean mediacheck = FALSE;
+    gchar **remaining = NULL;
+    GOptionContext *optCon = g_option_context_new(NULL);
+    GError *optErr = NULL;
+    GOptionEntry optionTable[] = {
+        { "cmdline", 0, 0, G_OPTION_ARG_STRING, &cmdLine, NULL, NULL },
+        { "ksfile", 0, 0, G_OPTION_ARG_STRING, &ksFile, NULL, NULL },
+        { "mediacheck", 0, 0, G_OPTION_ARG_NONE, &mediacheck, NULL, NULL },
+        { "virtpconsole", 0, 0, G_OPTION_ARG_STRING, &virtpcon, NULL, NULL },
+        { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &remaining,
+          NULL, NULL },
+        { NULL },
+    };
+
+    /* get init PID if we have it */
+    if ((f = fopen("/var/run/init.pid", "r")) != NULL) {
+        char linebuf[256];
+
+        while (fgets(linebuf, sizeof(linebuf), f) != NULL) {
+            errno = 0;
+            init_pid = strtol(linebuf, NULL, 10);
+            if (errno == EINVAL || errno == ERANGE) {
+                logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+                init_pid = 1;
+            }
+        }
+
+        fclose(f);
+    }
+
+    signal(SIGUSR1, loaderUsrXHandler);
+    signal(SIGUSR2, loaderUsrXHandler);
+
+    /* Make sure sort order is right. */
+    setenv ("LC_COLLATE", "C", 1);	
+
+    /* Very first thing, set up tracebacks and debug features. */
+    rc = anaconda_trace_init();
+
+    /* now we parse command line options */
+    g_option_context_set_help_enabled(optCon, FALSE);
+    g_option_context_add_main_entries(optCon, optionTable, NULL);
+
+    if (!g_option_context_parse(optCon, &argc, &argv, &optErr)) {
+        fprintf(stderr, "bad option: %s\n", optErr->message);
+        g_error_free(optErr);
+        g_option_context_free(optCon);
+        doExit(1);
+    }
+
+    g_option_context_free(optCon);
+
+    if (remaining) {
+        fprintf(stderr, "unexpected argument: %s\n", remaining[0]);
+        g_strfreev(remaining);
+        doExit(1);
+    }
+
+    g_strfreev(remaining);
+
+    if (!access("/var/run/loader.run", R_OK)) {
+        printf(_("loader has already been run.  Starting shell.\n"));
+        execl("/bin/sh", "-/bin/sh", NULL);
+        doExit(0);
+    }
+
+    f = fopen("/var/run/loader.run", "w+");
+    fprintf(f, "%d\n", getpid());
+    fclose(f);
+
+    /* The fstat checks disallows serial console if we're running through
+       a pty. This is handy for Japanese. */
+    fstat(0, &sb);
+    if (major(sb.st_rdev) != 3 && major(sb.st_rdev) != 136 && 
+        (virtpcon == NULL)){
+        if ((ioctl (0, TIOCLINUX, &twelve) < 0) && 
+            (ioctl(0, TIOCGSERIAL, &si) != -1))
+            flags |= LOADER_FLAGS_SERIAL;
+    }
+
+    if (mediacheck) flags |= LOADER_FLAGS_MEDIACHECK;
+    if (ksFile) flags |= LOADER_FLAGS_KICKSTART;
+    if (virtpcon) flags |= LOADER_FLAGS_VIRTPCONSOLE;
+
+    /* uncomment to send mac address in ks=http:/ header by default*/
+    flags |= LOADER_FLAGS_KICKSTART_SEND_MAC;
+
+    /* JKFIXME: I do NOT like this... it also looks kind of bogus */
+#if defined(__s390__) || defined(__s390x__)
+    flags |= LOADER_FLAGS_NOSHELL;
+#endif
+
+    openLog();
+    
+    /* XXX if RHEL, enable the AUTODD feature by default,
+     * but we should come with more general way how to control this */
+    if (!strncmp(getProductName(), "Red Hat", 7)) {
+        flags |= LOADER_FLAGS_AUTOMODDISK;
+    }
+
+    memset(&loaderData, 0, sizeof(loaderData));
+    loaderData.method = -1;
+    loaderData.fw_loader_pid = -1;
+    loaderData.fw_search_pathz_len = -1;
+    loaderData.dhcpTimeout = -1;
+
+    extraArgs[0] = NULL;
+    parseCmdLineFlags(&loaderData, cmdLine);
+
+    logMessage(INFO, "anaconda version %s on %s starting", VERSION, getProductArch());
+
+    if ((FL_SERIAL(flags) || FL_VIRTPCONSOLE(flags)) && 
+        !hasGraphicalOverride()) {
+        logMessage(INFO, "text mode forced due to serial/virtpconsole");
+        flags |= LOADER_FLAGS_TEXT;
+    }
+    set_fw_search_path(&loaderData, "/firmware:/lib/firmware");
+    start_fw_loader(&loaderData);
+
+    arg = "/lib/modules/module-info";
+    modInfo = newModuleInfoSet();
+    if (readModuleInfo(arg, modInfo, NULL, 0)) {
+        fprintf(stderr, "failed to read %s\n", arg);
+        sleep(5);
+        stop_fw_loader(&loaderData);
+        doExit(1);
+    }
+    initializeConsole();
+
+    checkForRam();
+
+    /* iSeries vio console users will be ssh'ing in to the primary
+       partition, so use a terminal type that is appripriate */
+    if (isVioConsole())
+        setenv("TERM", "vt100", 1);
+
+    mlLoadModuleSet("cramfs:squashfs:iscsi_tcp");
+
+    loadScsiDhModules();
+
+#if !defined(__s390__) && !defined(__s390x__)
+    mlLoadModuleSet("floppy:edd:pcspkr:iscsi_ibft");
+#endif
+
+#ifdef ENABLE_IPV6
+    if (!FL_NOIPV6(flags))
+        mlLoadModule("ipv6", NULL);
+#endif
+
+    /* now let's do some initial hardware-type setup */
+#if defined(__powerpc__)
+    mlLoadModule("spufs", NULL);
+#endif
+
+    if (loaderData.lang && (loaderData.lang_set == 1)) {
+        setLanguage(loaderData.lang, 1);
+    }
+
+    /* FIXME: this is a bit of a hack */
+    loaderData.modInfo = modInfo;
+
+    /* If there is /.rundepmod file present, rerun depmod */
+    if (!access("/.rundepmod", R_OK)){
+        if (system("depmod -a")) {
+            /* this is not really fatal error, it might still work, log it */
+            logMessage(ERROR, "Error running depmod -a for initrd overlay");
+        }
+    }
+
+    /* this allows us to do an early load of modules specified on the
+     * command line to allow automating the load order of modules so that
+     * eg, certain scsi controllers are definitely first.
+     * FIXME: this syntax is likely to change in a future release
+     *        but is done as a quick hack for the present.
+     */
+    if (!mlInitModuleConfig()) {
+        logMessage(ERROR, "unable to initialize kernel module loading");
+        abort();
+    }
+
+    earlyModuleLoad(0);
+
+    /* Save list of preloaded modules so we can restore the state */
+    moduleState = mlSaveModuleState();
+
+    /* Load all known devices */
+    busProbe(FL_NOPROBE(flags));
+
+    if (FL_AUTOMODDISK(flags)) {
+        /* Load all autodetected DDs */
+        logMessage(INFO, "Trying to detect vendor driver discs");
+        dd = findDriverDiskByLabel();
+        dditer = dd;
+        while(dditer) {
+            /* load the DD */
+            if (loadDriverDiskFromPartition(&loaderData, (char*)(dditer->data))) {
+                logMessage(ERROR, "Automatic driver disk loader failed for %s.", (char*)(dditer->data));
+            }
+            else {
+                logMessage(INFO, "Automatic driver disk loader succeeded for %s.", (char*)(dditer->data));
+
+                /* Unload all devices and load them again to use the updated modules */
+                mlRestoreModuleState(moduleState);
+                busProbe(0);
+            }
+            
+            /* clean the device record */
+            free((char*)(dditer->data));
+            dditer->data = NULL;
+
+            /* next DD */
+            dditer = g_slist_next(dditer);
+        }
+        g_slist_free(dd);
+    }
+
+    if (FL_MODDISK(flags)) {
+        startNewt();
+        loadDriverDisks(DEVICE_ANY, &loaderData, moduleState);
+    }
+
+    if (!access("/dd.img", R_OK)) {
+        logMessage(INFO, "found /dd.img, loading drivers");
+        getDDFromSource(&loaderData, "path:/dd.img", moduleState);
+    }
+    
+    /* Reset depmod & modprobe to normal mode and get the rest of drivers*/
+    mlFreeModuleState(moduleState);
+    busProbe(FL_NOPROBE(flags));
+
+    /* Disable all network interfaces in NetworkManager by default */
+#if !defined(__s390__) && !defined(__s390x__)
+    int i;
+
+    if ((i = writeDisabledNetInfo()) != 0) {
+        logMessage(ERROR, "writeDisabledNetInfo failure: %d", i);
+    }
+#endif
+
+    /* Start NetworkManager now so it's always available to talk to. */
+    if (iface_start_NetworkManager())
+        logMessage(INFO, "failed to start NetworkManager");
+
+    if (!FL_CMDLINE(flags))
+        startNewt();
+
+    /* can't run gdbserver until after network modules are loaded */
+    doGdbserver(&loaderData);
+
+    /* JKFIXME: we'd really like to do this before the busprobe, but then
+     * we won't have network devices available (and that's the only thing
+     * we support with this right now */
+    if (loaderData.ddsrc != NULL) {
+        getDDFromSource(&loaderData, loaderData.ddsrc, NULL);
+    }
+
+    /* JKFIXME: loaderData->ksFile is set to the arg from the command line,
+     * and then getKickstartFile() changes it and sets FL_KICKSTART.  
+     * kind of weird. */
+    if (loaderData.ksFile || ksFile) {
+        logMessage(INFO, "getting kickstart file");
+
+        if (!ksFile)
+            getKickstartFile(&loaderData);
+        if (FL_KICKSTART(flags) && 
+            (ksReadCommands((ksFile)?ksFile:loaderData.ksFile)!=LOADER_ERROR)) {
+            runKickstart(&loaderData);
+        }
+    }
+
+    if (FL_EARLY_NETWORKING(flags)) {
+        kickstartNetworkUp(&loaderData, &iface);
+    }
+
+    if (FL_TELNETD(flags))
+        startTelnetd(&loaderData);
+
+    url = doLoaderMain(&loaderData, modInfo);
+
+    /* unlink dirs and link to the ones in /mnt/runtime */
+    migrate_runtime_directory("/usr");
+    migrate_runtime_directory("/lib");
+    migrate_runtime_directory("/lib64");
+    ret = symlink("/mnt/runtime/etc/selinux", "/etc/selinux");
+    copyDirectory("/mnt/runtime/etc","/etc", NULL, copyErrorFn);
+    copyDirectory("/mnt/runtime/var","/var", NULL, copyErrorFn);
+
+    /* now load SELinux policy before exec'ing anaconda and the shell
+     * (if we're using SELinux) */
+    if (FL_SELINUX(flags)) {
+        if (mount("/selinux", "/selinux", "selinuxfs", 0, NULL)) {
+            logMessage(ERROR, "failed to mount /selinux: %m, disabling SELinux");
+            flags &= ~LOADER_FLAGS_SELINUX;
+        } else {
+            if (loadpolicy() == 0) {
+                setexeccon(ANACONDA_CONTEXT);
+            } else {
+                logMessage(ERROR, "failed to load policy, disabling SELinux");
+                flags &= ~LOADER_FLAGS_SELINUX;
+            }
+        }
+    }
+
+    logMessage(INFO, "getting ready to spawn shell now");
+
+    spawnShell();  /* we can attach gdb now :-) */
+
+    if (FL_NOPROBE(flags) && !loaderData.ksFile) {
+        startNewt();
+        manualDeviceCheck(&loaderData);
+    }
+
+    if (loaderData.updatessrc)
+        loadUpdatesFromRemote(loaderData.updatessrc, &loaderData);
+    else if (FL_UPDATES(flags))
+        loadUpdates(&loaderData);
+
+    /* make sure /tmp/updates exists so that magic in anaconda to */
+    /* symlink rhpl/ will work                                    */
+    if (access("/tmp/updates", F_OK))
+        mkdirChain("/tmp/updates");
+
+    add_fw_search_dir(&loaderData, "/tmp/updates/firmware");
+    add_fw_search_dir(&loaderData, "/tmp/product/firmware");
+
+    add_to_path_env("PYTHONPATH", "/tmp/updates");
+    add_to_path_env("PYTHONPATH", "/tmp/updates/iw");
+    add_to_path_env("PYTHONPATH", "/tmp/updates/textw");
+    add_to_path_env("PYTHONPATH", "/tmp/product");
+    add_to_path_env("LD_LIBRARY_PATH", "/tmp/updates");
+    add_to_path_env("LD_LIBRARY_PATH", "/tmp/product");
+    add_to_path_env("PATH", "/tmp/updates");
+    add_to_path_env("PATH", "/tmp/product");
+
+    stop_fw_loader(&loaderData);
+    start_fw_loader(&loaderData);
+
+    mlLoadModuleSet("raid0:raid1:raid5:raid6:raid456:raid10:linear:dm-mod:dm-zero:dm-mirror:dm-snapshot:dm-multipath:dm-round-robin:dm-crypt:cbc:sha256:lrw:xts");
+
+    if (!access("/mnt/runtime/usr/lib/libunicode-lite.so.1", R_OK))
+        setenv("LD_PRELOAD", "/mnt/runtime/usr/lib/libunicode-lite.so.1", 1);
+    if (!access("/mnt/runtime/usr/lib64/libunicode-lite.so.1", R_OK))
+        setenv("LD_PRELOAD", "/mnt/runtime/usr/lib64/libunicode-lite.so.1", 1);
+
+    argptr = anacondaArgs;
+
+    path = getenv("PATH");
+    while (path && path[0]) {
+        int n = strcspn(path, ":");
+        char c, *binpath;
+
+        c = path[n];
+        path[n] = '\0';
+        checked_asprintf(&binpath, "%s/anaconda", path);
+        path[n] = c;
+
+        if (!access(binpath, X_OK)) {
+            *argptr++ = strdupa(binpath);
+            free(binpath);
+            break;
+        }
+        free(binpath);
+        path += n + 1;
+    }
+
+    logMessage(INFO, "Running anaconda script %s", *(argptr-1));
+
+    *argptr++ = "--stage2";
+    if (strncmp(url, "ftp:", 4)) {
+        *argptr++ = url;
+    } else {
+        int fd, ret;
+
+        fd = open("/tmp/ftp-stage2", O_CREAT | O_TRUNC | O_RDWR, 0600);
+        ret = write(fd, url, strlen(url));
+        ret = write(fd, "\r", 1);
+        close(fd);
+        *argptr++ = "@/tmp/ftp-stage2";
+    }
+
+    /* add extra args - this potentially munges extraArgs */
+    tmparg = extraArgs;
+    while (*tmparg) {
+        char *idx;
+
+        logMessage(DEBUGLVL, "adding extraArg %s", *tmparg);
+        idx = strchr(*tmparg, '=');
+        if (idx &&  ((idx-*tmparg) < strlen(*tmparg))) {
+            *idx = '\0';
+            *argptr++ = *tmparg;
+            *argptr++ = idx+1;
+        } else {
+            *argptr++ = *tmparg;
+        }
+
+        tmparg++;
+    }
+
+    if (FL_AUTOMODDISK(flags))
+        *argptr++ = "--dlabel";
+
+    if (FL_NOIPV4(flags))
+        *argptr++ = "--noipv4";
+
+#ifdef ENABLE_IPV6
+    if (FL_NOIPV6(flags))
+        *argptr++ = "--noipv6";
+#endif
+
+#if defined(__s390__) || defined(__s390x__)
+    *argptr++ = "--headless";
+#endif
+
+    if (FL_KICKSTART(flags)) {
+        *argptr++ = "--kickstart";
+        *argptr++ = loaderData.ksFile;
+    }
+
+    if (FL_SERIAL(flags))
+        *argptr++ = "--serial";
+
+    if (FL_RESCUE(flags)) {
+        *argptr++ = "--rescue";
+    } else {
+        if (FL_TEXT(flags))
+            *argptr++ = "-T";
+        else if (FL_GRAPHICAL(flags))
+            *argptr++ = "--graphical";
+        if (FL_CMDLINE(flags))
+            *argptr++ = "-C";
+        if (!FL_SELINUX(flags))
+            *argptr++ = "--noselinux";
+        else if (FL_SELINUX(flags))
+            *argptr++ = "--selinux";
+
+        if (FL_VIRTPCONSOLE(flags)) {
+            *argptr++ = "--virtpconsole";
+            *argptr++ = virtpcon;
+        }
+
+        if (loaderData.updatessrc && FL_UPDATES(flags)) {
+            *argptr++ = "--updates";
+            *argptr++ = loaderData.updatessrc;
+        }
+
+        if (loaderData.dogtailurl) {
+            *argptr++ = "--dogtail";
+            *argptr++ = loaderData.dogtailurl;
+        }
+
+        if ((loaderData.lang) && !FL_NOPASS(flags)) {
+            *argptr++ = "--lang";
+            *argptr++ = loaderData.lang;
+        }
+
+        if ((loaderData.kbd) && !FL_NOPASS(flags)) {
+            *argptr++ = "--keymap";
+            *argptr++ = loaderData.kbd;
+        }
+
+        if (loaderData.logLevel) {
+            *argptr++ = "--loglevel";
+            *argptr++ = loaderData.logLevel;
+        }
+
+        if (loaderData.instRepo) {
+           *argptr++ = "--repo";
+            if (strncmp(loaderData.instRepo, "ftp:", 4)) {
+                *argptr++ = loaderData.instRepo;
+            } else {
+                int fd, ret;
+
+                fd = open("/tmp/ftp-repo", O_CREAT | O_TRUNC | O_RDWR, 0600);
+                ret = write(fd, loaderData.instRepo, strlen(loaderData.instRepo));
+                ret = write(fd, "\r", 1);
+                close(fd);
+                *argptr++ = "@/tmp/ftp-repo";
+            }
+        }
+
+        if (loaderData.proxy && strcmp("", loaderData.proxy)) {
+            *argptr++ = "--proxy";
+
+            *argptr++ = strdup(loaderData.proxy);
+
+            if (loaderData.proxyUser && strcmp(loaderData.proxyUser, "")) {
+                int fd, ret;
+
+                fd = open("/tmp/proxy", O_CREAT|O_TRUNC|O_RDWR, 0600);
+                ret = write(fd, loaderData.proxyUser, strlen(loaderData.proxyUser));
+                ret = write(fd, "\r\n", 2);
+
+                if (loaderData.proxyPassword && strcmp(loaderData.proxyPassword, "")) {
+                    ret = write(fd, loaderData.proxyPassword, strlen(loaderData.proxyPassword));
+                    ret = write(fd, "\r\n", 2);
+                }
+
+                close(fd);
+
+                *argptr++ = "--proxyAuth";
+                *argptr++ = "/tmp/proxy";
+            }
+        }
+    }
+    
+    *argptr = NULL;
+    
+    stopNewt();
+    closeLog();
+
+    if (FL_RESCUE(flags)) {
+        fmt = _("Running anaconda %s, the %s rescue mode - please wait.\n");
+    } else {
+        fmt = _("Running anaconda %s, the %s system installer - please wait.\n");
+    }
+    printf(fmt, VERSION, getProductName());
+
+    if (!(pid = fork())) {
+        if (execv(anacondaArgs[0], anacondaArgs) == -1) {
+           fprintf(stderr,"exec of anaconda failed: %m\n");
+           doExit(1);
+        }
+    }
+
+    waitpid(pid, &status, 0);
+
+    if (!WIFEXITED(status) || (WIFEXITED(status) && WEXITSTATUS(status))) {
+        rc = 1;
+    } else {
+        rc = 0;
+    }
+
+    if ((rc == 0) && (FL_POWEROFF(flags) || FL_HALT(flags))) {
+        if (!(pid = fork())) {
+            char * cmd = (FL_POWEROFF(flags) ? strdup("/sbin/poweroff") :
+                          strdup("/sbin/halt"));
+            if (execl(cmd, cmd, NULL) == -1) {
+                fprintf(stderr, "exec of poweroff failed: %m\n");
+                doExit(1);
+            }
+        }
+        waitpid(pid, &status, 0);
+    }
+
+    stop_fw_loader(&loaderData);
+#if defined(__s390__) || defined(__s390x__)
+    /* at the latest possibility signal init=linuxrc.s390 to reboot/halt */
+    logMessage(INFO, "Sending signal %d to process %d\n",
+               init_sig, init_pid);
+    kill(init_pid, init_sig);
+#endif
+    doExit(rc);
+
+    doExit(1);
+}
+
+/* vim:set sw=4 sts=4 et: */
diff --git a/bin/loader/loader.h b/bin/loader/loader.h
new file mode 100644
index 0000000..c64c475
--- /dev/null
+++ b/bin/loader/loader.h
@@ -0,0 +1,193 @@
+/*
+ * loader.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+
+#ifndef LOADER_H
+#define LOADER_H
+
+#define LOADER_OK 0
+#define LOADER_BACK 1
+#define LOADER_NOOP 2
+#define LOADER_ERROR -1
+
+/* #0 unused */
+/* #1 unused */
+#define LOADER_FLAGS_TEXT               (((uint64_t) 1) << 2)
+#define LOADER_FLAGS_RESCUE             (((uint64_t) 1) << 3)
+#define LOADER_FLAGS_KICKSTART          (((uint64_t) 1) << 4)
+#define LOADER_FLAGS_KICKSTART_SEND_MAC (((uint64_t) 1) << 5)
+#define LOADER_FLAGS_POWEROFF           (((uint64_t) 1) << 6)
+#define LOADER_FLAGS_NOPROBE              (((uint64_t) 1) << 7)
+#define LOADER_FLAGS_MODDISK            (((uint64_t) 1) << 8)
+#define LOADER_FLAGS_EARLY_NETWORKING   (((uint64_t) 1) << 9)
+#define LOADER_FLAGS_SERIAL             (((uint64_t) 1) << 10)
+#define LOADER_FLAGS_UPDATES            (((uint64_t) 1) << 11)
+#define LOADER_FLAGS_KSFILE             (((uint64_t) 1) << 12)
+#define LOADER_FLAGS_HALT               (((uint64_t) 1) << 13)
+#define LOADER_FLAGS_SELINUX            (((uint64_t) 1) << 14)
+#define LOADER_FLAGS_VIRTPCONSOLE       (((uint64_t) 1) << 15)
+/* #16 unused */
+#define LOADER_FLAGS_NOSHELL            (((uint64_t) 1) << 17)
+/* #18 unused */
+#define LOADER_FLAGS_TELNETD            (((uint64_t) 1) << 19)
+#define LOADER_FLAGS_NOPASS             (((uint64_t) 1) << 20)
+/* #21 unused */
+#define LOADER_FLAGS_MEDIACHECK         (((uint64_t) 1) << 22)
+/* #23 unused */
+#define LOADER_FLAGS_ASKMETHOD          (((uint64_t) 1) << 24)
+#define LOADER_FLAGS_ASKNETWORK         (((uint64_t) 1) << 25)
+/* #26 unused */
+/* #27 unused */
+#define LOADER_FLAGS_CMDLINE            (((uint64_t) 1) << 28)
+#define LOADER_FLAGS_GRAPHICAL          (((uint64_t) 1) << 29)
+#define LOADER_FLAGS_NOIPV4             (((uint64_t) 1) << 31)
+#ifdef ENABLE_IPV6
+#define LOADER_FLAGS_NOIPV6             (((uint64_t) 1) << 32)
+#endif
+#define LOADER_FLAGS_IP_PARAM           (((uint64_t) 1) << 33)
+#ifdef ENABLE_IPV6
+#define LOADER_FLAGS_IPV6_PARAM         (((uint64_t) 1) << 34)
+#endif
+#define LOADER_FLAGS_IS_KICKSTART       (((uint64_t) 1) << 35)
+#define LOADER_FLAGS_ALLOW_WIRELESS     (((uint64_t) 1) << 36)
+#define LOADER_FLAGS_HAVE_CMSCONF       (((uint64_t) 1) << 37)
+#define LOADER_FLAGS_NOKILL		(((uint64_t) 1) << 38)
+#define LOADER_FLAGS_KICKSTART_SEND_SERIAL   (((uint64_t) 1) << 39)
+#define LOADER_FLAGS_AUTOMODDISK        (((uint64_t) 1) << 40)
+
+#define FL_TEXT(a)               ((a) & LOADER_FLAGS_TEXT)
+#define FL_RESCUE(a)             ((a) & LOADER_FLAGS_RESCUE)
+#define FL_KICKSTART(a)          ((a) & LOADER_FLAGS_KICKSTART)
+#define FL_KICKSTART_SEND_MAC(a) ((a) & LOADER_FLAGS_KICKSTART_SEND_MAC)
+#define FL_POWEROFF(a)           ((a) & LOADER_FLAGS_POWEROFF)
+#define FL_NOPROBE(a)            ((a) & LOADER_FLAGS_NOPROBE)
+#define FL_MODDISK(a)            ((a) & LOADER_FLAGS_MODDISK)
+#define FL_EARLY_NETWORKING(a)   ((a) & LOADER_FLAGS_EARLY_NETWORKING)
+#define FL_SERIAL(a)             ((a) & LOADER_FLAGS_SERIAL)
+#define FL_UPDATES(a)            ((a) & LOADER_FLAGS_UPDATES)
+#define FL_KSFILE(a)             ((a) & LOADER_FLAGS_KSFILE)
+#define FL_NOSHELL(a)            ((a) & LOADER_FLAGS_NOSHELL)
+#define FL_TELNETD(a)            ((a) & LOADER_FLAGS_TELNETD)
+#define FL_NOPASS(a)             ((a) & LOADER_FLAGS_NOPASS)
+#define FL_MEDIACHECK(a)         ((a) & LOADER_FLAGS_MEDIACHECK)
+#define FL_ASKMETHOD(a)          ((a) & LOADER_FLAGS_ASKMETHOD)
+#define FL_GRAPHICAL(a)          ((a) & LOADER_FLAGS_GRAPHICAL)
+#define FL_CMDLINE(a)            ((a) & LOADER_FLAGS_CMDLINE)
+#define FL_HALT(a)               ((a) & LOADER_FLAGS_HALT)
+#define FL_SELINUX(a)            ((a) & LOADER_FLAGS_SELINUX)
+#define FL_VIRTPCONSOLE(a)       ((a) & LOADER_FLAGS_VIRTPCONSOLE)
+#define FL_ASKNETWORK(a)         ((a) & LOADER_FLAGS_ASKNETWORK)
+#define FL_NOIPV4(a)             ((a) & LOADER_FLAGS_NOIPV4)
+#ifdef ENABLE_IPV6
+#define FL_NOIPV6(a)             ((a) & LOADER_FLAGS_NOIPV6)
+#endif
+#define FL_IP_PARAM(a)           ((a) & LOADER_FLAGS_IP_PARAM)
+#ifdef ENABLE_IPV6
+#define FL_IPV6_PARAM(a)         ((a) & LOADER_FLAGS_IPV6_PARAM)
+#endif
+#define FL_IS_KICKSTART(a)       ((a) & LOADER_FLAGS_IS_KICKSTART)
+#define FL_ALLOW_WIRELESS(a)     ((a) & LOADER_FLAGS_ALLOW_WIRELESS)
+#define FL_HAVE_CMSCONF(a)       ((a) & LOADER_FLAGS_HAVE_CMSCONF)
+#define FL_NOKILL(a)		 ((a) & LOADER_FLAGS_NOKILL)
+#define FL_KICKSTART_SEND_SERIAL(a) ((a) & LOADER_FLAGS_KICKSTART_SEND_SERIAL)
+#define FL_AUTOMODDISK(a)        ((a) & LOADER_FLAGS_AUTOMODDISK)
+
+void doExit(int) __attribute__ ((noreturn));
+void startNewt(void);
+void stopNewt(void);
+char * getProductName(void);
+char * getProductPath(void);
+char * getProductArch(void);
+
+#include "moduleinfo.h"
+#include "../isys/devices.h"
+/* JKFIXME: I don't like all of the _set attribs, but without them,
+ * we can't tell if it was explicitly set by kickstart/cmdline or 
+ * if we just got it going through the install.   */
+struct loaderData_s {
+    char * lang;
+    int lang_set;
+    char * kbd;
+    int kbd_set;
+    char * netDev;
+    int netDev_set;
+    char * bootIf;
+    int bootIf_set;
+    char * netCls;
+    int netCls_set;
+    char *ipv4, *netmask, *gateway, *dns, *hostname, *peerid, *ethtool, *subchannels, *portname, *essid, *wepkey, *nettype, *ctcprot, *layer2, *portno, *macaddr;
+#ifdef ENABLE_IPV6
+    char *ipv6;
+    int ipv6info_set;
+    char *gateway6;
+#endif
+    int mtu;
+    int noDns;
+    int dhcpTimeout;
+    int ipinfo_set;
+    char * ksFile;
+    int method;
+    char * ddsrc;
+    void * stage2Data;
+    char * logLevel;
+    char * updatessrc;
+    char * dogtailurl;
+    char * gdbServer;
+    char * instRepo;
+
+    pid_t fw_loader_pid;
+    char *fw_search_pathz;
+    size_t fw_search_pathz_len;
+
+    moduleInfoSet modInfo;
+
+    int inferredStage2, invalidRepoParam;
+
+    /* Proxy info needs to be in the loaderData so we can get these
+     * settings off the command line, too.
+     */
+    char *proxy;
+    char *proxyUser;
+    char *proxyPassword;
+};
+
+/* 64 bit platforms, definitions courtesy of glib */
+#if defined (__x86_64__) || defined(__ia64__) || defined(__alpha__) || defined(__powerpc64__) || defined(__s390x__) || (defined(__sparc__) && defined(__arch64__))
+#define POINTER_TO_INT(p)  ((int) (long) (p))
+#define INT_TO_POINTER(i)  ((void *) (long) (i))
+#else
+#define POINTER_TO_INT(p)  ((int) (p))
+#define INT_TO_POINTER(i)  ((void *) (i))
+#endif
+
+/* library paths */
+#if defined(__x86_64__) || defined(__s390x__) || defined(__powerpc64__)
+#define LIBPATH "/lib64:/usr/lib64:/usr/X11R6/lib64:/usr/kerberos/lib64:/mnt/usr/lib64:/mnt/sysimage/lib64:/mnt/sysimage/usr/lib64"
+#else
+#define LIBPATH "/lib:/usr/lib:/usr/X11R6/lib:/usr/kerberos/lib:/mnt/usr/lib:/mnt/sysimage/lib:/mnt/sysimage/usr/lib"
+#endif
+
+#define checked_asprintf(...)                                       \
+    if (asprintf( __VA_ARGS__ ) == -1) {                            \
+        logMessage(CRITICAL, "%s: %d: %m", __func__, __LINE__);     \
+        abort();                                                    \
+    }
+
+#endif
diff --git a/bin/loader/loadermisc.c b/bin/loader/loadermisc.c
new file mode 100644
index 0000000..64e80a2
--- /dev/null
+++ b/bin/loader/loadermisc.c
@@ -0,0 +1,150 @@
+/*
+ * loadermisc.c - miscellaneous loader functions that don't seem to fit
+ * anywhere else (yet)  (was misc.c)
+ * JKFIXME: need to break out into reasonable files based on function
+ *
+ * Copyright (C) 1999, 2000, 2001, 2002  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "../isys/log.h"
+
+#include "windows.h"
+
+int copyFileFd(int infd, char * dest, progressCB pbcb,
+               struct progressCBdata *data, long long total) {
+    int outfd;
+    char buf[4096];
+    int i;
+    int rc = 0;
+    long long count = 0;
+
+    outfd = open(dest, O_CREAT | O_RDWR, 0666);
+
+    if (outfd < 0) {
+        logMessage(ERROR, "failed to open %s: %m", dest);
+        return 1;
+    }
+
+    while ((i = read(infd, buf, sizeof(buf))) > 0) {
+        if (write(outfd, buf, i) != i) {
+            rc = 1;
+            break;
+        }
+
+        count += i;
+
+        if (pbcb && data && total) {
+            pbcb(data, count, total);
+        }
+    }
+
+    close(outfd);
+
+    return rc;
+}
+
+int copyFile(char * source, char * dest) {
+    int infd = -1;
+    int rc;
+
+    infd = open(source, O_RDONLY);
+
+    if (infd < 0) {
+        logMessage(ERROR, "failed to open %s: %m", source);
+        return 1;
+    }
+
+    rc = copyFileFd(infd, dest, NULL, NULL, 0);
+
+    close(infd);
+
+    return rc;
+}
+
+int simpleStringCmp(const void * a, const void * b) {
+    const char * first = *((const char **) a);
+    const char * second = *((const char **) b);
+
+    return strverscmp(first, second);
+}
+
+/* look for available memory.  note: won't ever report more than the 
+ * 900 megs or so supported by the -BOOT kernel due to not using e820 */
+int totalMemory(void) {
+    int fd;
+    int bytesRead;
+    char buf[4096];
+    char * chptr, * start;
+    int total = 0;
+
+    fd = open("/proc/meminfo", O_RDONLY);
+    if (fd < 0) {
+        logMessage(ERROR, "failed to open /proc/meminfo: %m");
+        return 0;
+    }
+
+    bytesRead = read(fd, buf, sizeof(buf) - 1);
+    if (bytesRead < 0) {
+        logMessage(ERROR, "failed to read from /proc/meminfo: %m");
+        close(fd);
+        return 0;
+    }
+
+    close(fd);
+    buf[bytesRead] = '\0';
+
+    chptr = buf;
+    while (*chptr && !total) {
+        if (strncmp(chptr, "MemTotal:", 9)) {
+            chptr++;
+            continue;
+        }
+
+        start = ++chptr ;
+        while (*chptr && *chptr != '\n') chptr++;
+
+        *chptr = '\0';
+
+        while (!isdigit(*start) && *start) start++;
+        if (!*start) {
+            logMessage(WARNING, "no number appears after MemTotal tag");
+            return 0;
+        }
+
+        chptr = start;
+        while (*chptr && isdigit(*chptr)) {
+            total = (total * 10) + (*chptr - '0');
+            chptr++;
+        }
+    }
+
+    logMessage(INFO, "%d kB are available", total);
+
+    return total;
+}
diff --git a/bin/loader/loadermisc.h b/bin/loader/loadermisc.h
new file mode 100644
index 0000000..23ebf4a
--- /dev/null
+++ b/bin/loader/loadermisc.h
@@ -0,0 +1,33 @@
+/*
+ * loadermisc.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef H_LOADER_MISC_H
+#define H_LOADER_MISC_H
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "windows.h"
+
+int copyFile(char * source, char * dest);
+int copyFileFd(int infd, char * dest, progressCB pbcb,
+               struct progressCBdata *data, long long total);
+int simpleStringCmp(const void * a, const void * b);
+int totalMemory(void);
+
+#endif
diff --git a/bin/loader/mediacheck.c b/bin/loader/mediacheck.c
new file mode 100644
index 0000000..4bec1c8
--- /dev/null
+++ b/bin/loader/mediacheck.c
@@ -0,0 +1,115 @@
+/*
+ * simple program to check implanted md5sum in an iso 9660 image
+ *
+ * Copyright (C) 2001, 2005  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Michael Fulbright <msf redhat com>
+ *            Dustin Kirkland <dustin kirkland gmail com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <newt.h>
+#include <libcheckisomd5.h>
+
+#include "../isys/log.h"
+
+#include "lang.h"
+#include "windows.h"
+
+int doMediaCheck(char *file, char *descr) {
+    struct progressCBdata data;
+    newtComponent t, f, scale, label;
+    int rc;
+    int dlen;
+    int llen;
+    char tmpstr[1024];
+
+    if (access(file, R_OK) < 0) {
+	newtWinMessage(_("Error"), _("OK"), _("Unable to find install image "
+					      "%s"), file);
+	return -1;
+    }
+
+    if (descr)
+	snprintf(tmpstr, sizeof(tmpstr), _("Checking \"%s\"."), descr);
+    else
+	snprintf(tmpstr, sizeof(tmpstr), _("Checking media."));
+
+    dlen = strlen(tmpstr);
+    if (dlen > 65)
+	dlen = 65;
+
+    newtCenteredWindow(dlen+8, 6, _("Media Check"));
+    t = newtTextbox(1, 1, dlen+4, 3, NEWT_TEXTBOX_WRAP);
+
+    newtTextboxSetText(t, tmpstr);
+    llen = strlen(tmpstr);
+
+    label = newtLabel(llen+1, 1, "-");
+    f = newtForm(NULL, NULL, 0);
+    newtFormAddComponent(f, t);
+    scale = newtScale(3, 3, dlen, 100);
+    newtFormAddComponent(f, scale);
+
+    newtDrawForm(f);
+    newtRefresh();
+
+    data.scale = scale;
+    data.label = label;
+
+    rc = mediaCheckFile(file, progressCallback, &data);
+
+    newtFormDestroy(f);
+    newtPopWindow();
+
+    if (rc == ISOMD5SUM_CHECK_NOT_FOUND) {
+	logMessage(WARNING, "mediacheck: %s (%s) has no checksum info", file, descr);
+	newtWinMessage(_("Error"), _("OK"),
+		       _("Unable to find the checksum in the "
+			 "image.  This probably "
+			 "means the disc was created without adding the "
+			 "checksum."));
+    } else if (rc == ISOMD5SUM_FILE_NOT_FOUND) {
+        logMessage(WARNING, "mediacheck: %s (%s) open failed", file, descr);
+        newtWinMessage(_("Error"), _("OK"),
+                       _("Unable to open the image."));
+    } else if (rc == ISOMD5SUM_CHECK_FAILED) {
+        logMessage(ERROR, "mediacheck: %s (%s) FAILED", file, descr);
+        newtWinMessage(_("Error"), _("OK"),
+                       _("The image which was just tested has errors. "
+                         "This could be due to a "
+                         "corrupt download or a bad disc.  "
+                         "If applicable, please clean the disc "
+                         "and try again.  If this test continues to fail you "
+                         "should not continue the install."));
+    } else if (rc == ISOMD5SUM_CHECK_PASSED) {
+        logMessage(INFO, "mediacheck: %s (%s) PASSED", file, descr);
+        newtWinMessage(_("Success"), _("OK"),
+                       _("The image which was just tested was successfully "
+                         "verified.  It should be OK to install from this "
+                         "media.  Note that not all media/drive errors can "
+                         "be detected by the media check."));
+    }
+
+
+    return rc;
+}
diff --git a/bin/loader/mediacheck.h b/bin/loader/mediacheck.h
new file mode 100644
index 0000000..ab2f887
--- /dev/null
+++ b/bin/loader/mediacheck.h
@@ -0,0 +1,25 @@
+/*
+ * mediacheck.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MEDIACHECK_H
+#define MEDIACHECK_H
+
+int doMediaCheck(char *file, char *descr);
+
+#endif
diff --git a/bin/loader/method.c b/bin/loader/method.c
new file mode 100644
index 0000000..3ca669f
--- /dev/null
+++ b/bin/loader/method.c
@@ -0,0 +1,570 @@
+/*
+ * method.c - generic install method setup functions
+ *
+ * Copyright (C) 2002  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <libgen.h>
+
+#include "copy.h"
+#include "loader.h"
+#include "loadermisc.h"
+#include "lang.h"
+#include "mediacheck.h"
+#include "method.h"
+
+#include "../isys/imount.h"
+#include "../isys/isys.h"
+#include "../isys/cpio.h"
+#include "../isys/log.h"
+
+#include "devt.h"
+
+#include "nfsinstall.h"
+#include "hdinstall.h"
+#include "urlinstall.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+static void stripTrailingSlash(char *path) {
+    size_t len = strlen(path);
+
+    if (len == 0)
+        return;
+    if (path[len-1] == '/')
+        path[len-1] = '\0';
+}
+
+int umountLoopback(char * mntpoint, char * device) {
+    int loopfd;
+
+    umount(mntpoint);
+
+    logMessage(INFO, "umounting loopback %s %s", mntpoint, device);
+
+    loopfd = open(device, O_RDONLY);
+
+    if (ioctl(loopfd, LOOP_CLR_FD, 0) == -1)
+        logMessage(ERROR, "LOOP_CLR_FD failed for %s %s: %m", mntpoint, device);
+
+    close(loopfd);
+
+    return 0;
+}
+
+int mountLoopback(char *fsystem, char *mntpoint, char *device) {
+    char *opts, *err = NULL;
+
+    if (device == NULL) {
+        logMessage(ERROR, "no loopback device given");
+        return LOADER_ERROR;
+    }
+
+    if (access(fsystem, F_OK) != 0) {
+       logMessage(ERROR, "file %s is not accessible", fsystem);
+       return LOADER_ERROR;
+    }
+
+    checked_asprintf(&opts, "ro,loop=%s", device);
+
+    if (doPwMount(fsystem, mntpoint, "auto", opts, &err)) {
+        logMessage(ERROR, "failed to mount loopback device %s on %s as %s: %s",
+                   device, mntpoint, fsystem, err);
+        return LOADER_ERROR;
+    }
+
+    logMessage(INFO, "mounted loopback device %s on %s as %s", mntpoint, device, fsystem);
+
+    return 0;
+}
+
+/* returns the *absolute* path (malloced) to the #1 iso image */
+/* get timestamp and description of ISO image from stamp file */
+/* returns 0 on success, -1 otherwise                         */
+int readStampFileFromIso(char *file, char **timestamp, char **releasedescr) {
+    DIR * dir;
+    FILE *f;
+    struct dirent * ent;
+    struct stat sb;
+    char *stampfile;
+    char *descr, *tstamp;
+    char tmpstr[1024];
+    int  filetype;
+    int  rc;
+
+    lstat(file, &sb);
+    if (S_ISBLK(sb.st_mode)) {
+	filetype = 1;
+	if (doPwMount(file, "/tmp/testmnt", "iso9660", "ro", NULL)) {
+	    logMessage(ERROR, "Failed to mount device %s to get description",
+                       file);
+	    return -1;
+	}
+    } else if (S_ISREG(sb.st_mode)) {
+	filetype = 2;
+	if (mountLoopback(file, "/tmp/testmnt", "/dev/loop6")) {
+	    logMessage(ERROR, "Failed to mount iso %s to get description",
+                       file);
+	    return -1;
+	}
+    } else {
+	    logMessage(ERROR, "Unknown type of file %s to get description",
+                       file);
+	    return -1;
+    }
+
+    if (!(dir = opendir("/tmp/testmnt"))) {
+	umount("/tmp/testmnt");
+	if (filetype == 2)
+	    umountLoopback("/tmp/testmnt", "/dev/loop6");
+	return -1;
+    }
+
+    errno = 0;
+    stampfile = NULL;
+    while ((ent = readdir(dir))) {
+	if (!strncmp(ent->d_name, ".discinfo", 9)) {
+	    stampfile = strdup(".discinfo");
+	    break;
+	}
+    }
+
+    closedir(dir);
+    descr = NULL;
+    tstamp = NULL;
+    if (stampfile) {
+	snprintf(tmpstr, sizeof(tmpstr), "/tmp/testmnt/%s", stampfile);
+	f = fopen(tmpstr, "r");
+	if (f) {
+	    char *tmpptr;
+
+	    /* readtime stamp line */
+	    tmpptr = fgets(tmpstr, sizeof(tmpstr), f);
+	    
+	    if (tmpptr)
+		tstamp = strdup(tmpstr);
+
+	    /* now read OS description line */
+	    if (tmpptr)
+		tmpptr = fgets(tmpstr, sizeof(tmpstr), f);
+
+	    if (tmpptr)
+		descr = strdup(tmpstr);
+
+	    /* skip over arch */
+	    if (tmpptr)
+		tmpptr = fgets(tmpstr, sizeof(tmpstr), f);
+
+	    /* now get the CD number */
+	    if (tmpptr) {
+		unsigned int len;
+		char *p, *newstr;
+
+		tmpptr = fgets(tmpstr, sizeof(tmpstr), f);
+		
+		/* nuke newline from end of descr, stick number on end*/
+		for (p=descr+strlen(descr); p != descr && !isspace(*p); p--);
+
+		*p = '\0';
+		len = strlen(descr) + strlen(tmpstr) + 10;
+		newstr = malloc(len);
+		strncpy(newstr, descr, len-1);
+		strncat(newstr, " ", len-1);
+
+		/* is this a DVD or not?  If disc id has commas, like */
+		/* "1,2,3", its a DVD                                 */
+		if (strchr(tmpstr, ','))
+		    strncat(newstr, "DVD\n", len-1);
+		else {
+		    strncat(newstr, "disc ", len-1);
+		    strncat(newstr, tmpstr, len-1);
+		}
+
+		free(descr);
+		descr = newstr;
+	    }
+
+	    fclose(f);
+	}
+    }
+
+    free(stampfile);
+
+    umount("/tmp/testmnt");
+    if (filetype == 2)
+	umountLoopback("/tmp/testmnt", "/dev/loop6");
+
+    if (descr != NULL && tstamp != NULL) {
+	descr[strlen(descr)-1] = '\0';
+	*releasedescr = descr;
+
+	tstamp[strlen(tstamp)-1] = '\0';
+	*timestamp = tstamp;
+
+	rc = 0;
+    } else {
+	rc = 1;
+    }	
+
+    return rc;
+}
+
+/* XXX this ignores "location", which should be fixed
+ *
+ * Given a starting isoFile, will offer choice to mediacheck it and
+ * all other ISO images in the same directory with the same stamp
+ */
+void queryIsoMediaCheck(char *isoFile) {
+    DIR * dir;
+    struct dirent * ent;
+    char *isoDir;
+    char isoImage[1024];
+    char tmpmessage[1024];
+    char *master_timestamp;
+    char *tmpstr;
+    int rc, first;
+
+    /* dont bother to test in automated installs */
+    if (FL_KICKSTART(flags) && !FL_MEDIACHECK(flags))
+	return;
+
+    /* if they did not specify to mediacheck explicitely then return */
+    if (!FL_MEDIACHECK(flags))
+	return;
+
+    /* check that file is actually an iso */
+    if (!fileIsIso(isoFile))
+	return;
+
+    /* get stamp of isoFile, free descr since we dont care */
+    readStampFileFromIso(isoFile, &master_timestamp, &tmpstr);
+    free(tmpstr);
+    
+    /* get base path from isoFile */
+    tmpstr = strdup(isoFile);
+    isoDir = strdup(dirname(tmpstr));
+    free(tmpstr);
+
+    logMessage(DEBUGLVL, "isoFile = %s", isoFile);
+    logMessage(DEBUGLVL, "isoDir  = %s", isoDir);
+    logMessage(DEBUGLVL, "Master Timestemp = %s", master_timestamp);
+
+    if (!(dir = opendir(isoDir))) {
+	newtWinMessage(_("Error"), _("OK"), 
+		       _("Failed to read directory %s: %m"),
+		       isoDir);
+	free(isoDir);
+	free(master_timestamp);
+	return;
+    }
+
+    /* Walk through the directories looking for a CD images. */
+    errno = 0;
+    first = 0;
+    while (1) {
+	char *nextname;
+	char *tdescr, *tstamp;
+
+	if (first) {
+	    first = 1;
+	    nextname = isoFile;
+	} else {
+	    ent = readdir(dir);
+	    if (!ent)
+		break;
+
+	    nextname = ent->d_name;
+	}
+
+	/* synthesize name of iso from isoDir and file entry */
+	snprintf(isoImage, sizeof(isoImage), "%s/%s", isoDir, nextname);
+
+	/* see if this is an iso image */
+	if (!fileIsIso(isoImage)) {
+	    errno = 0;
+	    continue;
+	}
+
+	/* see if its part of the current CD set */
+	readStampFileFromIso(isoImage, &tstamp, &tdescr);
+	if (strcmp(tstamp, master_timestamp)) {
+	    errno = 0;
+	    continue;
+	}
+	    
+	/* found a valid candidate, proceed */
+	snprintf(tmpmessage, sizeof(tmpmessage),
+		 _("Would you like to perform a checksum "
+		   "test of the ISO image:\n\n   %s?"), isoImage);
+
+	rc = newtWinChoice(_("Checksum Test"), _("Test"), _("Skip"),
+			   tmpmessage);
+
+	if (rc == 2) {
+	    logMessage(INFO, "mediacheck: skipped checking of %s", isoImage);
+	    if (tdescr)
+		free(tdescr);
+	    continue;
+	} else {
+	    doMediaCheck(isoImage, tdescr);
+	    if (tdescr)
+		free(tdescr);
+
+	    continue;
+	}
+    }
+
+    free(isoDir);
+    free(master_timestamp);
+    closedir(dir);
+}
+
+static void copyWarnFn (char *msg) {
+   logMessage(WARNING, msg);
+}
+
+static void copyErrorFn (char *msg) {
+   newtWinMessage(_("Error"), _("OK"), _(msg));
+}
+
+/* 
+ * unpack a gzipped cpio ball into a tree rooted at rootDir
+ * returns 0 on success, 1 on failure
+ */
+int unpackCpioBall(char * ballPath, char * rootDir) {
+    gzFile fd;
+    char *buf, *cwd;
+    int rc = 1;
+
+    if (access(ballPath, R_OK))
+        return 1;
+
+    if (access(rootDir, R_OK))
+        mkdirChain(rootDir);
+
+    buf = (char *)malloc(PATH_MAX);
+    cwd = getcwd(buf, PATH_MAX);
+    if ((rc = chdir(rootDir)) == 0) {
+        fd = gunzip_open(ballPath);
+        if (fd) {
+            if (!installCpioFile(fd, NULL, NULL, 0)) {
+                logMessage(INFO, "copied contents of %s into %s", ballPath,
+                           rootDir);
+                rc = chdir(cwd);
+                return 0;
+            }
+            gunzip_close(fd);
+        }
+        rc = chdir(cwd);
+    }
+
+    return 1;
+}
+
+void copyUpdatesImg(char * path) {
+    if (!access(path, R_OK)) {
+        if (!mountLoopback(path, "/tmp/update-disk", "/dev/loop7")) {
+            copyDirectory("/tmp/update-disk", "/tmp/updates", copyWarnFn,
+                          copyErrorFn);
+            umountLoopback("/tmp/update-disk", "/dev/loop7");
+            unlink("/tmp/update-disk");
+        } else {
+            unpackCpioBall(path, "/tmp/updates");
+        }
+    }
+}
+
+void copyProductImg(char * path) {
+    if (!access(path, R_OK)) {
+        if (!mountLoopback(path, "/tmp/product-disk", "/dev/loop7")) {
+            copyDirectory("/tmp/product-disk", "/tmp/product", copyWarnFn,
+                          copyErrorFn);
+            umountLoopback("/tmp/product-disk", "/dev/loop7");
+            unlink("/tmp/product-disk");
+        }
+    }
+}
+
+/** Bind the uncompressed second stage to /mnt/runtime.
+ *
+ * return 0 on success, 1 on failure to mount.
+ */
+int mountStage2Direct(char *stage2Path) {
+    if (access(stage2Path, R_OK)) {
+        return 1;
+    }
+
+    char *target = "/mnt/runtime";
+    char *error = NULL;
+    if (doBindMount(stage2Path, target, &error)) {
+        logMessage(ERROR, "failed to bind %s to %s: %s",
+                   stage2Path, target, error);
+        free(error);
+        return 1;
+    }
+    logMessage(INFO, "successfully bound %s to %s", stage2Path, target);
+    return 0;
+}
+
+/* mount a second stage, verify the stamp file, copy updates 
+ * Returns 0 on success, 1 on failure to mount, -1 on bad stamp */
+int mountStage2(char *stage2path) {
+    if (access(stage2path, R_OK)) {
+        return 1;
+    }
+
+    if (mountLoopback(stage2path, "/mnt/runtime", "/dev/loop0")) {
+        return 1;
+    }
+
+    return 0;
+}
+
+
+/* copies a second stage from fd to dest and mounts on mntpoint */
+int copyFileAndLoopbackMount(int fd, char * dest, char * device, char * mntpoint,
+                             progressCB pbcb, struct progressCBdata *data,
+                             long long total) {
+    int rc;
+    struct stat sb;
+
+    rc = copyFileFd(fd, dest, pbcb, data, total);
+    stat(dest, &sb);
+    logMessage(DEBUGLVL, "copied %" PRId64 " bytes to %s (%s)", sb.st_size, dest, 
+               ((rc) ? " incomplete" : "complete"));
+    
+    if (rc) {
+	/* just to make sure */
+	unlink(dest);
+	return 1;
+    }
+
+    if (mountLoopback(dest, mntpoint, device)) {
+        /* JKFIXME: this used to be fatal, but that seems unfriendly */
+        logMessage(ERROR, "Error mounting %s on %s: %m", device, mntpoint);
+        return 1;
+    }
+
+    return 0;
+}
+
+/* given a device name (w/o '/dev' on it), try to get a file */
+/* Error codes: 
+      1 - could not create device node
+      2 - could not mount device as ext2, vfat, or iso9660
+      3 - file named path not there
+*/
+int getFileFromBlockDevice(char *device, char *path, char * dest) {
+    int rc, i;
+    char file[4096];
+
+    logMessage(INFO, "getFileFromBlockDevice(%s, %s)", device, path);
+
+    /* some USB thumb drives and hard drives are slow to initialize */
+    /* retry up to 5 times or 31 seconds */
+    rc = doPwMount(device, "/tmp/mnt", "auto", "ro", NULL);
+    for (i = 0; mountMightSucceedLater(rc) && i < 5; ++i) {
+        logMessage(INFO, "sleeping to wait for USB storage devices");
+        sleep(1 << i);
+        rc = doPwMount(device, "/tmp/mnt", "auto", "ro", NULL);
+        logMessage(ERROR, "error code: %d", rc);
+    }
+    if (rc) {
+        logMessage(ERROR, "failed to mount /dev/%s: %m", device);
+        return 2;
+    }
+
+    snprintf(file, sizeof(file), "/tmp/mnt/%s", path);
+    logMessage(INFO, "Searching for file on path %s", file);
+    
+    if (access(file, R_OK)) {
+	rc = 3;
+    } else {
+	copyFile(file, dest);
+	rc = 0;
+	logMessage(INFO, "file copied to %s", dest);
+    }    
+
+    umount("/tmp/mnt");
+    unlink("/tmp/mnt");
+    return rc;
+}
+
+void setStage2LocFromCmdline(char * arg, struct loaderData_s * ld) {
+    if (!strncmp(arg, "nfs:", 4)) {
+        ld->method = METHOD_NFS;
+        ld->stage2Data = calloc(sizeof(struct nfsInstallData *), 1);
+
+        parseNfsHostPathOpts(arg + 4,
+          &(((struct nfsInstallData *)ld->stage2Data)->host),
+          &(((struct nfsInstallData *)ld->stage2Data)->directory),
+          &(((struct nfsInstallData *)ld->stage2Data)->mountOpts));
+        stripTrailingSlash(((struct nfsInstallData *)ld->stage2Data)->directory);
+    } else if (!strncmp(arg, "nfsiso:", 7)) {
+        ld->method = METHOD_NFS;
+        ld->stage2Data = calloc(sizeof(struct nfsInstallData *), 1);
+
+        parseNfsHostPathOpts(arg + 7,
+          &(((struct nfsInstallData *)ld->stage2Data)->host),
+          &(((struct nfsInstallData *)ld->stage2Data)->directory),
+          &(((struct nfsInstallData *)ld->stage2Data)->mountOpts));
+    } else if (!strncmp(arg, "ftp:", 4) ||
+               !strncmp(arg, "http", 4)) {
+        ld->method = METHOD_URL;
+        ld->stage2Data = calloc(sizeof(struct urlInstallData *), 1);
+        ((urlInstallData *)ld->stage2Data)->url = strdup(arg);
+    } else if (!strncmp(arg, "cdrom:", 6)) {
+        ld->method = METHOD_CDROM;
+    } else if (!strncmp(arg, "harddrive:", 10) ||
+               !strncmp(arg, "hd:", 3)) {
+        size_t offset;
+
+	arg += strcspn(arg, ":");
+	if (!*arg || !*(arg+1))
+	    return;
+	arg += 1;
+        offset = strcspn(arg, ":");
+
+        ld->method = METHOD_HD;
+        ld->stage2Data = calloc(sizeof(struct hdInstallData *), 1);
+        ((struct hdInstallData *)ld->stage2Data)->partition = strndup(arg, offset);
+	arg += offset;
+	if (*arg && *(arg+1))
+            ((struct hdInstallData *)ld->stage2Data)->directory = strdup(arg+1);
+        else
+            ((struct hdInstallData *)ld->stage2Data)->directory = NULL;
+    }
+}
diff --git a/bin/loader/method.h b/bin/loader/method.h
new file mode 100644
index 0000000..cabd1c2
--- /dev/null
+++ b/bin/loader/method.h
@@ -0,0 +1,60 @@
+/*
+ * method.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef H_METHOD
+#define H_METHOD
+
+#include "loader.h"
+#include "windows.h"
+
+/* method identifiers, needs to match struct installMethod order in loader.c */
+enum {
+    METHOD_CDROM,
+    METHOD_HD,
+    METHOD_NFS,
+    METHOD_URL
+};
+
+struct installMethod {
+    char * name;
+    int network;
+    enum deviceType type;
+    char * (*mountImage)(struct installMethod * method,
+                         char * location, struct loaderData_s * loaderData);
+};
+
+int umountLoopback(char * mntpoint, char * device);
+int mountLoopback(char * fsystem, char * mntpoint, char * device);
+
+int readStampFileFromIso(char *file, char **descr, char **timestamp);
+void queryIsoMediaCheck(char * isoDir);
+
+int mountStage2(char *stage2path);
+int mountStage2Direct(char *stage2path);
+int copyFileAndLoopbackMount(int fd, char *dest, char *device, char *mntpoint,
+                             progressCB pbcb, struct progressCBdata *data, long long total);
+int getFileFromBlockDevice(char *device, char *path, char * dest);
+
+int unpackCpioBall(char * ballPath, char * rootDir);
+void copyUpdatesImg(char * path);
+void copyProductImg(char * path);
+
+void setStage2LocFromCmdline(char * arg, struct loaderData_s * ld);
+
+#endif
diff --git a/bin/loader/mkctype.c b/bin/loader/mkctype.c
new file mode 100644
index 0000000..12eaba0
--- /dev/null
+++ b/bin/loader/mkctype.c
@@ -0,0 +1,76 @@
+/*
+ * mkctype.c
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+
+#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
+# define __ctype_b (*__ctype_b_loc())
+# define __ctype_tolower (*__ctype_tolower_loc())
+# define __ctype_toupper (*__ctype_toupper_loc())
+#endif
+
+int main(int argc, char ** argv) {
+    int i;
+
+    printf("#include <sys/types.h>\n\n");
+
+    printf("static const unsigned short int __ctype_b_internal[] = {");
+
+    for (i = -128; i < 256; i++) {
+	if (!(i % 8)) {
+	    printf("\n");
+	}
+
+	printf("\t0x%x,", __ctype_b[i]);
+    }
+
+    printf("\n};\n\n");
+    printf("const unsigned short int * __ctype_b = __ctype_b_internal + 128;\n\n");
+
+    printf("const int __ctype_toupper_internal[] = {");
+    for (i = -128; i < 256; i++) {
+	if (!(i % 8)) {
+	    printf("\n");
+	}
+
+	printf("\t0x%x,", __ctype_toupper[i]);
+    }
+
+    printf("\n};\n\n");
+    printf("const int * __ctype_toupper = __ctype_toupper_internal + 128;\n\n");
+
+    printf("const int __ctype_tolower_internal[] = {");
+    for (i = -128; i < 256; i++) {
+	if (!(i % 8)) {
+	    printf("\n");
+	}
+
+	printf("\t0x%x,", __ctype_tolower[i]);
+    }
+
+    printf("\n};\n\n");
+    printf("const int * __ctype_tolower = __ctype_tolower_internal + 128;\n\n");
+
+    printf ("const unsigned short int **__ctype_b_loc (void) { return &__ctype_b; }\n");
+    printf ("const int **__ctype_toupper_loc (void) { return &__ctype_toupper; }\n");
+    printf ("const int **__ctype_tolower_loc (void) { return &__ctype_tolower; }\n\n");
+
+    return 0;
+};
diff --git a/bin/loader/moduleinfo.c b/bin/loader/moduleinfo.c
new file mode 100644
index 0000000..2e0ab77
--- /dev/null
+++ b/bin/loader/moduleinfo.c
@@ -0,0 +1,276 @@
+/*
+ * moduleinfo.c - module info functionality
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ */
+
+#include <alloca.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <stdio.h>
+
+#include "moduleinfo.h"
+
+struct moduleInfo * getModuleList(moduleInfoSet mis, 
+                                  enum driverMajor major) {
+    struct moduleInfo * miList, * next;
+    int i;
+
+    next = miList = malloc(sizeof(*miList) * mis->numModules + 1);
+    for (i = 0; i < mis->numModules; i++) {
+        if (mis->moduleList[i].major == major || major == DRIVER_NONE) {
+            *next = mis->moduleList[i];
+            next++;
+        }
+    }
+
+    if (next == miList) {
+        free(next);
+        return NULL;
+    }
+
+    next->moduleName = NULL;
+    next++;
+
+    miList = realloc(miList, sizeof(*miList) * (next - miList));
+    return miList;
+}
+
+struct moduleInfo * findModuleInfo(moduleInfoSet mis, 
+                                   const char * moduleName) {
+    int i;
+    struct moduleInfo * found = NULL;
+
+    for (i = 0; i < mis->numModules; i++) {
+        if (!strcmp(moduleName, mis->moduleList[i].moduleName)) {
+            if (!found)
+                found = mis->moduleList + i;
+            else if (found->locationID && !mis->moduleList[i].locationID)
+                ;
+            else
+                found = mis->moduleList + i;
+        }
+    }
+
+    return found;
+}
+
+moduleInfoSet newModuleInfoSet(void) {
+    return calloc(sizeof(struct moduleInfoSet_s), 1);
+}
+
+/* filename: file to read module-info from
+ * mis: moduleInfoSet
+ * location: moduleBallLocation struct describing the location of 
+ *           these modules.  (may be NULL)
+ * override: 1 if modules from this module ball should override old ones
+ *           of the same name.
+ */
+int readModuleInfo(const char * filename, moduleInfoSet mis, 
+                   void * location, int override) {
+    int fd, isIndented;
+    char * buf, * start, * next = NULL, * chptr;
+    struct stat sb;
+    char oldch;
+    struct moduleInfo * nextModule;
+    int modulesAlloced;
+    int i;
+    int found = 0, skipModule = 0;
+
+    fd = open(filename, O_RDONLY);
+    if (fd < 0) return -1;
+ 
+    fstat(fd, &sb);
+    buf = alloca(sb.st_size + 1);
+    i = read(fd, buf, sb.st_size);
+    buf[sb.st_size] = '\0';
+    close(fd);
+
+    if (i != sb.st_size)
+        return -1;
+
+    nextModule = NULL;
+    modulesAlloced = mis->numModules;
+
+    if (strncmp(buf, "Version 0\n", 10)) return -1;
+
+    start = buf + 10;
+    while (start && *start) {
+        chptr = strchr(start, '\n');
+        if (chptr) {
+            /* slice and dice */
+            next = chptr + 1;
+        } else {
+            chptr += strlen(start) - 1;
+        }
+
+        chptr--;
+        while (isspace(*chptr)) chptr--;
+        chptr++;
+        *chptr = '\0';
+
+        isIndented = 0;
+        if (isspace(*start)) {
+            while (isspace(*start) && *start != '\n') start++;
+            isIndented = 1;
+        }
+
+        if (*start != '\n' && *start && *start != '#') {
+            if (!isIndented) {
+                if (nextModule && nextModule->moduleName &&
+                    nextModule == (mis->moduleList + mis->numModules)) {
+                        mis->numModules++; 
+                }
+
+                if (mis->numModules == modulesAlloced) {
+                    modulesAlloced += 5;
+                    mis->moduleList = realloc(mis->moduleList,
+                        modulesAlloced * sizeof(*mis->moduleList));
+                }
+
+                nextModule = NULL;
+                found = 0;
+                skipModule = 0;
+                for (i = 0; i < mis->numModules; i++) {
+                    if (!strcmp(mis->moduleList[i].moduleName, start)) {
+                        if (override) 
+                            nextModule = mis->moduleList + i;
+                        else
+                            skipModule = 1;
+                        found = 1;
+                        break;
+                    }
+                }
+
+                if (!found && !nextModule) {
+                    nextModule = mis->moduleList + mis->numModules;
+
+                    nextModule->moduleName = strdup(start);
+                } 
+
+                if (nextModule) {
+                    nextModule->major = DRIVER_NONE;
+                    nextModule->minor = DRIVER_MINOR_NONE;
+                    nextModule->description = NULL;
+                    nextModule->flags = 0;
+                    nextModule->args = NULL;
+                    nextModule->numArgs = 0;
+                    nextModule->locationID = location;
+                }
+            } else if (!nextModule && skipModule) {
+                /* we're skipping this one (not overriding), do nothing */
+            } else if (!nextModule && skipModule) {
+                /* ACK! syntax error */
+                fprintf(stderr, "module-info syntax error in %s\n", filename);
+                return 1;
+            } else if (nextModule->major == DRIVER_NONE) {
+                chptr = start + strlen(start) - 1;
+                while (!isspace(*chptr) && chptr > start) chptr--;
+                if (chptr != start) chptr++;
+
+                if (!strcmp(chptr, "eth")) {
+                    nextModule->major = DRIVER_NET;
+                    nextModule->minor = DRIVER_MINOR_ETHERNET;
+                } else if (!strcmp(chptr, "tr")) {
+                    nextModule->major = DRIVER_NET;
+                    nextModule->minor = DRIVER_MINOR_TR;
+                } else if (!strcmp(chptr, "scsi_hostadapter") ||
+                           !strcmp(chptr, "scsi")) {
+                    nextModule->major = DRIVER_SCSI;
+                } else if (!strcmp(chptr, "pcmcia")) {
+                    nextModule->major = DRIVER_PCMCIA;
+                } else if (!strcmp(chptr, "fs")) {
+                    nextModule->major = DRIVER_FS;
+                } else if (!strcmp(chptr, "cdrom")) {
+                    nextModule->major = DRIVER_CDROM;
+                } else if (!strcmp(chptr, "ide")) {
+                    nextModule->major = DRIVER_IDE;
+                } else {
+                    nextModule->major = DRIVER_OTHER;
+                }
+            } else if (!nextModule->description) {
+                chptr = start + strlen(start) - 1;
+                if (*start == '"' && *chptr == '"') {
+                    start++;
+                    *chptr = '\0';
+                    nextModule->description = strdup(start);
+                }
+            } else {
+                nextModule->args = realloc(nextModule->args,
+                        sizeof(*nextModule->args) * (nextModule->numArgs + 1));
+                chptr = start;
+                while (!isspace(*chptr) && *chptr) chptr++;
+                if (*chptr) {
+                    oldch = *chptr;
+                    *chptr = '\0';
+                    nextModule->args[nextModule->numArgs].arg = strdup(start);
+
+                    start = chptr + 1;
+                    while (*start && isspace(*start)) start++;
+
+                    if (*start == '"') {
+                        start++;
+                        chptr = strchr(start, '"');
+                        if (chptr) {
+                            *chptr = '\0';
+                            nextModule->args[nextModule->numArgs].description = 
+                                strdup(start);
+                            nextModule->numArgs++;
+                        }
+                    }
+                }
+            }
+        }
+
+        start = next;
+    }
+
+    /* do we need to add in this last module? */
+    if (nextModule && ((nextModule - mis->moduleList) == mis->numModules))
+        mis->numModules++;
+
+    return 0;
+}
+
+void freeModuleInfoSet(moduleInfoSet mis) {
+    int i, j;
+
+    for (i = 0; i < mis->numModules; i++) {
+        if (mis->moduleList[i].moduleName) 
+            free(mis->moduleList[i].moduleName);
+
+        if (mis->moduleList[i].description) 
+            free(mis->moduleList[i].description);
+
+        for (j = 0; i < mis->moduleList[i].numArgs; j++) {
+            if (mis->moduleList[i].args[j].arg) 
+                free(mis->moduleList[i].args[j].arg) ;
+            if (mis->moduleList[i].args[j].description) 
+                free(mis->moduleList[i].args[j].description) ;
+        }
+    }
+
+    free(mis);
+}
diff --git a/bin/loader/moduleinfo.h b/bin/loader/moduleinfo.h
new file mode 100644
index 0000000..72f6d71
--- /dev/null
+++ b/bin/loader/moduleinfo.h
@@ -0,0 +1,78 @@
+/*
+ * moduleinfo.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MODULEINFO_H
+#define MODULEINFO_H
+
+enum driverMajor { DRIVER_NONE = 0, DRIVER_SCSI, DRIVER_NET, DRIVER_CDROM,
+		   DRIVER_PCMCIA, DRIVER_FS, DRIVER_IDE, DRIVER_OTHER = 1000,
+                   DRIVER_ANY = 5000 };
+enum driverMinor { DRIVER_MINOR_NONE = 0, DRIVER_MINOR_ETHERNET,
+		   DRIVER_MINOR_TR };
+
+struct moduleArg {
+    char * arg;
+    char * description;
+};
+
+#define MI_FLAG_NOMISCARGS	(1 << 0)
+
+struct moduleInfo {
+    char * moduleName;
+    char * description;
+    enum driverMajor major;
+    enum driverMinor minor;
+    int numArgs;
+    struct moduleArg * args;
+    int flags;
+    void * locationID;
+};
+
+struct moduleInfoSet_s {
+    struct moduleInfo * moduleList;
+    int numModules;
+};
+
+struct moduleBallLocation {
+    char * path; /* path to module ball that this driver is from. if NULL,
+                  * implies /modules/modules.cgz */
+    char * title; /* title used for driver disk -- may be NULL */
+    int version;  /* module ball version, used to determine layout */
+};
+#define CURRENT_MODBALLVER 1
+
+/* valid moduleball versions
+ * 0: old single-arch module ball, modules are in uname.release
+ * 1: multi-arch, modules are in uname.release/arch
+ */
+
+typedef struct moduleInfoSet_s * moduleInfoSet;
+
+moduleInfoSet newModuleInfoSet(void);
+void freeModuleInfoSet(moduleInfoSet mis);
+int readModuleInfo(const char * filename, moduleInfoSet mis, void * path, int override);
+struct moduleInfo * findModuleInfo(moduleInfoSet mis, 
+				   const char * moduleName);
+
+/* NULL moduleName indicates the end of the list; the list must be freed() */
+struct moduleInfo * getModuleList(moduleInfoSet mis, 
+				  enum driverMajor major);
+
+
+#endif
diff --git a/bin/loader/modules.c b/bin/loader/modules.c
new file mode 100644
index 0000000..89f956c
--- /dev/null
+++ b/bin/loader/modules.c
@@ -0,0 +1,530 @@
+/*
+ * modules.c - module loading functionality
+ *
+ * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+ *               2008, 2009  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ *            David Cantrell <dcantrell redhat com>
+ */
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <assert.h>
+
+#include "../isys/log.h"
+
+#include "loader.h"
+#include "modules.h"
+#include "windows.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+static GSList *modopts = NULL;
+static GSList *blacklist = NULL;
+
+static gboolean _isValidModule(gchar *module) {
+    gint fd = -1, i = 0;
+    gchar *path = NULL, *buf = NULL, *modname = NULL;
+    gchar *ends[] = { ".ko.gz:", ".ko:", NULL };
+    struct utsname utsbuf;
+    struct stat sbuf;
+
+    if (uname(&utsbuf) == -1) {
+        logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+        return FALSE;
+    }
+
+    if (asprintf(&path, "/lib/modules/%s/modules.dep", utsbuf.release) == -1) {
+        logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+        return FALSE;
+    }
+
+    if (stat(path, &sbuf) == -1) {
+        logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+        free(path);
+        return FALSE;
+    }
+
+    if ((fd = open(path, O_RDONLY)) == -1) {
+        logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+        free(path);
+        return FALSE;
+    } else {
+        free(path);
+    }
+
+    buf = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+    if (!buf || buf == MAP_FAILED) {
+        close(fd);
+        return FALSE;
+    }
+
+    close(fd);
+
+    while (ends[i] != NULL) {
+        if (asprintf(&modname, "/%s%s", module, ends[i]) == -1) {
+            logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+            return FALSE;
+        }
+
+        if (g_strstr_len(buf, -1, modname) != NULL) {
+            munmap(buf, sbuf.st_size);
+            free(modname);
+            return TRUE;
+        }
+
+        free(modname);
+        modname = NULL;
+        i++;
+    }
+
+    munmap(buf, sbuf.st_size);
+    return FALSE;
+}
+
+static void _addOption(const gchar *module, const gchar *option) {
+    gboolean found = FALSE;
+    GSList *iterator = modopts;
+    module_t *modopt = NULL;
+    gchar *tmpopt = g_strdup(option);
+
+    while (iterator != NULL) {
+        modopt = (module_t *) iterator->data;
+
+        if (!strncmp(modopt->name, module, strlen(modopt->name))) {
+            found = TRUE;
+            break;
+        }
+
+        iterator = g_slist_next(iterator);
+    }
+
+    if (found) {
+        modopt->options = g_slist_append(modopt->options, tmpopt);
+    } else {
+        if ((modopt = g_malloc0(sizeof(module_t))) == NULL) {
+            logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+            abort();
+        }
+
+        modopt->name = g_strdup(module);
+        modopt->options = NULL;
+        modopt->options = g_slist_append(modopt->options, tmpopt);
+        modopts = g_slist_append(modopts, modopt);
+    }
+
+    return;
+}
+
+static gboolean _writeModulesConf(gchar *conf) {
+    gint fd = -1, rc = 0, len = 0;
+    GSList *iterator = modopts;
+    GString *buf = g_string_new("# Module options and blacklists written by anaconda\n");
+
+    if (conf == NULL) {
+        /* XXX: should this use mkstemp() ? */
+        conf = "/tmp/modprobe.conf";
+    }
+
+    if ((fd = open(conf, O_WRONLY | O_CREAT, 0644)) == -1) {
+        logMessage(ERROR, "error opening to %s: %m", conf);
+        return FALSE;
+    }
+
+    while (iterator != NULL) {
+        module_t *modopt = iterator->data;
+        GSList *optiterator = modopt->options;
+        g_string_append_printf(buf, "options %s", modopt->name);
+
+        while (optiterator != NULL) {
+            gchar *option = (gchar *) optiterator->data;
+            g_string_append_printf(buf, " %s", option);
+            optiterator = g_slist_next(optiterator);
+        }
+
+        g_string_append(buf, "\n");
+        iterator = g_slist_next(iterator);
+    }
+
+    iterator = blacklist;
+
+    while (iterator != NULL) {
+        gchar *module = (gchar *) iterator->data;
+        g_string_append_printf(buf, "blacklist %s\n", module);
+        iterator = g_slist_next(iterator);
+    }
+
+    len = buf->len;
+    rc = write(fd, buf->str, len);
+    close(fd);
+    g_string_free(buf, TRUE);
+
+    return (rc == len);
+}
+
+static gboolean _doLoadModule(const gchar *module, gchar **args) {
+    gint child;
+    gint status;
+
+    if (!(child = fork())) {
+        gint i, rc;
+        gchar **argv = NULL;
+        gint fd = -1;
+
+        if ((argv = g_malloc0(3 * sizeof(*argv))) == NULL) {
+            logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+            abort();
+        }
+
+        if ((fd = open("/dev/tty3", O_RDWR)) == -1) {
+            logMessage(ERROR, "%s (%d): %m", __func__, __LINE__);
+        } else {
+            dup2(fd, 0);
+            dup2(fd, 1);
+            dup2(fd, 2);
+            close(fd);
+        }
+
+        argv[0] = "/sbin/modprobe";
+        argv[1] = g_strdup(module);
+        argv[2] = NULL;
+
+        if (args) {
+            for (i = 0; args[i] ; i++) {
+                _addOption(module, args[i]);
+            }
+            _writeModulesConf(MODULES_CONF);
+        }
+
+        rc = execv("/sbin/modprobe", argv);
+        g_strfreev(argv);
+        _exit(rc);
+    }
+
+    waitpid(child, &status, 0);
+
+    if (!WIFEXITED(status) || (WIFEXITED(status) && WEXITSTATUS(status))) {
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+gboolean mlInitModuleConfig(void) {
+    gint i = 0;
+    gchar *cmdline = NULL;
+    gchar **options = NULL;
+    GError *readErr = NULL;
+
+    /* read module options out of /proc/cmdline and into a structure */
+    if (!g_file_get_contents("/proc/cmdline", &cmdline, NULL, &readErr)) {
+        logMessage(ERROR, "unable to read /proc/cmdline: %s", readErr->message);
+        g_error_free(readErr);
+        return _writeModulesConf(MODULES_CONF);
+    }
+
+    cmdline = g_strchomp(cmdline);
+    options = g_strsplit(cmdline, " ", 0);
+    g_free(cmdline);
+
+    if (options == NULL) {
+        return _writeModulesConf(MODULES_CONF);
+    }
+
+    while (options[i] != NULL) {
+        gchar *tmpmod = NULL;
+        gchar **fields = NULL;
+
+        if (g_strstr_len(options[i], -1, "=") == NULL) {
+            i++;
+            continue;
+        }
+
+        if (!strncmp(options[i], "blacklist=", 10)) {
+            if ((fields = g_strsplit(options[i], "=", 0)) != NULL) {
+                if (g_strv_length(fields) == 2) {
+                    tmpmod = g_strdup(fields[1]);
+                    blacklist = g_slist_append(blacklist, tmpmod);
+                }
+            }
+        } else if ((fields = g_strsplit(options[i], ".", 0)) != NULL) {
+            if (g_strv_length(fields) == 2) {
+                if (_isValidModule(fields[0])) {
+                    _addOption(fields[0], fields[1]);
+                }
+            }
+        }
+
+        if (fields != NULL) {
+            g_strfreev(fields);
+        }
+
+        i++;
+    }
+
+    if (options != NULL) {
+        g_strfreev(options);
+    }
+
+    return _writeModulesConf(MODULES_CONF);
+}
+
+/* load a module with a given list of arguments */
+gboolean mlLoadModule(const gchar *module, gchar **args) {
+    return _doLoadModule(module, args);
+}
+
+/* loads a : separated list of modules */
+gboolean mlLoadModuleSet(const gchar *modNames) {
+    gchar **mods = NULL, **iterator = NULL;
+    gboolean rc = FALSE;
+
+    if (modNames == NULL) {
+        return FALSE;
+    }
+
+    if ((mods = g_strsplit(modNames, ":", 0)) != NULL) {
+        iterator = mods;
+
+        while (*iterator != NULL) {
+            rc |= _doLoadModule(*iterator, NULL);
+            iterator++;
+        }
+    } else {
+        return FALSE;
+    }
+
+    g_strfreev(mods);
+    return rc;
+}
+
+gboolean mlAddBlacklist(gchar *module) {
+    gchar *tmpmod = NULL;
+
+    if (module == NULL) {
+        return FALSE;
+    }
+
+    tmpmod = g_strdup(module);
+    blacklist = g_slist_append(blacklist, tmpmod);
+    return _writeModulesConf(MODULES_CONF);
+}
+
+gboolean mlRemoveBlacklist(gchar *module) {
+    GSList *iterator = blacklist;
+
+    if (module == NULL) {
+        return FALSE;
+    }
+
+    while (iterator != NULL) {
+        if (!strcmp((gchar *) iterator->data, module)) {
+            iterator = g_slist_delete_link(blacklist, iterator);
+            continue;
+        } else {
+            iterator = g_slist_next(iterator);
+        }
+    }
+
+    return TRUE;
+}
+
+void loadKickstartModule(struct loaderData_s * loaderData,
+                         int argc, char **argv) {
+    gchar *opts = NULL;
+    gchar *module = NULL;
+    gchar **args = NULL, **remaining = NULL;
+    gboolean rc;
+    GOptionContext *optCon = g_option_context_new(NULL);
+    GError *optErr = NULL;
+    GOptionEntry ksDeviceOptions[] = {
+        { "opts", 0, 0, G_OPTION_ARG_STRING, &opts, NULL, NULL },
+        { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &remaining,
+          NULL, NULL },
+        { NULL },
+    };
+
+    g_option_context_set_help_enabled(optCon, FALSE);
+    g_option_context_add_main_entries(optCon, ksDeviceOptions, NULL);
+
+    if (!g_option_context_parse(optCon, &argc, &argv, &optErr)) {
+        startNewt();
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("Bad argument to device kickstart method "
+                         "command: %s"), optErr->message);
+        g_error_free(optErr);
+        g_option_context_free(optCon);
+        return;
+    }
+
+    g_option_context_free(optCon);
+
+    if ((remaining != NULL) && (g_strv_length(remaining) == 1)) {
+        module = remaining[0];
+    }
+
+    if (!module) {
+        startNewt();
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("A module name must be specified for "
+                         "the kickstart device command."));
+        return;
+    }
+
+    if (opts) {
+        args = g_strsplit(opts, " ", 0);
+    }
+
+    rc = mlLoadModule(module, args);
+    g_strfreev(args);
+    return;
+}
+
+inline gint gcmp(gconstpointer a, gconstpointer b, gpointer userptr)
+{
+    return g_strcmp0(a, b);
+}
+
+int processModuleLines(GTree *data, int (*f)(gchar**, GTree*)){
+    char *line = NULL;
+    size_t linesize = 0;
+    gchar** lineparts = NULL;
+    int count = 0;
+
+    FILE *file = fopen("/proc/modules", "r");
+    if (file == NULL)
+        return -1;
+
+    while (1) {
+        if (getline(&line, &linesize, file) < 0)
+            break;
+
+        if (*line == NULL)
+            break;
+
+        lineparts = g_strsplit_set(line, " ", 4);
+
+        free(line);
+        line = NULL;
+
+        int ret = f(lineparts, data);
+        g_strfreev(lineparts);
+
+        if (ret < 0)
+            break;
+        count+=ret;
+    }
+
+    fclose(file);
+    return count;
+}
+
+inline int cb_savestate(gchar** parts, GTree *data)
+{
+    logMessage(DEBUGLVL, "Saving module %s", parts[0]);
+    g_tree_insert(data, g_strdup(parts[0]), (gchar*)1);
+    return 1;
+}
+
+GTree* mlSaveModuleState()
+{
+    GTree *state = NULL;
+
+    state = g_tree_new_full(gcmp, NULL, g_free, NULL);
+    if(!state)
+        return NULL;
+
+    processModuleLines(state, cb_savestate);
+
+    return state;
+}
+
+inline int cb_restorestate(gchar** parts, GTree *data)
+{
+    pid_t pid;
+    int status;
+
+    /* this module has to stay loaded */
+    if (g_tree_lookup(data, parts[0])){
+        return 0;
+    }
+
+    /* this module is still required */
+    if (parts[2][0] != '0') {
+        return 0;
+    }
+
+    /* rmmod parts[0] */
+    pid = fork();
+    if (pid == 0) {
+        execl("/sbin/rmmod", "-f", parts[0], NULL);
+        _exit(1);
+    }
+    else if (pid < 0) {
+        logMessage(ERROR, "Module %s removal FAILED", parts[0]);
+        return 0;
+    }
+
+    waitpid(pid, &status, 0);
+    if (WEXITSTATUS(status)) {
+        logMessage(DEBUGLVL, "Module %s was NOT removed", parts[0]);
+        return 0;
+    }
+    else{
+        logMessage(DEBUGLVL, "Module %s was removed", parts[0]);
+        return 1;
+    }
+    
+    return 0;
+}
+
+void mlRestoreModuleState(GTree *state)
+{
+    if(!state)
+        return;
+
+    logMessage(INFO, "Restoring module state...");
+
+    /* repeat until we can't remove anything else */
+    while (processModuleLines(state, cb_restorestate) > 0)
+        /* noop */;
+}
+
+void mlFreeModuleState(GTree *state)
+{
+    if(!state)
+        return;
+
+    g_tree_destroy(state);
+}
diff --git a/bin/loader/modules.h b/bin/loader/modules.h
new file mode 100644
index 0000000..605d01e
--- /dev/null
+++ b/bin/loader/modules.h
@@ -0,0 +1,47 @@
+/*
+ * modules.h
+ *
+ * Copyright (C) 2007, 2009  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): David Cantrell <dcantrell redhat com>
+ */
+
+#ifndef H_MODULES
+#define H_MODULES
+
+#include <glib.h>
+#include "loader.h"
+#include "moduleinfo.h"
+
+#define MODULES_CONF "/etc/modprobe.d/anaconda.conf"
+
+typedef struct _module_t {
+    gchar *name;
+    GSList *options;
+} module_t;
+
+gboolean mlInitModuleConfig(void);
+gboolean mlLoadModule(const gchar *, gchar **);
+gboolean mlLoadModuleSet(const gchar *);
+gboolean mlAddBlacklist(gchar *);
+gboolean mlRemoveBlacklist(gchar *);
+void loadKickstartModule(struct loaderData_s *, int, char **);
+
+GTree* mlSaveModuleState();
+void mlRestoreModuleState(GTree *state);
+void mlFreeModuleState(GTree *state);
+
+#endif
diff --git a/bin/loader/net.c b/bin/loader/net.c
new file mode 100644
index 0000000..0a3afa1
--- /dev/null
+++ b/bin/loader/net.c
@@ -0,0 +1,2122 @@
+/*
+ * net.c
+ *
+ * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005  Red Hat, Inc.
+ *               2006, 2007, 2008, 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): David Cantrell <dcantrell redhat com>
+ */
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <resolv.h>
+#include <net/if.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <NetworkManager.h>
+#include <nm-client.h>
+
+#include "../isys/isys.h"
+#include "../isys/ethtool.h"
+#include "../isys/iface.h"
+#include "../isys/log.h"
+
+#include "lang.h"
+#include "loader.h"
+#include "loadermisc.h"
+#include "method.h"
+#include "net.h"
+#include "windows.h"
+#include "ibft.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+/**
+ * Callback function for the CIDR entry boxes on the manual TCP/IP
+ * configuration window.
+ *
+ * @param co The entry field that triggered the callback.
+ * @param dptr Pointer to intfconfig_s data structure for this field.
+ * @see intfconfig_s
+ */
+static void cidrCallback(newtComponent co, void * dptr) {
+    struct intfconfig_s * data = dptr;
+    int cidr, upper = 0;
+    struct in_addr addr;
+
+    if (co == data->cidr4Entry) {
+        if (data->cidr4 == NULL && data->ipv4 == NULL)
+            return;
+
+        if (inet_pton(AF_INET, data->cidr4, &addr) >= 1)
+            return;
+
+        errno = 0;
+        cidr = strtol(data->cidr4, NULL, 10);
+        if ((errno == ERANGE && (cidr == LONG_MIN || cidr == LONG_MAX)) ||
+            (errno != 0 && cidr == 0)) {
+            logMessage(ERROR, "%s: %d: %m", __func__, __LINE__);
+            abort();
+        }
+
+        if (strcmp(data->ipv4, ""))
+            upper = 32;
+#ifdef ENABLE_IPV6
+    } else if (co == data->cidr6Entry) {
+        if (data->cidr6 == NULL && data->ipv6 == NULL)
+            return;
+
+        errno = 0;
+        cidr = strtol(data->cidr6, NULL, 10);
+        if ((errno == ERANGE && (cidr == LONG_MIN || cidr == LONG_MAX)) ||
+            (errno != 0 && cidr == 0)) {
+            logMessage(ERROR, "%s: %d: %m", __func__, __LINE__);
+            abort();
+        }
+
+        if (strcmp(data->ipv6, ""))
+            upper = 128;
+#endif
+    }
+
+    if (upper != 0) {
+        if (cidr < 1 || cidr > upper) {
+            newtWinMessage(_("Invalid Prefix"), _("Retry"),
+                           _("Prefix must be between 1 and 32 "
+                             "for IPv4 networks or between 1 and 128 "
+                             "for IPv6 networks"));
+        }
+    }
+}
+
+static void ipCallback(newtComponent co, void * dptr) {
+    int i;
+    char *buf, *octet;
+    struct intfconfig_s * data = dptr;
+
+    if (co == data->ipv4Entry) {
+        /* do we need to guess a netmask for the user? */
+        if (data->cidr4 == NULL && data->ipv4 != NULL) {
+            buf = strdup(data->ipv4);
+            octet = strtok(buf, ".");
+            errno = 0;
+            i = strtol(octet, NULL, 10);
+
+            if ((errno == ERANGE && (i == LONG_MIN || i == LONG_MAX)) ||
+                (errno != 0 && i == 0)) {
+                logMessage(ERROR, "%s: %d: %m", __func__, __LINE__);
+                abort();
+            }
+
+            free(buf);
+            free(octet);
+
+            if (i >= 0 && i <= 127)
+                newtEntrySet(data->cidr4Entry, "8", 1);
+            else if (i >= 128 && i <= 191)
+                newtEntrySet(data->cidr4Entry, "16", 1);
+            else if (i >= 192 && i <= 222)
+                newtEntrySet(data->cidr4Entry, "24", 1);
+        }
+
+        return;
+#ifdef ENABLE_IPV6
+    } else if (co == data->ipv6Entry) {
+        /* users must provide a mask, we can't guess for ipv6 */
+        return;
+#endif
+    }
+}
+
+static void setMethodSensitivity(void *dptr, int radio_button_count) {
+    int i = 0;
+
+    for (i = 0; i < radio_button_count; i++) {
+        newtCheckboxSetFlags(*((newtComponent *) dptr), NEWT_FLAG_DISABLED,
+                             NEWT_FLAGS_TOGGLE);
+        dptr += sizeof (newtComponent);
+    }
+
+    return;
+}
+
+static void v4MethodCallback(newtComponent co, void *dptr) {
+    setMethodSensitivity(dptr, 2);
+    return;
+}
+
+#ifdef ENABLE_IPV6
+static void v6MethodCallback(newtComponent co, void *dptr) {
+    setMethodSensitivity(dptr, 3);
+    return;
+}
+#endif
+
+static void parseEthtoolSettings(struct loaderData_s * loaderData) {
+    char * option, * buf;
+    ethtool_duplex duplex = ETHTOOL_DUPLEX_UNSPEC;
+    ethtool_speed speed = ETHTOOL_SPEED_UNSPEC;
+    
+    buf = strdup(loaderData->ethtool);
+    option = strtok(buf, " ");
+    while (option) {
+        if (option[strlen(option) - 1] == '\"')
+            option[strlen(option) - 1] = '\0';
+        if (option[0] == '\"')
+            option++;
+        if (!strncmp(option, "duplex", 6)) {
+            if (!strncmp(option + 7, "full", 4)) 
+                duplex = ETHTOOL_DUPLEX_FULL;
+            else if (!strncmp(option + 7, "half", 4))
+                duplex = ETHTOOL_DUPLEX_HALF;
+            else
+                logMessage(WARNING, "Unknown duplex setting: %s", option + 7);
+            option = strtok(NULL, " ");
+        } else if (!strncmp("speed", option, 5)) {
+            if (!strncmp(option + 6, "1000", 4))
+                speed = ETHTOOL_SPEED_1000;
+            else if (!strncmp(option + 6, "100", 3))
+                speed = ETHTOOL_SPEED_100;
+            else if (!strncmp(option + 6, "10", 2))
+                speed = ETHTOOL_SPEED_10;
+            else
+                logMessage(WARNING, "Unknown speed setting: %s", option + 6);
+            option = strtok(NULL, " ");
+        } else {
+            logMessage(WARNING, "Unknown ethtool setting: %s", option);
+        }
+        option = strtok(NULL, " ");
+    }
+    setEthtoolSettings(loaderData->netDev, speed, duplex);
+    free(buf);
+}
+
+/* given loader data from kickstart, populate network configuration struct */
+void setupIfaceStruct(iface_t * iface, struct loaderData_s * loaderData) {
+    struct in_addr addr;
+    struct in6_addr addr6;
+    char * c;
+
+    memset(&addr, 0, sizeof(addr));
+    memset(&addr6, 0, sizeof(addr6));
+
+    if (loaderData->ethtool) {
+        parseEthtoolSettings(loaderData);
+    }
+
+    if (loaderData->netCls_set) {
+        iface->vendorclass = loaderData->netCls;
+    } else {
+        iface->vendorclass = NULL;
+    }
+
+    if (loaderData->ipinfo_set && loaderData->ipv4 != NULL) {
+	/* this is iBFT configured device */
+	if (!strncmp(loaderData->ipv4, "ibft", 4)) {
+	    char *devmacaddr = iface_mac2str(loaderData->netDev);
+	    iface->ipv4method = IPV4_IBFT_METHOD;
+	    iface->isiBFT = 1;
+
+	    /* Problems with getting the info from iBFT or iBFT uses dhcp*/
+	    if(!devmacaddr || !ibft_present()){
+		iface->ipv4method = IPV4_DHCP_METHOD;
+		logMessage(INFO, "iBFT is not present");
+	    }
+
+	    /* MAC address doesn't match */
+	    else if(strcasecmp(ibft_iface_mac(), devmacaddr)){
+		iface->ipv4method = IPV4_DHCP_METHOD;
+		logMessage(INFO, "iBFT doesn't know what NIC to use - falling back to DHCP");
+	    }
+	    else if(ibft_iface_dhcp()){
+		iface->ipv4method = IPV4_IBFT_DHCP_METHOD;
+		logMessage(INFO, "iBFT is configured to use DHCP");
+	    }
+	    if(devmacaddr) free(devmacaddr);
+	}
+        /* this is how we specify dhcp */
+        else if (!strncmp(loaderData->ipv4, "dhcp", 4)) {
+            iface->dhcptimeout = loaderData->dhcpTimeout;
+            iface->ipv4method = IPV4_DHCP_METHOD;
+        } else if (inet_pton(AF_INET, loaderData->ipv4, &addr) >= 1) {
+            iface->ipaddr.s_addr = addr.s_addr;
+            iface->ipv4method = IPV4_MANUAL_METHOD;
+        } else { /* invalid ip information, disable the setting of ip info */
+            loaderData->ipinfo_set = 0;
+            iface->ipv4method = 0;
+            loaderData->ipv4 = NULL;
+        }
+     }
+
+    if (loaderData->netmask != NULL) {
+        if (inet_pton(AF_INET, loaderData->netmask, &iface->netmask) <= 0) {
+            logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                       strerror(errno));
+        }
+    }
+
+    if (loaderData->gateway != NULL) {
+        if (inet_pton(AF_INET, loaderData->gateway, &iface->gateway) <= 0) {
+            logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                       strerror(errno));
+        }
+    }
+
+#ifdef ENABLE_IPV6
+    if (loaderData->ipv6info_set && loaderData->ipv6 != NULL) {
+        if (!strncmp(loaderData->ipv6, "dhcp", 4)) {
+            iface->ipv6method = IPV6_DHCP_METHOD;
+        } else if (!strncmp(loaderData->ipv6, "auto", 4)) {
+            iface->ipv6method = IPV6_AUTO_METHOD;
+        } else if (inet_pton(AF_INET6, loaderData->ipv6, &addr6) >= 1) {
+            memcpy(&iface->ip6addr, &addr6, sizeof(struct in6_addr));
+            iface->ipv6method = IPV6_MANUAL_METHOD;
+        } else {
+            iface->ipv6method = 0;
+            loaderData->ipv6info_set = 0;
+            loaderData->ipv6 = NULL;
+        }
+    }
+
+    if (loaderData->gateway6 != NULL) {
+        if (inet_pton(AF_INET6, loaderData->gateway6, &iface->gateway6) <= 0) {
+            logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                       strerror(errno));
+        }
+    }
+#endif
+
+    /* iBFT configured DNS */
+    if(iface->ipv4method == IPV4_IBFT_METHOD){
+	if(iface->numdns<MAXNS){
+	    if(ibft_iface_dns1() && inet_pton(AF_INET, ibft_iface_dns1(), &addr)>=1){
+		iface->dns[iface->numdns] = strdup(ibft_iface_dns1());
+		iface->numdns++;
+		logMessage(INFO, "adding iBFT dns server %s", ibft_iface_dns1());
+	    }
+	}
+	if(iface->numdns<MAXNS){
+	    if(ibft_iface_dns2() && inet_pton(AF_INET, ibft_iface_dns2(), &addr)>=1){
+		iface->dns[iface->numdns] = strdup(ibft_iface_dns2());
+		iface->numdns++;
+		logMessage(INFO, "adding iBFT dns server %s", ibft_iface_dns2());
+	    }
+	}
+    }
+
+    if (loaderData->dns) {
+        char * buf;
+        char ret[INET6_ADDRSTRLEN+1];
+        buf = strdup(loaderData->dns);
+
+        /* Scan the dns parameter for multiple comma-separated IP addresses */
+        c = strtok(buf, ",");
+        while ((iface->numdns < MAXNS) && (c != NULL)) {
+            if (inet_pton(AF_INET, c, &addr) >= 1) {
+                iface->dns[iface->numdns] = strdup(c);
+                iface->numdns++;
+
+                if (inet_ntop(AF_INET, &addr, ret, INET_ADDRSTRLEN) == NULL) {
+                    logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno));
+                } else {
+                    logMessage(DEBUGLVL, "adding dns4 %s", ret);
+                    c = strtok(NULL, ",");
+                }
+            } else if (inet_pton(AF_INET6, c, &addr6) >= 1) {
+                iface->dns[iface->numdns] = strdup(c);
+                iface->numdns++;
+
+                if (inet_ntop(AF_INET6, &addr6, ret, INET6_ADDRSTRLEN) == NULL) {
+                    logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno));
+                } else {
+                    logMessage(DEBUGLVL, "adding dns6 %s", ret);
+                    c = strtok(NULL, ",");
+                }
+            }
+        }
+
+
+
+        logMessage(INFO, "dnsservers is %s", loaderData->dns);
+    }
+
+    if (loaderData->hostname) {
+        logMessage(INFO, "setting specified hostname of %s",
+                   loaderData->hostname);
+        iface->hostname = strdup(loaderData->hostname);
+    }
+
+    if (loaderData->mtu) {
+        iface->mtu = loaderData->mtu;
+    }
+
+    if (loaderData->peerid) {
+        iface->peerid = strdup(loaderData->peerid);
+    }
+
+    if (loaderData->subchannels) {
+        iface->subchannels = strdup(loaderData->subchannels);
+    }
+
+    if (loaderData->ctcprot) {
+        iface->ctcprot = strdup(loaderData->ctcprot);
+    }
+
+    if (loaderData->portname) {
+        iface->portname = strdup(loaderData->portname);
+    }
+
+    if (loaderData->nettype) {
+        iface->nettype = strdup(loaderData->nettype);
+    }
+
+    if (loaderData->ethtool) {
+        parseEthtoolSettings(loaderData);
+    }
+
+    if (loaderData->layer2) {
+        iface->layer2 = strdup(loaderData->layer2);
+    }
+
+    if (loaderData->portno) {
+        iface->portno = strdup(loaderData->portno);
+    }
+
+    if (loaderData->noDns) {
+        iface->flags |= IFACE_FLAGS_NO_WRITE_RESOLV_CONF;
+    }
+
+    iface->dhcptimeout = loaderData->dhcpTimeout;
+
+    return;
+}
+
+int readNetConfig(char * device, iface_t * iface,
+                  char * dhcpclass, int methodNum) {
+    int err;
+    int ret;
+    int i = 0;
+    struct netconfopts opts;
+    struct in_addr addr;
+    struct intfconfig_s ipcomps;
+
+    /* ipcomps contains the user interface components */
+    ipcomps.ipv4 = NULL;
+    ipcomps.cidr4 = NULL;
+    ipcomps.gw = NULL;
+#ifdef ENABLE_IPV6
+    ipcomps.ipv6 = NULL;
+    ipcomps.cidr6 = NULL;
+    ipcomps.gw6 = NULL;
+#endif
+    ipcomps.ns = NULL;
+
+    /* init opts */
+    opts.ipv4Choice = 0;
+#ifdef ENABLE_IPV6
+    opts.ipv6Choice = 0;
+#endif
+
+    /* JKFIXME: we really need a way to override this and be able to change
+     * our network config */
+    if (!FL_ASKNETWORK(flags) &&
+        ((iface->ipv4method > IPV4_UNUSED_METHOD) ||
+         (iface->ipv6method > IPV4_UNUSED_METHOD))) {
+        logMessage(INFO, "doing kickstart... setting it up");
+
+        err = writeEnabledNetInfo(iface);
+        if (err) {
+            logMessage(ERROR, "failed to write %s data for %s (%d)",
+                       SYSCONFIG_PATH, iface->device, err);
+            return LOADER_BACK;
+        }
+
+        i = get_connection(iface);
+        newtPopWindow();
+
+        if (i > 0) {
+            if (FL_CMDLINE(flags)) {
+                fprintf(stderr, _("There was an error configuring your network "
+                                  "interface."));
+                fprintf(stderr, _("\nThis cannot be corrected in cmdline mode.\n"
+                                  "Halting.\n"));
+                exit(1);
+            }
+
+            newtWinMessage(_("Network Error"), _("Retry"),
+                           _("There was an error configuring your network "
+                             "interface."));
+            return LOADER_BACK;
+        }
+
+        return LOADER_NOOP;
+    }
+
+    /* dhcp/manual network configuration loop */
+    i = 1;
+    while (i == 1) {
+        ret = configureTCPIP(device, iface, &opts, methodNum);
+
+        if (ret == LOADER_NOOP) {
+            /* dhcp selected, proceed */
+            i = 0;
+        } else if (ret == LOADER_OK) {
+            /* do manual configuration */
+            ret = manualNetConfig(device, iface, &ipcomps, &opts);
+
+            if (ret == LOADER_BACK) {
+                continue;
+            } else if (ret == LOADER_OK) {
+                i = 0;
+            }
+        } else if (ret == LOADER_BACK) {
+            return LOADER_BACK;
+        }
+    }
+
+    /* calculate any missing IPv4 pieces */
+    if (opts.ipv4Choice == '*') {
+        memset(&addr, 0, sizeof(addr));
+        addr.s_addr = (iface->ipaddr.s_addr) & (iface->netmask.s_addr);
+
+        if (iface->broadcast.s_addr == 0) {
+            iface->broadcast.s_addr = addr.s_addr | ~(iface->netmask.s_addr);
+        }
+    }
+
+    /* bring up the interface */
+    err = writeEnabledNetInfo(iface);
+    if (err) {
+        logMessage(ERROR, "failed to write %s data for %s (%d)",
+                   SYSCONFIG_PATH, iface->device, err);
+        iface->ipv4method = IPV4_UNUSED_METHOD;
+        iface->ipv6method = IPV6_UNUSED_METHOD;
+        return LOADER_BACK;
+    }
+
+    i = get_connection(iface);
+    newtPopWindow();
+
+    if (i > 0) {
+        newtWinMessage(_("Network Error"), _("Retry"),
+                       _("There was an error configuring your network "
+                         "interface."));
+        iface->ipv4method = IPV4_UNUSED_METHOD;
+        iface->ipv6method = IPV6_UNUSED_METHOD;
+        return LOADER_ERROR;
+    }
+
+    return LOADER_OK;
+}
+
+int configureTCPIP(char * device, iface_t * iface,
+                   struct netconfopts * opts, int methodNum) {
+    int i = 0, z = 0, skipForm = 0, ret;
+    newtComponent f, okay, back, answer;
+    newtComponent ipv4Checkbox, v4Method[2];
+#ifdef ENABLE_IPV6
+    newtComponent ipv6Checkbox, v6Method[3];
+#endif
+    newtGrid grid, checkgrid, buttons;
+
+    /* UI WINDOW 1: ask for ipv4 choice, ipv6 choice, and conf methods */
+
+    /* IPv4 checkbox */
+    if (!opts->ipv4Choice) {
+        if (FL_NOIPV4(flags) && !FL_IP_PARAM(flags))
+            opts->ipv4Choice = ' ';
+        else
+            opts->ipv4Choice = '*';
+    }
+
+    ipv4Checkbox = newtCheckbox(-1, -1, _("Enable IPv4 support"),
+                                opts->ipv4Choice, NULL, &(opts->ipv4Choice));
+    v4Method[0] = newtRadiobutton(-1, -1, DHCP_METHOD_STR, 1, NULL);
+    v4Method[1] = newtRadiobutton(-1, -1, MANUAL_METHOD_STR, 0, v4Method[0]);
+
+#ifdef ENABLE_IPV6
+    /* IPv6 checkbox */
+    if (!opts->ipv6Choice) {
+        if (FL_NOIPV6(flags) && !FL_IPV6_PARAM(flags))
+            opts->ipv6Choice = ' ';
+        else
+            opts->ipv6Choice = '*';
+    }
+
+    ipv6Checkbox = newtCheckbox(-1, -1, _("Enable IPv6 support"),
+                                opts->ipv6Choice, NULL, &(opts->ipv6Choice));
+    v6Method[0] = newtRadiobutton(-1, -1, AUTO_METHOD_STR, 1, NULL);
+    v6Method[1] = newtRadiobutton(-1, -1, DHCPV6_METHOD_STR, 0, v6Method[0]);
+    v6Method[2] = newtRadiobutton(-1, -1, MANUAL_METHOD_STR, 0, v6Method[1]);
+#endif
+
+    /* button bar at the bottom of the window */
+    buttons = newtButtonBar(_("OK"), &okay, _("Back"), &back, NULL);
+
+    /* checkgrid contains the toggle options for net configuration */
+#ifdef ENABLE_IPV6
+    checkgrid = newtCreateGrid(1, 8);
+#else
+    checkgrid = newtCreateGrid(1, 3);
+#endif
+
+    newtGridSetField(checkgrid, 0, 0, NEWT_GRID_COMPONENT, ipv4Checkbox,
+                     0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+    for (i = 1; i < 3; i++)
+        newtGridSetField(checkgrid, 0, i, NEWT_GRID_COMPONENT, v4Method[i-1],
+                         7, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+
+#ifdef ENABLE_IPV6
+    newtGridSetField(checkgrid, 0, 4, NEWT_GRID_COMPONENT, ipv6Checkbox,
+                     0, 1, 0, 0, NEWT_ANCHOR_LEFT, 0);
+    for (i = 5; i < 8; i++)
+        newtGridSetField(checkgrid, 0, i, NEWT_GRID_COMPONENT, v6Method[i-5],
+                         7, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+#endif
+
+    /* main window layout */
+    grid = newtCreateGrid(1, 2);
+    newtGridSetField(grid, 0, 0, NEWT_GRID_SUBGRID, checkgrid,
+                     0, 0, 0, 1, 0, 0);
+    newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, buttons,
+                     0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+    f = newtForm(NULL, NULL, 0);
+    newtGridAddComponentsToForm(grid, f, 1);
+    newtGridWrappedWindow(grid, _("Configure TCP/IP"));
+    newtGridFree(grid, 1);
+
+    /* callbacks */
+    newtComponentAddCallback(ipv4Checkbox, v4MethodCallback, &v4Method);
+#ifdef ENABLE_IPV6
+    newtComponentAddCallback(ipv6Checkbox, v6MethodCallback, &v6Method);
+#endif
+
+    /* match radio button sensitivity to initial checkbox choices */
+    if (opts->ipv4Choice == ' ')
+        setMethodSensitivity(&v4Method, 2);
+
+#ifdef ENABLE_IPV6
+    if (opts->ipv6Choice == ' ')
+        setMethodSensitivity(&v6Method, 3);
+#endif
+
+#ifdef ENABLE_IPV6
+    /* If the user provided any of the following boot paramters, skip
+     * prompting for network configuration information:
+     *     ip=<val> ipv6=<val>
+     *     noipv4 noipv6
+     *     ip=<val> noipv6
+     *     ipv6=<val> noipv4
+     */
+    if ((FL_IP_PARAM(flags) && FL_IPV6_PARAM(flags)) ||
+        (FL_IP_PARAM(flags) && FL_NOIPV6(flags)) ||
+        (FL_IPV6_PARAM(flags) && FL_NOIPV4(flags)) ||
+        (FL_NOIPV4(flags) && FL_NOIPV6(flags))) {
+        skipForm = 1;
+        newtPopWindow();
+    }
+#else
+    if (FL_IP_PARAM(flags) || FL_NOIPV4(flags)) {
+        skipForm = 1;
+        newtPopWindow();
+    }
+#endif
+
+    /* run the form */
+    do {
+        if (!skipForm) {
+            answer = newtRunForm(f);
+
+            if (answer == back) {
+                newtFormDestroy(f);
+                newtPopWindow();
+                return LOADER_BACK;
+            }
+
+            /* need at least one stack */
+#ifdef ENABLE_IPV6
+            if (opts->ipv4Choice == ' ' && opts->ipv6Choice == ' ') {
+#else
+            if (opts->ipv4Choice == ' ') {
+#endif
+                newtWinMessage(_("Missing Protocol"), _("Retry"),
+                               _("You must select at least one protocol (IPv4 "
+                                 "or IPv6)."));
+                continue;
+            }
+
+            /* NFS only works over IPv4 */
+            if (opts->ipv4Choice == ' ' && methodNum == METHOD_NFS) {
+                newtWinMessage(_("IPv4 Needed for NFS"), _("Retry"),
+                           _("NFS installation method requires IPv4 support."));
+                continue;
+            }
+        }
+
+        /* what TCP/IP stacks do we use? what conf methods? */
+        if (opts->ipv4Choice == '*') {
+            flags &= ~LOADER_FLAGS_NOIPV4;
+            for (z = IPV4_FIRST_METHOD; z <= IPV4_LAST_METHOD; z++)
+                if (newtRadioGetCurrent(v4Method[0]) == v4Method[z-1])
+                    iface->ipv4method = z;
+        } else {
+            flags |= LOADER_FLAGS_NOIPV4;
+        }
+
+#ifdef ENABLE_IPV6
+        if (opts->ipv6Choice == '*') {
+            flags &= ~LOADER_FLAGS_NOIPV6;
+            for (z = IPV6_FIRST_METHOD; z <= IPV6_LAST_METHOD; z++)
+                if (newtRadioGetCurrent(v6Method[0]) == v6Method[z-1])
+                    iface->ipv6method = z;
+        } else {
+            flags |= LOADER_FLAGS_NOIPV6;
+        }
+#endif
+
+        /* do interface configuration (call DHCP here, or return for manual) */
+#ifdef ENABLE_IPV6
+        if ((!FL_NOIPV4(flags) && iface->ipv4method == IPV4_DHCP_METHOD) ||
+            (!FL_NOIPV6(flags) && (iface->ipv6method == IPV6_AUTO_METHOD ||
+                                   iface->ipv6method == IPV6_DHCP_METHOD))) {
+#else
+        if (!FL_NOIPV4(flags) && iface->ipv4method == IPV4_DHCP_METHOD) {
+#endif
+            /* DHCP selected, exit the loop */
+            ret = LOADER_NOOP;
+            i = 1;
+#ifdef ENABLE_IPV6
+        } else if ((!FL_NOIPV4(flags) && iface->ipv4method == IPV4_MANUAL_METHOD) ||
+                   (!FL_NOIPV6(flags) && iface->ipv6method == IPV6_MANUAL_METHOD)) {
+#else
+        } else if (!FL_NOIPV4(flags) && iface->ipv4method == IPV4_MANUAL_METHOD) {
+#endif
+
+            /* manual IP configuration selected */
+            ret = LOADER_OK;
+            i = 1;
+        }
+    } while (i != 1);
+
+    newtFormDestroy(f);
+    newtPopWindow();
+    return ret;
+}
+
+int manualNetConfig(char * device, iface_t * iface,
+                    struct intfconfig_s * ipcomps, struct netconfopts * opts) {
+    int i, rows, pos, cidr, have[2], stack[2];
+    char *buf = NULL;
+    char ret[48];
+    struct in_addr addr;
+#ifdef ENABLE_IPV6
+    struct in6_addr addr6;
+    int prefix;
+#endif
+    struct in_addr *tmpaddr = NULL;
+    newtComponent f, okay, back, answer;
+    newtGrid egrid = NULL;
+    newtGrid qgrid = NULL;
+#ifdef ENABLE_IPV6
+    newtGrid rgrid = NULL;
+#endif
+    newtGrid buttons, grid;
+    newtComponent text = NULL;
+
+    memset(ret, '\0', INET6_ADDRSTRLEN+1);
+
+    /* so we don't perform this test over and over */
+    stack[IPV4] = opts->ipv4Choice == '*' &&
+                  iface->ipv4method == IPV4_MANUAL_METHOD;
+#ifdef ENABLE_IPV6
+    stack[IPV6] = opts->ipv6Choice == '*' &&
+                  iface->ipv6method == IPV6_MANUAL_METHOD;
+#endif
+
+    /* UI WINDOW 2 (optional): manual IP config for non-DHCP installs */
+    rows = 2;
+    for (i = 0; i < 2; i++) {
+        if (stack[i]) {
+            rows++;
+        }
+    }
+    egrid = newtCreateGrid(4, rows);
+
+    pos = 0;
+
+    /* IPv4 entry items */
+    if (stack[IPV4]) {
+        newtGridSetField(egrid, 0, pos, NEWT_GRID_COMPONENT,
+                         newtLabel(-1, -1, _("IPv4 address:")),
+                         0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+
+        ipcomps->ipv4Entry = newtEntry(-1, -1, NULL, 16, &ipcomps->ipv4, 0);
+        ipcomps->cidr4Entry = newtEntry(-1, -1, NULL, 16, &ipcomps->cidr4, 0);
+
+        /* use a nested grid for ipv4 addr & netmask */
+        qgrid = newtCreateGrid(3, 1);
+
+        newtGridSetField(qgrid, 0, 0, NEWT_GRID_COMPONENT,
+                         ipcomps->ipv4Entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+        newtGridSetField(qgrid, 1, 0, NEWT_GRID_COMPONENT,
+                         newtLabel(-1, -1, _("/")),
+                         1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+        newtGridSetField(qgrid, 2, 0, NEWT_GRID_COMPONENT,
+                         ipcomps->cidr4Entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+
+        newtGridSetField(egrid, 1, pos, NEWT_GRID_SUBGRID, qgrid,
+                         0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+
+        newtComponentAddCallback(ipcomps->ipv4Entry, ipCallback, ipcomps);
+        newtComponentAddCallback(ipcomps->cidr4Entry, cidrCallback, ipcomps);
+
+        /* populate fields if we have data already */
+        if (iface_have_in_addr(&iface->ipaddr)) {
+            if (inet_ntop(AF_INET, &iface->ipaddr, ret,
+                          INET_ADDRSTRLEN) == NULL) {
+                logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                           strerror(errno));
+            }
+        } else if (iface_have_in_addr(&iface->ipaddr)) {
+            if (inet_ntop(AF_INET, &iface->ipaddr, ret,
+                          INET_ADDRSTRLEN) == NULL) {
+                logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                           strerror(errno));
+            }
+        }
+
+        if (*ret) {
+            newtEntrySet(ipcomps->ipv4Entry, ret, 1);
+        }
+
+        if (iface_have_in_addr(&iface->netmask)) {
+            if (inet_ntop(AF_INET, &iface->netmask, ret,
+                          INET_ADDRSTRLEN) == NULL) {
+                logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                           strerror(errno));
+            }
+        } else if (iface_have_in_addr(&iface->netmask)) {
+            if (inet_ntop(AF_INET, &iface->netmask, ret,
+                          INET_ADDRSTRLEN) == NULL) {
+                logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                           strerror(errno));
+            }
+        }
+
+        if (*ret) {
+            newtEntrySet(ipcomps->cidr4Entry, ret, 1);
+        }
+
+        pos++;
+    }
+
+#ifdef ENABLE_IPV6
+    /* IPv6 entry items */
+    if (stack[IPV6]) {
+        newtGridSetField(egrid, 0, pos, NEWT_GRID_COMPONENT,
+                         newtLabel(-1, -1, _("IPv6 address:")),
+                         0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+
+        ipcomps->ipv6Entry = newtEntry(-1, -1, NULL, 41, &ipcomps->ipv6, 0);
+        ipcomps->cidr6Entry = newtEntry(-1, -1, NULL, 4, &ipcomps->cidr6, 0);
+
+        /* use a nested grid for ipv6 addr & netmask */
+        rgrid = newtCreateGrid(3, 1);
+
+        newtGridSetField(rgrid, 0, 0, NEWT_GRID_COMPONENT,
+                         ipcomps->ipv6Entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+        newtGridSetField(rgrid, 1, 0, NEWT_GRID_COMPONENT,
+                         newtLabel(-1, -1, _("/")),
+                         1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+        newtGridSetField(rgrid, 2, 0, NEWT_GRID_COMPONENT,
+                         ipcomps->cidr6Entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+
+        newtGridSetField(egrid, 1, pos, NEWT_GRID_SUBGRID, rgrid,
+                         0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+
+        newtComponentAddCallback(ipcomps->ipv6Entry, ipCallback, ipcomps);
+        newtComponentAddCallback(ipcomps->cidr6Entry, cidrCallback, ipcomps);
+
+        /* populate fields if we have data already */
+        if (iface_have_in6_addr(&iface->ip6addr)) {
+            if (inet_ntop(AF_INET6, &iface->ip6addr, ret,
+                          INET6_ADDRSTRLEN) == NULL) {
+                logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                           strerror(errno));
+            }
+        } else if (iface_have_in6_addr(&iface->ip6addr)) {
+            if (inet_ntop(AF_INET6, &iface->ip6addr, ret,
+                          INET6_ADDRSTRLEN) == NULL) {
+                logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                           strerror(errno));
+            }
+        }
+
+        if (*ret) {
+            newtEntrySet(ipcomps->ipv6Entry, ret, 1);
+        }
+
+        if (iface->ip6prefix) {
+            if (asprintf(&buf, "%d", iface->ip6prefix) == -1) {
+                buf = NULL;
+            }
+        } else if (iface->ip6prefix) {
+            if (asprintf(&buf, "%d", iface->ip6prefix) == -1) {
+                buf = NULL;
+            }
+        }
+
+        if (buf != NULL) {
+            newtEntrySet(ipcomps->cidr6Entry, buf, 1);
+            free(buf);
+        }
+
+        pos++;
+    }
+#endif
+
+    /* common entry items */
+    ipcomps->gwEntry = newtEntry(-1, -1, NULL, 41, &ipcomps->gw, 0);
+    ipcomps->nsEntry = newtEntry(-1, -1, NULL, 41, &ipcomps->ns, 0);
+
+    newtGridSetField(egrid, 0, pos, NEWT_GRID_COMPONENT,
+                     newtLabel(-1, -1, _("Gateway:")),
+                     0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+    newtGridSetField(egrid, 1, pos, NEWT_GRID_COMPONENT,
+                     ipcomps->gwEntry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+
+    pos++;
+
+    newtGridSetField(egrid, 0, pos, NEWT_GRID_COMPONENT,
+                     newtLabel(-1, -1, _("Name Server:")),
+                     0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+    newtGridSetField(egrid, 1, pos, NEWT_GRID_COMPONENT,
+                     ipcomps->nsEntry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+
+    if (iface_have_in_addr(&iface->gateway)) {
+        if (inet_ntop(AF_INET, &iface->gateway, ret,
+                      INET_ADDRSTRLEN) == NULL) {
+            logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                       strerror(errno));
+        } else {
+            newtEntrySet(ipcomps->gwEntry, ret, 1);
+        }
+    } else if (iface_have_in6_addr(&iface->gateway6)) {
+        if (inet_ntop(AF_INET6, &iface->gateway6, ret,
+                      INET6_ADDRSTRLEN) == NULL) {
+            logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                       strerror(errno));
+        } else {
+            newtEntrySet(ipcomps->gwEntry, ret, 1);
+        }
+    }
+
+    if (iface->numdns) {
+        newtEntrySet(ipcomps->nsEntry, iface->dns[0], 1);
+    } else if (iface->numdns) {
+        newtEntrySet(ipcomps->nsEntry, iface->dns[0], 1);
+    }
+
+    newtComponentAddCallback(ipcomps->gwEntry, ipCallback, ipcomps);
+    newtComponentAddCallback(ipcomps->nsEntry, ipCallback, ipcomps);
+
+    /* button bar at the bottom of the window */
+    buttons = newtButtonBar(_("OK"), &okay, _("Back"), &back, NULL);
+
+    /* main window layout */
+    grid = newtCreateGrid(1, 3);
+
+    checked_asprintf(&buf,
+                     _("Enter the IPv4 and/or the IPv6 address and prefix "
+                       "(address / prefix).  For IPv4, the dotted-quad "
+                       "netmask or the CIDR-style prefix are acceptable. "
+                       "The gateway and name server fields must be valid IPv4 "
+                       "or IPv6 addresses."));
+
+    text = newtTextboxReflowed(-1, -1, buf, 52, 0, 10, 0);
+
+    newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
+                     0, 0, 0, 1, NEWT_ANCHOR_LEFT, 0);
+    newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, egrid,
+                     0, 0, 0, 1, NEWT_ANCHOR_LEFT, 0);
+    newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
+                     0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+    f = newtForm(NULL, NULL, 0);
+    newtGridAddComponentsToForm(grid, f, 1);
+    newtGridWrappedWindow(grid, _("Manual TCP/IP Configuration"));
+    newtGridFree(grid, 1);
+
+    have[IPV4] = 0;
+    have[IPV6] = 0;
+
+    for (i = IPV4; i <= IPV6; i++) {
+        if (!stack[i]) {
+            have[i] = 2;
+        }
+    }
+
+    /* run the form */
+    while ((have[IPV4] != 2) || (have[IPV6] != 2)) {
+        answer = newtRunForm(f);
+
+        /* collect IPv4 data */
+        if (stack[IPV4]) {
+            if (ipcomps->ipv4) {
+                if (inet_pton(AF_INET, ipcomps->ipv4, &iface->ipaddr) <= 0) {
+                    logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                               strerror(errno));
+                } else {
+                    have[IPV4]++;
+                }
+            }
+
+            if (ipcomps->cidr4) {
+                if (inet_pton(AF_INET, ipcomps->cidr4, &iface->netmask) >= 1) {
+                    have[IPV4]++;
+                } else {
+                    errno = 0;
+                    cidr = strtol(ipcomps->cidr4, NULL, 10);
+
+                    if ((errno == ERANGE && (cidr == LONG_MIN ||
+                                             cidr == LONG_MAX)) ||
+                        (errno != 0 && cidr == 0)) {
+                        logMessage(ERROR, "%s: %d: %m", __func__, __LINE__);
+                        abort();
+                    }
+
+                    if (cidr >= 1 && cidr <= 32) {
+                        tmpaddr = iface_prefix2netmask(cidr);
+                        if (tmpaddr != NULL) {
+                            memcpy(&iface->netmask, tmpaddr,
+                                   sizeof(struct in_addr));
+                            have[IPV4]++;
+                        } else {
+                            iface->netmask.s_addr = 0;
+                        }
+                    }
+                }
+            }
+        }
+
+#ifdef ENABLE_IPV6
+        /* collect IPv6 data */
+        if (stack[IPV6]) {
+            if (ipcomps->ipv6) {
+                if (inet_pton(AF_INET6, ipcomps->ipv6, &iface->ip6addr) <= 0) {
+                    logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                               strerror(errno));
+                } else {
+                    have[IPV6]++;
+                }
+            }
+
+            if (ipcomps->cidr6) {
+                errno = 0;
+                prefix = strtol(ipcomps->cidr6, NULL, 10);
+
+                if ((errno == ERANGE && (prefix == LONG_MIN ||
+                                         prefix == LONG_MAX)) ||
+                    (errno != 0 && prefix == 0)) {
+                    logMessage(ERROR, "%s: %d: %m", __func__, __LINE__);
+                    abort();
+                }
+
+                if (prefix > 0 || prefix <= 128) {
+                    iface->ip6prefix = prefix;
+                    have[IPV6]++;
+                }
+            }
+        }
+#endif
+
+        /* collect common network settings */
+        if (ipcomps->gw) {
+            if (inet_pton(AF_INET, ipcomps->gw, &iface->gateway) <= 0) {
+               memset(&iface->gateway, 0, sizeof(iface->gateway));
+
+               if (inet_pton(AF_INET6, ipcomps->gw, &iface->gateway6) <= 0) {
+                   logMessage(ERROR, "%s (%d): %s", __func__, __LINE__,
+                              strerror(errno));
+                   memset(&iface->gateway6, 0, sizeof(iface->gateway6));
+               }
+            }
+        }
+
+        /* gather nameservers */
+        if (ipcomps->ns) {
+#ifdef ENABLE_IPV6
+            if ((inet_pton(AF_INET, ipcomps->ns, &addr) >= 1) ||
+                (inet_pton(AF_INET6, ipcomps->ns, &addr6) >= 1)) {
+#else
+            if (inet_pton(AF_INET, ipcomps->ns, &addr) >= 1) {
+#endif
+                iface->dns[0] = strdup(ipcomps->ns);
+                if (iface->numdns < 1)
+                    iface->numdns = 1;
+            }
+        }
+
+        /* user selected back, but we've saved what they entered already */
+        if (answer == back) {
+            newtFormDestroy(f);
+            newtPopWindow();
+            free(buf);
+            return LOADER_BACK;
+        }
+
+        /* we might be done now */
+        if (stack[IPV4] && have[IPV4] != 2) {
+            have[IPV4] = 0;
+            newtWinMessage(_("Missing Information"), _("Retry"),
+                           _("You must enter both a valid IPv4 address and a "
+                             "network mask or CIDR prefix."));
+        }
+
+#ifdef ENABLE_IPV6
+        if (stack[IPV6] && have[IPV6] != 2) {
+            have[IPV6] = 0;
+            newtWinMessage(_("Missing Information"), _("Retry"),
+                           _("You must enter both a valid IPv6 address and a "
+                             "CIDR prefix."));
+        }
+#endif
+
+        strcpy(iface->device, device);
+    }
+
+    free(buf);
+    newtFormDestroy(f);
+    newtPopWindow();
+
+    return LOADER_OK;
+}
+
+/*
+ * By default, we disable all network interfaces and then only
+ * bring up the ones the user wants.
+ */
+int writeDisabledNetInfo(void) {
+    int i = 0;
+    char *ofile = NULL;
+    char *nfile = NULL;
+    FILE *fp = NULL;
+    struct device **devs = NULL;
+
+    devs = getDevices(DEVICE_NETWORK);
+
+    if (devs == NULL) {
+        return 1;
+    }
+
+    for (i = 0; devs[i]; i++) {
+        /* remove dhclient-DEVICE.conf if we have it */
+        if (asprintf(&ofile, "/etc/dhcp/dhclient-%s.conf", devs[i]->device) == -1) {
+            return 5;
+        }
+
+        if (!access(ofile, R_OK|W_OK)) {
+            if (unlink(ofile)) {
+                logMessage(ERROR, "error removing %s", ofile);
+            }
+        }
+
+        if (ofile) {
+            free(ofile);
+            ofile = NULL;
+        }
+
+        /* write disabled ifcfg-DEVICE file */
+        
+        checked_asprintf(&ofile, "%s/.ifcfg-%s",
+                         NETWORK_SCRIPTS_PATH,
+                         devs[i]->device);
+        checked_asprintf(&nfile, "%s/ifcfg-%s",
+                         NETWORK_SCRIPTS_PATH,
+                         devs[i]->device);
+
+        if ((fp = fopen(ofile, "w")) == NULL) {
+            free(ofile);
+            return 2;
+        }
+
+        fprintf(fp, "DEVICE=%s\n", devs[i]->device);
+        fprintf(fp, "HWADDR=%s\n", iface_mac2str(devs[i]->device));
+        fprintf(fp, "ONBOOT=no\n");
+        fprintf(fp, "NM_CONTROLLED=no\n");
+
+        if (fclose(fp) == EOF) {
+            return 3;
+        }
+
+        if (rename(ofile, nfile) == -1) {
+            free(ofile);
+            free(nfile);
+            return 4;
+        }
+
+        if (ofile) {
+            free(ofile);
+            ofile = NULL;
+        }
+
+        if (nfile) {
+            free(nfile);
+            nfile = NULL;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Write out network interface control files:
+ *     /etc/sysconfig/network-scripts/ifcfg-DEVICE
+ *     /etc/sysconfig/network
+ */
+int writeEnabledNetInfo(iface_t *iface) {
+    int i = 0, osa_layer2 = 0, osa_portno = 0;
+    mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+    FILE *fp = NULL;
+    char buf[INET6_ADDRSTRLEN+1];
+    char *ofile = NULL;
+    char *nfile = NULL;
+    struct utsname kv;
+
+    memset(&buf, '\0', sizeof(buf));
+
+    if ((mkdir(NETWORK_SCRIPTS_PATH, mode) == -1) && (errno != EEXIST)) {
+        return 16;
+    }
+
+    /* write vendor class */
+    if (iface->vendorclass == NULL) {
+        if (uname(&kv) == -1) {
+            iface->vendorclass = "anaconda";
+        } else {
+            if (asprintf(&iface->vendorclass, "anaconda-%s %s %s",
+                         kv.sysname, kv.release, kv.machine) == -1 ) {
+                return 20;
+            }
+        }
+    }
+
+    if (asprintf(&ofile, "/etc/dhcp/dhclient-%s.conf", iface->device) == -1) {
+        return 17;
+    }
+
+    if ((fp = fopen(ofile, "w")) == NULL) {
+        free(ofile);
+        return 18;
+    }
+
+    fprintf(fp, "send vendor-class-identifier \"%s\";\n",
+            iface->vendorclass);
+
+    if (fclose(fp) == EOF) {
+        free(ofile);
+        return 19;
+    }
+
+    if (ofile) {
+        free(ofile);
+        ofile = NULL;
+    }
+
+    /* write out new ifcfg-DEVICE file */
+    if (asprintf(&ofile, "%s/.ifcfg-%s",
+                 NETWORK_SCRIPTS_PATH, iface->device) == -1) {
+        return 1;
+    }
+
+    if (asprintf(&nfile, "%s/ifcfg-%s",
+                 NETWORK_SCRIPTS_PATH, iface->device) == -1) {
+        return 13;
+    }
+
+    if ((fp = fopen(ofile, "w")) == NULL) {
+        free(ofile);
+        return 2;
+    }
+
+    fprintf(fp, "DEVICE=%s\n", iface->device);
+    fprintf(fp, "HWADDR=%s\n", iface_mac2str(iface->device));
+    fprintf(fp, "ONBOOT=yes\n");
+
+    if (!FL_NOIPV4(flags)) {
+        if (iface->ipv4method == IPV4_IBFT_METHOD) {
+	    /* When initrd and NM support iBFT, we should just write
+	     * BOOTPROTO=ibft and let NM deal with it. Until than,
+	     * just use static and do it ourselves. */
+            fprintf(fp, "BOOTPROTO=static\n");
+	    if(ibft_iface_ip()) fprintf(fp, "IPADDR=%s\n", ibft_iface_ip());
+	    if(ibft_iface_mask()) fprintf(fp, "NETMASK=%s\n", ibft_iface_mask());
+	    if(ibft_iface_gw()) fprintf(fp, "GATEWAY=%s\n", ibft_iface_gw());
+        } else if (iface->ipv4method == IPV4_IBFT_DHCP_METHOD) {
+            fprintf(fp, "BOOTPROTO=dhcp\n");
+        } else if (iface->ipv4method == IPV4_DHCP_METHOD) {
+            fprintf(fp, "BOOTPROTO=dhcp\n");
+        } else if (iface->ipv4method == IPV4_MANUAL_METHOD) {
+            fprintf(fp, "BOOTPROTO=static\n");
+
+            if (iface_have_in_addr(&iface->ipaddr)) {
+                if (inet_ntop(AF_INET, &iface->ipaddr, buf,
+                              INET_ADDRSTRLEN) == NULL) {
+                    free(ofile);
+                    fclose(fp);
+                    return 3;
+                }
+
+                fprintf(fp, "IPADDR=%s\n", buf);
+            }
+
+            if (iface_have_in_addr(&iface->netmask)) {
+                if (inet_ntop(AF_INET, &iface->netmask, buf,
+                              INET_ADDRSTRLEN) == NULL) {
+                    free(ofile);
+                    fclose(fp);
+                    return 4;
+                }
+
+                fprintf(fp, "NETMASK=%s\n", buf);
+            }
+
+            if (iface_have_in_addr(&iface->broadcast)) {
+                if (inet_ntop(AF_INET, &iface->broadcast, buf,
+                              INET_ADDRSTRLEN) == NULL) {
+                    free(ofile);
+                    fclose(fp);
+                    return 5;
+                }
+
+                fprintf(fp, "BROADCAST=%s\n", buf);
+            }
+
+            if (iface_have_in_addr(&iface->gateway)) {
+                if (inet_ntop(AF_INET, &iface->gateway, buf,
+                              INET_ADDRSTRLEN) == NULL) {
+                    free(ofile);
+                    fclose(fp);
+                    return 6;
+                }
+
+                fprintf(fp, "GATEWAY=%s\n", buf);
+            }
+        }
+    }
+
+#ifdef ENABLE_IPV6
+    if (!FL_NOIPV6(flags)) {
+        if (iface->ipv6method == IPV6_AUTO_METHOD ||
+            iface->ipv6method == IPV6_DHCP_METHOD ||
+            iface->ipv6method == IPV6_MANUAL_METHOD) {
+            fprintf(fp, "IPV6INIT=yes\n");
+
+            if (iface->ipv6method == IPV6_AUTO_METHOD) {
+                fprintf(fp, "IPV6_AUTOCONF=yes\n");
+            } else if (iface->ipv6method == IPV6_DHCP_METHOD) {
+                fprintf(fp, "DHCPV6C=yes\n");
+            } else if (iface->ipv6method == IPV6_MANUAL_METHOD) {
+                if (iface_have_in6_addr(&iface->ip6addr)) {
+                    if (inet_ntop(AF_INET6, &iface->ip6addr, buf,
+                                  INET6_ADDRSTRLEN) == NULL) {
+                        free(ofile);
+                        fclose(fp);
+                        return 7;
+                    }
+
+                    if (iface->ip6prefix) {
+                        fprintf(fp, "IPV6ADDR=%s/%d\n", buf, iface->ip6prefix);
+                    } else {
+                        fprintf(fp, "IPV6ADDR=%s\n", buf);
+                    }
+                }
+            }
+
+            if (iface_have_in6_addr(&iface->gateway6)) {
+                if (inet_ntop(AF_INET6, &iface->gateway6, buf,
+                              INET6_ADDRSTRLEN) == NULL) {
+                    free(ofile);
+                    fclose(fp);
+                    return 8;
+                }
+
+                fprintf(fp, "IPV6_DEFAULTGW=%s\n", buf);
+            }
+        }
+    }
+#endif
+
+    if (iface->numdns > 0) {
+        for (i = 0; i < iface->numdns; i++) {
+            fprintf(fp, "DNS%d=%s\n", i+1, iface->dns[i]);
+        }
+    }
+
+    if (iface->hostname) {
+        fprintf(fp, "HOSTNAME=%s\n", iface->hostname);
+    }
+
+    if (iface->domain) {
+        fprintf(fp, "DOMAIN=%s\n", iface->domain);
+    }
+
+    if (iface->mtu) {
+        fprintf(fp, "MTU=%d\n", iface->mtu);
+    }
+
+    if (iface->peerid) {
+        fprintf(fp, "PEERID=%s\n", iface->peerid);
+    }
+
+    if (iface->subchannels) {
+        fprintf(fp, "SUBCHANNELS=%s\n", iface->subchannels);
+    }
+
+    if (iface->portname) {
+        fprintf(fp, "PORTNAME=%s\n", iface->portname);
+    }
+
+    if (iface->nettype) {
+        fprintf(fp, "NETTYPE=%s\n", iface->nettype);
+    }
+
+    if (iface->ctcprot) {
+        fprintf(fp, "CTCPROT=%s\n", iface->ctcprot);
+    }
+
+    if (iface->layer2 && !strcmp(iface->layer2, "1")) {
+        osa_layer2 = 1;
+    }
+
+    if (iface->portno && !strcmp(iface->portno, "1")) {
+        osa_portno = 1;
+    }
+
+    if (osa_layer2 || osa_portno) {
+        fprintf(fp, "OPTIONS=\"");
+
+        if (osa_layer2) {
+            fprintf(fp, "layer2=1");
+        }
+
+        if (osa_layer2 && osa_portno) {
+            fprintf(fp, " ");
+        }
+
+        if (osa_portno) {
+            fprintf(fp, "portno=1");
+        }
+
+        fprintf(fp, "\"\n");
+    }
+
+    if (iface->macaddr) {
+        fprintf(fp, "MACADDR=%s\n", iface->macaddr);
+    }
+
+    if (fclose(fp) == EOF) {
+        free(ofile);
+        free(nfile);
+        return 8;
+    }
+
+    if (rename(ofile, nfile) == -1) {
+        free(ofile);
+        free(nfile);
+        return 14;
+    }
+
+    if (ofile) {
+        free(ofile);
+    }
+
+    if (nfile) {
+        free(nfile);
+    }
+
+    /* Global settings */
+    if ((fp = fopen(SYSCONFIG_PATH"/.network", "w")) == NULL) {
+        return 9;
+    }
+
+    if (!FL_NOIPV4(flags)) {
+        fprintf(fp, "NETWORKING=yes\n");
+    }
+
+#ifdef ENABLE_IPV6
+    if (!FL_NOIPV6(flags)) {
+        fprintf(fp, "NETWORKING_IPV6=yes\n");
+    }
+#endif
+
+    if (iface->hostname != NULL) {
+        fprintf(fp, "HOSTNAME=%s\n", iface->hostname);
+    }
+
+    if (iface_have_in_addr(&iface->gateway)) {
+        if (inet_ntop(AF_INET, &iface->gateway, buf,
+                      INET_ADDRSTRLEN) == NULL) {
+            fclose(fp);
+            return 10;
+        }
+
+        fprintf(fp, "GATEWAY=%s\n", buf);
+    }
+
+#ifdef ENABLE_IPV6
+    if (iface_have_in6_addr(&iface->gateway6)) {
+        if (inet_ntop(AF_INET6, &iface->gateway6, buf,
+                      INET6_ADDRSTRLEN) == NULL) {
+            fclose(fp);
+            return 11;
+        }
+
+        fprintf(fp, "IPV6_DEFAULTGW=%s\n", buf);
+    }
+#endif
+
+    if (fclose(fp) == EOF) {
+        return 12;
+    }
+
+    if (rename(SYSCONFIG_PATH"/.network",
+               SYSCONFIG_PATH"/network") == -1) {
+        return 15;
+    }
+
+    return 0;
+}
+
+void setKickstartNetwork(struct loaderData_s * loaderData, int argc, 
+                         char ** argv) {
+    iface_t iface;
+    gchar *bootProto = NULL, *device = NULL, *class = NULL, *ethtool = NULL;
+    gchar *essid = NULL, *wepkey = NULL, *onboot = NULL;
+    gint mtu = 1500, dhcpTimeout = -1;
+    gboolean noipv4 = FALSE, noipv6 = FALSE, noDns = FALSE, noksdev = FALSE;
+    GOptionContext *optCon = g_option_context_new(NULL);
+    GError *optErr = NULL;
+    GOptionEntry ksOptions[] = {
+        { "bootproto", 0, 0, G_OPTION_ARG_STRING, &bootProto, NULL, NULL },
+        { "device", 0, 0, G_OPTION_ARG_STRING, &device, NULL, NULL },
+        { "dhcpclass", 0, 0, G_OPTION_ARG_STRING, &class, NULL, NULL },
+        { "gateway", 'g', 0, G_OPTION_ARG_STRING, &loaderData->gateway,
+          NULL, NULL },
+        { "ip", 'i', 0, G_OPTION_ARG_STRING, &loaderData->ipv4, NULL, NULL },
+        { "mtu", 0, 0, G_OPTION_ARG_INT, &mtu, NULL, NULL },
+        { "nameserver", 'n', 0, G_OPTION_ARG_STRING, &loaderData->dns,
+          NULL, NULL },
+        { "netmask", 'm', 0, G_OPTION_ARG_STRING, &loaderData->netmask,
+          NULL, NULL },
+        { "noipv4", 0, 0, G_OPTION_ARG_NONE, &noipv4, NULL, NULL },
+        { "noipv6", 0, 0, G_OPTION_ARG_NONE, &noipv6, NULL, NULL },
+        { "nodns", 0, 0, G_OPTION_ARG_NONE, &noDns, NULL, NULL },
+        { "hostname", 'h', 0, G_OPTION_ARG_STRING, &loaderData->hostname,
+          NULL, NULL },
+        { "ethtool", 0, 0, G_OPTION_ARG_STRING, &ethtool, NULL, NULL },
+        { "essid", 0, 0, G_OPTION_ARG_STRING, &essid, NULL, NULL },
+        { "wepkey", 0, 0, G_OPTION_ARG_STRING, &wepkey, NULL, NULL },
+        { "onboot", 0, 0, G_OPTION_ARG_STRING, &onboot, NULL, NULL },
+        { "notksdevice", 0, 0, G_OPTION_ARG_NONE, &noksdev, NULL, NULL },
+        { "dhcptimeout", 0, 0, G_OPTION_ARG_INT, &dhcpTimeout, NULL, NULL },
+        { NULL },
+    };
+
+    iface_init_iface_t(&iface);
+
+    g_option_context_set_help_enabled(optCon, FALSE);
+    g_option_context_add_main_entries(optCon, ksOptions, NULL);
+
+    if (!g_option_context_parse(optCon, &argc, &argv, &optErr)) {
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("Bad argument to kickstart network command: %s"),
+                       optErr->message);
+        g_error_free(optErr);
+    }
+
+    g_option_context_free(optCon);
+
+    /* if they've specified dhcp/bootp use dhcp for the interface */
+    if (bootProto && (!strncmp(bootProto, "dhcp", 4) || 
+                       !strncmp(bootProto, "bootp", 4))) {
+        loaderData->ipv4 = strdup("dhcp");
+        loaderData->ipinfo_set = 1;
+    } else if (loaderData->ipv4) {
+        /* JKFIXME: this assumes a bit... */
+        loaderData->ipinfo_set = 1;
+    }
+
+    /* now make sure the specified bootproto is valid */
+    if (bootProto && strcmp(bootProto, "dhcp") && strcmp(bootProto, "bootp") &&
+        strcmp(bootProto, "static") && strcmp(bootProto, "query")) {
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("Bad bootproto %s specified in network command"),
+                       bootProto);
+    }
+
+    if (!noksdev) {
+        if (device) {
+            /* If --device=MAC was given, translate into a device name now. */
+            if (index(device, ':') != NULL)
+                loaderData->netDev = iface_mac2device(device);
+            else
+                loaderData->netDev = strdup(device);
+
+            loaderData->netDev_set = 1;
+        }
+
+        if (class) {
+            loaderData->netCls = strdup(class);
+            loaderData->netCls_set = 1;
+        }
+
+        if (ethtool) {
+            if (loaderData->ethtool)
+                free(loaderData->ethtool);
+            loaderData->ethtool = strdup(ethtool);
+            free(ethtool);
+        }
+
+        if (essid) {
+            if (loaderData->essid)
+                free(loaderData->essid);
+            loaderData->essid = strdup(essid);
+            free(essid);
+        }
+
+        if (wepkey) {
+            if (loaderData->wepkey)
+                free(loaderData->wepkey);
+            loaderData->wepkey = strdup(wepkey);
+            free(wepkey);
+        }
+
+        if (mtu) {
+           loaderData->mtu = mtu;
+        }
+
+        if (noipv4)
+            flags |= LOADER_FLAGS_NOIPV4;
+
+#ifdef ENABLE_IPV6
+        if (noipv6)
+            flags |= LOADER_FLAGS_NOIPV6;
+#endif
+    }
+
+    if (noDns) {
+        loaderData->noDns = 1;
+    }
+
+    /* Make sure the network is always up if there's a network line in the
+     * kickstart file, as %post/%pre scripts might require that.
+     */
+    if (loaderData->method != METHOD_NFS && loaderData->method != METHOD_URL) {
+        if (kickstartNetworkUp(loaderData, &iface))
+            logMessage(ERROR, "unable to bring up network");
+    }
+}
+
+/* if multiple interfaces get one to use from user.   */
+/* NOTE - uses kickstart data available in loaderData */
+int chooseNetworkInterface(struct loaderData_s * loaderData) {
+    int i, rc, ask, idrc, secs, deviceNums = 0, deviceNum, foundDev = 0;
+    unsigned int max = 40;
+    char **devices;
+    char **deviceNames;
+    char *ksMacAddr = NULL, *seconds = strdup("10"), *idstr = NULL;
+    struct device **devs;
+    int lookForLink = 0;
+    struct newtWinEntry entry[] = {{N_("Seconds:"), (char **) &seconds, 0},
+                                   {NULL, NULL, 0 }};
+
+    devs = getDevices(DEVICE_NETWORK);
+    if (!devs) {
+        logMessage(ERROR, "no network devices in choose network device!");
+        return LOADER_ERROR;
+    }
+
+    for (i = 0; devs[i]; i++);
+
+    devices = alloca((i + 1) * sizeof(*devices));
+    deviceNames = alloca((i + 1) * sizeof(*devices));
+    if (loaderData->netDev && (loaderData->netDev_set) == 1) {
+        if ((loaderData->bootIf && (loaderData->bootIf_set) == 1) &&
+            !strcasecmp(loaderData->netDev, "bootif")) {
+            ksMacAddr = g_ascii_strup(loaderData->bootIf, -1);
+        } else {
+            ksMacAddr = g_ascii_strup(loaderData->netDev, -1);
+        }
+    }
+
+    for (i = 0; devs[i]; i++) {
+        if (!devs[i]->device)
+            continue;
+
+        if (devs[i]->description) {
+            deviceNames[deviceNums] = alloca(strlen(devs[i]->device) +
+                                      strlen(devs[i]->description) + 4);
+            sprintf(deviceNames[deviceNums],"%s - %.50s",
+                    devs[i]->device, devs[i]->description);
+
+            if (strlen(deviceNames[deviceNums]) > max)
+                max = strlen(deviceNames[deviceNums]);
+
+            devices[deviceNums] = devs[i]->device;
+        } else {
+            devices[deviceNums] = devs[i]->device;
+            deviceNames[deviceNums] = devs[i]->device;
+        }
+
+        deviceNums++;
+
+        /* this device has been set and we don't really need to ask 
+         * about it again... */
+        if (loaderData->netDev && (loaderData->netDev_set == 1)) {
+            if (!strcmp(loaderData->netDev, devs[i]->device)) {
+                foundDev = 1;
+            } else if (ksMacAddr != NULL) {
+                /* maybe it's a mac address */
+                char *devmacaddr = iface_mac2str(devs[i]->device);
+
+                if ((devmacaddr != NULL) && !strcmp(ksMacAddr, devmacaddr)) {
+                    foundDev = 1;
+                    free(loaderData->netDev);
+                    loaderData->netDev = devs[i]->device;
+                    if (devmacaddr != NULL)
+                        free(devmacaddr);
+                    break;
+                }
+
+                if (devmacaddr != NULL)
+                    free(devmacaddr);
+            }
+        }
+    }
+
+    if (ksMacAddr)
+        free(ksMacAddr);
+    if (foundDev == 1)
+        return LOADER_NOOP;
+
+    devices[deviceNums] = NULL;
+    deviceNames[deviceNums] = NULL;
+    qsort(devices, deviceNums, sizeof(*devices), simpleStringCmp);
+    qsort(deviceNames, deviceNums, sizeof(*devices), simpleStringCmp);
+
+    /* ASSERT: we should *ALWAYS* have a network device when we get here */
+    if (!deviceNums) {
+        logMessage(CRITICAL, "no network device in chooseNetworkInterface");
+        return LOADER_ERROR;
+    }
+
+    /* If there is iBFT table and ksdevice doesn't say otherwise, use it */
+    while (!loaderData->netDev_set || !strcmp(loaderData->netDev, "ibft")) {
+        char *devmacaddr = NULL;
+        char *ibftmacaddr = "";
+
+        /* get MAC from the iBFT table */
+        if (!(ibftmacaddr = ibft_iface_mac())) { /* iBFT not present or error */
+            logMessage(ERROR, "iBFT doesn't couldn't provide valid NIC MAC address");
+            break;
+        }
+
+        logMessage(INFO, "looking for iBFT configured device %s with link",
+                   ibftmacaddr);
+
+        for (i = 0; devs[i]; i++) {
+            if (!devs[i]->device)
+                continue;
+
+            devmacaddr = iface_mac2str(devs[i]->device);
+
+            if(!strcasecmp(devmacaddr, ibftmacaddr)){
+                logMessage(INFO,
+                           "%s has the right MAC (%s), checking for link",
+                           devs[i]->device, devmacaddr);
+                free(devmacaddr);
+
+                /* wait for the link (max 5s) */
+                for (rc = 0; rc < 5; rc++) {
+                    if (get_link_status(devs[i]->device) == 0) {
+                        logMessage(INFO, "%s still has no link, waiting", devs[i]->device);
+                        sleep(1);                 
+                    } else {
+                        lookForLink = 0;
+                        loaderData->netDev = devs[i]->device;
+                        loaderData->netDev_set = 1;
+                        logMessage(INFO, "%s has link, using it", devs[i]->device);
+
+                        /* set the IP method to ibft if not requested differently */
+                        if (loaderData->ipv4 == NULL) {
+                            loaderData->ipv4 = strdup("ibft");
+                            loaderData->ipinfo_set = 1;
+                            logMessage(INFO,
+                                       "%s will be configured using iBFT values",
+                                       devices[i]);
+                        }
+
+                        return LOADER_NOOP;
+                    }
+                }
+
+                logMessage(INFO, "%s has no link, skipping it", devices[i]);
+
+                break;
+            } else {
+                free(devmacaddr);
+            }
+        }
+
+        break;
+    }
+
+    if ((loaderData->netDev && (loaderData->netDev_set == 1)) &&
+        !strcmp(loaderData->netDev, "link")) {
+        lookForLink = 1;
+    }
+
+    if (lookForLink) {
+        logMessage(INFO, "looking for first netDev with link");
+
+        for (rc = 0; rc < 5; rc++) {
+            for (i = 0; i < deviceNums; i++) {
+                if (get_link_status(devices[i]) == 1) {
+                    loaderData->netDev = devices[i];
+                    logMessage(INFO, "%s has link, using it", devices[i]);
+                    return LOADER_NOOP;
+                }
+            }
+
+            sleep(1);
+        }
+
+        logMessage(WARNING,
+                   "wanted netdev with link, but none present.  prompting");
+    }
+
+    /* JKFIXME: if we only have one interface and it doesn't have link,
+     * do we go ahead? */
+    if (deviceNums == 1) {
+        logMessage(INFO, "only have one network device: %s", devices[0]);
+        loaderData->netDev = devices[0];
+        loaderData->netDev_set = 1;
+        return LOADER_NOOP;
+    }
+
+    if (FL_CMDLINE(flags)) {
+        fprintf(stderr, "No way to determine which NIC to use, and cannot "
+                        "prompt in cmdline\nmode.  Halting.\n");
+        fprintf(stderr, "Please use the ksdevice= parameter to specify the "
+                        "device name (e.g., eth0)\n or the MAC address of "
+                        "the NIC to use for installation.\n");
+        exit(1);
+    }
+
+    startNewt();
+
+    if (max > 70)
+        max = 70;
+
+    /* JKFIXME: should display link status */
+    deviceNum = 0;
+    ask = 1;
+    while (ask) {
+        rc = newtWinMenu(_("Networking Device"),
+                         _("You have multiple network devices on this system. "
+                           "Which would you like to install through?"),
+                         max, 10, 10,
+                         deviceNums < 6 ? deviceNums : 6, deviceNames,
+                         &deviceNum, _("OK"), _("Identify"), _("Back"), NULL);
+
+        if (rc == 2) {
+            if (!devices[deviceNum]) {
+                logMessage(ERROR, "NIC %d contains no device name", deviceNum);
+                continue;
+            }
+
+            checked_asprintf(&idstr, "%s %s %s",
+                             _("You can identify the physical port for"),
+                             devices[deviceNum],
+                             _("by flashing the LED lights for a number of "
+                               "seconds.  Enter a number between 1 and 30 to "
+                               "set the duration to flash the LED port "
+                               "lights."));
+
+            i = 1;
+            while (i) {
+                idrc = newtWinEntries(_("Identify NIC"), idstr, 50, 5, 15, 24,
+                                      entry, _("OK"), _("Back"), NULL);
+
+                if (idrc == 0 || idrc == 1) {
+                    errno = 0;
+                    secs = strtol((const char *) seconds, NULL, 10);
+                    if (errno == EINVAL || errno == ERANGE) {
+                        logMessage(ERROR, "strtol() failure in %s: %m",
+                                   __func__);
+                        continue;
+                    }
+
+                    if (secs <=0 || secs > 300) {
+                        newtWinMessage(_("Invalid Duration"), _("OK"),
+                                       _("You must enter the number of "
+                                         "seconds as an integer between 1 "
+                                         "and 30."));
+                        continue;
+                    }
+
+                    idrc = 41 + strlen(devices[deviceNum]);
+                    if (secs > 9) {
+                        idrc += 1;
+                    }
+
+                    winStatus(idrc, 3, NULL,
+                              _("Flashing %s port lights for %d seconds."),
+                              devices[deviceNum], secs);
+
+                    if (identifyNIC(devices[deviceNum], secs)) {
+                        logMessage(ERROR,
+                                   "error during physical NIC identification");
+                    }
+
+                    newtPopWindow();
+                    i = 0;
+                } else if (idrc == 2) {
+                    i = 0;
+                }
+            }
+        } else if (rc == 3) {
+            ask = 0;
+            return LOADER_BACK;
+        } else {
+            ask = 0;
+        }
+    }
+
+    loaderData->netDev = devices[deviceNum];
+    return LOADER_OK;
+}
+
+/* JKFIXME: bad name.  this function brings up networking early on a 
+ * kickstart install so that we can do things like grab the ks.cfg from
+ * the network */
+int kickstartNetworkUp(struct loaderData_s * loaderData, iface_t * iface) {
+    int rc, err;
+
+    if ((is_nm_connected() == TRUE) &&
+        (loaderData->netDev != NULL) && (loaderData->netDev_set == 1))
+        return 0;
+
+    memset(iface, 0, sizeof(*iface));
+
+    do {
+        do {
+            /* this is smart and does the right thing based on whether or not
+             * we have ksdevice= specified */
+            rc = chooseNetworkInterface(loaderData);
+
+            if (rc == LOADER_ERROR) {
+                /* JKFIXME: ask for a driver disk? */
+                logMessage(ERROR, "no network drivers for doing kickstart");
+                return -1;
+            } else if (rc == LOADER_BACK) {
+                return -1;
+            }
+
+            /* insert device into iface structure */
+            strcpy(iface->device, loaderData->netDev);
+
+            break;
+        } while (1);
+
+        /* we don't want to end up asking about interface more than once
+         * if we're in a kickstart-ish case (#100724) */
+        loaderData->netDev_set = 1;
+
+        /* default to DHCP for IPv4 if nothing is provided */
+        if (loaderData->ipv4 == NULL) {
+            loaderData->ipv4 = strdup("dhcp");
+            loaderData->ipinfo_set = 1;
+        }
+
+        setupIfaceStruct(iface, loaderData);
+        rc = readNetConfig(loaderData->netDev, iface, loaderData->netCls,
+                           loaderData->method);
+
+        if (rc == LOADER_ERROR) {
+            logMessage(ERROR, "unable to setup networking");
+            return -1;
+        } else if (rc == LOADER_BACK) {
+            /* Going back to the interface selection screen, so unset anything
+             * we set before attempting to bring the incorrect interface up.
+             */
+            if ((rc = writeDisabledNetInfo()) != 0) {
+                logMessage(ERROR, "writeDisabledNetInfo failure (%s): %d",
+                           __func__, rc);
+            }
+
+            loaderData->netDev_set = 0;
+            loaderData->ipinfo_set = 0;
+            free(loaderData->ipv4);
+            loaderData->ipv4 = NULL;
+            break;
+        } else {
+            break;
+        }
+
+        err = writeEnabledNetInfo(iface);
+        if (err) {
+            logMessage(ERROR,
+                       "failed to write %s data for %s (%d)",
+                       SYSCONFIG_PATH, iface->device, err);
+            return -1;
+        }
+
+        err = get_connection(iface);
+        newtPopWindow();
+
+        if (err) {
+            logMessage(ERROR, "failed to start NetworkManager (%d)", err);
+            return -1;
+        }
+    } while (1);
+
+    return 0;
+}
+
+void splitHostname (char *str, char **host, char **port)
+{
+    char *rightbrack = strchr(str, ']');
+    char *firstcolon = strchr(str, ':');
+    char *secondcolon = strrchr(str, ':');
+
+    *host = NULL;
+    *port = NULL;
+
+    if (*str == '[' && rightbrack) {
+        /* An IPv6 address surrounded by brackets, optionally with a colon and
+         * port number.
+         */
+        char *colon = strrchr(rightbrack, ':');
+
+        if (colon) {
+            *host = strndup(str+1, rightbrack-1-str);
+            *port = strdup(colon+1);
+        }
+        else
+            *host = strndup(str+1, rightbrack-1-str);
+    } else if (firstcolon && secondcolon && firstcolon != secondcolon) {
+        /* An IPv6 address without brackets.  Don't make the user surround the
+         * address with brackets if there's no port number.
+         */
+        *host = strdup(str);
+    } else {
+        /* An IPv4 address, optionally with a colon and port number. */
+        char *colon = strrchr(str, ':');
+
+        if (colon) {
+            *host = strndup(str, colon-str);
+            *port = strdup(colon+1);
+        }
+        else
+            *host = strdup(str);
+    }
+}
+
+/*
+ * Start NetworkManager and wait for a valid link, return non-zero on error.
+ */
+int get_connection(iface_t *iface) {
+    int count = 0;
+    NMClient *client = NULL;
+    NMState state;
+    GMainLoop *loop;
+    GMainContext *ctx;
+
+    if (iface == NULL) {
+        return 1;
+    }
+
+    logMessage(DEBUGLVL, "configuring device %s", iface->device);
+
+    /* display status */
+    if (FL_CMDLINE(flags)) {
+        printf(_("Waiting for NetworkManager to configure %s.\n"),
+               iface->device);
+    } else {
+        winStatus(55, 3, NULL,
+                  _("Waiting for NetworkManager to configure %s.\n"),
+                  iface->device, 0);
+    }
+
+    g_type_init();
+
+    client = nm_client_new();
+    if (!client) {
+        logMessage(ERROR, "%s (%d): could not connect to system bus",
+                   __func__, __LINE__);
+        return 2;
+    }
+
+    /* Create a loop for processing dbus signals */
+    loop = g_main_loop_new(NULL, FALSE);
+    ctx = g_main_loop_get_context(loop);
+
+    /* pump the loop until all the messages are clear */
+    while (g_main_context_pending (ctx)) {
+        g_main_context_iteration (ctx, FALSE);
+    }
+
+    /* send message and block until a reply or error comes back */
+    while (count < 45) {
+        /* pump the loop again to clear the messages */
+        while (g_main_context_pending (ctx)) {
+            g_main_context_iteration (ctx, FALSE);
+        }
+        state = nm_client_get_state(client);
+
+        if (state == NM_STATE_CONNECTED) {
+            logMessage(INFO, "%s (%d): NetworkManager connected",
+                       __func__, __LINE__);
+            res_init();
+            g_object_unref(client);
+            return 0;
+        }
+
+        sleep(1);
+        count++;
+    }
+
+    g_main_loop_unref(loop);
+    g_object_unref(client);
+    return 3;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4: */
diff --git a/bin/loader/net.h b/bin/loader/net.h
new file mode 100644
index 0000000..8245084
--- /dev/null
+++ b/bin/loader/net.h
@@ -0,0 +1,77 @@
+/*
+ * net.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef H_LOADER_NET
+#define H_LOADER_NET
+
+#include <newt.h>
+#include "../isys/iface.h"
+#include "loader.h"
+
+#define DHCP_METHOD_STR   _("Dynamic IP configuration (DHCP)")
+#define MANUAL_METHOD_STR _("Manual configuration")
+#ifdef ENABLE_IPV6
+#define DHCPV6_METHOD_STR _("Dynamic IP configuration (DHCPv6)")
+#define AUTO_METHOD_STR   _("Automatic neighbor discovery")
+#endif
+
+#define SYSCONFIG_PATH       "/etc/sysconfig"
+#define NETWORK_SCRIPTS_PATH "/etc/sysconfig/network-scripts"
+
+struct intfconfig_s {
+    newtComponent ipv4Entry, cidr4Entry;
+    newtComponent gwEntry, nsEntry;
+    const char *ipv4, *cidr4;
+#ifdef ENABLE_IPV6
+    newtComponent ipv6Entry, cidr6Entry;
+    const char *ipv6, *cidr6;
+    const char *gw6;
+#endif
+    const char *gw, *ns;
+};
+
+struct netconfopts {
+    char ipv4Choice;
+#ifdef ENABLE_IPV6
+    char ipv6Choice;
+#endif
+};
+
+typedef int int32;
+
+int readNetConfig(char * device, iface_t * iface,
+                  char * dhcpclass, int methodNum);
+int configureTCPIP(char * device, iface_t * iface, struct netconfopts * opts,
+                   int methodNum);
+int manualNetConfig(char * device, iface_t * iface,
+                    struct intfconfig_s * ipcomps, struct netconfopts * opts);
+void debugNetworkInfo(iface_t * iface);
+int writeDisabledNetInfo(void);
+int writeEnabledNetInfo(iface_t * iface);
+int chooseNetworkInterface(struct loaderData_s * loaderData);
+void setupIfaceStruct(iface_t * iface, struct loaderData_s * loaderData);
+int setupWireless(iface_t * iface);
+void setKickstartNetwork(struct loaderData_s * loaderData, int argc, 
+                         char ** argv);
+int kickstartNetworkUp(struct loaderData_s * loaderData,
+                       iface_t * iface);
+void splitHostname (char *str, char **host, char **port);
+int get_connection(iface_t * iface);
+
+#endif
diff --git a/bin/loader/nfsinstall.c b/bin/loader/nfsinstall.c
new file mode 100644
index 0000000..b6c3c82
--- /dev/null
+++ b/bin/loader/nfsinstall.c
@@ -0,0 +1,586 @@
+/*
+ * nfsinstall.c - code to set up nfs installs
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ * 2006, 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <fcntl.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <glib.h>
+#include <nm-client.h>
+#include <nm-device.h>
+#include <nm-dhcp4-config.h>
+
+#include "copy.h"
+#include "loader.h"
+#include "lang.h"
+#include "loadermisc.h"
+#include "kickstart.h"
+#include "method.h"
+#include "nfsinstall.h"
+#include "net.h"
+#include "cdinstall.h"
+#include "windows.h"
+
+#include "../isys/imount.h"
+#include "../isys/iface.h"
+#include "../isys/log.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+/**
+ * Test whether the mounted stage2 path is an uncompreseed image, not a squashfs.
+ * 
+ * Asusme path is readable.
+ */
+static int isNfsMountDirect(const char * path) {
+    struct stat stat_info;
+    if (stat(path, &stat_info))
+        return 0;
+
+    if (!S_ISDIR(stat_info.st_mode))
+        /* if it's not a directory, then it's not an uncompressed image */
+        return 0;
+
+    char * buildstamp;
+    checked_asprintf(&buildstamp, "%s/%s", path, ".buildstamp");
+    if (access(buildstamp, F_OK))
+        /* if it doesn't contain buildstamp, then it's not an uncompressed image */
+        return 0;
+    free(buildstamp);
+
+    return 1;
+}
+
+static int nfsGetSetup(char ** hostptr, char ** dirptr, char ** optsptr) {
+    struct newtWinEntry entries[4];
+    char * buf;
+    char * newServer = *hostptr ? strdup(*hostptr) : NULL;
+    char * newDir = *dirptr ? strdup(*dirptr) : NULL;
+    char * newMountOpts = *optsptr ? strdup(*optsptr) : NULL;
+    int rc;
+
+    entries[0].text = _("NFS server name:");
+    entries[0].value = &newServer;
+    entries[0].flags = NEWT_FLAG_SCROLL;
+    
+    checked_asprintf(&entries[1].text, _("%s directory:"), getProductName());
+
+    entries[1].value = &newDir;
+    entries[1].flags = NEWT_FLAG_SCROLL;
+    entries[2].text = _("NFS mount options (optional):");
+    entries[2].value = &newMountOpts;
+    entries[2].flags = NEWT_FLAG_SCROLL;
+    entries[3].text = NULL; 
+    entries[3].value = NULL;
+
+    if (asprintf(&buf, _("Please enter the server and path to your %s "
+                         "installation image and optionally additional "
+                         "NFS mount options."), getProductName()) == -1) {
+        logMessage(CRITICAL, "%s: %d: %m", __func__, __LINE__);
+        abort();
+    }
+
+    do {
+        rc = newtWinEntries(_("NFS Setup"), buf, 60, 5, 15,
+                            24, entries, _("OK"), _("Back"), NULL);
+    } while ((!strcmp(newServer, "") || !strcmp(newDir, "")) && rc != 2);
+
+    free(buf);
+    free(entries[1].text);
+
+    if (rc == 2) {
+        if (newServer) free(newServer);
+        if (newDir) free(newDir);
+        if (newMountOpts) free(newMountOpts);
+        return LOADER_BACK;
+    }
+
+    if (*hostptr) free(*hostptr);
+    if (*dirptr) free(*dirptr);
+    if (*optsptr) free(*optsptr);
+    *hostptr = newServer;
+    *dirptr = newDir;
+    *optsptr = newMountOpts;
+
+    return 0;
+}
+
+void parseNfsHostPathOpts(char *url, char **host, char **path, char **opts) {
+    char *tmp;
+    char *hostsrc;
+
+    logMessage(DEBUGLVL, "parseNfsHostPathOpts url: |%s|", url);
+
+    hostsrc = strdup(url);
+    *host = hostsrc;
+    tmp = strchr(*host, ':');
+
+    if (tmp) {
+       *path = strdup(tmp + 1);
+       *tmp = '\0';
+    }
+    else {
+        *path = malloc(sizeof(char *));
+        **path = '\0';
+    }
+
+    tmp = strchr(*path, ':');
+    if (tmp && (strlen(tmp) > 1)) {
+	char * c = tmp;
+        *opts = *host;
+        *host = *path;
+	*path = strdup(c + 1);
+	*c = '\0';
+    } else {
+	*opts = NULL;
+    }
+
+    logMessage(DEBUGLVL, "parseNfsHostPathOpts host: |%s|", *host);
+    logMessage(DEBUGLVL, "parseNfsHostPathOpts path: |%s|", *path);
+    logMessage(DEBUGLVL, "parseNfsHostPathOpts opts: |%s|", *opts);
+}
+
+static void addDefaultKickstartFile(char **file, char *ip) {
+    /* if the filename ends with / or is null, use default kickstart
+     * name of IP_ADDRESS-kickstart appended to *file
+     */
+    if ((*file) && (((*file)[strlen(*file) - 1] == '/') ||
+                    ((*file)[strlen(*file) - 1] == '\0'))) {
+        checked_asprintf(file, "%s%s-kickstart", *file, ip);
+        logMessage(DEBUGLVL, "addDefaultKickstartFile file: |%s|", *file);
+    }
+}
+
+char * mountNfsImage(struct installMethod * method,
+                     char * location, struct loaderData_s * loaderData) {
+    char * host = NULL;
+    char * directory = NULL;
+    char * mountOpts = NULL;
+    char * fullPath = NULL;
+    char * url = NULL;
+
+    enum { NFS_STAGE_NFS, NFS_STAGE_MOUNT, NFS_STAGE_DONE,
+           NFS_STAGE_UPDATES } stage = NFS_STAGE_NFS;
+
+    int rc;
+
+    /* JKFIXME: ASSERT -- we have a network device setup when we get here */
+    while (stage != NFS_STAGE_DONE) {
+        switch (stage) {
+        case NFS_STAGE_NFS:
+            if (loaderData->method == METHOD_NFS && loaderData->stage2Data) {
+                host = ((struct nfsInstallData *)loaderData->stage2Data)->host;
+                directory = ((struct nfsInstallData *)loaderData->stage2Data)->directory;
+
+                if (((struct nfsInstallData *)
+                    loaderData->stage2Data)->mountOpts == NULL) {
+                    mountOpts = strdup("ro");
+                } else {
+                    checked_asprintf(&mountOpts, "ro,%s",
+                                     ((struct nfsInstallData *)
+                                      loaderData->stage2Data)->mountOpts);
+                }
+
+                logMessage(INFO, "host is %s, dir is %s, opts are '%s'", host, directory, mountOpts);
+
+                if (!host || !directory) {
+                    logMessage(ERROR, "missing host or directory specification");
+
+                    if (loaderData->inferredStage2)
+                        loaderData->invalidRepoParam = 1;
+
+                    loaderData->method = -1;
+                    break;
+                } else {
+                    host = strdup(host);
+                    directory = strdup(directory);
+                }
+            } else {
+                char *colonopts, *substr, *tmp;
+
+                logMessage(INFO, "going to do nfsGetSetup");
+                if (nfsGetSetup(&host, &directory, &mountOpts) == LOADER_BACK) {
+                    loaderData->stage2Data = NULL;
+                    return NULL;
+                }
+
+                /* If the user-provided URL points at a repo instead of a
+                 * stage2 image, fix that up now.
+                 */
+                substr = strstr(directory, ".img");
+                if (!substr || (substr && *(substr+4) != '\0')) {
+                    if (mountOpts && strlen(mountOpts)) {
+                        checked_asprintf(&colonopts, ":%s", mountOpts);
+                    } else {
+                        colonopts = strdup("");
+                    }
+
+                    checked_asprintf(&(loaderData->instRepo), "nfs%s:%s:%s",
+                                     colonopts, host, directory);
+                    checked_asprintf(&tmp, "nfs%s:%s:%s/images/install.img",
+                                     colonopts, host, directory);
+
+                    setStage2LocFromCmdline(tmp, loaderData);
+                    free(host);
+                    free(directory);
+                    free(mountOpts);
+                    free(colonopts);
+                    free(tmp);
+                    continue;
+                }
+
+                loaderData->invalidRepoParam = 1;
+            }
+
+            stage = NFS_STAGE_MOUNT;
+            break;
+
+        case NFS_STAGE_MOUNT: {
+            char *buf;
+
+            checked_asprintf(&fullPath, "%s:%.*s", host,
+                             (int) (strrchr(directory, '/')-directory),
+                             directory);
+            logMessage(INFO, "mounting nfs path %s", fullPath);
+
+            stage = NFS_STAGE_NFS;
+
+            if (!doPwMount(fullPath, "/mnt/stage2", "nfs", mountOpts, NULL)) {
+                checked_asprintf(&buf, "/mnt/stage2/%s",
+                                 strrchr(directory, '/') + 1);
+
+                if (!access(buf, R_OK)) {
+                    logMessage(INFO, "can access %s", buf);
+                    if (isNfsMountDirect(buf)) {
+                        logMessage(INFO, "using uncompressed stage2 image");
+                        rc = mountStage2Direct(buf);
+                    } else {
+                        rc = mountStage2(buf);
+                    }
+
+                    if (rc == 0) {
+                        stage = NFS_STAGE_UPDATES;
+                        checked_asprintf(&url, "nfs:%s:%s", host,
+                                         directory);
+                        free(buf);
+                        break;
+                    } else {
+                        logMessage(WARNING, "unable to mount %s", buf);
+                        free(buf);
+                        break;
+                    }
+                } else {
+                    logMessage(WARNING, "unable to access %s", buf);
+                    free(buf);
+                    umount("/mnt/stage2");
+                }
+            } else {
+                newtWinMessage(_("Error"), _("OK"),
+                               _("That directory could not be mounted from "
+                                 "the server."));
+                if (loaderData->method >= 0)
+                    loaderData->method = -1;
+
+                if (loaderData->inferredStage2)
+                    loaderData->invalidRepoParam = 1;
+
+                break;
+            }
+
+            checked_asprintf(&buf,
+                             _("That directory does not seem to "
+                               "contain a %s installation image."),
+                             getProductName());
+
+            newtWinMessage(_("Error"), _("OK"), buf);
+            free(buf);
+
+            if (loaderData->method >= 0)
+                loaderData->method = -1;
+
+            if (loaderData->inferredStage2)
+                loaderData->invalidRepoParam = 1;
+
+            break;
+        }
+
+        case NFS_STAGE_UPDATES: {
+            char *buf;
+
+            checked_asprintf(&buf, "%.*s/RHupdates",
+                             (int) (strrchr(fullPath, '/')-fullPath),
+                             fullPath);
+
+            logMessage(INFO, "mounting nfs path %s for updates", buf);
+
+            if (!doPwMount(buf, "/tmp/update-disk", "nfs", mountOpts, NULL)) {
+                logMessage(INFO, "Using RHupdates/ for NFS install");
+                copyDirectory("/tmp/update-disk", "/tmp/updates", NULL, NULL);
+                umount("/tmp/update-disk");
+                unlink("/tmp/update-disk");
+            } else {
+                logMessage(INFO, "No RHupdates/ directory found, skipping");
+            }
+
+            stage = NFS_STAGE_DONE;
+            break;
+        }
+
+        case NFS_STAGE_DONE:
+            break;
+        }
+    }
+
+    free(host);
+    free(directory);
+    if (mountOpts)
+        free(mountOpts);
+    if (fullPath)
+        free(fullPath);
+
+    return url;
+}
+
+
+void setKickstartNfs(struct loaderData_s * loaderData, int argc,
+                     char ** argv) {
+    char *substr = NULL;
+    gchar *host = NULL, *dir = NULL, *mountOpts = NULL;
+    GOptionContext *optCon = g_option_context_new(NULL);
+    GError *optErr = NULL;
+    GOptionEntry ksNfsOptions[] = {
+        { "server", 0, 0, G_OPTION_ARG_STRING, &host, NULL, NULL },
+        { "dir", 0, 0, G_OPTION_ARG_STRING, &dir, NULL, NULL },
+        { "opts", 0, 0, G_OPTION_ARG_STRING, &mountOpts, NULL, NULL },
+        { NULL },
+    };
+
+    logMessage(INFO, "kickstartFromNfs");
+
+    g_option_context_set_help_enabled(optCon, FALSE);
+    g_option_context_add_main_entries(optCon, ksNfsOptions, NULL);
+
+    if (!g_option_context_parse(optCon, &argc, &argv, &optErr)) {
+        startNewt();
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("Bad argument to NFS kickstart method "
+                         "command: %s"), optErr->message);
+        g_error_free(optErr);
+        g_option_context_free(optCon);
+        return;
+    }
+
+    g_option_context_free(optCon);
+
+    if (!host || !dir) {
+        logMessage(ERROR, "host and directory for nfs kickstart not specified");
+        return;
+    }
+
+    loaderData->method = METHOD_NFS;
+    loaderData->stage2Data = NULL;
+
+    substr = strstr(dir, ".img");
+    if (!substr || (substr && *(substr+4) != '\0')) {
+        checked_asprintf(&(loaderData->instRepo), "nfs:%s:%s", host, dir);
+
+        logMessage(INFO, "results of nfs, host is %s, dir is %s, opts are '%s'",
+                   host, dir, mountOpts);
+    } else {
+        loaderData->stage2Data = calloc(sizeof(struct nfsInstallData *), 1);
+        ((struct nfsInstallData *)loaderData->stage2Data)->host = host;
+        ((struct nfsInstallData *)loaderData->stage2Data)->directory = dir;
+        ((struct nfsInstallData *)loaderData->stage2Data)->mountOpts = mountOpts;
+
+        logMessage(INFO, "results of nfs, host is %s, dir is %s, opts are '%s'",
+                   ((struct nfsInstallData *) loaderData->stage2Data)->host,
+                   ((struct nfsInstallData *) loaderData->stage2Data)->directory,
+                   ((struct nfsInstallData *) loaderData->stage2Data)->mountOpts);
+    }
+}
+
+
+int getFileFromNfs(char * url, char * dest, struct loaderData_s * loaderData) {
+    char * host = NULL, *path = NULL, * file = NULL, * opts = NULL;
+    char * chk = NULL, *ip = NULL;
+    int failed = 0, i = 0;
+    iface_t iface;
+    NMClient *client = NULL;
+    NMState state;
+    const GPtrArray *devices;
+
+    if (kickstartNetworkUp(loaderData, &iface)) {
+        logMessage(ERROR, "unable to bring up network");
+        return 1;
+    }
+
+    /* if they just did 'linux ks', they want us to figure it out from
+     * the dhcp/bootp information
+     */
+    if (!url) {
+        g_type_init();
+
+        client = nm_client_new();
+        if (!client) {
+            logMessage(CRITICAL, "%s (%d): failure creating NM proxy",
+                       __func__, __LINE__);
+            return 1;
+        }
+
+        state = nm_client_get_state(client);
+        if (state != NM_STATE_CONNECTED) {
+            logMessage(ERROR, "%s (%d): no active network devices",
+                       __func__, __LINE__);
+            g_object_unref(client);
+            return 1;
+        }
+
+        devices = nm_client_get_devices(client);
+        for (i = 0; i < devices->len; i++) {
+            NMDevice *candidate = g_ptr_array_index(devices, i);
+            const char *devname = nm_device_get_iface(candidate);
+            NMDHCP4Config *dhcp = NULL;
+            const char *server_name = NULL;
+            const char *filename = NULL;
+            struct in_addr addr;
+            char nextserver[INET_ADDRSTRLEN+1];
+
+            if (nm_device_get_state(candidate) != NM_DEVICE_STATE_ACTIVATED)
+                continue;
+
+            if (strcmp(iface.device, devname))
+                continue;
+
+            dhcp = nm_device_get_dhcp4_config(candidate);
+            if (!dhcp) {
+                logMessage(ERROR, "no boot options received by DHCP");
+                continue;
+            }
+
+            server_name = nm_dhcp4_config_get_one_option(dhcp, "server_name");
+            if (!server_name) {
+                logMessage(ERROR, "no bootserver was found");
+                g_object_unref(client);
+                return 1;
+            }
+
+            /* 'server_name' may be a hostname or an IPv4 address */
+            memset(&nextserver, '\0', sizeof(nextserver));
+            if (inet_pton(AF_INET, server_name, &addr) >= 1) {
+                strcpy(nextserver, server_name);
+            } else {
+                struct hostent *he = gethostbyname(server_name);
+                if (he != NULL) {
+                    if (inet_ntop(AF_INET, he->h_addr_list[0],
+                                  nextserver, INET_ADDRSTRLEN) == NULL) {
+                        memset(&nextserver, '\0', sizeof(nextserver));
+                    }
+                }
+            }
+
+            filename = nm_dhcp4_config_get_one_option(dhcp, "filename");
+            if (filename == NULL) {
+                checked_asprintf(&url, "%s:/kickstart/", nextserver);
+                logMessage(ERROR, "bootp: no bootfile received");
+            } else {
+                checked_asprintf(&url, "%s:%s", nextserver, filename);
+                logMessage(INFO, "bootp: bootfile is %s", filename);
+            }
+
+            break;
+        }
+
+        g_object_unref(client);
+    }
+
+    /* get the IP of the target system */
+    if ((ip = iface_ip2str(loaderData->netDev, AF_INET)) == NULL) {
+        logMessage(ERROR, "iface_ip2str returned NULL");
+        return 1;
+    }
+
+    logMessage(INFO, "url is %s", url);
+
+    parseNfsHostPathOpts(url, &host, &path, &opts);
+    addDefaultKickstartFile(&path, ip);
+
+    /* nfs has to be a little bit different... split off the last part as
+     * the file and then concatenate host + dir path */
+    file = strrchr(path, '/');
+    if (!file) {
+        file = path;
+    } else {
+        *file++ ='\0';
+        chk = host + strlen(host)-1;
+
+        if (*chk == '/' || *path == '/') {
+            checked_asprintf(&host, "%s:%s", host, path);
+        } else {
+            checked_asprintf(&host, "%s:/%s", host, path);
+        }
+    }
+
+    logMessage(INFO, "file location: nfs:%s/%s", host, file);
+
+    if (!doPwMount(host, "/tmp/mnt", "nfs", opts, NULL)) {
+        char * buf;
+
+        checked_asprintf(&buf, "/tmp/mnt/%s", file);
+
+        if (copyFile(buf, dest)) {
+            logMessage(ERROR, "failed to copy file to %s", dest);
+            failed = 1;
+        }
+
+        free(buf);
+    } else {
+        logMessage(ERROR, "failed to mount nfs source");
+        failed = 1;
+    }
+
+    free(host);
+    free(path);
+    if (ip) free(ip);
+
+    umount("/tmp/mnt");
+    unlink("/tmp/mnt");
+
+    return failed;
+}
+
+int kickstartFromNfs(char * url, struct loaderData_s * loaderData) {
+    return getFileFromNfs(url, "/tmp/ks.cfg", loaderData);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4: */
diff --git a/bin/loader/nfsinstall.h b/bin/loader/nfsinstall.h
new file mode 100644
index 0000000..99a8b06
--- /dev/null
+++ b/bin/loader/nfsinstall.h
@@ -0,0 +1,40 @@
+/*
+ * nfsinstall.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFSINSTALL_H
+#define NFSINSTALL_H
+
+#include "method.h"
+
+struct nfsInstallData {
+    char * host;
+    char * directory;
+    char * mountOpts;
+};
+
+
+void setKickstartNfs(struct loaderData_s * loaderData, int argc,
+                     char ** argv);
+int kickstartFromNfs(char * url, struct loaderData_s * loaderData);
+char * mountNfsImage(struct installMethod * method,
+                     char * location, struct loaderData_s * loaderData);
+int getFileFromNfs(char * url, char * dest, struct loaderData_s * loaderData);
+void parseNfsHostPathOpts(char * url, char ** host, char ** path, char ** opts);
+
+#endif
diff --git a/bin/loader/rpmextract.c b/bin/loader/rpmextract.c
new file mode 100644
index 0000000..d1549b8
--- /dev/null
+++ b/bin/loader/rpmextract.c
@@ -0,0 +1,325 @@
+/* unpack the payload of RPM package to the current directory
+ * 
+ * File name: rpmextract.c
+ * Date:      2009/12/18
+ * Author:    Martin Sivak <msivak at redhat dot com>
+ * 
+ * Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rpm/rpmlib.h>		/* rpmReadPackageFile .. */
+#include <rpm/rpmtag.h>
+#include <rpm/rpmio.h>
+#include <rpm/rpmpgp.h>
+
+#include <rpm/rpmts.h>
+
+#include <stdio.h>
+#include <archive.h>
+#include <archive_entry.h>
+
+#include "loader.h"
+#include "rpmextract.h"
+
+#include "../isys/log.h"
+
+/*
+ * internal structure to pass to libarchive callbacks
+ */
+
+struct cpio_mydata {
+    FD_t gzdi;
+    char *buffer;
+};
+
+/*
+ * libarchive callbacks
+ */
+
+ssize_t rpm_myread(struct archive *a, void *client_data, const void **buff)
+{
+    struct cpio_mydata *mydata = client_data;
+    *buff = mydata->buffer;
+    return Fread(mydata->buffer, BUFFERSIZE, 1, mydata->gzdi);
+}
+
+int rpm_myclose(struct archive *a, void *client_data)
+{
+    struct cpio_mydata *mydata = client_data;
+    if (mydata->gzdi > 0)
+        Fclose(mydata->gzdi);
+    return ARCHIVE_OK;
+}
+
+/* read data from RPM header */
+
+const char * headerGetString(Header h, rpmTag tag)
+{
+    const char *res = NULL;
+    struct rpmtd_s td;
+
+    if (headerGet(h, tag, &td, HEADERGET_MINMEM)) {
+        if (rpmtdCount(&td) == 1) {
+            res = rpmtdGetString(&td);
+        }
+        rpmtdFreeData(&td);
+    }
+    return res;
+}
+
+/*
+ * explode source RPM into the current directory
+ * use filters to skip packages and files we do not need
+ */
+int explodeRPM(const char *source,
+        filterfunc filter,
+        dependencyfunc provides,
+        dependencyfunc deps,
+        void* userptr)
+{
+    char buffer[BUFFERSIZE+1]; /* make space for trailing \0 */
+    FD_t fdi;
+    Header h;
+    char * rpmio_flags = NULL;
+    rpmRC rc;
+    FD_t gzdi;
+    struct archive *cpio;
+    struct archive_entry *cpio_entry;
+    struct cpio_mydata cpio_mydata;
+
+    rpmts ts;
+    rpmVSFlags vsflags;
+    const char *compr;
+
+    if (strcmp(source, "-") == 0)
+        fdi = fdDup(STDIN_FILENO);
+    else
+        fdi = Fopen(source, "r.ufdio");
+
+    if (Ferror(fdi)) {
+        const char *srcname = (strcmp(source, "-") == 0) ? "<stdin>" : source;
+        logMessage(ERROR, "%s: %s\n", srcname, Fstrerror(fdi));
+        return EXIT_FAILURE;
+    }
+    rpmReadConfigFiles(NULL, NULL);
+
+    /* Initialize RPM transaction */
+    ts = rpmtsCreate();
+    vsflags = 0;
+
+    /* Do not check digests, signatures or headers */
+    vsflags |= _RPMVSF_NODIGESTS;
+    vsflags |= _RPMVSF_NOSIGNATURES;
+    vsflags |= RPMVSF_NOHDRCHK;
+    (void) rpmtsSetVSFlags(ts, vsflags);
+
+    rc = rpmReadPackageFile(ts, fdi, "rpm2dir", &h);
+
+    ts = rpmtsFree(ts);
+
+    switch (rc) {
+        case RPMRC_OK:
+        case RPMRC_NOKEY:
+        case RPMRC_NOTTRUSTED:
+            break;
+        case RPMRC_NOTFOUND:
+            logMessage(ERROR, "%s is not an RPM package", source);
+            return EXIT_FAILURE;
+            break;
+        case RPMRC_FAIL:
+        default:
+            logMessage(ERROR, "error reading header from %s package\n", source);
+            return EXIT_FAILURE;
+            break;
+    }
+
+    /* Retrieve all dependencies and run them through deps function */
+    while (deps) {
+        struct rpmtd_s td;
+        const char *depname;
+
+        if (!headerGet(h, RPMTAG_REQUIRENAME, &td, HEADERGET_MINMEM))
+            break;
+
+        /* iterator */
+        while ((depname = rpmtdNextString(&td))) {
+            if (deps(depname, userptr)) {
+                Fclose(fdi);
+                return EXIT_BADDEPS;
+            }
+        }
+        rpmtdFreeData(&td);
+        break;
+    }
+
+    /* Retrieve all provides and run them through provides function */
+    while (provides) {
+        struct rpmtd_s td;
+        const char *depname;
+        int found = 0;
+
+        if (!headerGet(h, RPMTAG_PROVIDES, &td, HEADERGET_MINMEM))
+            break;
+
+        /* iterator */
+        while ((depname = rpmtdNextString(&td))) {
+            if (!provides(depname, userptr)) {
+                found++;
+            }
+        }
+        rpmtdFreeData(&td);
+        if (found<=0)
+            return EXIT_BADDEPS;
+        break;
+    }
+
+    /* Retrieve type of payload compression. */
+    compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
+    if (compr && strcmp(compr, "gzip")) {
+        checked_asprintf(&rpmio_flags, "r.%sdio", compr);
+    }
+    else {
+        checked_asprintf(&rpmio_flags, "r.gzdio");
+    }
+
+    /* Open uncompressed cpio stream */
+    gzdi = Fdopen(fdi, rpmio_flags);
+    free(rpmio_flags);
+
+    if (gzdi == NULL) {
+        logMessage(ERROR, "cannot re-open payload: %s\n", Fstrerror(gzdi));
+        return EXIT_FAILURE;
+    }
+
+    /* initialize cpio decompressor */
+    cpio = archive_read_new();
+    if (cpio==NULL) {
+        Fclose(gzdi);
+        return -1;
+    }
+
+    cpio_mydata.gzdi = gzdi;
+    cpio_mydata.buffer = buffer;
+    archive_read_support_compression_all(cpio);
+    archive_read_support_format_all(cpio);
+    rc = archive_read_open(cpio, &cpio_mydata, NULL, rpm_myread, rpm_myclose);
+
+    /* check the status of archive_open */
+    if (rc != ARCHIVE_OK){
+        Fclose(gzdi);
+        return -1;
+    }
+
+    /* read all files in cpio archive */
+    while ((rc = archive_read_next_header(cpio, &cpio_entry)) == ARCHIVE_OK){
+        const struct stat *fstat;
+        int64_t fsize;
+        const char* filename;
+        int needskip = 1; /* do we need to read the data to get to the next header? */
+        int offset = 0;
+        int towrite = 0;
+
+        filename = archive_entry_pathname(cpio_entry);
+        fstat = archive_entry_stat(cpio_entry);
+        fsize = archive_entry_size(cpio_entry);
+
+        /* Strip leading slashes */
+        while (filename[offset] == '/')
+            offset+=1;
+
+        /* Strip leading ./ */
+        while (filename[offset] == '.' && filename[offset+1] == '/')
+            offset+=2;
+
+        /* Other file type - we do not care except special cases */
+        if (!S_ISREG(fstat->st_mode))
+            towrite = 1;
+        else
+            towrite = 2;
+
+        if (filter && filter(filename+offset, fstat, userptr)) {
+            /* filter this file */
+            towrite = 0;
+        }
+
+        /* Create directories */
+        char* dirname = strdup(filename+offset);
+
+        /* If the dup fails, let's hope the dirs already exist */
+        if (dirname){
+            char* dirptr = dirname;
+            while (dirptr && *dirptr) {
+                dirptr = strchr(dirptr, '/');
+                if (dirptr) {
+                    *dirptr = 0;
+                    mkdir(dirname, 0700);
+                    *dirptr = '/';
+                    dirptr++;
+                }
+            }
+            free(dirname);
+        }
+
+        /* Regular file */
+        if (towrite>=2) {
+            FILE *fdout = fopen(filename+offset, "w");
+
+            if (fdout==NULL){
+                rc = 33;
+                break;
+            }
+            
+            rc = archive_read_data_into_fd(cpio, fileno(fdout));
+            if (rc!=ARCHIVE_OK) {
+                /* XXX We didn't get the file.. well.. */
+                needskip = 0;
+            } else {
+                needskip = 0;
+                fclose(fdout);
+            }
+        }
+
+        /* symlink, we assume that the path contained in symlink
+         * is shorter than BUFFERSIZE */
+        while (towrite && S_ISLNK(fstat->st_mode)) {
+            char symlinkbuffer[BUFFERSIZE-1];
+
+            needskip = 0;
+            if ((rc = archive_read_data(cpio, symlinkbuffer, fsize))!=ARCHIVE_OK) {
+                /* XXX We didn't get the file.. well.. */
+                break;
+            }
+
+            if (symlink(buffer, filename+offset)) {
+                logMessage(ERROR, "Failed to create symlink %s -> %s", filename+offset, buffer);
+            }
+
+            break;
+        }
+
+        if(needskip)
+            archive_read_data_skip(cpio);
+    }
+
+    archive_read_finish(cpio);
+
+    return rc != ARCHIVE_OK;
+}
diff --git a/bin/loader/rpmextract.h b/bin/loader/rpmextract.h
new file mode 100644
index 0000000..53a90cf
--- /dev/null
+++ b/bin/loader/rpmextract.h
@@ -0,0 +1,45 @@
+/*
+   File name: rpmextract.h
+   Date:      2009/09/16
+   Author:    msivak
+
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef __RPMEXTRACT_H__
+#define __RPMEXTRACT_H__
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define EXIT_BADDEPS 4
+#define BUFFERSIZE 1024
+
+/* both filter functions return 0 - match, 1 - match not found */
+typedef int (*filterfunc)(const char* name, const struct stat *fstat, void *userptr);
+typedef int (*dependencyfunc)(const char* depends, void *userptr);
+
+int explodeRPM(const char* file,
+               filterfunc filter,
+               dependencyfunc provides,
+               dependencyfunc deps,
+               void* userptr);
+
+#endif
+
+/* end of rpmextract.h */
diff --git a/bin/loader/selinux.c b/bin/loader/selinux.c
new file mode 100644
index 0000000..66bfe4d
--- /dev/null
+++ b/bin/loader/selinux.c
@@ -0,0 +1,56 @@
+/*
+ * selinux.c - Various SELinux related functionality needed for the loader.
+ * Portions extracted from libselinux which was released as public domain
+ * software by the NSA.
+ *
+ * Copyright (C) 2004  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Jeremy Katz <katzj redhat com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <string.h>
+
+#include "loader.h"
+#include "loadermisc.h"
+#include "../isys/log.h"
+
+int loadpolicy() {
+    int pid, status;
+
+    logMessage(INFO, "Loading SELinux policy");
+
+    if (!(pid = fork())) {
+        setenv("LD_LIBRARY_PATH", LIBPATH, 1);
+        execl("/sbin/load_policy",
+              "/sbin/load_policy", "-q", NULL);
+        logMessage(ERROR, "exec of load_policy failed: %m");
+        exit(1);
+    }
+
+    waitpid(pid, &status, 0);
+    if (WIFEXITED(status) && (WEXITSTATUS(status) != 0))
+        return 1;
+
+    return 0;
+}
+
diff --git a/bin/loader/selinux.h b/bin/loader/selinux.h
new file mode 100644
index 0000000..5877ddd
--- /dev/null
+++ b/bin/loader/selinux.h
@@ -0,0 +1,27 @@
+/*
+ * selinux.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SELINUX_H
+#define SELINUX_H
+
+int loadpolicy();
+
+#define ANACONDA_CONTEXT "system_u:system_r:anaconda_t:s0"
+
+#endif
diff --git a/bin/loader/shutdown.c b/bin/loader/shutdown.c
new file mode 100644
index 0000000..3b481f2
--- /dev/null
+++ b/bin/loader/shutdown.c
@@ -0,0 +1,153 @@
+/*
+ * shutdown.c
+ *
+ * Shutdown a running system.  If built with -DAS_SHUTDOWN=1, then
+ * it builds a standalone shutdown binary.
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/reboot.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "init.h"
+
+void disableSwap(void);
+void unmountFilesystems(void);
+
+static void performTerminations(void) {
+	sync();
+	printf("sending termination signals...");
+	kill(-1, 15);
+	sleep(2);
+	printf("done\n");
+
+	printf("sending kill signals...");
+	kill(-1, 9);
+	sleep(2);
+	printf("done\n");
+}
+
+static void performUnmounts(void) {
+	int ignore;
+
+	printf("disabling swap...\n");
+	disableSwap();
+
+	printf("unmounting filesystems...\n"); 
+	unmountFilesystems();
+
+	printf("waiting for mdraid sets to become clean...\n"); 
+	ignore = system("/sbin/mdadm --wait-clean --scan");
+}
+
+static void performReboot(reboot_action rebootAction) {
+    switch (rebootAction) {
+    case POWEROFF:
+        printf("powering off system\n");
+        sleep(2);
+        reboot(RB_POWER_OFF);
+        break;
+    case REBOOT:
+        printf("rebooting system\n");
+        sleep(2);
+#if USE_MINILIBC
+        reboot(0xfee1dead, 672274793, 0x1234567);
+#else
+        reboot(RB_AUTOBOOT);
+#endif
+        break;
+    case HALT:
+        printf("halting system\n");
+        reboot(RB_HALT_SYSTEM);
+        break;
+    default:
+        break;
+    }
+}
+
+static void performDelayedReboot()
+{
+    printf("The system will be rebooted when you press Ctrl-C or Ctrl-Alt-Delete.\n");
+    while (1) {
+        sleep(1);
+    }
+}
+
+void shutDown(int doKill, reboot_action rebootAction)
+{
+    static int reentered = 0;
+    
+    if (reentered) {
+        performUnmounts();
+        performTerminations();
+        performReboot(rebootAction);
+    }
+    reentered = 1;
+    if (rebootAction != DELAYED_REBOOT && doKill) {
+        performUnmounts();
+        performTerminations();
+        performReboot(rebootAction);
+    } else {
+        performDelayedReboot();
+    }
+    exit(0);
+}
+
+#ifdef AS_SHUTDOWN
+int main(int argc, char ** argv) {
+    int fd;
+    reboot_action rebootAction = HALT;
+    int doKill = 1;
+    int i = 1;
+
+    while (i < argc) {
+      if (!strncmp("-r", argv[i], 2))
+        rebootAction = REBOOT;
+      else if (!strncmp("--nokill", argv[i], 8))
+        doKill = 0;
+      else if (!strncmp("-P", argv[i], 2))
+        rebootAction = POWEROFF;
+      i++;
+    }
+
+    /* ignore some signals so we don't kill ourself */
+    signal(SIGINT, SIG_IGN);
+    signal(SIGTSTP, SIG_IGN);
+
+    /* now change to / */
+    i = chdir("/");
+
+    /* redirect output to the real console */
+    fd = open("/dev/console", O_RDWR);
+    dup2(fd, 0);
+    dup2(fd, 1);
+    dup2(fd, 2);
+    close(fd);
+
+    shutDown(doKill, rebootAction);
+    return 0;
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 ts=4: */
diff --git a/bin/loader/simplemot b/bin/loader/simplemot
new file mode 100755
index 0000000..bebc1cf
--- /dev/null
+++ b/bin/loader/simplemot
@@ -0,0 +1,81 @@
+#!/usr/bin/perl
+#
+# simplemot
+#
+# Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+$inone = 0;
+$intran = 0;
+$total = 0;
+
+binmode(STDIN, ":raw");
+binmode(STDOUT, ":raw");
+
+while (<>) {
+    if (!$inone && /^msgid/) {
+	chop;
+	$str = substr($_, 7, length($_) - 8);
+	$inone = 1;
+    } elsif ($inone && /^"/) {
+	chop;
+	$str .= substr($_, 1, length($_) - 2);
+    } elsif ($inone) {
+	$inone = 0;
+
+	$str =~ s/\\n/\n/g;
+	$str =~ s/\\t/\t/g;
+	$str =~ s/\\"/"/g;
+
+	# the string is complete -- calculate a hash
+	$sum = 0;
+	$xor = 0;
+	for ($i = 0; $i < length($str); $i++) {
+	    $char = ord(substr($str, $i, 1));
+	    $sum += $char;
+	    $xor ^= $char;
+	}
+
+	$total = ($sum << 16) | (($xor & 0xFF) << 8) | (length($str) & 0xFF);
+    }
+
+    if (!$intran && /^msgstr/) {
+	chop;
+	$tran = substr($_, 8, length($_) - 9);
+	$intran = 1;
+    } elsif ($intran && /^"/) {
+	chop;
+	$tran .= substr($_, 1, length($_) - 2);
+    } elsif ($intran) {
+	$intran = 0;
+
+	$tran =~ s/\\n/\n/g;
+	$tran =~ s/\\t/\t/g;
+	$tran =~ s/\\"/"/g;
+
+	if (!$total && $str) {
+	    print STDERR "Missing string for $tran";
+	    exit 1
+	} elsif ($str && $tran) {
+	    print pack("Nn", $total, length($tran));
+	    print $tran;
+
+	    #if ($tran < 60) {
+		#printf STDERR ("0x%x %s\n", $total, $tran);
+	    #}
+	}
+    }
+}
diff --git a/bin/loader/telnet.c b/bin/loader/telnet.c
new file mode 100644
index 0000000..3c123ae
--- /dev/null
+++ b/bin/loader/telnet.c
@@ -0,0 +1,273 @@
+/*
+ * telnet.c -- basic telnet protocol handling for ttywatch
+ *
+ * Copyright (C) 2001  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Michael K. Johnson <johnsonm redhat com>
+ */
+
+/* Shamelessly stolen from ttywatch -- oot */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "telnet.h"
+#include "../isys/log.h"
+
+#define IAC "\xff"
+#define DONT "\xfe"
+#define WONT "\xfc"
+#define WILL "\xfb"
+#define DO "\xfd"
+#define SB "\xfa"
+#define SE "\xf0"
+#define ECHO "\x01"
+#define SUPPRESS_GO_AHEAD "\x03"
+#define TERMINAL_TYPE "\x18"
+#define NAWS "\x1f"
+#define LINEMODE "\x22"
+#define NEWENVIRON "\x27"
+#define MODE "\x01"
+
+/* Make a request.  Not intended to be RFC-compatible, just enough
+ * to convince telnet clients to do what we want...  To do this
+ * right, we would have to honestly negotiate, not speak blind.
+ *
+ * For now, assume all responses will be favorable and stripped
+ * out in telnet_process_input()...  Sending it all in a single
+ * write makes it more efficient because it will all go out in a
+ * single packet, and the responses are more likely to all come
+ * back in a single packet (and thus, practically, a single read)
+ * too.
+ */
+void
+telnet_negotiate(int socket, char ** term_type_ptr, int * heightPtr,
+		 int * widthPtr) {
+    char ch;
+    int done = 0;
+    char * termType = NULL;
+    int termLength = 0, termAlloced = 0;
+    enum { ST_NONE, ST_TERMTYPE, ST_WINDOWSIZE } state;
+    char sizeBuf[4];
+    int height = -1, width = -1;
+    char * sizePtr = sizeBuf;
+    char request[]=
+      IAC DONT ECHO
+      IAC WILL ECHO
+      IAC WILL NAWS
+      IAC WILL SUPPRESS_GO_AHEAD
+      IAC DO SUPPRESS_GO_AHEAD
+      IAC DONT NEWENVIRON
+      IAC WONT NEWENVIRON
+      IAC WONT LINEMODE
+      IAC DO NAWS
+      IAC SB TERMINAL_TYPE "\x01" IAC SE
+      ;
+    int ret;
+
+    ret = write(socket, request, sizeof(request)-1);
+
+    /* Read from the terminal until we get the terminal type. This will
+       do bad things if the client doesn't send the terminal type, but
+       those clients have existed for aeons (right?) */
+
+    do {
+	ret = read(socket, &ch, 1);
+	if (ch != '\xff') {
+	    abort();
+	}
+
+	ret = read(socket, &ch, 1);	    /* command */
+
+	if (ch != '\xfa') {
+	    ret = read(socket, &ch, 1);   /* verb */
+	    continue;
+	}
+
+	ret = read(socket, &ch, 1);   /* suboption */
+	if (ch == '\x18') {
+	    state = ST_TERMTYPE;
+	    ret = read(socket, &ch, 1);	    /* should be 0x0! */
+	    done = 1;
+	} else if (ch == '\x1f') {
+	    state = ST_WINDOWSIZE;
+	} else {
+	    state = ST_NONE;;
+	}
+
+	ret = read(socket, &ch, 1);   /* data */
+	while (ch != '\xff') {
+	    if (state == ST_TERMTYPE) {
+		if (termAlloced == termLength) {
+		    termAlloced += 10;
+		    termType = realloc(termType, termAlloced + 1);
+		}
+
+		termType[termLength++] = tolower(ch);
+	    } else if (state == ST_WINDOWSIZE) {
+		if ((sizePtr - sizeBuf) < (int)sizeof(sizeBuf))
+		    *sizePtr++ = ch;
+	    }
+
+	    ret = read(socket, &ch, 1);   /* data */
+	}
+
+	ret = read(socket, &ch, 1);   /* should be a SE */
+
+    } while (!done);
+
+    termType[termLength] = '\0';
+
+    if (sizePtr - sizeBuf == sizeof(sizeBuf)) {
+	width = (sizeBuf[0] << 8) + sizeBuf[1];
+	height = (sizeBuf[2] << 8) + sizeBuf[3];
+    }
+
+    if (heightPtr) *heightPtr = height;
+    if (widthPtr) *widthPtr = width;
+
+    if (term_type_ptr) *term_type_ptr = termType;
+}
+
+int
+telnet_process_input(telnet_state * ts, char *data, int len) {
+    char *s, *d; /* source, destination */
+
+#   if DEBUG_TELNET
+    printf("\nprinting packet:");
+    for (s=data; s<data+len; s++) {
+	if (!((s-data)%10))
+	    printf("\n %03d: ", s-data);
+	printf("%02x ", *s & 0x000000FF);
+    }
+    printf("\n");
+#   endif /* DEBUG_TELNET */
+
+    for (s=data, d=data; s<data+len; s++) {
+	switch (*ts) {
+	case TS_DATA:
+	    if (*s == '\xff') { /* IAC */
+		*ts = TS_IAC;
+		continue;
+	    }
+#if	    DEBUG_TELNET
+	    printf("copying data element '%c'\n", *s);
+#endif	    /* DEBUG_TELNET */
+	    if (s>d) {
+		*(d++) = *s;
+	    } else {
+		d++;
+	    }
+	    break;
+
+	case TS_IAC:
+	    if (*s == '\xfa') { /* SB */
+		*ts = TS_SB;
+		continue;
+	    }
+	    /* if not SB, skip IAC verb object */
+#	    if DEBUG_TELNET
+	    printf("skipping verb/object (offset %d)...\n", s-data-1);
+#	    endif /* DEBUG_TELNET */
+	    s += 1;
+	    *ts = TS_DATA;
+	    break;
+
+	case TS_SB:
+#	    if DEBUG_TELNET
+	    printf("skipping SB (offset %d)...\n", s-data-1);
+#	    endif /* DEBUG_TELNET */
+	    while (s < (data+(len-1))) {
+		if (*s == '\xff') {
+		    break; /* fall through to TS_SB_IAC setting below */
+		} else {
+		    s++;
+		}
+	    }
+	    if (*s == '\xff') {
+		*ts = TS_SB_IAC;
+	    }
+	    break;
+
+	case TS_SB_IAC:
+	    if (*s == '\xf0') { /* SE */
+#		if DEBUG_TELNET
+		printf("SE ends SB (offset %d)...\n", s-data-1);
+#		endif /* DEBUG_TELNET */
+		*ts = TS_DATA;
+	    } else {
+#		if DEBUG_TELNET
+		printf("IAC without SE in SB (offset %d)\n", s-data-1);
+#		endif /* DEBUG_TELNET */
+		*ts = TS_SB;
+	    }
+	    break;
+
+	default:
+	    logMessage(WARNING, "unknown telnet state %d for data element %c",
+                       *ts, *s);
+	    *ts = TS_DATA;
+	    break;
+	}
+    }
+
+    /* calculate new length after copying data around */
+    len = d - data;
+#if DEBUG_TELNET
+    printf("returning len: %d of packet:", len);
+    for (s=data; s<data+len; s++) {
+	if (!((s-data)%10))
+	    printf("\n %03d: ", s-data);
+	printf("%02x ", *s & 0x000000FF);
+    }
+    printf("\n");
+#endif /* DEBUG_TELNET */
+
+    return len;
+}
+
+/* The telnet protocol requires CR/NL instead of just NL
+ * We normally deal with Unix, which just uses NL, so we need to translate.
+ *
+ * It would be easy to go through line-by-line and write each line, but
+ * that would create more packet overhead by sending out one packet
+ * per line, and over things like slow PPP connections, that is painful.
+ * Therefore, instead, we create a modified copy of the data and write
+ * the whole modified copy at once.
+ */
+void
+telnet_send_output(int sock, char *data, int len) {
+    char *s, *d; /* source, destination */
+    char *buf;
+    int ret;
+
+    buf = alloca((len*2)+1);  /* max necessary size */
+
+    /* just may need to add CR before NL (but do not double existing CRs) */
+    for (s=data, d=buf; d-buf<len; s++, d++) {
+	if ((*s == '\n') && (s == data || (*(s-1) != '\r'))) {
+	    /* NL without preceding CR */
+	    *(d++) = '\r';
+	    len++;
+	}
+	*d = *s;
+    }
+
+    /* now send it... */
+    ret = write(sock, buf, len);
+}
diff --git a/bin/loader/telnet.h b/bin/loader/telnet.h
new file mode 100644
index 0000000..5c34154
--- /dev/null
+++ b/bin/loader/telnet.h
@@ -0,0 +1,40 @@
+/*
+ * telnet.h -- basic telnet protocol handling for ttywatch
+ *
+ * Copyright (C) 2001  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Michael K. Johnson <johnsonm redhat com>
+ */
+
+#ifndef __TELNET_H__
+#define __TELNET_H__
+
+typedef enum {
+	TS_DATA = 0,
+	TS_IAC,
+	TS_SB,
+	TS_SB_IAC,
+} telnet_state;
+
+void
+telnet_negotiate(int socket, char ** term_type_ptr, int * heightPtr,
+		 int * widthPtr);
+int
+telnet_process_input(telnet_state * ts, char *data, int len);
+void
+telnet_send_output(int sock, char *data, int len);
+
+#endif /* __TELNET_H__ */
diff --git a/bin/loader/telnetd.c b/bin/loader/telnetd.c
new file mode 100644
index 0000000..219df78
--- /dev/null
+++ b/bin/loader/telnetd.c
@@ -0,0 +1,256 @@
+/*
+ * telnetd.c - glue to tie telnet.c from ttywatch to the loader
+ *
+ * Copyright (C) 2002  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <newt.h>
+#include <pty.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "../isys/log.h"
+
+#include "lang.h"
+#include "loader.h"
+#include "modules.h"
+#include "net.h"
+#include "telnet.h"
+#include "windows.h"
+
+#ifndef IPPORT_TELNET
+#define IPPORT_TELNET 23
+#endif
+
+/* boot flags */
+extern uint64_t flags;
+
+/* Forks, keeping the loader as our child (so we know when it dies). */
+int beTelnet(void) {
+    int sock;
+    int conn;
+    socklen_t addrLength;
+    pid_t child;
+    int i;
+    int masterFd, ttyFd;
+    struct sockaddr_in address;
+    char buf[4096];
+    struct pollfd fds[3];
+    telnet_state ts = TS_DATA;
+    char * termType;
+    int height, width;
+    struct winsize ws;
+
+    if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+        logMessage(ERROR, "socket: %s", strerror(errno));
+        return -1;
+    }
+
+    address.sin_family = AF_INET;
+    address.sin_port = htons(IPPORT_TELNET);
+    memset(&address.sin_addr, 0, sizeof(address.sin_addr));
+    addrLength = sizeof(address);
+
+    /* Let the kernel reuse the socket address. This lets us run
+       twice in a row, without waiting for the (ip, port) tuple
+       to time out. Makes testing much easier*/
+    conn = 1;
+    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &conn, sizeof(conn));
+
+    bind(sock, (struct sockaddr *) &address, sizeof(address));
+    listen(sock, 5);
+
+    winStatus(45, 3, _("Telnet"), _("Waiting for telnet connection."));
+
+    if ((conn = accept(sock, (struct sockaddr *) &address, &addrLength)) < 0) {
+        newtWinMessage(_("Error"), _("OK"), "accept failed: %s",
+                       strerror(errno));
+        close(sock);
+        return -1;
+    }
+
+    stopNewt();
+    close(sock);
+    telnet_negotiate(conn, &termType, &height, &width);
+
+#ifdef DEBUG_TELNET
+    printf("got term type %s\n", termType);
+#endif
+
+    masterFd = open("/dev/ptmx", O_RDWR);
+    if (masterFd < 0) {
+        logMessage(CRITICAL, "cannot open /dev/ptmx");
+        close(conn);
+        return -1;
+    }
+
+    if (height != -1 && width != -1) {
+#ifdef DEBUG_TELNET
+        printf("setting window size to %d x %d\n", width, height);
+#endif
+        ws.ws_row = height;
+        ws.ws_col = width;
+        ioctl(masterFd, TIOCSWINSZ, &ws);
+    }
+
+
+    child = fork();
+
+    if (child) {
+#ifndef DEBUG_TELNET
+        startNewt();
+        winStatus(45, 3, _("Telnet"), _("Running anaconda via telnet."));
+#endif
+
+        fds[0].events = POLLIN;
+        fds[0].fd = masterFd;
+
+        fds[1].events = POLLIN;
+        fds[1].fd = conn;
+
+        while ((i = poll(fds, 2, -1)) > 0) {
+            if (fds[0].revents) {
+                i = read(masterFd, buf, sizeof(buf));
+#ifdef DEBUG_TELNET
+                {
+                    int j;
+                    int row;
+
+                    for (row = 0; row < (i / 12) + 1; row++) {
+                        printf("wrote:");
+
+                        for (j = (row * 12); j < i && j < ((row + 1) * 12); j++)
+                            printf(" 0x%2x", (unsigned char) buf[j]);
+
+                        printf("\nwrote:");
+
+                        for (j = (row*12); j < i && j < ((row+1)*12); j++) {
+                            if (isprint(buf[j]))
+                                printf("   %c ", buf[j]);
+                            else
+                                printf("     ");
+                        }
+
+                        printf("\n");
+                    }
+                }
+#endif
+                /* child died */
+                if (i < 0)
+                    break;
+
+                telnet_send_output(conn, buf, i);
+            }
+
+            if (fds[1].revents) {
+                int ret;
+                i = read(conn, buf, sizeof(buf));
+
+                /* connection went away */
+                if (!i)
+                    break;
+
+                i = telnet_process_input(&ts, buf, i);
+                ret = write(masterFd, buf, i);
+#ifdef DEBUG_TELNET
+                {
+                    int j;
+
+                    printf("got:");
+                    for (j = 0; j < i; j++)
+                        printf(" 0x%x", (unsigned char) buf[j]);
+                    printf("\n");
+                }
+#endif
+            }
+        }
+
+        if (i < 0) {
+            logMessage(ERROR, "poll: %s", strerror(errno));
+        }
+
+#ifndef DEBUG_TELNET
+        stopNewt();
+#endif
+
+        kill(child, SIGTERM);
+        close(conn);
+        doExit(0);
+    }
+
+    unlockpt(masterFd);
+    grantpt(masterFd);
+    ttyFd = open(ptsname(masterFd), O_RDWR);
+    close(masterFd);
+    setsid();
+    close(0);
+    close(1);
+    close(2);
+
+    if (ttyFd != 0) {
+        dup2(ttyFd, 0);
+        close(ttyFd);
+    }
+
+    dup2(0, 1);
+    dup2(0, 2);
+
+    /* brand new tty! */
+    setenv("TERM", termType, 1);
+
+    startNewt();
+
+    return 0;
+}
+
+void startTelnetd(struct loaderData_s * loaderData) {
+    char *ipaddr = NULL;
+    iface_t iface;
+
+    iface_init_iface_t(&iface);
+
+    if (kickstartNetworkUp(loaderData, &iface)) {
+        logMessage(ERROR, "unable to bring up network");
+        return;
+    }
+
+    ipaddr = iface_ip2str(iface.device, AF_INET);
+    if (ipaddr == NULL) {
+        logMessage(ERROR, "%s (%d): no IP address found for %s",
+                   __func__, __LINE__, iface.device);
+        return;
+    }
+
+    logMessage(INFO, "going to beTelnet for %s", ipaddr);
+    if (!beTelnet())
+        flags |= LOADER_FLAGS_TEXT | LOADER_FLAGS_NOSHELL;
+
+    return;
+}
diff --git a/bin/loader/telnetd.h b/bin/loader/telnetd.h
new file mode 100644
index 0000000..fedb0fa
--- /dev/null
+++ b/bin/loader/telnetd.h
@@ -0,0 +1,25 @@
+/*
+ * telnetd.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TELNETD_H
+#define TELNETD_H
+
+void startTelnetd(struct loaderData_s * loaderData);
+
+#endif
diff --git a/bin/loader/udelay.h b/bin/loader/udelay.h
new file mode 100644
index 0000000..5315074
--- /dev/null
+++ b/bin/loader/udelay.h
@@ -0,0 +1,199 @@
+/*
+ * udelay.h -- udelay and other time related functions.
+ *
+ * Copyright (C) 2006, 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Peter Jones <pjones redhat com>
+ */
+
+#ifndef UDELAY_H
+#define UDELAY_H 1
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <time.h>
+
+#define USECS_PER_SEC 1000000LL
+#define NSECS_PER_USEC 1000LL
+#define NSECS_PER_SEC (NSECS_PER_USEC * USECS_PER_SEC)
+
+static inline void
+nsectospec(long long nsecs, struct timespec *ts)
+{
+    if (nsecs < 0) {
+        ts->tv_sec = -1;
+        ts->tv_nsec = -1;
+        return;
+    }
+    ts->tv_sec = nsecs / NSECS_PER_SEC;
+    ts->tv_nsec = (nsecs % NSECS_PER_SEC);
+}
+
+static inline void
+usectospec(long long usecs, struct timespec *ts)
+{
+    if (usecs > 0 && LLONG_MAX / NSECS_PER_USEC > usecs)
+        usecs *= NSECS_PER_USEC;
+    
+    nsectospec(usecs, ts);
+}
+
+static inline int
+speczero(struct timespec *ts)
+{
+    return (ts->tv_sec == 0 && ts->tv_nsec == 0);
+}
+
+static inline int
+specinf(struct timespec *ts)
+{
+    return (ts->tv_sec < 0 || ts->tv_nsec < 0);
+}
+
+static inline long long
+spectonsec(struct timespec *ts)
+{
+    long long nsecs = 0;
+    if (specinf(ts))
+        return -1;
+    
+    nsecs = ts->tv_sec * NSECS_PER_SEC;
+    nsecs += ts->tv_nsec;
+    return nsecs;
+}
+
+static inline long long
+spectousec(struct timespec *ts)
+{
+    long long usecs = spectonsec(ts);
+
+    return usecs < 0 ? usecs : usecs / NSECS_PER_USEC;
+}
+
+static inline int
+gettimespecofday(struct timespec *ts)
+{
+    struct timeval tv = {0, 0};
+    int rc;
+
+    rc = gettimeofday(&tv, NULL);
+    if (rc >= 0) {
+        ts->tv_sec = tv.tv_sec;
+        ts->tv_nsec = tv.tv_usec * NSECS_PER_USEC;
+    }
+    return rc;
+}
+
+/* minuend minus subtrahend equals difference */
+static inline void
+tssub(struct timespec *minuend, struct timespec *subtrahend,
+      struct timespec *difference)
+{
+    long long m, s, d;
+
+    m = spectonsec(minuend);
+    s = spectonsec(subtrahend);
+
+    if (s < 0) {
+        d = 0;
+    } else if (m < 0) {
+        d = -1;
+    } else {
+        m -= s;
+        d = m < 0 ? 0 : m;
+    }
+
+    nsectospec(d, difference);
+    return;
+}
+
+static inline void
+tsadd(struct timespec *augend, struct timespec *addend, struct timespec *sum)
+{
+    long long aug, add;
+
+    aug = spectonsec(augend);
+    add = spectonsec(addend);
+
+//    printf("aug: %Ld add: %Ld\n", aug, add);
+
+    if (aug < 0 || add < 0)
+        nsectospec(-1, sum);
+    else if (LLONG_MAX - MAX(add,aug) < MAX(add,aug))
+        nsectospec(LLONG_MAX, sum);
+    else
+        nsectospec(aug+add, sum);
+    return;
+}
+
+#define tsGT(x,y) (tscmp((x), (y)) < 0)
+#define tsGE(x,y) (tscmp((x), (y)) <= 0)
+#define tsET(x,y) (tscmp((x), (y)) == 0)
+#define tsNE(x,y) (tscmp((x), (y)) != 0)
+#define tsLE(x,y) (tscmp((x), (y)) >= 0)
+#define tsLT(x,y) (tscmp((x), (y)) > 0)
+
+static inline int
+tscmp(struct timespec *a, struct timespec *b)
+{
+    long long m, s;
+    long long rc;
+
+    m = spectonsec(a);
+    s = spectonsec(b);
+
+    if (s < 0) {
+        rc = 1;
+        if (m < 0)
+            rc = 0;
+    } else if (m < 0) {
+        rc = -1;
+    } else {
+        rc = MIN(MAX(s-m, -1), 1);
+    }
+
+    return rc;
+}
+
+static inline void
+udelayspec(struct timespec total)
+{
+    struct timespec rem;
+    if (specinf(&total)) {
+        do {
+            usectospec(LLONG_MAX, &rem);
+        } while (nanosleep(&rem, &rem) == -1 && errno == EINTR);
+    } else {
+        rem = total;
+        while (nanosleep(&rem, &rem) == -1 && errno == EINTR)
+            ;
+    }
+}
+
+static inline void
+udelay(long long usecs)
+{
+    struct timespec rem = {0,0};
+
+    usectospec(usecs, &rem);
+    udelayspec(rem);
+}
+
+#endif /* UDELAY_H */
+/*
+ * vim:ts=8:sw=4:sts=4:et
+ */
diff --git a/bin/loader/undomounts.c b/bin/loader/undomounts.c
new file mode 100644
index 0000000..af5caaa
--- /dev/null
+++ b/bin/loader/undomounts.c
@@ -0,0 +1,239 @@
+/*
+ * undomounts.c: Handles some basic unmounting stuff for init
+ * Broken out so that it can be used on s390 in a shutdown binary
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/swap.h>
+#include <unistd.h>
+
+#include "devt.h"
+
+/* Defined in linux/fs.h, but inside __KERNEL__. */
+#ifdef MNT_DETACH
+#undef MNT_DETACH
+#endif
+
+#define MNT_DETACH 0x00000002
+
+struct unmountInfo {
+    char * name;
+    int mounted;
+    int loopDevice;
+    enum { FS, LOOP } what;
+} ;
+
+void undoLoop(struct unmountInfo * fs, int numFs, int this);
+
+static void printstr(char * string) {
+    int ret;
+    
+    ret = write(1, string, strlen(string));
+}
+
+void undoMount(struct unmountInfo * fs, int numFs, int this) {
+    size_t len = strlen(fs[this].name);
+    int i;
+
+    if (!fs[this].mounted) return;
+    fs[this].mounted = 0;
+
+    /* unmount everything underneath this */
+    for (i = 0; i < numFs; i++) {
+	if (fs[i].name && (strlen(fs[i].name) >= len) &&
+	    (fs[i].name[len] == '/') && 
+	    !strncmp(fs[this].name, fs[i].name, len)) {
+	    if (fs[i].what == LOOP)
+		undoLoop(fs, numFs, i);
+	    else
+		undoMount(fs, numFs, i);
+	} 
+    }
+
+    printf("\t%s", fs[this].name);
+    /* don't need to unmount /tmp.  it is busy anyway. */
+    if (umount2(fs[this].name, MNT_DETACH) < 0) {
+        printf(" umount failed (%d)", errno);
+    } else {
+        printf(" done");
+    }
+    printf("\n");
+}
+
+void undoLoop(struct unmountInfo * fs, int numFs, int this) {
+    int i;
+    int fd;
+
+    if (!fs[this].mounted) return;
+    fs[this].mounted = 0;
+
+    /* find the device mount */
+    for (i = 0; i < numFs; i++) {
+	if (fs[i].what == FS && (fs[i].loopDevice == fs[this].loopDevice))
+	    break;
+    }
+
+    if (i < numFs) {
+	/* the device is mounted, unmount it (and recursively, anything
+	 * underneath) */
+	undoMount(fs, numFs, i);
+    }
+
+    unlink("/tmp/loop");
+    mknod("/tmp/loop", 0600 | S_IFBLK, (7 << 8) | fs[this].loopDevice);
+    printf("\tdisabling /dev/loop%d", fs[this].loopDevice);
+    if ((fd = open("/tmp/loop", O_RDONLY, 0)) < 0) {
+	printf(" failed to open device: %d", errno);
+    } else {
+	if (ioctl(fd, LOOP_CLR_FD, 0))
+	    printf(" LOOP_CLR_FD failed: %d", errno);
+	close(fd);
+    }
+
+    printf("\n");
+}
+
+void unmountFilesystems(void) {
+    int fd, size;
+    char buf[65535];			/* this should be big enough */
+    char * chptr, * start;
+    struct unmountInfo filesystems[500];
+    int numFilesystems = 0;
+    int i;
+    struct loop_info li;
+    char * device;
+    struct stat sb;
+
+    fd = open("/proc/mounts", O_RDONLY, 0);
+    if (fd < 1) {
+	/* FIXME: was perror */
+	printstr("failed to open /proc/mounts");
+	sleep(2);
+	return;
+    }
+
+    size = read(fd, buf, sizeof(buf) - 1);
+    buf[size] = '\0';
+
+    close(fd);
+
+    chptr = buf;
+    while (*chptr) {
+	device = chptr;
+	while (*chptr != ' ') chptr++;
+	*chptr++ = '\0';
+	start = chptr;
+	while (*chptr != ' ') chptr++;
+	*chptr++ = '\0';
+
+	if (strcmp(start, "/") && strcmp(start, "/tmp") &&
+            strcmp(start, "/dev")) {
+	    filesystems[numFilesystems].name = strdup(start);
+	    filesystems[numFilesystems].what = FS;
+	    filesystems[numFilesystems].mounted = 1;
+
+	    stat(start, &sb);
+	    if ((sb.st_dev >> 8) == 7) {
+		filesystems[numFilesystems].loopDevice = sb.st_dev & 0xf;
+	    } else {
+		filesystems[numFilesystems].loopDevice = -1;
+	    }
+
+	    numFilesystems++;
+	}
+
+	while (*chptr != '\n') chptr++;
+	chptr++;
+    }
+
+    for (i = 0; i < 7; i++) {
+	unlink("/tmp/loop");
+	mknod("/tmp/loop", 0600 | S_IFBLK, (7 << 8) | i);
+	if ((fd = open("/tmp/loop", O_RDONLY, 0)) >= 0) {
+	    if (!ioctl(fd, LOOP_GET_STATUS, &li) && li.lo_name[0]) {
+		filesystems[numFilesystems].name = strdup(li.lo_name);
+		filesystems[numFilesystems].what = LOOP;
+		filesystems[numFilesystems].mounted = 1;
+		filesystems[numFilesystems].loopDevice = i;
+		numFilesystems++;
+	    }
+
+	    close(fd);
+	}
+    }
+
+    for (i = 0; i < numFilesystems; i++) {
+	if (filesystems[i].what == LOOP) {
+	    undoLoop(filesystems, numFilesystems, i);
+	}
+    }
+
+    for (i = 0; i < numFilesystems; i++) {
+	if ((filesystems[i].mounted) && (filesystems[i].name)) {
+	    undoMount(filesystems, numFilesystems, i);
+	}
+    }
+
+    for (i = 0; i < numFilesystems; i++) 
+        free(filesystems[i].name);
+}
+
+void disableSwap(void) {
+    int fd;
+    char buf[4096];
+    int i;
+    char * start;
+    char * chptr;
+
+    if ((fd = open("/proc/swaps", O_RDONLY, 0)) < 0) return;
+
+    i = read(fd, buf, sizeof(buf) - 1);
+    close(fd);
+    if (i < 0) return;
+    buf[i] = '\0';
+
+    start = buf;
+    while (*start) {
+	while (*start != '\n' && *start) start++;
+	if (!*start) return;
+
+	start++;
+	if (*start != '/') return;
+	chptr = start;
+	while (*chptr && *chptr != ' ') chptr++;
+	if (!(*chptr)) return;
+	*chptr = '\0';
+	printf("\t%s", start);
+	if (swapoff(start)) 
+	    printf(" failed (%d)", errno);
+	printf("\n");
+
+	start = chptr + 1;
+    }
+}
diff --git a/bin/loader/unicode-linedraw-chars.txt b/bin/loader/unicode-linedraw-chars.txt
new file mode 100644
index 0000000..c1a4814
--- /dev/null
+++ b/bin/loader/unicode-linedraw-chars.txt
@@ -0,0 +1,22 @@
+─
+│
+┌
+┐
+└
+┘
+┤
+├
+┴
+┬
+┼
+▒
+◆
+°
+±
+·
+←
+→
+↓
+↑
+▒
+▮
diff --git a/bin/loader/urlinstall.c b/bin/loader/urlinstall.c
new file mode 100644
index 0000000..54d1398
--- /dev/null
+++ b/bin/loader/urlinstall.c
@@ -0,0 +1,414 @@
+/*
+ * urlinstall.c - code to set up url (ftp/http) installs
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <unistd.h>
+#include <errno.h>
+#include <glib.h>
+
+#include "../isys/iface.h"
+#include "../isys/log.h"
+
+#include "copy.h"
+#include "kickstart.h"
+#include "loader.h"
+#include "loadermisc.h"
+#include "lang.h"
+#include "method.h"
+#include "net.h"
+#include "method.h"
+#include "urlinstall.h"
+#include "cdinstall.h"
+#include "urls.h"
+#include "windows.h"
+
+/* boot flags */
+extern uint64_t flags;
+
+char **extraHeaders = NULL;
+
+static char **headers() {
+    int len = 2;
+
+    /* The list of HTTP headers is unlikely to change, unless a new ethernet
+     * device suddenly shows up since last time we downloaded a file.  So,
+     * cache the result here to save some time.
+     */
+    if (extraHeaders != NULL)
+        return extraHeaders;
+
+    if ((extraHeaders = realloc(extraHeaders, 2*sizeof(char *))) == NULL) {
+        logMessage(CRITICAL, "%s: %d: %m", __func__, __LINE__);
+        abort();
+    }
+    
+    checked_asprintf(&extraHeaders[0], "X-Anaconda-Architecture: %s", getProductArch());
+    checked_asprintf(&extraHeaders[1], "X-Anaconda-System-Release: %s", getProductName());
+
+    if (FL_KICKSTART_SEND_MAC(flags)) {
+        /* find all ethernet devices and make a header entry for each one */
+        int i;
+        char *dev, *mac;
+        struct device **devices;
+
+        devices = getDevices(DEVICE_NETWORK);
+        for (i = 0; devices && devices[i]; i++) {
+            dev = devices[i]->device;
+            mac = iface_mac2str(dev);
+
+            if (mac) {
+                extraHeaders = realloc(extraHeaders, (len+1)*sizeof(char *));
+                checked_asprintf(&extraHeaders[len], "X-RHN-Provisioning-MAC-%d: %s %s",
+                                 i, dev, mac);
+
+                len++;
+                free(mac);
+            }
+        }
+    }
+
+    if (FL_KICKSTART_SEND_SERIAL(flags) && !access("/sbin/dmidecode", X_OK)) {
+        FILE *f;
+        char sn[1024];
+        size_t sn_len;
+
+        if ((f = popen("/sbin/dmidecode -s system-serial-number", "r")) == NULL) {
+            logMessage(CRITICAL, "%s: %d: %m", __func__, __LINE__);
+            abort();
+        }
+
+        sn_len = fread(sn, sizeof(char), 1023, f);
+        if (ferror(f)) {
+            logMessage(CRITICAL, "%s: %d: %m", __func__, __LINE__);
+            abort();
+        }
+
+        sn[sn_len] = '\0';
+        pclose(f);
+
+        extraHeaders = realloc(extraHeaders, (len+1)*sizeof(char *));
+
+        checked_asprintf(&extraHeaders[len], "X-System-Serial-Number: %s", sn);
+
+        len++;
+    }
+
+    extraHeaders = realloc(extraHeaders, (len+1)*sizeof(char *));
+    extraHeaders[len] = NULL;
+    return extraHeaders;
+}
+
+static int loadSingleUrlImage(struct loaderData_s *loaderData, struct iurlinfo *ui,
+                              char *dest, char *mntpoint, char *device, int silentErrors) {
+    char **ehdrs = NULL;
+    int status;
+
+    if (!strncmp(ui->url, "http", 4))
+        ehdrs = headers();
+
+    status = urlinstTransfer(loaderData, ui, ehdrs, dest);
+    if (status) {
+        if (!silentErrors) {
+            newtWinMessage(_("Error"), _("OK"),
+                           _("Unable to retrieve %s."), ui->url);
+        }
+
+        return 2;
+    }
+
+    if (dest != NULL) {
+        if (mountLoopback(dest, mntpoint, device)) {
+            logMessage(ERROR, "Error mounting %s on %s: %m", device, mntpoint);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static void copyWarnFn (char *msg) {
+   logMessage(WARNING, msg);
+}
+
+static void copyErrorFn (char *msg) {
+   newtWinMessage(_("Error"), _("OK"), _(msg));
+}
+
+static int loadUrlImages(struct loaderData_s *loaderData, struct iurlinfo *ui) {
+    char *oldUrl, *path, *dest, *slash;
+    int rc;
+
+    oldUrl = strdup(ui->url);
+    free(ui->url);
+
+    /* Figure out the path where updates.img and product.img files are
+     * kept.  Since ui->url points to a stage2 image file, we just need
+     * to trim off the file name and look in the same directory.
+     */
+    if ((slash = strrchr(oldUrl, '/')) == NULL)
+        return 0;
+
+    if ((path = strndup(oldUrl, slash-oldUrl)) == NULL)
+        path = oldUrl;
+
+    /* grab the updates.img before install.img so that we minimize our
+     * ramdisk usage */
+    checked_asprintf(&ui->url, "%s/%s", path, "updates.img");
+
+    if (!loadSingleUrlImage(loaderData, ui, "/tmp/updates-disk.img", "/tmp/update-disk",
+                            "/dev/loop7", 1)) {
+        copyDirectory("/tmp/update-disk", "/tmp/updates", copyWarnFn,
+                      copyErrorFn);
+        umountLoopback("/tmp/update-disk", "/dev/loop7");
+        unlink("/tmp/updates-disk.img");
+        unlink("/tmp/update-disk");
+    } else if (!access("/tmp/updates-disk.img", R_OK)) {
+        unpackCpioBall("/tmp/updates-disk.img", "/tmp/updates");
+        unlink("/tmp/updates-disk.img");
+    }
+
+    free(ui->url);
+
+    /* grab the product.img before install.img so that we minimize our
+     * ramdisk usage */
+    checked_asprintf(&ui->url, "%s/%s", path, "product.img");
+
+    if (!loadSingleUrlImage(loaderData, ui, "/tmp/product-disk.img", "/tmp/product-disk",
+                            "/dev/loop7", 1)) {
+        copyDirectory("/tmp/product-disk", "/tmp/product", copyWarnFn,
+                      copyErrorFn);
+        umountLoopback("/tmp/product-disk", "/dev/loop7");
+        unlink("/tmp/product-disk.img");
+        unlink("/tmp/product-disk");
+    }
+
+    free(ui->url);
+    ui->url = strdup(oldUrl);
+
+    checked_asprintf(&dest, "/tmp/install.img");
+
+    rc = loadSingleUrlImage(loaderData, ui, dest, "/mnt/runtime", "/dev/loop0", 0);
+    free(dest);
+    free(oldUrl);
+
+    if (rc) {
+        if (rc != 2) 
+            newtWinMessage(_("Error"), _("OK"),
+                           _("Unable to retrieve the install image."));
+        return 1;
+    }
+
+    return 0;
+}
+
+char *mountUrlImage(struct installMethod *method, char *location,
+                    struct loaderData_s *loaderData) {
+    urlInstallData *stage2Data = (urlInstallData *) loaderData->stage2Data;
+    struct iurlinfo ui;
+
+    enum { URL_STAGE_MAIN, URL_STAGE_FETCH,
+           URL_STAGE_DONE } stage = URL_STAGE_MAIN;
+
+    memset(&ui, 0, sizeof(ui));
+
+    while (stage != URL_STAGE_DONE) {
+        switch(stage) {
+            case URL_STAGE_MAIN: {
+                /* If the stage2= parameter was given (or inferred from repo=)
+                 * then use that configuration info to fetch the image.  This
+                 * could also have come from kickstart.  Else, we need to show
+                 * the UI.
+                 */
+                if (loaderData->method == METHOD_URL && stage2Data) {
+                    ui.url = strdup(stage2Data->url);
+                    logMessage(INFO, "URL_STAGE_MAIN: url is %s", ui.url);
+
+                    if (!ui.url) {
+                        logMessage(ERROR, "missing URL specification");
+                        loaderData->method = -1;
+                        free(loaderData->stage2Data);
+                        loaderData->stage2Data = NULL;
+
+                        if (loaderData->inferredStage2)
+                            loaderData->invalidRepoParam = 1;
+
+                        break;
+                    }
+
+                    /* ks info was adequate, lets skip to fetching image */
+                    stage = URL_STAGE_FETCH;
+                    break;
+                } else {
+                    char *substr;
+
+                    if (urlMainSetupPanel(loaderData, &ui)) {
+                        loaderData->stage2Data = NULL;
+                        return NULL;
+                    }
+
+                    /* If the user-provided URL points at a repo instead of
+                     * a stage2 image, fix it up now.
+                     */
+                    substr = strstr(ui.url, ".img");
+                    if (!substr || (substr && *(substr+4) != '\0')) {
+                        loaderData->instRepo = strdup(ui.url);
+
+                        checked_asprintf(&ui.url, "%s/images/install.img",
+                                         ui.url);
+                    }
+
+                    loaderData->invalidRepoParam = 1;
+                }
+
+                stage = URL_STAGE_FETCH;
+                break;
+            }
+
+            case URL_STAGE_FETCH: {
+                if (loadUrlImages(loaderData, &ui)) {
+                    stage = URL_STAGE_MAIN;
+
+                    if (loaderData->method >= 0)
+                        loaderData->method = -1;
+
+                    if (loaderData->inferredStage2)
+                        loaderData->invalidRepoParam = 1;
+                } else {
+                    stage = URL_STAGE_DONE;
+                }
+
+                break;
+            }
+
+            case URL_STAGE_DONE:
+                break;
+        }
+    }
+
+    return ui.url;
+}
+
+int getFileFromUrl(char * url, char * dest, 
+                   struct loaderData_s * loaderData) {
+    struct iurlinfo ui;
+    char **ehdrs = NULL;
+    int rc;
+    iface_t iface;
+
+    iface_init_iface_t(&iface);
+
+    if (kickstartNetworkUp(loaderData, &iface)) {
+        logMessage(ERROR, "unable to bring up network");
+        return 1;
+    }
+
+    memset(&ui, 0, sizeof(ui));
+    ui.url = url;
+
+    logMessage(INFO, "file location: %s", url);
+
+    if (!strncmp(url, "http", 4)) {
+        ehdrs = headers();
+    }
+
+    rc = urlinstTransfer(loaderData, &ui, ehdrs, dest);
+    if (rc) {
+        logMessage(ERROR, "failed to retrieve %s", ui.url);
+        return 1;
+    }
+
+    return 0;
+}
+
+/* pull kickstart configuration file via http */
+int kickstartFromUrl(char * url, struct loaderData_s * loaderData) {
+    return getFileFromUrl(url, "/tmp/ks.cfg", loaderData);
+}
+
+void setKickstartUrl(struct loaderData_s * loaderData, int argc,
+		    char ** argv) {
+    char *substr = NULL;
+    gchar *url = NULL, *proxy = NULL;
+    GOptionContext *optCon = g_option_context_new(NULL);
+    GError *optErr = NULL;
+    GOptionEntry ksUrlOptions[] = {
+        { "url", 0, 0, G_OPTION_ARG_STRING, &url, NULL, NULL },
+        { "proxy", 0, 0, G_OPTION_ARG_STRING, &proxy, NULL, NULL },
+        { NULL },
+    };
+
+    logMessage(INFO, "kickstartFromUrl");
+
+    g_option_context_set_help_enabled(optCon, FALSE);
+    g_option_context_add_main_entries(optCon, ksUrlOptions, NULL);
+
+    if (!g_option_context_parse(optCon, &argc, &argv, &optErr)) {
+        startNewt();
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("Bad argument to URL kickstart method "
+                         "command: %s"), optErr->message);
+        g_error_free(optErr);
+        g_option_context_free(optCon);
+        return;
+    }
+
+    g_option_context_free(optCon);
+
+    if (!url) {
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("Must supply a --url argument to Url kickstart method."));
+        return;
+    }
+
+    /* determine install type */
+    if (strncmp(url, "http", 4) && strncmp(url, "ftp://";, 6)) {
+        newtWinMessage(_("Kickstart Error"), _("OK"),
+                       _("Unknown Url method %s"), url);
+        return;
+    }
+
+    substr = strstr(url, ".img");
+    if (!substr || (substr && *(substr+4) != '\0')) {
+        loaderData->instRepo = strdup(url);
+    } else {
+        if ((loaderData->stage2Data = calloc(sizeof(urlInstallData *), 1)) == NULL)
+            return;
+
+        ((urlInstallData *)loaderData->stage2Data)->url = url;
+        loaderData->method = METHOD_URL;
+    }
+
+    if (proxy) {
+        splitProxyParam(proxy, &loaderData->proxyUser,
+			       &loaderData->proxyPassword,
+			       &loaderData->proxy);
+    }
+    logMessage(INFO, "results of url ks, url %s", url);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4: */
diff --git a/bin/loader/urlinstall.h b/bin/loader/urlinstall.h
new file mode 100644
index 0000000..710b0ae
--- /dev/null
+++ b/bin/loader/urlinstall.h
@@ -0,0 +1,36 @@
+/*
+ * urlinstall.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef URLINSTALL_H
+#define URLINSTALL_H
+
+#include "method.h"
+#include "urls.h"
+
+typedef struct iurlinfo urlInstallData;
+
+void setKickstartUrl(struct loaderData_s * loaderData, int argc,
+		     char ** argv);
+int kickstartFromUrl(char * url, struct loaderData_s * loaderData);
+char * mountUrlImage(struct installMethod * method,
+                     char * location, struct loaderData_s * loaderData);
+int getFileFromUrl(char * url, char * dest, struct loaderData_s * loaderData);
+
+
+#endif
diff --git a/bin/loader/urls.c b/bin/loader/urls.c
new file mode 100644
index 0000000..c0a9f53
--- /dev/null
+++ b/bin/loader/urls.c
@@ -0,0 +1,371 @@
+/*
+ * urls.c - url handling code
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2009  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ *            Chris Lumens <clumens redhat com>
+ */
+
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <newt.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <errno.h>
+#include <curl/curl.h>
+
+#include "../isys/log.h"
+
+#include "lang.h"
+#include "loader.h"
+#include "loadermisc.h"
+#include "urls.h"
+#include "windows.h"
+#include "net.h"
+
+#define NMATCH 10
+
+/* boot flags */
+extern uint64_t flags;
+
+/* This is just a wrapper around the windows.c progress callback that accepts
+ * the arguments libcurl provides.
+ */
+int progress_cb(void *data, double dltotal, double dlnow, double ultotal, double ulnow) {
+    struct progressCBdata *cb_data = (struct progressCBdata *) data;
+
+    progressCallback(cb_data, dlnow, dltotal);
+    return 0;
+}
+
+int splitProxyParam(char *param, char **user, char **password, char **proxy) {
+    /* proxy=[protocol://][username[:password] ]host[:port] */
+    char *pattern = "([[:alpha:]]+://)?(([[:alnum:]]+)(:[^:@]+)?@)?([^:]+)(:[[:digit:]]+)?(/.*)?";
+    regex_t re;
+    regmatch_t pmatch[NMATCH];
+
+    if (regcomp(&re, pattern, REG_EXTENDED)) {
+        return 0;
+    }
+
+    if (regexec(&re, param, NMATCH, pmatch, 0) == REG_NOMATCH) {
+        regfree(&re);
+        return 0;
+    }
+
+    /* Match 0 is always the whole string (assuming regexec matched anything)
+     * so skip it.  Then, these indices are just the number of the starting
+     * paren in pattern above.  Make sure to change these whenever changing
+     * the pattern.
+     */
+    if (pmatch[3].rm_so != -1)
+        *user = strndup(param+pmatch[3].rm_so, pmatch[3].rm_eo-pmatch[3].rm_so);
+
+    /* Skip the leading colon. */
+    if (pmatch[4].rm_so != -1)
+        *password = strndup(param+pmatch[4].rm_so+1, pmatch[4].rm_eo-pmatch[4].rm_so-1);
+
+    if (pmatch[5].rm_so != -1) {
+        char *portStr = "";
+
+        if (pmatch[6].rm_so != -1)
+            portStr = strndup(param+pmatch[6].rm_so, pmatch[6].rm_eo-pmatch[6].rm_so);
+
+        /* If no parameter was given, default to HTTP.  yum will want to know
+         * the protocol, and curl will just ignore it if given.
+         */
+        if (pmatch[1].rm_so != -1) {
+            checked_asprintf(proxy, "%.*s%.*s%s", pmatch[1].rm_eo-pmatch[1].rm_so,
+                                                  param+pmatch[1].rm_so,
+                                                  pmatch[5].rm_eo-pmatch[5].rm_so,
+                                                  param+pmatch[5].rm_so,
+                                                  portStr);
+        } else {
+            checked_asprintf(proxy, "http://%.*s%s";, pmatch[5].rm_eo-pmatch[5].rm_so,
+                                                     param+pmatch[5].rm_so,
+                                                     portStr);
+        }
+    }
+
+    regfree(&re);
+    return 1;
+}
+
+int urlinstTransfer(struct loaderData_s *loaderData, struct iurlinfo *ui,
+                    char **extraHeaders, char *dest) {
+    struct progressCBdata *cb_data;
+    CURL *curl = NULL;
+    CURLcode status;
+    struct curl_slist *headers = NULL;
+    char *version;
+    FILE *f = NULL;
+
+    logMessage(INFO, "transferring %s", ui->url);
+
+    f = fopen(dest, "w");
+
+    /* Initialize libcurl */
+    curl_global_init(CURL_GLOBAL_SSL);
+    curl = curl_easy_init();
+
+    checked_asprintf(&version, "anaconda/%s", VERSION);
+
+    curl_easy_setopt(curl, CURLOPT_USERAGENT, version);
+    curl_easy_setopt(curl, CURLOPT_URL, ui->url);
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, f);
+    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
+    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10);
+    curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
+
+    /* If a proxy was provided, add the options for that now. */
+    if (loaderData->proxy && strcmp(loaderData->proxy, "")) {
+        curl_easy_setopt(curl, CURLOPT_PROXY, loaderData->proxy);
+
+        if (loaderData->proxyUser && strcmp(loaderData->proxyUser, ""))
+            curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME,
+                             loaderData->proxyUser);
+
+        if (loaderData->proxyPassword && strcmp(loaderData->proxyPassword, ""))
+            curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD,
+                             loaderData->proxyPassword);
+    }
+
+    if (extraHeaders) {
+        int i;
+        for (i = 0; extraHeaders[i] != NULL; i++) {
+            headers = curl_slist_append(headers, extraHeaders[i]);
+        }
+
+        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
+    }
+
+    /* Only set up the progress bar if we've got a UI to display it. */
+    if (FL_CMDLINE(flags)) {
+        printf("%s %s...\n", _("Retrieving"), ui->url);
+    } else {
+        char *filename;
+
+        filename = strrchr(ui->url, '/');
+        if (!filename)
+           filename = ui->url;
+
+        cb_data = winProgressBar(70, 5, _("Retrieving"), "%s %s...", _("Retrieving"), filename);
+
+        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
+        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_cb);
+        curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, cb_data);
+    }
+
+    /* Finally, do the transfer. */
+    status = curl_easy_perform(curl);
+    if (status)
+        logMessage(ERROR, "Error downloading %s: %s", ui->url, curl_easy_strerror(status));
+
+    if (!FL_CMDLINE(flags))
+       newtPopWindow();
+
+    if (headers)
+        curl_slist_free_all(headers);
+
+    fclose(f);
+    free(version);
+
+    curl_easy_cleanup(curl);
+    curl_global_cleanup();
+
+    return status;
+}
+
+char * addrToIp(char * hostname) {
+    struct in_addr ad;
+    struct in6_addr ad6;
+    char *ret;
+    struct hostent *host;
+
+    if ((ret = malloc(INET6_ADDRSTRLEN+1)) == NULL)
+        return hostname;
+
+    if (inet_ntop(AF_INET, &ad, ret, INET_ADDRSTRLEN) != NULL)
+        return ret;
+    else if (inet_ntop(AF_INET6, &ad6, ret, INET6_ADDRSTRLEN) != NULL)
+        return ret;
+    else if ((host = gethostbyname(hostname)) != NULL)
+        return host->h_name;
+    else
+        return NULL;
+}
+
+static void setProxySensitivity(newtComponent co, void *dptr) {
+    int i;
+
+    /* It's 3 because there are three entry boxes in the proxy grid.  Lame. */
+    for (i = 0; i < 3; i++) {
+        newtEntrySetFlags(*((newtComponent *) dptr), NEWT_FLAG_DISABLED,
+                          NEWT_FLAGS_TOGGLE);
+        dptr += sizeof(newtComponent);
+    }
+
+    return;
+}
+
+int urlMainSetupPanel(struct loaderData_s *loaderData, struct iurlinfo * ui) {
+    newtComponent form, okay, cancel, urlEntry, proxyCheckbox;
+    newtComponent proxyEntries[3];
+    newtComponent answer, text;
+    char enableProxy;
+    char *url = "", *proxy = "", *proxyUser = "", *proxyPassword = "";
+    char * reflowedText = NULL;
+    int width, height;
+    newtGrid buttons, grid, proxyGrid;
+    char * buf = NULL;
+
+    /* Populate the UI with whatever initial value we've got. */
+    if (ui && ui->url)
+        url = ui->url;
+
+    if (loaderData->proxy)
+        proxy = loaderData->proxy;
+
+    if (loaderData->proxyUser)
+        proxyUser = loaderData->proxyUser;
+
+    if (loaderData->proxyPassword)
+        proxyPassword = loaderData->proxyPassword;
+
+    buttons = newtButtonBar(_("OK"), &okay, _("Back"), &cancel, NULL);
+
+    checked_asprintf(&buf,
+                     _("Please enter the URL containing the %s installation image on your server."),
+                     getProductName());
+
+    reflowedText = newtReflowText(buf, 47, 5, 5, &width, &height);
+    free(buf);
+
+    text = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP);
+    newtTextboxSetText(text, reflowedText);
+    free(reflowedText);
+
+    urlEntry = newtEntry(22, 8, url, 60, (const char **) &url,
+                         NEWT_ENTRY_SCROLL);
+
+    /* If we've been provided with proxy settings already, enable the proxy
+     * grid.  This will make sure all the fields get filled in, too.
+     */
+    enableProxy = loaderData->proxy != NULL && strcmp("", loaderData->proxy) ? '*' : ' ';
+
+    proxyCheckbox = newtCheckbox(-1, -1, _("Enable HTTP proxy"), enableProxy,
+                                 NULL, &enableProxy);
+    newtComponentAddCallback(proxyCheckbox, setProxySensitivity, &proxyEntries);
+
+    proxyEntries[0] = newtEntry(-1, -1, proxy, 35, (const char **) &proxy, NEWT_FLAG_SCROLL);
+    proxyEntries[1] = newtEntry(-1, -1, proxyUser, 15, (const char **) &proxyUser, NEWT_FLAG_SCROLL);
+    proxyEntries[2] = newtEntry(-1, -1, proxyPassword, 15, (const char **) &proxyPassword, NEWT_FLAG_SCROLL|NEWT_FLAG_PASSWORD);
+
+    /* Set the initial proxy grid sensitivity to match. */
+    if (enableProxy == ' ')
+        setProxySensitivity(proxyCheckbox, proxyEntries);
+
+    proxyGrid = newtCreateGrid(2, 3);
+    newtGridSetField(proxyGrid, 0, 0, NEWT_GRID_COMPONENT,
+                     newtLabel(-1, -1, _("Proxy URL")),
+                     0, 0, 0, 0, 0, NEWT_ANCHOR_LEFT);
+    newtGridSetField(proxyGrid, 1, 0, NEWT_GRID_COMPONENT, proxyEntries[0],
+                     0, 0, 0, 0, 0, NEWT_ANCHOR_LEFT);
+    newtGridSetField(proxyGrid, 0, 1, NEWT_GRID_COMPONENT,
+                     newtLabel(-1, -1, _("Username")),
+                     0, 0, 0, 1, 0, NEWT_ANCHOR_LEFT);
+    newtGridSetField(proxyGrid, 1, 1, NEWT_GRID_COMPONENT, proxyEntries[1],
+                     0, 0, 0, 1, 0, NEWT_ANCHOR_LEFT);
+    newtGridSetField(proxyGrid, 0, 2, NEWT_GRID_COMPONENT,
+                     newtLabel(-1, -1, _("Password")),
+                     0, 0, 0, 1, 0, NEWT_ANCHOR_LEFT);
+    newtGridSetField(proxyGrid, 1, 2, NEWT_GRID_COMPONENT, proxyEntries[2],
+                     0, 0, 0, 1, 0, NEWT_ANCHOR_LEFT);
+
+    grid = newtCreateGrid(1, 5);
+    newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
+                     0, 0, 0, 1, 0, 0);
+    newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, urlEntry,
+                     0, 0, 0, 1, 0, 0);
+    newtGridSetField(grid, 0, 2, NEWT_GRID_COMPONENT, proxyCheckbox,
+                     0, 0, 0, 1, 0, NEWT_ANCHOR_LEFT);
+    newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, proxyGrid,
+                     0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+    newtGridSetField(grid, 0, 4, NEWT_GRID_SUBGRID, buttons,
+                     0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+    form = newtForm(NULL, NULL, 0);
+    newtGridAddComponentsToForm(grid, form, 1); 
+    newtGridWrappedWindow(grid, _("URL Setup"));
+    newtGridFree(grid, 1);
+
+    do {
+        answer = newtRunForm(form);
+        if (answer != cancel) {
+            if (!strlen(url)) {
+                newtWinMessage(_("Error"), _("OK"),
+                               _("You must enter a URL."));
+                continue;
+            }
+
+            if (strncmp(url, "http", 4) && strncmp(url, "ftp://";, 6)) {
+                newtWinMessage(_("Error"), _("OK"),
+                               _("URL must be either an ftp or http URL"));
+                continue;
+            }
+
+            ui->url = strdup(url);
+
+            if (enableProxy == '*') {
+               loaderData->proxy = strdup(proxy);
+               loaderData->proxyUser = strdup(proxyUser);
+               loaderData->proxyPassword = strdup(proxyPassword);
+            } else {
+               loaderData->proxy = "";
+               loaderData->proxyUser = "";
+               loaderData->proxyPassword = "";
+            }
+
+            /* FIXME:  add back in hostname checking */
+        }
+
+        break;
+    } while (1);
+
+    if (answer == cancel) {
+        newtFormDestroy(form);
+        newtPopWindow();
+
+        return LOADER_BACK;
+    }
+
+    newtFormDestroy(form);
+    newtPopWindow();
+
+    return 0;
+}
diff --git a/bin/loader/urls.h b/bin/loader/urls.h
new file mode 100644
index 0000000..4ca538f
--- /dev/null
+++ b/bin/loader/urls.h
@@ -0,0 +1,35 @@
+/*
+ * urls.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef H_LOADER_URLS
+#define H_LOADER_URLS
+
+#include "loader.h"
+#include "windows.h"
+
+struct iurlinfo {
+    char * url;
+};
+
+int splitProxyParam(char *param, char **user, char **password, char **proxy);
+int urlMainSetupPanel(struct loaderData_s *loaderData, struct iurlinfo * ui);
+int urlinstTransfer(struct loaderData_s *loaderData, struct iurlinfo *ui,
+                    char **extraHeaders, char *dest);
+
+#endif
diff --git a/bin/loader/windows.c b/bin/loader/windows.c
new file mode 100644
index 0000000..51b00db
--- /dev/null
+++ b/bin/loader/windows.c
@@ -0,0 +1,121 @@
+/*
+ * windows.c - simple popup windows used by the loader
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt redhat com>
+ *            Matt Wilson <msw redhat com>
+ *            Michael Fulbright <msf redhat com>
+ *            Jeremy Katz <katzj redhat com>
+ */
+
+#include <errno.h>
+#include <newt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <math.h>
+
+#include "../isys/log.h"
+
+#include "windows.h"
+
+void winStatus(int width, int height, char * title, char * text, ...) {
+    newtComponent t, f;
+    char * buf = NULL;
+    va_list args;
+
+    va_start(args, text);
+
+    if (vasprintf(&buf, text, args) != -1) {
+        newtCenteredWindow(width, height, title);
+
+        t = newtTextbox(1, 1, width - 2, height - 2, NEWT_TEXTBOX_WRAP);
+        newtTextboxSetText(t, buf);
+        f = newtForm(NULL, NULL, 0);
+
+        free(buf);
+
+        newtFormAddComponent(f, t);
+
+        newtDrawForm(f);
+        newtRefresh();
+        newtFormDestroy(f);
+    }
+
+    va_end(args);
+}
+
+
+void scsiWindow(const char * driver) {
+    winStatus(40, 3, _("Loading SCSI driver"),
+        _("Loading %s driver"), driver);
+}
+
+int progressCallback(void *pbdata, long long pos, long long total) {
+    struct progressCBdata *data = pbdata;
+    char tickmark[2] = "-";
+    char *ticks = "-\\|/";
+    int x = ceil(pos * 100.0 / total);
+
+    newtScaleSet(data->scale, x);
+    *tickmark = ticks[x % 4];
+
+    newtLabelSetText(data->label, tickmark);
+    newtRefresh();
+    return 0;
+}
+
+struct progressCBdata *winProgressBar(int width, int height, char *title, char *text, ...) {
+    struct progressCBdata *data;
+    char *buf = NULL;
+    va_list args;
+    int llen;
+    newtComponent t, f, scale, label;
+
+    va_start(args, text);
+
+    if (vasprintf(&buf, text, args) != -1) {
+        va_end(args);
+        newtCenteredWindow(width, height, title);
+        t = newtTextbox(1, 1, width - 2, height - 2, NEWT_TEXTBOX_WRAP);
+        newtTextboxSetText(t, buf);
+        llen = strlen(buf);
+        free(buf);
+        label = newtLabel(llen + 1, 1, "-");
+        f = newtForm(NULL, NULL, 0);
+        newtFormAddComponent(f, t);
+        scale = newtScale(3, 3, width - 6, 100);
+        newtFormAddComponent(f, scale);
+        newtDrawForm(f);
+        newtRefresh();
+
+        if ((data = malloc(sizeof(struct progressCBdata))) == NULL) {
+            logMessage(ERROR, "%s: %d: %m", __func__, __LINE__);
+            abort();
+        }
+
+        data->scale = scale;
+        data->label = label;
+        return data;
+    }
+
+    return NULL;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4: */
diff --git a/bin/loader/windows.h b/bin/loader/windows.h
new file mode 100644
index 0000000..a1646d4
--- /dev/null
+++ b/bin/loader/windows.h
@@ -0,0 +1,43 @@
+/*
+ * windows.h
+ *
+ * Copyright (C) 2007  Red Hat, Inc.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _WINDOWS_H_
+#define _WINDOWS_H_
+
+#include <newt.h>
+
+#include "lang.h"
+
+void winStatus(int width, int height, char * title, char * text, ...);
+void scsiWindow(const char * driver);
+
+#define errorWindow(String) \
+	newtWinMessage(_("Error"), _("OK"), String, strerror (errno));
+
+typedef void (*progressCB) (void *pbdata, long long offset, long long total);
+
+struct progressCBdata {
+    newtComponent scale;
+    newtComponent label;
+};
+
+int progressCallback(void *pbdata, long long pos, long long total);
+struct progressCBdata *winProgressBar(int width, int height, char *title, char *text, ...);
+
+#endif /* _WINDOWS_H_ */
diff --git a/bootdisk/Makefile.am b/bootdisk/Makefile.am
deleted file mode 100644
index e6ba4bd..0000000
--- a/bootdisk/Makefile.am
+++ /dev/null
@@ -1,22 +0,0 @@
-# bootdisk/Makefile.am for anaconda
-#
-# 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 Lesser General Public License as published
-# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: David Cantrell <dcantrell redhat com>
-
-SUBDIRS = i386 ppc sparc s390x x86_64
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/bootdisk/i386/Makefile.am b/bootdisk/i386/Makefile.am
deleted file mode 100644
index 030b8d5..0000000
--- a/bootdisk/i386/Makefile.am
+++ /dev/null
@@ -1,25 +0,0 @@
-# bootdisk/i386/Makefile.am for anaconda
-#
-# 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 Lesser General Public License as published
-# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: David Cantrell <dcantrell redhat com>
-
-if IS_I386
-bootdir        = $(datadir)/$(PACKAGE_NAME)/boot
-dist_boot_DATA = boot.msg grub.conf syslinux.cfg
-endif
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/bootdisk/i386/boot.msg b/bootdisk/i386/boot.msg
deleted file mode 100644
index ff54899..0000000
--- a/bootdisk/i386/boot.msg
+++ /dev/null
@@ -1,5 +0,0 @@
- 
-splash.lss
-
- -  Press the 01<ENTER>07 key to begin the installation process.
-
diff --git a/bootdisk/i386/grub.conf b/bootdisk/i386/grub.conf
deleted file mode 100644
index 6e94d05..0000000
--- a/bootdisk/i386/grub.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-#debug --graphics
-default=0
-splashimage= SPLASHPATH@
-timeout 5
-hiddenmenu
-title @PRODUCT@ @VERSION@
-	kernel @KERNELPATH@
-	initrd @INITRDPATH@
diff --git a/bootdisk/i386/syslinux.cfg b/bootdisk/i386/syslinux.cfg
deleted file mode 100644
index 06a0842..0000000
--- a/bootdisk/i386/syslinux.cfg
+++ /dev/null
@@ -1,33 +0,0 @@
-default linux
-prompt 1
-timeout 600
-
-display boot.msg
-
-menu background splash.jpg
-menu title Welcome to @PRODUCT@ @VERSION !
-menu color border 0 #ffffffff #00000000
-menu color sel 7 #ffffffff #ff000000
-menu color title 0 #ffffffff #00000000
-menu color tabmsg 0 #ffffffff #00000000
-menu color unsel 0 #ffffffff #00000000
-menu color hotsel 0 #ff000000 #ffffffff
-menu color hotkey 7 #ffffffff #ff000000
-menu color scrollbar 0 #ffffffff #00000000
-
-label linux
-  menu label ^Install a new system or upgrade an existing system
-  menu default
-  kernel vmlinuz
-  append initrd=initrd.img
-label vesa
-  menu label Install system with ^basic video driver
-  kernel vmlinuz
-  append initrd=initrd.img xdriver=vesa nomodeset
-label rescue
-  menu label ^Rescue installed system
-  kernel vmlinuz
-  append initrd=initrd.img rescue
-label local
-  menu label Boot from ^local drive
-  localboot 0xffff
diff --git a/bootdisk/ppc/Makefile.am b/bootdisk/ppc/Makefile.am
deleted file mode 100644
index 4f6e298..0000000
--- a/bootdisk/ppc/Makefile.am
+++ /dev/null
@@ -1,26 +0,0 @@
-# bootdisk/ppc/Makefile.am for anaconda
-#
-# 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 Lesser General Public License as published
-# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: David Cantrell <dcantrell redhat com>
-
-if IS_PPC
-bootdir        = $(datadir)/$(PACKAGE_NAME)/boot
-dist_boot_DATA = magic ofboot.b yaboot.conf.in bootinfo.txt mapping \
-                 yaboot.conf.3264
-endif
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/bootdisk/ppc/bootinfo.txt b/bootdisk/ppc/bootinfo.txt
deleted file mode 100644
index ac766d4..0000000
--- a/bootdisk/ppc/bootinfo.txt
+++ /dev/null
@@ -1,169 +0,0 @@
-<chrp-boot> <description>Linux</description> 
-<os-name>Linux</os-name> 
-<boot-script>boot &device;:\ppc\chrp\yaboot</boot-script> 
-<icon size=64,64 color-space=3,3,2> 
-<bitmap> FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
-FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 </bitmap> </icon> </chrp-boot>
diff --git a/bootdisk/ppc/magic b/bootdisk/ppc/magic
deleted file mode 100644
index 387727c..0000000
--- a/bootdisk/ppc/magic
+++ /dev/null
@@ -1,81 +0,0 @@
-#
-# Example magic file for mkhybrid
-#
-# The "message" for the offset MUST be 4 characters for the CREATOR
-# and 4 characters for the TYPE - white space is optional between them.
-# Any other characters on this line are ignored. Continuation lines (starting
-# with '>') are also ignored i.e. only the initial offset lines are used.
-#
-# The continuation lines are given here, but they do not need to exist.
-
-#
-# James Pearson 20/5/98
-
-# off	type		test		message
-
-# GIF
-0	string		GIF8		8BIM GIFf
->4	string		7a		\b, version 8%s,
->4	string		9a		\b, version 8%s,
->6	leshort		>0		%hd x
->8	leshort		>0		%hd,
-#>10	byte		&0x80		color mapped,
-#>10	byte&0x07	=0x00		2 colors
-#>10	byte&0x07	=0x01		4 colors
-#>10	byte&0x07	=0x02		8 colors
-#>10	byte&0x07	=0x03		16 colors
-#>10	byte&0x07	=0x04		32 colors
-#>10	byte&0x07	=0x05		64 colors
-#>10	byte&0x07	=0x06		128 colors
-#>10	byte&0x07	=0x07		256 colors
-
-# JPEG images
-#
-0	ubeshort		0xffd8		8BIM JPEG  image data
-
-# StuffIt
-#
-0	string		SIT!		SIT!SIT!
-
-# standard unix compress
-0	string		\037\235	LZIV ZIVU
->2	byte&0x80	>0		block compressed
->2	byte&0x1f	x		%d bits
-
-# gzip (GNU zip, not to be confused with Info-ZIP or PKWARE zip archiver)
-0       string          \037\213        GNUz ZIVU gzip compressed data
->2      byte            <8              \b, reserved method,
->2      byte            8               \b, deflated,
->3	byte		&0x01		ASCII,
->3	byte		&0x02		continuation,
->3	byte		&0x04		extra field,
->3	byte		&0x08		original filename,
->3	byte		&0x10		comment,
->3	byte		&0x20		encrypted,
->4	ledate		x		last modified: %s,
->8	byte		2		max compression,
->8	byte		4		max speed,
->9	byte		=0x00		os: MS-DOS
->9	byte		=0x01		os: Amiga
->9	byte		=0x02		os: VMS
->9	byte		=0x03		os: Unix
->9	byte		=0x05		os: Atari
->9	byte		=0x06		os: OS/2
->9	byte		=0x07		os: MacOS
->9	byte		=0x0A		os: Tops/20
->9	byte		=0x0B		os: Win/32
-
-# Postscript
-0	string		%!		ASPSTEXT
->2	string		PS-Adobe-	conforming
->>11	string		>\0		at level %.3s
->>>15	string		EPS		- type %s
->>>15	string		Query		- type %s
->>>15	string		ExitServer	- type %s
-# Some PCs have the annoying habit of adding a ^D as a document separator
-0	string		\004%!		ASPS TEXT PostScript document text
->3	string		PS-Adobe-	conforming
->>12	string		>\0		at level %.3s
->>>16	string		EPS		- type %s
->>>16	string		Query		- type %s
->>>16	string		ExitServer	- type %s
diff --git a/bootdisk/ppc/mapping b/bootdisk/ppc/mapping
deleted file mode 100644
index cf83076..0000000
--- a/bootdisk/ppc/mapping
+++ /dev/null
@@ -1,27 +0,0 @@
-# Example filename mapping file
-#
-# yaboot		Raw	'UNIX'	'boot'	"Bootstrap"
-# vmlinux		Raw	'UNIX'	'boot'	"Bootstrap"
-#
-# EXTN          XLate   CREATOR   TYPE     Comment
-COPYING         Ascii   'ttxt'  'ttro'  "Text File"
-CREDITS         Ascii   'ttxt'  'ttro'  "Text File"
-README          Ascii   'ttxt'  'ttro'  "Text File"
-RPM-GPG-KEY     Ascii   'ttxt'  'ttro'  "Text File"
-RELEASE_NOTES   Ascii   'ttxt'  'ttro'  "Text File"
-.b              Raw     'chrp'  'tbxi'  "Macintosh Toolbox ROM file"
-.gif            Raw     '8BIM'  'GIFf'  "Gif File"
-.jpg            Raw     '8BIM'  'JPEG'  "Jpeg File"
-.tif            Raw     '8BIM'  'TIFF'  "Photoshop TIFF image"
-.hqx            Ascii   'BnHq'  'TEXT'  "BinHex file"
-.doc            Raw     'MSWD'  'WDBN'  "Word file"
-.mov            Raw     'TVOD'  'MooV'  "QuickTime Movie"
-.html           Ascii   'MOSS'  'TEXT'  "HTML File"
-.htm            Ascii   'MOSS'  'TEXT'  "HTML File"
-.conf           Ascii   'ttxt'  'TEXT'  "config file"
-.txt            Ascii   'ttxt'  'TEXT'  "Text File"
-.tbxi           Raw     'chrp'  'tbxi'  "Macintosh Toolbox ROM file"
-.sea            Raw     'aust'  'APPL'  "Self Expanding Archive"
-.sit            Raw     'SIT!'  'SITD'  "Stuffit Expander file"
-*               Raw     '????'  '????'  "Unknown"
-
diff --git a/bootdisk/ppc/ofboot.b b/bootdisk/ppc/ofboot.b
deleted file mode 100644
index c811894..0000000
--- a/bootdisk/ppc/ofboot.b
+++ /dev/null
@@ -1,74 +0,0 @@
-<CHRP-BOOT>
-<COMPATIBLE>
-MacRISC MacRISC3 MacRISC4
-</COMPATIBLE>
-
-<DESCRIPTION>
-Boot Chooser
-</DESCRIPTION>
-
-<BOOT-SCRIPT>
-" screen" output
-load-base release-load-area
-" /cpus/@0" find-package if
- " 64-bit" rot get-package-property 0= if
-  2drop
-  " boot cd:,\ppc\mac\yaboot conf=cd:,\ppc\ppc64\yaboot.conf" eval
- else
-  " boot cd:,\ppc\mac\yaboot conf=cd:,\ppc\ppc32\yaboot.conf" eval
- then
-then
-</BOOT-SCRIPT>
-
-<OS-BADGE-ICONS>
-1010
-000000000000F8FEACF6000000000000
-0000000000F5FFFFFEFEF50000000000
-00000000002BFAFEFAFCF70000000000
-0000000000F65D5857812B0000000000
-0000000000F5350B2F88560000000000
-0000000000F6335708F8FE0000000000
-00000000005600F600F5FD8100000000
-00000000F9F8000000F5FAFFF8000000
-000000008100F5F50000F6FEFE000000
-000000F8F700F500F50000FCFFF70000
-00000088F70000F50000F5FCFF2B0000
-0000002F582A00F5000008ADE02C0000
-00090B0A35A62B0000002D3B350A0000
-000A0A0B0B3BF60000505E0B0A0B0A00
-002E350B0B2F87FAFCF45F0B2E090000
-00000007335FF82BF72B575907000000
-000000000000ACFFFF81000000000000
-000000000081FFFFFFFF810000000000
-0000000000FBFFFFFFFFAC0000000000
-000000000081DFDFDFFFFB0000000000
-000000000081DD5F83FFFD0000000000
-000000000081DDDF5EACFF0000000000
-0000000000FDF981F981FFFF00000000
-00000000FFACF9F9F981FFFFAC000000
-00000000FFF98181F9F981FFFF000000
-000000ACACF981F981F9F9FFFFAC0000
-000000FFACF9F981F9F981FFFFFB0000
-00000083DFFBF981F9F95EFFFFFC0000
-005F5F5FDDFFFBF9F9F983DDDD5F0000
-005F5F5F5FDD81F9F9E7DF5F5F5F5F00
-0083DD5F5F83FFFFFFFFDF5F835F0000
-000000FBDDDFACFBACFBDFDFFB000000
-000000000000FFFFFFFF000000000000
-0000000000FFFFFFFFFFFF0000000000
-0000000000FFFFFFFFFFFF0000000000
-0000000000FFFFFFFFFFFF0000000000
-0000000000FFFFFFFFFFFF0000000000
-0000000000FFFFFFFFFFFF0000000000
-0000000000FFFFFFFFFFFFFF00000000
-00000000FFFFFFFFFFFFFFFFFF000000
-00000000FFFFFFFFFFFFFFFFFF000000
-000000FFFFFFFFFFFFFFFFFFFFFF0000
-000000FFFFFFFFFFFFFFFFFFFFFF0000
-000000FFFFFFFFFFFFFFFFFFFFFF0000
-00FFFFFFFFFFFFFFFFFFFFFFFFFF0000
-00FFFFFFFFFFFFFFFFFFFFFFFFFFFF00
-00FFFFFFFFFFFFFFFFFFFFFFFFFF0000
-000000FFFFFFFFFFFFFFFFFFFF000000
-</OS-BADGE-ICONS>
-</CHRP-BOOT>
diff --git a/bootdisk/ppc/yaboot.conf.3264 b/bootdisk/ppc/yaboot.conf.3264
deleted file mode 100644
index 8b5af08..0000000
--- a/bootdisk/ppc/yaboot.conf.3264
+++ /dev/null
@@ -1,14 +0,0 @@
-init-message = "\nWelcome to the %PRODUCT% %VERSION% installer!\nUse 'linux32' for 32-bit kernel.\n\n"
-timeout=6000
-default=linux
-
-image=/ppc/ppc64/vmlinuz
-	label=linux64
-	alias=linux
-	initrd=/ppc/ppc64/ramdisk.image.gz
-	read-only
-
-image=/ppc/ppc32/vmlinuz
-	label=linux32
-	initrd=/ppc/ppc32/ramdisk.image.gz
-	read-only
diff --git a/bootdisk/ppc/yaboot.conf.in b/bootdisk/ppc/yaboot.conf.in
deleted file mode 100644
index d06768a..0000000
--- a/bootdisk/ppc/yaboot.conf.in
+++ /dev/null
@@ -1,8 +0,0 @@
-init-message = "\nWelcome to the %BITS%-bit %PRODUCT% %VERSION% installer!\nHit <TAB> for boot options.\n\n"
-timeout=6000
-default=linux
-
-image=/ppc/ppc%BITS%/vmlinuz
-	label=linux
-	initrd=/ppc/ppc%BITS%/ramdisk.image.gz
-	read-only
diff --git a/bootdisk/s390x/Makefile.am b/bootdisk/s390x/Makefile.am
deleted file mode 100644
index c75ccbe..0000000
--- a/bootdisk/s390x/Makefile.am
+++ /dev/null
@@ -1,25 +0,0 @@
-# bootdisk/s390x/Makefile.am for anaconda
-#
-# 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 Lesser General Public License as published
-# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: David Cantrell <dcantrell redhat com>
-
-if IS_S390
-bootdir        = $(datadir)/$(PACKAGE_NAME)/boot
-dist_boot_DATA = generic.ins generic.prm redhat.exec
-endif
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/bootdisk/s390x/generic.ins b/bootdisk/s390x/generic.ins
deleted file mode 100644
index a690f2e..0000000
--- a/bootdisk/s390x/generic.ins
+++ /dev/null
@@ -1,5 +0,0 @@
-* minimal lpar ins file
-images/kernel.img 0x00000000
-images/initrd.img @INITRD_LOAD_ADDRESS@
-images/generic.prm 0x00010480
-images/initrd.addrsize 0x00010408
diff --git a/bootdisk/s390x/generic.prm b/bootdisk/s390x/generic.prm
deleted file mode 100644
index e953ce2..0000000
--- a/bootdisk/s390x/generic.prm
+++ /dev/null
@@ -1 +0,0 @@
-root=/dev/ram0 ro ip=off ramdisk_size=40000 cio_ignore=all,!0.0.0009
diff --git a/bootdisk/s390x/redhat.exec b/bootdisk/s390x/redhat.exec
deleted file mode 100644
index f1e5931..0000000
--- a/bootdisk/s390x/redhat.exec
+++ /dev/null
@@ -1,9 +0,0 @@
-/* */
-'CL RDR'
-'PURGE RDR ALL'
-'SPOOL PUNCH * RDR'
-'PUNCH KERNEL IMG A (NOH'
-'PUNCH GENERIC PRM A (NOH'
-'PUNCH INITRD IMG A (NOH'
-'CH RDR ALL KEEP NOHOLD'
-'I 00C'
diff --git a/bootdisk/sparc/Makefile.am b/bootdisk/sparc/Makefile.am
deleted file mode 100644
index 4d2c3f2..0000000
--- a/bootdisk/sparc/Makefile.am
+++ /dev/null
@@ -1,25 +0,0 @@
-# bootdisk/sparc/Makefile.am for anaconda
-#
-# 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 Lesser General Public License as published
-# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: Dennis Gilmore <dgilmore redhat com>
-
-if IS_SPARC
-bootdir        = $(datadir)/$(PACKAGE_NAME)/boot
-dist_boot_DATA = boot.msg silo.conf
-endif
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/bootdisk/sparc/boot.msg b/bootdisk/sparc/boot.msg
deleted file mode 100644
index b28310e..0000000
--- a/bootdisk/sparc/boot.msg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-                   Welcome to Fedora SPARC Linux!
-
- -  To install or upgrade in graphical mode, press the <ENTER> key.
-
- -  To install or upgrade in text mode, type: linux text <ENTER>.
-
- -  To enter rescue mode] type: linux resuce <ENTER>.
-
diff --git a/bootdisk/sparc/silo.conf b/bootdisk/sparc/silo.conf
deleted file mode 100644
index 285546f..0000000
--- a/bootdisk/sparc/silo.conf
+++ /dev/null
@@ -1,17 +0,0 @@
-partition=1
-default=linux
-read-write
-timeout=100
-message=/boot/boot.msg
-image[sun4u]=/boot/vmlinuz
-        label=linux
-        alias=install
-        initrd=/boot/initrd.img
-image[sun4u]=/boot/vmlinuz
-        label=text
-        append=text
-        initrd=/boot/initrd.img
-image[sun4u]=/boot/vmlinuz
-        label=ks
-        append=ks
-        initrd=/boot/initrd.img
diff --git a/bootdisk/x86_64/Makefile.am b/bootdisk/x86_64/Makefile.am
deleted file mode 100644
index a4012c5..0000000
--- a/bootdisk/x86_64/Makefile.am
+++ /dev/null
@@ -1,25 +0,0 @@
-# bootdisk/x86_64/Makefile.am for anaconda
-#
-# 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 Lesser General Public License as published
-# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: David Cantrell <dcantrell redhat com>
-
-if IS_X86_64
-bootdir        = $(datadir)/$(PACKAGE_NAME)/boot
-dist_boot_DATA = boot.msg grub.conf syslinux.cfg
-endif
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/bootdisk/x86_64/boot.msg b/bootdisk/x86_64/boot.msg
deleted file mode 100644
index ff54899..0000000
--- a/bootdisk/x86_64/boot.msg
+++ /dev/null
@@ -1,5 +0,0 @@
- 
-splash.lss
-
- -  Press the 01<ENTER>07 key to begin the installation process.
-
diff --git a/bootdisk/x86_64/grub.conf b/bootdisk/x86_64/grub.conf
deleted file mode 100644
index 6e94d05..0000000
--- a/bootdisk/x86_64/grub.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-#debug --graphics
-default=0
-splashimage= SPLASHPATH@
-timeout 5
-hiddenmenu
-title @PRODUCT@ @VERSION@
-	kernel @KERNELPATH@
-	initrd @INITRDPATH@
diff --git a/bootdisk/x86_64/syslinux.cfg b/bootdisk/x86_64/syslinux.cfg
deleted file mode 100644
index 06a0842..0000000
--- a/bootdisk/x86_64/syslinux.cfg
+++ /dev/null
@@ -1,33 +0,0 @@
-default linux
-prompt 1
-timeout 600
-
-display boot.msg
-
-menu background splash.jpg
-menu title Welcome to @PRODUCT@ @VERSION !
-menu color border 0 #ffffffff #00000000
-menu color sel 7 #ffffffff #ff000000
-menu color title 0 #ffffffff #00000000
-menu color tabmsg 0 #ffffffff #00000000
-menu color unsel 0 #ffffffff #00000000
-menu color hotsel 0 #ff000000 #ffffffff
-menu color hotkey 7 #ffffffff #ff000000
-menu color scrollbar 0 #ffffffff #00000000
-
-label linux
-  menu label ^Install a new system or upgrade an existing system
-  menu default
-  kernel vmlinuz
-  append initrd=initrd.img
-label vesa
-  menu label Install system with ^basic video driver
-  kernel vmlinuz
-  append initrd=initrd.img xdriver=vesa nomodeset
-label rescue
-  menu label ^Rescue installed system
-  kernel vmlinuz
-  append initrd=initrd.img rescue
-label local
-  menu label Boot from ^local drive
-  localboot 0xffff
diff --git a/bootloader.py b/bootloader.py
deleted file mode 100644
index 30912e7..0000000
--- a/bootloader.py
+++ /dev/null
@@ -1,244 +0,0 @@
-#
-# bootloader.py: anaconda bootloader shims
-#
-# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006  Red Hat, Inc.
-# All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author(s): Erik Troan <ewt redhat com>
-#            Jeremy Katz <katzj redhat com>
-#
-
-import isys
-import parted
-import os, sys
-import iutil
-import string
-from flags import flags
-from constants import *
-from storage.devices import devicePathToName
-from storage import getReleaseString
-from booty.util import getDiskPart
-
-import gettext
-_ = lambda x: gettext.ldgettext("anaconda", x)
-
-import logging
-log = logging.getLogger("anaconda")
-
-import booty
-from booty import bootloaderInfo, checkbootloader
-
-def isEfiSystemPartition(part):
-    if not part.active:
-        return False
-    return (part.disk.type == "gpt" and
-            part.name == "EFI System Partition" and
-            part.getFlag(parted.PARTITION_BOOT) and
-            part.fileSystem.type in ("fat16", "fat32") and
-            isys.readFSLabel(part.getDeviceNodeName()) != "ANACONDA")
-
-def bootloaderSetupChoices(anaconda):
-    if anaconda.dir == DISPATCH_BACK:
-        rc = anaconda.intf.messageWindow(_("Warning"),
-                _("Filesystems have already been activated.  You "
-                  "cannot go back past this point.\n\nWould you like to "
-                  "continue with the installation?"),
-                type="custom", custom_icon=["error","error"],
-                custom_buttons=[_("_Exit installer"), _("_Continue")])
-
-        if rc == 0:
-            sys.exit(0)
-        return DISPATCH_FORWARD
-
-    if anaconda.ksdata and anaconda.ksdata.bootloader.driveorder:
-        anaconda.bootloader.updateDriveList(anaconda.ksdata.bootloader.driveorder)
-    else:
-        #We want the selected bootloader drive to be preferred
-        pref = anaconda.bootloader.drivelist[:1]
-        anaconda.bootloader.updateDriveList(pref)
-
-    if iutil.isEfi() and not anaconda.bootloader.device:
-        bootPart = None
-        partitions = anaconda.storage.partitions
-        for part in partitions:
-            if part.partedPartition.active and isEfiSystemPartition(part.partedPartition):
-                bootPart = part.name
-                break
-        if bootPart:
-            anaconda.bootloader.setDevice(bootPart)
-
-# iSeries bootloader on upgrades
-    if iutil.getPPCMachine() == "iSeries" and not anaconda.bootloader.device:
-        bootPart = None
-        partitions = anaconda.storage.partitions
-        for part in partitions:
-            if part.partedPartition.active and \
-               part.partedPartition.getFlag(parted.PARTITION_PREP):
-                bootPart = part.name
-                break
-        if bootPart:
-            anaconda.bootloader.setDevice(bootPart)
-
-    choices = anaconda.platform.bootloaderChoices(anaconda.bootloader)
-    if not choices and iutil.getPPCMachine() != "iSeries":
-	anaconda.dispatch.skipStep("instbootloader")
-    else:
-	anaconda.dispatch.skipStep("instbootloader", skip = 0)
-
-    # FIXME: ...
-    anaconda.bootloader.images.setup(anaconda.storage)
-
-    if anaconda.bootloader.defaultDevice != None and choices:
-        keys = choices.keys()
-        # there are only two possible things that can be in the keys
-        # mbr and boot.  boot is ALWAYS present.  so if the dev isn't
-        # listed, it was mbr and we should nicely fall back to boot
-        if anaconda.bootloader.defaultDevice not in keys:
-            log.warning("MBR not suitable as boot device; installing to partition")
-            anaconda.bootloader.defaultDevice = "boot"
-        anaconda.bootloader.setDevice(choices[anaconda.bootloader.defaultDevice][0])
-    elif choices and iutil.isMactel() and choices.has_key("boot"): # haccckkkk
-        anaconda.bootloader.setDevice(choices["boot"][0])        
-    elif choices and choices.has_key("mbr"):
-        anaconda.bootloader.setDevice(choices["mbr"][0])
-    elif choices and choices.has_key("boot"):
-        anaconda.bootloader.setDevice(choices["boot"][0])
-
-def fixedMdraidGrubTarget(anaconda, grubTarget):
-    # handle change made in F12 - before F12 mdX used to mean installation
-    # into mbrs of mdX members' disks
-    fixedGrubTarget = grubTarget
-    (product, version) = getReleaseString(anaconda.rootPath)
-    try:
-        if float(version) < 12:
-            stage1Devs = anaconda.bootloader.getPhysicalDevices(grubTarget)
-            fixedGrubTarget = getDiskPart(stage1Devs[0], anaconda.storage)[0]
-            log.info("Mdraid grub upgrade: %s -> %s" % (grubTarget,
-                                                       fixedGrubTarget))
-    except ValueError:
-        log.warning("Can't decide mdraid grub upgrade fix, product: %s, version: %s" % (product, version))
-
-    return fixedGrubTarget
-
-def writeBootloader(anaconda):
-    def dosync():
-        isys.sync()
-        isys.sync()
-        isys.sync()
-
-    if anaconda.bootloader.defaultDevice == -1:
-        return
-
-    if anaconda.bootloader.doUpgradeOnly:
-        (bootType, theDev) = checkbootloader.getBootloaderTypeAndBoot(anaconda.rootPath, storage=anaconda.storage)
-        
-        anaconda.bootloader.doUpgradeonly = 1
-        if bootType == "GRUB":
-            if theDev.startswith('/dev/md'):
-                theDev = fixedMdraidGrubTarget(anaconda,
-                                               devicePathToName(theDev))
-            anaconda.bootloader.useGrubVal = 1
-            anaconda.bootloader.setDevice(devicePathToName(theDev))
-        else:
-            anaconda.bootloader.doUpgradeOnly = 0    
-
-    w = anaconda.intf.waitWindow(_("Bootloader"), _("Installing bootloader."))
-
-    kernelList = []
-    otherList = []
-    # getDefault needs to return a device, but that's too invasive for now.
-    rootDev = anaconda.storage.rootDevice
-
-    if not anaconda.bootloader.images.getDefault():
-        defaultDev = None
-    else:
-        defaultDev = anaconda.storage.devicetree.getDeviceByName(anaconda.bootloader.images.getDefault())
-
-    kernelLabel = None
-    kernelLongLabel = None
-
-    for (dev, (label, longlabel, type)) in anaconda.bootloader.images.getImages().items():
-        if (rootDev is None and kernelLabel is None) or (dev == rootDev.name):
-	    kernelLabel = label
-            kernelLongLabel = longlabel
-	elif (not defaultDev and not dev) or (defaultDev and dev == defaultDev.name):
-	    otherList = [(label, longlabel, dev)] + otherList
-	else:
-	    otherList.append((label, longlabel, dev))
-
-    if kernelLabel is None:
-        log.error("unable to find default image, bailing")
-        w.pop()
-        return
-
-    plainLabelUsed = 0
-    defkern = "kernel"
-    for (version, arch, nick) in \
-            anaconda.backend.kernelVersionList(anaconda.rootPath):
-	if plainLabelUsed:
-            kernelList.append(("%s-%s" %(kernelLabel, nick),
-                               "%s-%s" %(kernelLongLabel, nick),
-                               version))
-	else:
-	    kernelList.append((kernelLabel, kernelLongLabel, version))
-            if nick != "base":
-                defkern = "kernel-%s" %(nick,)
-	    plainLabelUsed = 1
-
-    f = open(anaconda.rootPath + "/etc/sysconfig/kernel", "w+")
-    f.write("# UPDATEDEFAULT specifies if new-kernel-pkg should make\n"
-            "# new kernels the default\n")
-    # only update the default if we're setting the default to linux (#156678)
-    if (not defaultDev and not rootDev) or (defaultDev and rootDev.name == defaultDev.name):
-        f.write("UPDATEDEFAULT=yes\n")
-    else:
-        f.write("UPDATEDEFAULT=no\n")        
-    f.write("\n")
-    f.write("# DEFAULTKERNEL specifies the default kernel package type\n")
-    f.write("DEFAULTKERNEL=%s\n" %(defkern,))
-    f.close()
-
-    dosync()
-    try:
-        rc = anaconda.bootloader.write(anaconda.rootPath, anaconda.bootloader,
-                                       kernelList, otherList, defaultDev)
-        w.pop()
-
-        if rc and anaconda.intf:
-            anaconda.intf.messageWindow(_("Warning"),
-                               _("There was an error installing the bootloader.  "
-                                 "The system may not be bootable."))
-    except booty.BootyNoKernelWarning:
-        w.pop()
-        if anaconda.intf:
-            anaconda.intf.messageWindow(_("Warning"),
-                               _("No kernel packages were installed on the "
-                                 "system.  Bootloader configuration "
-                                 "will not be changed."))
-
-    dosync()
-
-def hasWindows(bl):
-    if not booty.doesDualBoot():
-        return False
-
-    foundWindows = False
-    for (dev, type) in bl.images.availableBootDevices(bl.storage):
-        if type in booty.dosFilesystems:
-            foundWindows = True
-            break
-
-    return foundWindows
diff --git a/cmdline.py b/cmdline.py
deleted file mode 100644
index a531940..0000000
--- a/cmdline.py
+++ /dev/null
@@ -1,221 +0,0 @@
-#
-# cmdline.py - non-interactive, very very simple frontend to anaconda
-#
-# Copyright (C) 2003, 2004, 2005, 2006, 2007  Red Hat, Inc.
-# All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author(s): Jeremy Katz <katzj redhat com
-#
-
-import time
-import signal
-import parted
-from constants import *
-from flags import flags
-from iutil import strip_markup
-from installinterfacebase import InstallInterfaceBase
-
-import gettext
-_ = lambda x: gettext.ldgettext("anaconda", x)
-
-import logging
-log = logging.getLogger("anaconda")
-
-stepToClasses = { "install" : "setupProgressDisplay" }
-
-class WaitWindow:
-    def pop(self):
-        pass
-    def refresh(self):
-        pass
-    def __init__(self, title, text):
-        print(text)
-
-class ProgressWindow:
-    def pop(self):
-        print("")
-
-    def pulse(self):
-        pass
-
-    def set(self, amount):
-        if amount == self.total:
-            print(_("Completed"))
-
-    def refresh(self):
-        pass
-
-    def __init__(self, title, text, total, updpct = 0.05, pulse = False):
-        self.total = total
-        print(text)
-        print(_("In progress"))
-
-class InstallInterface(InstallInterfaceBase):
-    def __init__(self):
-        InstallInterfaceBase.__init__(self)
-#        signal.signal(signal.SIGINT, signal.SIG_IGN)
-        signal.signal(signal.SIGTSTP, signal.SIG_DFL)
-        self.instProgress = None
-
-    def __del__(self):
-        pass
-
-    def shutdown(self):
-        pass
-
-    def suspend(self):
-        pass
-
-    def resume(self):
-        pass
-
-    def progressWindow(self, title, text, total, updpct = 0.05, pulse = False):
-        return ProgressWindow(title, text, total, updpct, pulse)
-
-    def kickstartErrorWindow(self, text):
-        s = _("The following error was found while parsing the "
-              "kickstart configuration file:\n\n%s") %(text,)
-        print(s)
-
-        while 1:
-            time.sleep(5)
-
-    def messageWindow(self, title, text, type="ok", default = None,
-                      custom_icon = None, custom_buttons = []):
-        if type == "ok":
-            print(text)
-        else:
-            print(_("Command line mode requires all choices to be specified in a kickstart configuration file."))
-            print(title)
-            print(text)
-            print(type, custom_buttons)
-
-            # don't exit
-            while 1:
-                time.sleep(5)
-
-    def detailedMessageWindow(self, title, text, longText=None, type="ok",
-                              default=None, custom_buttons=None,
-                              custom_icon=None, expanded=False):
-        if longText:
-            text += "\n\n%s" % longText
-
-        self.messageWindow(title, text, type=type, default=default,
-                           custom_buttons=custom_buttons, custom_icon=custom_icon)
-
-    def passphraseEntryWindow(self, device):
-        print(_("Can't have a question in command line mode!"))
-        print("(passphraseEntryWindow: '%s')" % device)
-        # don't exit
-        while 1:
-            time.sleep(5)
-
-    def getLUKSPassphrase(self, passphrase = "", isglobal = False):
-        print(_("Can't have a question in command line mode!"))
-        print("(getLUKSPassphrase)")
-        # don't exit
-        while 1:
-            time.sleep(5)
-
-    def enableNetwork(self):
-        print(_("Can't have a question in command line mode!"))
-        print("(enableNetwork)")
-        # don't exit
-        while 1:
-            time.sleep(5)
-
-    def resetInitializeDiskQuestion(self):
-        pass
-
-    def questionInitializeDisk(self, path, description, size, details=""):
-        print(_("Can't have a question in command line mode!"))
-        print("(questionInitializeDisk)")
-        # don't exit
-        while 1:
-            time.sleep(5)
-
-    def resetReinitInconsistentLVMQuestion(self):
-        pass
-
-    def questionReinitInconsistentLVM(self, pv_names=None, lv_name=None, vg_name=None):
-        print(_("Can't have a question in command line mode!"))
-        print("(questionReinitInconsistentLVM)")
-        # don't exit
-        while 1:
-            time.sleep(5)
-
-    def mainExceptionWindow(self, shortText, longTextFile):
-        print(shortText)
-
-    def waitWindow(self, title, text):
-        return WaitWindow(title, text)
-
-    def beep(self):
-        pass
-
-    def run(self, anaconda):
-        (step, instance) = anaconda.dispatch.currentStep()
-        while step:
-            if stepToClasses.has_key(step):
-                s = "nextWin = %s" %(stepToClasses[step],)
-                exec s
-                nextWin(instance)
-            else:
-                print("In interactive step %s, can't continue" %(step,))
-                while 1:
-                    time.sleep(1)
-
-            anaconda.dispatch.gotoNext()
-	    (step, instance) = anaconda.dispatch.currentStep()
-
-    def setInstallProgressClass(self, c):
-        self.instProgress = c
-
-    def setSteps(self, anaconda):
-        pass
-
-class progressDisplay:
-    def __init__(self):
-        self.pct = 0
-        self.display = ""
-
-    def __del__(self):
-        pass
-
-    def processEvents(self):
-        pass
-    def setShowPercentage(self, val):
-        pass
-    def get_fraction(self):
-        return self.pct
-    def set_fraction(self, pct):
-        self.pct = pct
-    def set_text(self, txt):
-        pass
-    def set_label(self, txt):
-        stripped = strip_markup(txt)
-        if stripped != self.display:
-            self.display = stripped
-            print(self.display)
-
-def setupProgressDisplay(anaconda):
-    if anaconda.dir == DISPATCH_BACK:
-        anaconda.intf.setInstallProgressClass(None)
-        return DISPATCH_BACK
-    else:
-        anaconda.intf.setInstallProgressClass(progressDisplay())
-        
-    return DISPATCH_FORWARD
diff --git a/command-stubs/Makefile.am b/command-stubs/Makefile.am
deleted file mode 100644
index cab5f89..0000000
--- a/command-stubs/Makefile.am
+++ /dev/null
@@ -1,23 +0,0 @@
-# command-stubs/Makefile.am for anaconda
-#
-# 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 Lesser General Public License as published
-# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: David Cantrell <dcantrell redhat com>
-
-commandstubsdir           = $(datadir)/$(PACKAGE_NAME)
-dist_commandstubs_SCRIPTS = *-stub
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/command-stubs/list-harddrives-stub b/command-stubs/list-harddrives-stub
deleted file mode 100755
index 2d9e225..0000000
--- a/command-stubs/list-harddrives-stub
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/python
-#
-# scan system for harddrives and output device name/size
-#
-# Copyright (C) 2007, 2009  Red Hat, Inc.  All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for