This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "IPFire 3.x development tree".
The branch, master has been updated via cef84a2302caaa68295accce3926187682408cdd (commit) via d69f13b794dfdc58d9f8fe55c3a52ea0e4cd2dd6 (commit) via 8af660c82d7a92a45ede9a490b81eef9ad44cc40 (commit) via 7103fae9a3299729d8f526984240e8f18aa03536 (commit) via c32179ec1604dbc8574f44b332148ee58c7ab6fa (commit) via 0119df5d5ddaa9a9a308066b70201d21d38a164d (commit) via 1ba4ef5f5afa90389ee3fe22d208335bac4fe15a (commit) via 891c03a61a1ea84543073a4ac2d7aa4063d67b4c (commit) via 5cd704a57c29c4d0153fcc8bbd101995e7328e23 (commit) via e32b127d7b9dbd2b4e967ef164dee8b244eee4ac (commit) via 874e27797455ec0c14d2f1a9f398f9be4710f242 (commit) via bc1b0b34f2f27ad819fc29c24672a298be2b958a (commit) via 671bd5bd9ca4ff6836773099b00c0f1c02503d8e (commit) via 0c60d0b6c673197d31e28bac3c0cc8b12d8afde0 (commit) via 087700b1d07e993ffb2d6691704a4fb801dad2ef (commit) via 05e3bacd26ad6cd313f9fb4b52a9a5ed39f3f353 (commit) via de2911caecd596f010db938a99f113ed2232ea3f (commit) via e3b623d3494146def613c28c3bada99c58eb4ade (commit) via be377bdec682154732332fe4bf2c42dbc5e478f5 (commit) via 11269fb78874d4e512e08d6e366b1d80e6afdc14 (commit) via 930ac77fc00c07dfd9617c66b6be518b261a6925 (commit) via e37957e6f3dc6a07d7170015cfc396ecb3a12cfd (commit) via 099849d41a65a69fdfc0cabd0a3210738d9da96f (commit) via 2a4aeefe0d89bfc7cc95d7571ab4e3d249fb72da (commit) via e9e4790c268d238a4c7bf7446805ed9d92024aa9 (commit) via 165e224570d884977ead0bedec1584f8867f1da9 (commit) via 13e6891ba60bb34853e80ce0b30173d0e48ef952 (commit) from 89cdd936d71b6dc477457b836ebbc7c78403f04a (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- commit cef84a2302caaa68295accce3926187682408cdd Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 18:11:04 2010 +0200
installer: Create /etc/passwd and /etc/group.
commit d69f13b794dfdc58d9f8fe55c3a52ea0e4cd2dd6 Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 17:30:20 2010 +0200
pomona: Update dependencies.
commit 8af660c82d7a92a45ede9a490b81eef9ad44cc40 Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 17:27:46 2010 +0200
initscripts: Hack that makes udevd start up.
We definately need to revert this later.
commit 7103fae9a3299729d8f526984240e8f18aa03536 Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 17:20:34 2010 +0200
pyblock: Update to 0.46.
Doesn't need libbdevid anymore.
commit c32179ec1604dbc8574f44b332148ee58c7ab6fa Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 17:16:02 2010 +0200
install: Create /tmp and /var/tmp in live system.
commit 0119df5d5ddaa9a9a308066b70201d21d38a164d Merge: 1ba4ef5f5afa90389ee3fe22d208335bac4fe15a 89cdd936d71b6dc477457b836ebbc7c78403f04a Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 16:44:34 2010 +0200
Merge branch 'master' of ssh://git.ipfire.org/pub/git/ipfire-3.x
commit 1ba4ef5f5afa90389ee3fe22d208335bac4fe15a Merge: 891c03a61a1ea84543073a4ac2d7aa4063d67b4c e3b623d3494146def613c28c3bada99c58eb4ade Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 16:43:03 2010 +0200
Merge branch 'installer-v2'
Conflicts: lfs/python-parted lfs/wireless-tools pkgs/core/pomona/src/autopart.py pkgs/core/pomona/src/backend.py pkgs/core/pomona/src/bootloader.py pkgs/core/pomona/src/cryptodev.py pkgs/core/pomona/src/dmraid.py pkgs/core/pomona/src/errors.py pkgs/core/pomona/src/flags.py pkgs/core/pomona/src/fsset.py pkgs/core/pomona/src/installer.py pkgs/core/pomona/src/instdata.py pkgs/core/pomona/src/isys/devices.c pkgs/core/pomona/src/isys/devices.h pkgs/core/pomona/src/isys/eddsupport.c pkgs/core/pomona/src/isys/eddsupport.h pkgs/core/pomona/src/isys/ethtool.c pkgs/core/pomona/src/isys/imount.c pkgs/core/pomona/src/isys/imount.h pkgs/core/pomona/src/isys/isofs.c pkgs/core/pomona/src/isys/lang.c pkgs/core/pomona/src/isys/lang.h pkgs/core/pomona/src/isys/linkdetect.c pkgs/core/pomona/src/isys/net.h pkgs/core/pomona/src/isys/smp.c pkgs/core/pomona/src/isys/smp.h pkgs/core/pomona/src/isys/str.c pkgs/core/pomona/src/isys/str.h pkgs/core/pomona/src/isys/stubs.h pkgs/core/pomona/src/isys/sundries.h pkgs/core/pomona/src/isys/vio.c pkgs/core/pomona/src/isys/wireless.c pkgs/core/pomona/src/isys/wireless.h pkgs/core/pomona/src/iutil.py pkgs/core/pomona/src/keyboard_models.py pkgs/core/pomona/src/lvm.py pkgs/core/pomona/src/network.py pkgs/core/pomona/src/packages.py pkgs/core/pomona/src/pakfireinstall.py pkgs/core/pomona/src/partErrors.py pkgs/core/pomona/src/partIntfHelpers.py pkgs/core/pomona/src/partRequests.py pkgs/core/pomona/src/partedUtils.py pkgs/core/pomona/src/partitioning.py pkgs/core/pomona/src/partitions.py pkgs/core/pomona/src/pomona_log.py pkgs/core/pomona/src/raid.py pkgs/core/pomona/src/scripts/getlangnames.py pkgs/core/pomona/src/timezone.py pkgs/core/pomona/src/tui.py pkgs/core/pomona/src/tui_bootloader.py pkgs/core/pomona/src/tui_complete.py pkgs/core/pomona/src/tui_confirm.py pkgs/core/pomona/src/tui_keyboard.py pkgs/core/pomona/src/tui_language.py pkgs/core/pomona/src/tui_network.py pkgs/core/pomona/src/tui_partition.py pkgs/core/pomona/src/tui_progress.py pkgs/core/pomona/src/tui_timezone.py pkgs/core/pomona/src/tui_userauth.py pkgs/core/pomona/src/tui_welcome.py pkgs/core/pomona/src/users.py pkgs/core/pomona/src/zonetab.py src/pomona/Makefile.inc src/pomona/isys/Makefile src/pomona/isys/imount.c src/pomona/isys/mount.c src/pomona/pomona src/rootfiles/core/python-parted
commit 891c03a61a1ea84543073a4ac2d7aa4063d67b4c Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 13:16:23 2010 +0200
dbus: Fix name of initscript.
commit 5cd704a57c29c4d0153fcc8bbd101995e7328e23 Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 13:15:32 2010 +0200
naoki: The installer system needs initscripts.
commit e32b127d7b9dbd2b4e967ef164dee8b244eee4ac Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 13:14:20 2010 +0200
installer: Don't load the kernel modules for filesystems.
commit 874e27797455ec0c14d2f1a9f398f9be4710f242 Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 13:13:40 2010 +0200
upstart: Depend on sysvinit.
So we will get all the other tools we are used to, too.
commit bc1b0b34f2f27ad819fc29c24672a298be2b958a Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 13:13:03 2010 +0200
pakfire: Allow special files in packages.
commit 671bd5bd9ca4ff6836773099b00c0f1c02503d8e Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 13:11:14 2010 +0200
QA: Ignore device nodes in /lib/udev/devices.
commit 0c60d0b6c673197d31e28bac3c0cc8b12d8afde0 Author: Michael Tremer michael.tremer@ipfire.org Date: Sat Apr 10 13:10:35 2010 +0200
udev: Create some essential device nodes.
commit 087700b1d07e993ffb2d6691704a4fb801dad2ef Author: Michael Tremer michael.tremer@ipfire.org Date: Fri Apr 9 00:17:17 2010 +0200
initscripts: Update dependency list.
commit 05e3bacd26ad6cd313f9fb4b52a9a5ed39f3f353 Author: Michael Tremer michael.tremer@ipfire.org Date: Fri Apr 9 00:15:03 2010 +0200
udev: Remove gobject-introspection as a dependency.
commit de2911caecd596f010db938a99f113ed2232ea3f Author: Michael Tremer michael.tremer@ipfire.org Date: Thu Apr 8 21:44:40 2010 +0200
generator: Change name of installer image.
installer.img -> installer.sfs.
commit e3b623d3494146def613c28c3bada99c58eb4ade Author: Michael Tremer michael.tremer@ipfire.org Date: Thu Jul 30 20:57:27 2009 +0200
Replaced tar call by $(EXTRACTOR)
commit be377bdec682154732332fe4bf2c42dbc5e478f5 Author: Michael Tremer michael.tremer@ipfire.org Date: Tue Jun 23 16:21:36 2009 +0200
wireless-tools: Passing CFLAGS to make.
commit 11269fb78874d4e512e08d6e366b1d80e6afdc14 Author: Michael Tremer michael.tremer@ipfire.org Date: Sun Jun 21 19:36:37 2009 +0200
Daily checkin.
commit 930ac77fc00c07dfd9617c66b6be518b261a6925 Author: Michael Tremer michael.tremer@ipfire.org Date: Sun May 24 22:23:33 2009 +0200
Daily checkin.
commit e37957e6f3dc6a07d7170015cfc396ecb3a12cfd Author: Michael Tremer michael.tremer@ipfire.org Date: Sun May 24 17:44:29 2009 +0200
Daily checkin.
commit 099849d41a65a69fdfc0cabd0a3210738d9da96f Author: Michael Tremer michael.tremer@ipfire.org Date: Sun May 10 22:35:46 2009 +0200
Daily checkin.
commit 2a4aeefe0d89bfc7cc95d7571ab4e3d249fb72da Author: Michael Tremer michael.tremer@ipfire.org Date: Thu Apr 30 15:49:44 2009 +0200
Daily checkin.
commit e9e4790c268d238a4c7bf7446805ed9d92024aa9 Author: Michael Tremer michael.tremer@ipfire.org Date: Wed Apr 29 21:30:12 2009 +0200
Don't debug installer with strace.
commit 165e224570d884977ead0bedec1584f8867f1da9 Author: Michael Tremer michael.tremer@ipfire.org Date: Wed Apr 29 21:29:50 2009 +0200
Updated python-parted.
commit 13e6891ba60bb34853e80ce0b30173d0e48ef952 Author: Michael Tremer michael.tremer@ipfire.org Date: Wed Apr 29 21:28:27 2009 +0200
Checkin in the shiny new installer.
-----------------------------------------------------------------------
Summary of changes: .gitignore | 1 + naoki/chroot.py | 2 +- .../core/dbus/{messagebus.conf => messagebus.init} | 0 pkgs/core/initscripts/init/udev.conf | 4 + pkgs/core/initscripts/initscripts.nm | 4 +- pkgs/core/pomona/pomona.nm | 4 +- pkgs/core/pomona/src/Makefile | 24 +- pkgs/core/pomona/src/Makefile.inc | 7 +- pkgs/core/pomona/src/autopart.py | 1609 ----------- pkgs/core/pomona/src/backend.py | 127 - pkgs/core/pomona/src/bootloader.py | 740 ----- pkgs/core/pomona/src/console.py | 172 +-- pkgs/core/pomona/src/constants.py | 73 +- pkgs/core/pomona/src/cryptodev.py | 252 -- pkgs/core/pomona/src/datastore.py | 13 + pkgs/core/pomona/src/dispatch.py | 226 +-- pkgs/core/pomona/src/dmraid.py | 302 -- pkgs/core/pomona/src/errors.py | 159 -- pkgs/core/pomona/src/exception.py | 76 +- pkgs/core/pomona/src/flags.py | 67 - pkgs/core/pomona/src/fsset.py | 2876 -------------------- pkgs/core/pomona/src/installer.py | 291 -- pkgs/core/pomona/src/instdata.py | 65 - pkgs/core/pomona/src/isys/Makefile | 42 +- pkgs/core/pomona/src/isys/devices.c | 171 -- pkgs/core/pomona/src/isys/devices.h | 42 - pkgs/core/pomona/src/isys/eddsupport.c | 319 --- pkgs/core/pomona/src/isys/eddsupport.h | 28 - pkgs/core/pomona/src/isys/ethtool.c | 94 - pkgs/core/pomona/src/isys/imount.h | 36 - pkgs/core/pomona/src/isys/isofs.c | 55 - pkgs/core/pomona/src/isys/isys.c | 741 +----- pkgs/core/pomona/src/isys/isys.h | 30 - pkgs/core/pomona/src/isys/isys.py | 639 +----- pkgs/core/pomona/src/isys/lang.c | 209 -- pkgs/core/pomona/src/isys/lang.h | 44 - pkgs/core/pomona/src/isys/linkdetect.c | 180 -- pkgs/core/pomona/src/isys/{imount.c => mount.c} | 89 +- pkgs/core/pomona/src/isys/mount.h | 13 + pkgs/core/pomona/src/isys/net.h | 58 - pkgs/core/pomona/src/isys/smp.c | 488 ---- pkgs/core/pomona/src/isys/smp.h | 26 - pkgs/core/pomona/src/isys/str.c | 125 - pkgs/core/pomona/src/isys/str.h | 29 - pkgs/core/pomona/src/isys/stubs.h | 44 - pkgs/core/pomona/src/isys/sundries.h | 88 - pkgs/core/pomona/src/isys/vio.c | 106 - pkgs/core/pomona/src/isys/wireless.c | 279 -- pkgs/core/pomona/src/isys/wireless.h | 29 - pkgs/core/pomona/src/iutil.py | 333 --- pkgs/core/pomona/src/keyboard.py | 131 + pkgs/core/pomona/src/keyboard_models.py | 259 -- pkgs/core/pomona/src/language.py | 109 + pkgs/core/pomona/src/log.py | 45 + pkgs/core/pomona/src/lvm.py | 613 ----- pkgs/core/pomona/src/network.py | 65 - pkgs/core/pomona/src/packages.py | 195 -- pkgs/core/pomona/src/pakfireinstall.py | 265 -- pkgs/core/pomona/src/partErrors.py | 33 - pkgs/core/pomona/src/partIntfHelpers.py | 547 ---- pkgs/core/pomona/src/partRequests.py | 1038 ------- pkgs/core/pomona/src/partedUtils.py | 1189 -------- pkgs/core/pomona/src/partition.py | 394 +++ pkgs/core/pomona/src/partitioning.py | 79 - pkgs/core/pomona/src/partitions.py | 1672 ------------ pkgs/core/pomona/src/po/Makefile | 14 +- pkgs/core/pomona/src/pomona | 22 +- pkgs/core/pomona/src/pomona.py | 113 + pkgs/core/pomona/src/pomona_log.py | 103 - pkgs/core/pomona/src/pychecker-false-positives | 9 +- pkgs/core/pomona/src/raid.py | 226 -- pkgs/core/pomona/src/runpychecker.sh | 4 +- pkgs/core/pomona/src/scripts/getlangnames.py | 22 - .../src/{storage_old => storage}/__init__.py | 14 +- .../src/{storage_old => storage}/deviceaction.py | 0 .../devicelibs/__init__.py | 0 .../{storage_old => storage}/devicelibs/crypto.py | 0 .../src/{storage_old => storage}/devicelibs/lvm.py | 0 .../{storage_old => storage}/devicelibs/swap.py | 4 +- .../pomona/src/{storage_old => storage}/devices.py | 2 +- .../src/{storage_old => storage}/devicetree.py | 6 +- .../pomona/src/{storage_old => storage}/errors.py | 0 .../{storage_old => storage}/formats/__init__.py | 0 .../src/{storage_old => storage}/formats/fs.py | 0 .../src/{storage_old => storage}/formats/luks.py | 0 .../src/{storage_old => storage}/formats/lvmpv.py | 0 .../src/{storage_old => storage}/formats/swap.py | 0 .../src/{storage_old => storage}/partitioning.py | 4 +- .../pomona/src/{storage_old => storage}/udev.py | 0 pkgs/core/pomona/src/storage_test.py | 5 - pkgs/core/pomona/src/text.py | 131 + pkgs/core/pomona/src/timezone.py | 51 - pkgs/core/pomona/src/tui.py | 414 --- pkgs/core/pomona/src/tui_bootloader.py | 453 --- pkgs/core/pomona/src/tui_complete.py | 42 - pkgs/core/pomona/src/tui_confirm.py | 45 - pkgs/core/pomona/src/tui_keyboard.py | 47 - pkgs/core/pomona/src/tui_language.py | 53 - pkgs/core/pomona/src/tui_network.py | 81 - pkgs/core/pomona/src/tui_partition.py | 1610 ----------- pkgs/core/pomona/src/tui_progress.py | 115 - pkgs/core/pomona/src/tui_timezone.py | 114 - pkgs/core/pomona/src/tui_userauth.py | 79 - pkgs/core/pomona/src/tui_welcome.py | 18 - pkgs/core/pomona/src/users.py | 157 -- pkgs/core/pomona/src/util.py | 45 + pkgs/core/pomona/src/windows.py | 180 ++ pkgs/core/pomona/src/zonetab.py | 119 - pkgs/core/python-pyblock/python-pyblock.nm | 10 +- pkgs/core/udev/udev.nm | 16 +- pkgs/core/upstart/upstart.nm | 2 +- src/install/etc/group | 33 + src/install/etc/passwd | 22 + src/install/root/.bash_profile | 2 +- tools/compressor | 2 +- tools/generator | 7 +- tools/py-compile | 8 +- tools/quality-agent.d/002-bad-symlinks | 4 + 118 files changed, 1468 insertions(+), 21005 deletions(-) rename pkgs/core/dbus/{messagebus.conf => messagebus.init} (100%) delete mode 100644 pkgs/core/pomona/src/autopart.py delete mode 100644 pkgs/core/pomona/src/backend.py delete mode 100644 pkgs/core/pomona/src/bootloader.py delete mode 100644 pkgs/core/pomona/src/cryptodev.py create mode 100644 pkgs/core/pomona/src/datastore.py delete mode 100644 pkgs/core/pomona/src/dmraid.py delete mode 100644 pkgs/core/pomona/src/errors.py delete mode 100644 pkgs/core/pomona/src/flags.py delete mode 100644 pkgs/core/pomona/src/fsset.py delete mode 100644 pkgs/core/pomona/src/installer.py delete mode 100644 pkgs/core/pomona/src/instdata.py delete mode 100644 pkgs/core/pomona/src/isys/devices.c delete mode 100644 pkgs/core/pomona/src/isys/devices.h delete mode 100644 pkgs/core/pomona/src/isys/eddsupport.c delete mode 100644 pkgs/core/pomona/src/isys/eddsupport.h delete mode 100644 pkgs/core/pomona/src/isys/ethtool.c delete mode 100644 pkgs/core/pomona/src/isys/imount.h delete mode 100644 pkgs/core/pomona/src/isys/isofs.c delete mode 100644 pkgs/core/pomona/src/isys/lang.c delete mode 100644 pkgs/core/pomona/src/isys/lang.h delete mode 100644 pkgs/core/pomona/src/isys/linkdetect.c rename pkgs/core/pomona/src/isys/{imount.c => mount.c} (65%) create mode 100644 pkgs/core/pomona/src/isys/mount.h delete mode 100644 pkgs/core/pomona/src/isys/net.h delete mode 100644 pkgs/core/pomona/src/isys/smp.c delete mode 100644 pkgs/core/pomona/src/isys/smp.h delete mode 100644 pkgs/core/pomona/src/isys/str.c delete mode 100644 pkgs/core/pomona/src/isys/str.h delete mode 100644 pkgs/core/pomona/src/isys/stubs.h delete mode 100644 pkgs/core/pomona/src/isys/sundries.h delete mode 100644 pkgs/core/pomona/src/isys/vio.c delete mode 100644 pkgs/core/pomona/src/isys/wireless.c delete mode 100644 pkgs/core/pomona/src/isys/wireless.h delete mode 100644 pkgs/core/pomona/src/iutil.py create mode 100644 pkgs/core/pomona/src/keyboard.py delete mode 100644 pkgs/core/pomona/src/keyboard_models.py create mode 100644 pkgs/core/pomona/src/language.py create mode 100644 pkgs/core/pomona/src/log.py delete mode 100644 pkgs/core/pomona/src/lvm.py delete mode 100644 pkgs/core/pomona/src/network.py delete mode 100644 pkgs/core/pomona/src/packages.py delete mode 100644 pkgs/core/pomona/src/pakfireinstall.py delete mode 100644 pkgs/core/pomona/src/partErrors.py delete mode 100644 pkgs/core/pomona/src/partIntfHelpers.py delete mode 100644 pkgs/core/pomona/src/partRequests.py delete mode 100644 pkgs/core/pomona/src/partedUtils.py create mode 100644 pkgs/core/pomona/src/partition.py delete mode 100644 pkgs/core/pomona/src/partitioning.py delete mode 100644 pkgs/core/pomona/src/partitions.py create mode 100644 pkgs/core/pomona/src/pomona.py delete mode 100644 pkgs/core/pomona/src/pomona_log.py delete mode 100644 pkgs/core/pomona/src/raid.py delete mode 100755 pkgs/core/pomona/src/scripts/getlangnames.py rename pkgs/core/pomona/src/{storage_old => storage}/__init__.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/deviceaction.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/devicelibs/__init__.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/devicelibs/crypto.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/devicelibs/lvm.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/devicelibs/swap.py (99%) rename pkgs/core/pomona/src/{storage_old => storage}/devices.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/devicetree.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/errors.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/formats/__init__.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/formats/fs.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/formats/luks.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/formats/lvmpv.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/formats/swap.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/partitioning.py (100%) rename pkgs/core/pomona/src/{storage_old => storage}/udev.py (100%) delete mode 100755 pkgs/core/pomona/src/storage_test.py create mode 100644 pkgs/core/pomona/src/text.py delete mode 100644 pkgs/core/pomona/src/timezone.py delete mode 100644 pkgs/core/pomona/src/tui.py delete mode 100644 pkgs/core/pomona/src/tui_bootloader.py delete mode 100644 pkgs/core/pomona/src/tui_complete.py delete mode 100644 pkgs/core/pomona/src/tui_confirm.py delete mode 100644 pkgs/core/pomona/src/tui_keyboard.py delete mode 100644 pkgs/core/pomona/src/tui_language.py delete mode 100644 pkgs/core/pomona/src/tui_network.py delete mode 100644 pkgs/core/pomona/src/tui_partition.py delete mode 100644 pkgs/core/pomona/src/tui_progress.py delete mode 100644 pkgs/core/pomona/src/tui_timezone.py delete mode 100644 pkgs/core/pomona/src/tui_userauth.py delete mode 100644 pkgs/core/pomona/src/tui_welcome.py delete mode 100644 pkgs/core/pomona/src/users.py create mode 100644 pkgs/core/pomona/src/util.py create mode 100644 pkgs/core/pomona/src/windows.py delete mode 100644 pkgs/core/pomona/src/zonetab.py create mode 100644 src/install/etc/group create mode 100644 src/install/etc/passwd
Difference in files: diff --git a/.gitignore b/.gitignore index ac3bb8e..88d9675 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ /*.tar.gz *.py[co] *~ +*.py[co] diff --git a/naoki/chroot.py b/naoki/chroot.py index 1941d58..35c01b0 100644 --- a/naoki/chroot.py +++ b/naoki/chroot.py @@ -522,7 +522,7 @@ class Generator(Environment): "less", "module-init-tools", "procps", "sed", "sysvinit", "udev", "util-linux-ng", "which", "dvdrtools", "kernel", "squashfs-tools", "syslinux", "zlib",], - "installer" : ["kernel", "pomona", "upstart",], + "installer" : ["initscripts", "kernel", "pomona", "upstart"], } _package_infos = backend.parse_package_info(_packages[type])
diff --git a/pkgs/core/dbus/messagebus.conf b/pkgs/core/dbus/messagebus.conf deleted file mode 100644 index b8717c0..0000000 --- a/pkgs/core/dbus/messagebus.conf +++ /dev/null @@ -1,15 +0,0 @@ -description "Starts the message bus daemon" -author "IPFire Team" - -start on stopped mountfs -stop on starting shutdown - -exec /usr/bin/dbus-daemon --config-file=/etc/dbus-1/system.conf --nofork -respawn - -pre-start script - dbus-uuidgen --ensure >/dev/null - if [ ! -d /var/run/dbus ]; then - mkdir /var/run/dbus - fi -end script diff --git a/pkgs/core/dbus/messagebus.init b/pkgs/core/dbus/messagebus.init new file mode 100644 index 0000000..b8717c0 --- /dev/null +++ b/pkgs/core/dbus/messagebus.init @@ -0,0 +1,15 @@ +description "Starts the message bus daemon" +author "IPFire Team" + +start on stopped mountfs +stop on starting shutdown + +exec /usr/bin/dbus-daemon --config-file=/etc/dbus-1/system.conf --nofork +respawn + +pre-start script + dbus-uuidgen --ensure >/dev/null + if [ ! -d /var/run/dbus ]; then + mkdir /var/run/dbus + fi +end script diff --git a/pkgs/core/initscripts/init/udev.conf b/pkgs/core/initscripts/init/udev.conf index 15da729..3d75755 100644 --- a/pkgs/core/initscripts/init/udev.conf +++ b/pkgs/core/initscripts/init/udev.conf @@ -22,6 +22,10 @@ pre-start script
# Copy static device nodes to /dev cp -a /lib/udev/devices/* /dev + + # This is a line that is required to get this work + # Looks like a timing problem of upstart + ls -lah /dev end script
exec /sbin/udevd diff --git a/pkgs/core/initscripts/initscripts.nm b/pkgs/core/initscripts/initscripts.nm index 00d449f..24218be 100644 --- a/pkgs/core/initscripts/initscripts.nm +++ b/pkgs/core/initscripts/initscripts.nm @@ -34,8 +34,8 @@ PKG_URL = PKG_LICENSE = GPLv3+ PKG_SUMMARY = The set of scripts that initalize the system.
-PKG_DEPS += coreutils e2fsprogs module-init-tools procps sysvinit \ - system-release upstart util-linux-ng +PKG_DEPS += bash coreutils e2fsprogs grep iproute2 module-init-tools \ + procps sed system-release udev util-linux-ng
define PKG_DESCRIPTION The initscripts package contains the basic system scripts used to boot \ diff --git a/pkgs/core/pomona/pomona.nm b/pkgs/core/pomona/pomona.nm index b5635b9..08f0461 100644 --- a/pkgs/core/pomona/pomona.nm +++ b/pkgs/core/pomona/pomona.nm @@ -35,8 +35,8 @@ PKG_LICENSE = GPLv3+ PKG_SUMMARY = The IPFire 3.x installer.
PKG_BUILD_DEPS+= pychecker -PKG_DEPS += e2fsprogs parted pciutils popt \ - pyfire python python-dbus python-parted +PKG_DEPS += e2fsprogs initscripts libuser newt parted pciutils popt \ + pyfire python python-dbus python-parted python-pyblock syslog-ng udev
define PKG_DESCRIPTION Pomona is the installer for IPFire 3.x. diff --git a/pkgs/core/pomona/src/Makefile b/pkgs/core/pomona/src/Makefile index ab6f497..41c9fc4 100644 --- a/pkgs/core/pomona/src/Makefile +++ b/pkgs/core/pomona/src/Makefile @@ -22,35 +22,29 @@ include Makefile.inc
SUBDIRS = isys po
-all: lang-names subdirs - -lang-names: lang-table - PYTHONPATH="./src/:." LANG=en_US.UTF-8 \ - ./scripts/getlangnames.py > lang-names.tmp - mv lang-names.tmp lang-names +all: subdirs
install: all + rm -rf $(PYTHONLIBDIR) -mkdir -p $(PYTHONLIBDIR) [ -d "$(PYTHONLIBDIR)" ] for d in $(SUBDIRS); do \ make DESTDIR=`cd $(DESTDIR); pwd` -C $$d install; \ [ $$? = 0 ] || exit 1; \ done - cp -vf *.py lang-{table,names} $(PYTHONLIBDIR) - sed -e "s/VERSION/$(VERSION)/g" \ - -e "s/SNAME/$(SNAME)/g" \ - -e "s/PNAME/$(PNAME)/g" \ - -e "s/NAME/$(NAME)/g" \ - -e "s/KVER/$(KVER)/g" \ - -i $(PYTHONLIBDIR)/constants.py + cp -avf *.py storage lang-table $(PYTHONLIBDIR) + #sed -e "s/VERSION/$(VERSION)/g" \ + # -e "s/SNAME/$(SNAME)/g" \ + # -e "s/NAME/$(NAME)/g" \ + # -i $(PYTHONLIBDIR)/constants.py -mkdir -p $(DESTDIR)/sbin - install -m 755 $(PSNAME) $(DESTDIR)/sbin/$(PSNAME) + install -m 755 pomona $(DESTDIR)/sbin/pomona
test: ./runpychecker.sh
clean: - rm -vf *.o *.so *.pyc *.pyo lang-names{,.tmp} + rm -vf *.o *.so *.pyc *.pyo for d in $(SUBDIRS); do make -C $$d clean; done
subdirs: diff --git a/pkgs/core/pomona/src/Makefile.inc b/pkgs/core/pomona/src/Makefile.inc index 998fae8..2878d11 100644 --- a/pkgs/core/pomona/src/Makefile.inc +++ b/pkgs/core/pomona/src/Makefile.inc @@ -18,11 +18,6 @@ # # ###############################################################################
-## Name of this program -# -PNAME = Pomona -PSNAME = pomona - DESTDIR=$(INSTALLER_DIR)
INSTALL = install -c @@ -30,7 +25,7 @@ INSTALL_PROGRAM = ${INSTALL} INSTALL_DATA = ${INSTALL} -m 644 INSTALLNLSDIR = $(DESTDIR)/usr/share/locale
-PYTHONLIBDIR = $(DESTDIR)/usr/lib/$(PSNAME) +PYTHONLIBDIR = $(DESTDIR)/usr/lib/pomona PYTHONINCLUDE= /usr/include/python2.6/
CC = $(CROSS)gcc diff --git a/pkgs/core/pomona/src/autopart.py b/pkgs/core/pomona/src/autopart.py deleted file mode 100644 index 0dcb89e..0000000 --- a/pkgs/core/pomona/src/autopart.py +++ /dev/null @@ -1,1609 +0,0 @@ -# -# autopart.py - auto partitioning logic -# -# Copyright (C) 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): Jeremy Katz katzj@redhat.com -# - -import parted -import copy -import string, sys -import fsset -import lvm -import logging -from pomona_log import logger, logFile -import cryptodev -import partedUtils -import partRequests -from constants import * -from errors import * - -import iutil -import isys - -log = logging.getLogger("pomona") - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - - -PARTITION_FAIL = -1 -PARTITION_SUCCESS = 0 - -BOOT_NOT_EXT2 = -1 -BOOTEFI_NOT_VFAT = -2 -BOOTALPHA_NOT_BSD = -3 -BOOTALPHA_NO_RESERVED_SPACE = -4 -BOOTIPSERIES_TOO_HIGH = -5 - -DEBUG_LVM_GROW = 0 - -# Add another logger for the LVM debugging, since there's a lot of that. -# Set DEBUG_LVM_GROW if you want to spew all this information to the log -# file. Otherwise it'll get ignored. -logger.addLogger ("pomona.lvm", minLevel=logging.DEBUG) -lvmLog = logging.getLogger("pomona.lvm") - -if DEBUG_LVM_GROW: - logger.addFileHandler (logFile, lvmLog, minLevel=logging.DEBUG) -else: - lvmLog.setLevel (logging.CRITICAL) - logger.addFileHandler (logFile, lvmLog, minLevel=logging.CRITICAL) - -# check that our "boot" partitions meet necessary constraints unless -# the request has its ignore flag set -def bootRequestCheck(req, diskset): - if not req.device or req.ignoreBootConstraints: - return PARTITION_SUCCESS - part = partedUtils.get_partition_by_name(diskset.disks, req.device) - if not part: - return PARTITION_SUCCESS - - return PARTITION_SUCCESS - -# Alpha requires a BSD partition to boot. Since we can be called after: -# -# - We re-attached an existing /boot partition (existing dev.drive) -# - We create a new one from a designated disk (no dev.drive) -# - We auto-create a new one from a designated set of disks (dev.drive -# is a list) -# -# it's simpler to get disk the partition belong to through dev.device -# Some other tests pertaining to a partition where /boot resides are: -# -# - There has to be at least 1 MB free at the begining of the disk -# (or so says the aboot manual.) - -def bootAlphaCheckRequirements(part): - disk = part.disk - - # Disklabel check - if not disk.type.name == "bsd": - return BOOTALPHA_NOT_BSD - - # The first free space should start at the begining of the drive - # and span for a megabyte or more. - free = disk.next_partition() - while free: - if free.type & parted.PARTITION_FREESPACE: - break - free = disk.next_partition(free) - if (not free or free.geom.start != 1L or - partedUtils.getPartSizeMB(free) < 1): - return BOOTALPHA_NO_RESERVED_SPACE - - return PARTITION_SUCCESS - - -def printNewRequestsCyl(diskset, newRequest): - for req in newRequest.requests: - if req.type != REQUEST_NEW: - continue - - part = partedUtils.get_partition_by_name(diskset.disks, req.device) -## print(req) -## print("Start Cyl:%s End Cyl: %s" % (partedUtils.start_sector_to_cyl(part.geom.dev, part.geom.start), -## partedUtils.end_sector_to_cyl(part.geom.dev, part.geom.end))) - -def printFreespaceitem(part): - return partedUtils.get_partition_name(part), part.geom.start, part.geom.end, partedUtils.getPartSizeMB(part) - -def printFreespace(free): - print("Free Space Summary:") - for drive in free.keys(): - print("On drive ", drive) - for part in free[drive]: - print("Freespace:", printFreespaceitem(part)) - - -def findFreespace(diskset): - free = {} - for drive in diskset.disks.keys(): - disk = diskset.disks[drive] - free[drive] = [] - part = disk.next_partition() - while part: - if part.type & parted.PARTITION_FREESPACE: - free[drive].append(part) - part = disk.next_partition(part) - return free - - -def bestPartType(disk, request): - numPrimary = len(partedUtils.get_primary_partitions(disk)) - maxPrimary = disk.max_primary_partition_count - if numPrimary == maxPrimary: - raise PartitioningError, "Unable to create additional primary partitions on /dev/%s" % (disk.dev.path[5:]) - if request.primary: - return parted.PARTITION_PRIMARY - if ((numPrimary == (maxPrimary - 1)) and - not disk.extended_partition and - disk.type.check_feature(parted.DISK_TYPE_EXTENDED)): - return parted.PARTITION_EXTENDED - return parted.PARTITION_PRIMARY - -class partlist: - def __init__(self): - self.parts = [] - - def __str__(self): - retval = "" - for p in self.parts: - retval = retval + "\t%s %s %s\n" % (partedUtils.get_partition_name(p), partedUtils.get_partition_file_system_type(p), partedUtils.getPartSizeMB(p)) - - return retval - - def reset(self): - dellist = [] - for part in self.parts: - dellist.append(part) - - for part in dellist: - self.parts.remove(part) - del part - - self.parts = [] - -def getMinimumSector(disk): - if disk.type.name == 'sun': - start = long(disk.dev.sectors * disk.dev.heads) - start /= long(1024 / disk.dev.sector_size) - return start + 1 - return 0L - -# first step of partitioning voodoo -# partitions with a specific start and end cylinder requested are -# placed where they were asked to go -def fitConstrained(diskset, requests, primOnly=0, newParts = None): - for request in requests.requests: - if request.type != REQUEST_NEW: - continue - if request.device: - continue - if primOnly and not request.primary and not requests.isBootable(request): - continue - if request.drive and (request.start != None): - if not request.end and not request.size: - raise PartitioningError, "Tried to create constrained partition without size or end" - - fsType = request.fstype.getPartedFileSystemType() - disk = diskset.disks[request.drive[0]] - if not disk: # this shouldn't happen - raise PartitioningError, "Selected to put partition on non-existent disk!" - - startSec = partedUtils.start_cyl_to_sector(disk.dev, request.start) - - if request.end: - endCyl = request.end - elif request.size: - endCyl = partedUtils.end_sector_to_cyl(disk.dev, ((1024L * 1024L * request.size) / disk.dev.sector_size) + startSec) - - endSec = partedUtils.end_cyl_to_sector(disk.dev, endCyl) - - if endSec > disk.dev.length: - raise PartitioningError, "Unable to create partition which extends beyond the end of the disk." - - # XXX need to check overlaps properly here - minSec = getMinimumSector(disk) - if startSec < minSec: - startSec = minSec - - if disk.type.check_feature(parted.DISK_TYPE_EXTENDED) and disk.extended_partition: - - if (disk.extended_partition.geom.start < startSec) and (disk.extended_partition.geom.end >= endSec): - partType = parted.PARTITION_LOGICAL - if request.primary: # they've required a primary and we can't do it - raise PartitioningError, "Cannot create another primary partition for %s." % request.mountpoint - # check to make sure we can still create more logical parts - if (len(partedUtils.get_logical_partitions(disk)) == - partedUtils.get_max_logical_partitions(disk)): - raise PartitioningError, "Cannot create another logical partition for %s." % request.mountpoint - else: - partType = parted.PARTITION_PRIMARY - else: - # XXX need a better way to do primary vs logical stuff - ret = bestPartType(disk, request) - - if ret == parted.PARTITION_PRIMARY: - partType = parted.PARTITION_PRIMARY - elif ret == parted.PARTITION_EXTENDED: - newp = disk.partition_new(parted.PARTITION_EXTENDED, None, startSec, endSec) - constraint = disk.dev.constraint_any() - disk.add_partition(newp, constraint) - disk.maximize_partition (newp, constraint) - newParts.parts.append(newp) - requests.nextUniqueID = requests.nextUniqueID + 1 - partType = parted.PARTITION_LOGICAL - else: # shouldn't get here - raise PartitioningError, "Impossible partition type to create" - newp = disk.partition_new (partType, fsType, startSec, endSec) - constraint = disk.dev.constraint_any () - try: - disk.add_partition (newp, constraint) - - except parted.error, msg: - raise PartitioningError, str(msg) - for flag in request.fstype.getPartedPartitionFlags(): - if not newp.is_flag_available(flag): - disk.delete_partition(newp) - raise PartitioningError, ("requested FileSystemType needs " - "a flag that is not available.") - newp.set_flag(flag, 1) - request.device = fsset.PartedPartitionDevice(newp).getDevice() - request.currentDrive = request.drive[0] - newParts.parts.append(newp) - -# get the list of the "best" drives to try to use... -# if currentdrive is set, use that, else use the drive list, or use -# all the drives -def getDriveList(request, diskset): - if request.currentDrive: - drives = request.currentDrive - elif request.drive: - drives = request.drive - else: - drives = diskset.disks.keys() - - if not type(drives) == type([]): - drives = [ drives ] - - drives.sort(isys.compareDrives) - - return drives - - -# fit partitions of a specific size with or without a specific disk -# into the freespace -def fitSized(diskset, requests, primOnly = 0, newParts = None): - todo = {} - - for request in requests.requests: - if request.type != REQUEST_NEW: - continue - if request.device: - continue - if primOnly and not request.primary and not requests.isBootable(request): - continue - if request.size == 0 and request.requestSize == 0: - request.requestSize = 1 - if requests.isBootable(request): - drives = getDriveList(request, diskset) - numDrives = 0 # allocate bootable requests first - else: - drives = getDriveList(request, diskset) - numDrives = len(drives) - if not todo.has_key(numDrives): - todo[numDrives] = [ request ] - else: - todo[numDrives].append(request) - - number = todo.keys() - number.sort() - free = findFreespace(diskset) - - for num in number: - for request in todo[num]: -# print("\nInserting ->", request) - if requests.isBootable(request): - isBoot = 1 - else: - isBoot = 0 - - largestPart = (0, None) - drives = getDriveList(request, diskset) - lvmLog.debug("Trying drives to find best free space out of %s" %(free,)) - for drive in drives: - # this request is bootable and we've found a large enough - # partition already, so we don't need to keep trying other - # drives. this keeps us on the first possible drive - if isBoot and largestPart[1]: - break -## print("Trying drive", drive) - disk = diskset.disks[drive] - numPrimary = len(partedUtils.get_primary_partitions(disk)) - numLogical = len(partedUtils.get_logical_partitions(disk)) - - # if there is an extended partition add it in - if disk.extended_partition: - numPrimary = numPrimary + 1 - - maxPrimary = disk.max_primary_partition_count - maxLogical = partedUtils.get_max_logical_partitions(disk) - - for part in free[drive]: - # if this is a free space outside extended partition - # make sure we have free primary partition slots - if not part.type & parted.PARTITION_LOGICAL: - if numPrimary == maxPrimary: - continue - else: - if numLogical == maxLogical: - continue - - lvmLog.debug( "Trying partition %s" % (printFreespaceitem(part),)) - partSize = partedUtils.getPartSizeMB(part) - # figure out what the request size will be given the - # geometry (#130885) - requestSectors = long((request.requestSize * 1024L * 1024L) / part.disk.dev.sector_size) - 1 - requestSizeMB = long((requestSectors * part.disk.dev.sector_size) / 1024L / 1024L) - lvmLog.debug("partSize %s request %s" % (partSize, request.requestSize)) - if partSize >= requestSizeMB and partSize > largestPart[0]: - if not request.primary or (not part.type & parted.PARTITION_LOGICAL): - largestPart = (partSize, part) - if isBoot: - break - - if not largestPart[1]: - # if the request has a size of zero, it can be allowed to not - # exist without any problems - if request.size > 0: - raise PartitioningError, "Not enough space left to create partition for %s" % request.mountpoint - else: - request.device = None - request.currentDrive = None - continue -# raise PartitioningError, "Can't fulfill request for partition: \n%s" %(request) - - lvmLog.debug("largestPart is %s" % (largestPart,)) - freespace = largestPart[1] - freeStartSec = freespace.geom.start - freeEndSec = freespace.geom.end - - dev = freespace.geom.dev - disk = freespace.disk - - startSec = freeStartSec - - endSec = startSec + long(((request.requestSize * 1024L * 1024L) / disk.dev.sector_size)) - 1 - - if endSec > freeEndSec: - endSec = freeEndSec - if startSec < freeStartSec: - startSec = freeStartSec - - if freespace.type & parted.PARTITION_LOGICAL: - partType = parted.PARTITION_LOGICAL - else: - # XXX need a better way to do primary vs logical stuff - ret = bestPartType(disk, request) - - if ret == parted.PARTITION_PRIMARY: - partType = parted.PARTITION_PRIMARY - elif ret == parted.PARTITION_EXTENDED: - newp = disk.partition_new(parted.PARTITION_EXTENDED, None, startSec, endSec) - constraint = dev.constraint_any() - disk.add_partition(newp, constraint) - disk.maximize_partition (newp, constraint) - newParts.parts.append(newp) - requests.nextUniqueID = requests.nextUniqueID + 1 - partType = parted.PARTITION_LOGICAL - - # now need to update freespace since adding extended - # took some space - found = 0 - part = disk.next_partition() - while part: - if part.type & parted.PARTITION_FREESPACE: - if part.geom.start > freeStartSec and part.geom.end <= freeEndSec: - found = 1 - freeStartSec = part.geom.start - freeEndSec = part.geom.end - break - - part = disk.next_partition(part) - - if not found: - raise PartitioningError, "Could not find free space after making new extended partition" - - startSec = freeStartSec - endSec = startSec + long(((request.requestSize * 1024L * 1024L) / disk.dev.sector_size)) - 1 - - if endSec > freeEndSec: - endSec = freeEndSec - if startSec < freeStartSec: - startSec = freeStartSec - - else: # shouldn't get here - raise PartitioningError, "Impossible partition to create" - - fsType = request.fstype.getPartedFileSystemType() - lvmLog.debug("creating newp with start=%s, end=%s, len=%s" % (startSec, endSec, endSec - startSec)) - newp = disk.partition_new (partType, fsType, startSec, endSec) - constraint = dev.constraint_any () - - try: - disk.add_partition (newp, constraint) - except parted.error, msg: - raise PartitioningError, str(msg) - for flag in request.fstype.getPartedPartitionFlags(): - if not newp.is_flag_available(flag): - disk.delete_partition(newp) - raise PartitioningError, ("requested FileSystemType needs " - "a flag that is not available.") - newp.set_flag(flag, 1) - - request.device = fsset.PartedPartitionDevice(newp).getDevice() - drive = newp.geom.dev.path[5:] - request.currentDrive = drive - newParts.parts.append(newp) - free = findFreespace(diskset) - -# grow logical partitions -# -# do this ONLY after all other requests have been allocated -# we just go through and adjust the size for the logical -# volumes w/o rerunning process partitions -# -def growLogicalVolumes(diskset, requests): - - if requests is None or diskset is None: - return - - # iterate over each volume group, grow logical volumes in each - for vgreq in requests.requests: - if vgreq.type != REQUEST_VG: - continue - - lvmLog.info("In growLogicalVolumes, considering VG %s", vgreq) - lvreqs = requests.getLVMLVForVG(vgreq) - - if lvreqs is None or len(lvreqs) < 1: - lvmLog.info("Apparently it had no logical volume requests, skipping.") - continue - - # come up with list of logvol that are growable - growreqs = [] - for lvreq in lvreqs: - if lvreq.grow: - growreqs.append(lvreq) - - # bail if none defined - if len(growreqs) < 1: - lvmLog.info("No growable logical volumes defined in VG %s.", vgreq) - continue - - lvmLog.info("VG %s has these growable logical volumes: %s", vgreq.volumeGroupName, reduce(lambda x,y: x + [y.uniqueID], growreqs, [])) - - # get remaining free space - if DEBUG_LVM_GROW: - vgfree = lvm.getVGFreeSpace(vgreq, requests, diskset) - lvmLog.debug("Free space in VG after initial partition formation = %s", (vgfree,)) - - # store size we are starting at - initsize = {} - cursize = {} - for req in growreqs: - size = req.getActualSize(requests, diskset) - size = lvm.clampPVSize(size, vgreq.pesize) - initsize[req.logicalVolumeName] = size - cursize[req.logicalVolumeName] = size - if req.maxSizeMB: - req.maxSizeMB = lvm.clampPVSize(req.maxSizeMB, vgreq.pesize) - lvmLog.debug("init sizes for %s: %s",req.logicalVolumeName, size) - - # now dolly out free space to all growing LVs - bailcount = 0 - while 1: - nochange = 1 - completed = [] - for req in growreqs: - lvmLog.debug("considering %s, start size = %s",req.logicalVolumeName, req.getStartSize()) - - # get remaining free space - vgfree = lvm.getVGFreeSpace(vgreq, requests, diskset) - - lvmLog.debug("Free space in VG = %s",vgfree) - - # compute fraction of remaining requests this - # particular request represents - totsize = 0.0 - for otherreq in growreqs: - if otherreq in completed: - continue - - lvmLog.debug("adding in %s %s %s", otherreq.logicalVolumeName, otherreq.getStartSize(), otherreq.maxSizeMB) - - size = otherreq.getActualSize(requests, diskset) - if otherreq.maxSizeMB: - if size < otherreq.maxSizeMB: - totsize = totsize + otherreq.getStartSize() - else: - lvmLog.debug("%s is now at %s, and passed maxsize of %s", otherreq.logicalVolumeName, size, otherreq.maxSizeMB) - else: - totsize = totsize + otherreq.getStartSize() - - lvmLog.debug("totsize -> %s",totsize) - - # if totsize is zero we have no growable reqs left - if totsize == 0: - break - - fraction = float(req.getStartSize())/float(totsize) - - newsize = lvm.clampPVSize(vgfree*fraction, vgreq.pesize) - newsize += cursize[req.logicalVolumeName] - - if req.maxSizeMB: - newsize = min(newsize, req.maxSizeMB) - - req.size = newsize - if req.size != cursize[req.logicalVolumeName]: - nochange = 0 - - cursize[req.logicalVolumeName] = req.size - - lvmLog.debug("Name, size, cursize, vgfree, fraction = %s %s %s %s %s", req.logicalVolumeName, req.size, cursize[req.logicalVolumeName], vgfree, fraction) - - completed.append(req) - - if nochange: - lvmLog.info("In growLogicalVolumes, no changes in size so breaking") - break - - bailcount = bailcount + 1 - if bailcount > 10: - lvmLog.info("In growLogicalVolumes, bailing after 10 interations.") - break - -# grow partitions -def growParts(diskset, requests, newParts): - - # returns free space segments for each drive IN SECTORS - def getFreeSpace(diskset): - free = findFreespace(diskset) - freeSize = {} - largestFree = {} - - # find out the amount of free space on each drive - for key in free.keys(): - if len(free[key]) == 0: - del free[key] - continue - freeSize[key] = 0 - largestFree[key] = 0 - for part in free[key]: - sz = partedUtils.getPartSize(part) - freeSize[key] += sz - if sz > largestFree[key]: - largestFree[key] = sz - - return (free, freeSize, largestFree) - - #### - # start of growParts - #### - newRequest = requests.copy() - -## print("new requests") -## printNewRequestsCyl(diskset, requests) -## print("orig requests") -## printNewRequestsCyl(diskset, newRequest) -## print("\n\n\n") - - (free, freeSize, largestFree) = getFreeSpace(diskset) - - # find growable partitions - growable = {} - growSize = {} - origSize = {} - for request in newRequest.requests: - if request.type != REQUEST_NEW or not request.grow: - continue - - origSize[request.uniqueID] = request.requestSize - if not growable.has_key(request.currentDrive): - growable[request.currentDrive] = [ request ] - else: - growable[request.currentDrive].append(request) - - # there aren't any drives with growable partitions, this is easy! - if not growable.keys(): - return - -## print("new requests before looping") -## printNewRequestsCyl(diskset, requests) -## print("\n\n\n") - - # loop over all drives, grow all growable partitions one at a time - grownList = [] - for drive in growable.keys(): - # no free space on this drive, so can't grow any of its parts - if not free.has_key(drive): - continue - - # process each request - # grow all growable partitions on this drive until all can grow no more - donegrowing = 0 - outer_iter = 0 - lastFreeSize = None - while not donegrowing and outer_iter < 20: - # if less than one sector left, we're done -# if drive not in freeSize.keys() or freeSize[drive] == lastFreeSize: - if drive not in freeSize.keys(): -# print("leaving outer loop because no more space on %s\n\n" % drive) - break -## print("\nAt start:") -## print(drive,freeSize.keys()) -## print(freeSize[drive], lastFreeSize) -## print("\n") - -## print(diskset.diskState()) - - - outer_iter = outer_iter + 1 - donegrowing = 1 - - # pull out list of requests we want to grow on this drive - growList = growable[drive] - - sector_size = diskset.disks[drive].dev.sector_size - cylsectors = diskset.disks[drive].dev.sectors*diskset.disks[drive].dev.heads - - # sort in order of request size, consider biggest first - n = 0 - while n < len(growList): - for request in growList: - if request.size < growList[n].size: - tmp = growList[n] - index = growList.index(request) - growList[n] = request - growList[index] = tmp - n = n + 1 - - # recalculate the total size of growable requests for this drive - # NOTE - we add up the ORIGINAL requested sizes, not grown sizes - growSize[drive] = 0 - for request in growList: - if request.uniqueID in grownList: - continue - growSize[drive] = growSize[drive] + origSize[request.uniqueID] - - thisFreeSize = getFreeSpace(diskset)[1] - # loop over requests for this drive - for request in growList: - # skip if we've finished growing this request - if request.uniqueID in grownList: - continue - - if drive not in freeSize.keys(): - donegrowing = 1 -# print("leaving inner loop because no more space on %s\n\n" % drive) - break - -## print("\nprocessing ID",request.uniqueID, request.mountpoint) -## print("growSize, freeSize = ",growSize[drive], freeSize[drive]) - - donegrowing = 0 - - # get amount of space actually used by current allocation - part = partedUtils.get_partition_by_name(diskset.disks, request.device) - startSize = partedUtils.getPartSize(part) - - # compute fraction of freespace which to give to this - # request. Weight by original request size - percent = origSize[request.uniqueID] / (growSize[drive] * 1.0) - growby = long(percent * thisFreeSize[drive]) - if growby < cylsectors: - growby = cylsectors; - maxsect = startSize + growby - -## print(request) -## print("percent, growby, maxsect, free", percent, growby, maxsect,freeSize[drive], startSize, lastFreeSize) -## print("max is ", maxsect) - - imposedMax = 0 - if request.maxSizeMB: - # round down a cylinder, see comment below - tmpint = request.maxSizeMB*1024.0*1024.0/sector_size - tmpint = long(tmpint / cylsectors) - maxUserSize = tmpint * cylsectors - if maxsect > maxUserSize: - maxsect = long(maxUserSize) - imposedMax = 1 - - else: - # XXX HACK enforce silent limit for swap otherwise it - # can grow up to 2TB! - if request.fstype.name == "swap": - (xxxint, tmpint) = iutil.swapSuggestion(quiet=1) - - # convert to sectors - tmpint = tmpint*1024*1024/sector_size - tmpint = long(tmpint / cylsectors) - maxsugswap = tmpint * cylsectors - userstartsize = origSize[request.uniqueID]*1024*1024/sector_size - if maxsugswap >= userstartsize: - maxsect = maxsugswap - imposedMax = 1 - lvmLog.warning("Enforced max swap size of %s based on suggested max swap", maxsect) - - - # round max fs limit down a cylinder, helps when growing - # so we don't end up with a free cylinder at end if - # maxlimit fell between cylinder boundaries - tmpint = request.fstype.getMaxSizeMB()*1024.0*1024.0/sector_size - tmpint = long(tmpint / cylsectors) - maxFSSize = tmpint * cylsectors - if maxsect > maxFSSize: - maxsect = long(maxFSSize) - imposedMax = 1 - - maxfree = largestFree[drive] - if maxsect > maxfree + startSize: - maxsect = long(maxfree) + startSize - imposedMax = 1 - -# print("freesize, max, maxfree = ",freeSize[drive],maxsect, maxfree) -# print("freeSizeMB, maxMB = ", freeSize[drive] * sector_size/(1024.0 * 1024.0), maxsect * sector_size/(1024.0*1024.0), largestFree[drive] * sector_size/(1024.0*1024.0)) -# print("startsize = ", startSize) - - min = startSize - max = maxsect - diff = max - min - cur = max - (diff / 2) - lastDiff = 0 - - # binary search -## print("start min, max, cur, diffs = ",min,max,cur,diff,lastDiff) - inner_iter = 0 - ret = PARTITION_SUCCESS # request succeeded with initial size - while (max != min) and (lastDiff != diff) and (inner_iter < 2000): -## printNewRequestsCyl(diskset, newRequest) - - # XXX need to request in sectors preferably, more accurate -## print("trying cur=%s" % cur) - request.requestSize = (cur*sector_size)/1024.0/1024.0 - - # try adding - try: - processPartitioning(diskset, newRequest, newParts) - min = cur - except PartitioningError, msg: - ret = PARTITION_FAIL - max = cur -## print("!!!!!!!!!!! processPartitioning failed - %s" % msg) - - lastDiff = diff - diff = max - min - -# print(min, max, diff, cylsectors) -# print(diskset.diskState()) - - cur = max - (diff / 2) - - inner_iter = inner_iter + 1 -# print("sizes at end of loop - cur: %s min:%s max:%s diff:%s lastDiff:%s" % (cur,min,max,diff,lastDiff)) - -# freeSize[drive] = freeSize[drive] - (min - startSize) -# print("shrinking freeSize to ",freeSize[drive], lastFreeSize) -# if freeSize[drive] < 0: -# print("freesize < 0!") -# freeSize[drive] = 0 - - # we could have failed on the last try, in which case we - # should go back to the smaller size - if ret == PARTITION_FAIL: -# print("growing finally failed at size", min) - request.requestSize = min*sector_size/1024.0/1024.0 - processPartitioning(diskset, newRequest, newParts) - -# print("end min, max, cur, diffs = ",min,max,cur,diff,lastDiff) -# print("%s took %s loops" % (request.mountpoint, inner_iter)) - lastFreeSize = freeSize[drive] - (free, freeSize, largestFree) = getFreeSpace(diskset) -# print(Freespace(free)) - - if ret == PARTITION_FAIL or (max == maxsect and imposedMax): -# print("putting ",request.uniqueID,request.mountpoint," in grownList") - grownList.append(request.uniqueID) - growSize[drive] = growSize[drive] - origSize[request.uniqueID] - if growSize[drive] < 0: -# print("growsize < 0!") - growSize[drive] = 0 - -def setPreexistParts(diskset, requests): - for request in requests: - if request.type != REQUEST_PREEXIST: - continue - if not diskset.disks.has_key(request.drive): - lvmLog.info("pre-existing partition on non-native disk %s, ignoring" %(request.drive,)) - continue - disk = diskset.disks[request.drive] - part = disk.next_partition() - while part: - if part.geom.start == request.start and part.geom.end == request.end: - if partedUtils.isEfiSystemPartition(part) and \ - request.fstype.name == "vfat": - request.fstype = fsset.fileSystemTypeGet("efi") - # if the partition is being resized, we do that now - if request.targetSize is not None: - startSec = part.geom.start - endSec = part.geom.start + long(((request.targetSize * 1024L * 1024L) / disk.dev.sector_size)) - 1 - - try: - g = part.geom.duplicate() - g.set_end(endSec) - constraint = g.constraint_exact() - part.set_geometry(constraint, startSec, endSec) - except parted.error, msg: - log.error("error setting geometry for partition %s: %s" %(partedUtils.get_partition_name(part), msg)) - raise PartitioningError, _("Error resizing partition %s.\n\n%s") %(partedUtils.get_partition_name(part), msg) - - if startSec != part.geom.start: - raise PartitioningError, _("Start of partition %s was moved when resizing") %(partedUtils.get_partition_name(part),) - - request.device = partedUtils.get_partition_name(part) - if request.fstype: - if request.fstype.getName() != request.origfstype.getName(): - if part.is_flag_available(parted.PARTITION_RAID): - if request.fstype.getName() == "software RAID": - part.set_flag(parted.PARTITION_RAID, 1) - else: - part.set_flag(parted.PARTITION_RAID, 0) - if part.is_flag_available(parted.PARTITION_LVM): - if request.fstype.getName() == "physical volume (LVM)": - part.set_flag(parted.PARTITION_LVM, 1) - else: - part.set_flag(parted.PARTITION_LVM, 0) - - partedUtils.set_partition_file_system_type(part, request.fstype) - - break - part = disk.next_partition(part) - -def deletePart(diskset, delete): - disk = diskset.disks[delete.drive] - part = disk.next_partition() - while part: - if part.geom.start == delete.start and part.geom.end == delete.end: - disk.delete_partition(part) - return - part = disk.next_partition(part) - -def processPartitioning(diskset, requests, newParts): - # collect a hash of all the devices that we have created extended - # partitions on. When we remove these extended partitions the logicals - # (all of which we created) will be destroyed along with it. - extendeds = {} - - for part in newParts.parts: - if part.type == parted.PARTITION_EXTENDED: - extendeds[part.geom.dev.path] = None - - # Go through the list again and check for each logical partition we have. - # If we created the extended partition on the same device as the logical - # partition, remove it from out list, as it will be cleaned up for us - # when the extended partition gets removed. - dellist = [] - for part in newParts.parts: - if (part.type & parted.PARTITION_LOGICAL - and extendeds.has_key(part.geom.dev.path)): - dellist.append(part) - - for part in dellist: - newParts.parts.remove(part) - - # Finally, remove all of the partitions we added in the last try from - # the disks. We'll start again from there. - for part in newParts.parts: - part.disk.delete_partition(part) - - newParts.reset() - - for request in requests.requests: - if request.type == REQUEST_NEW: - request.device = None - - setPreexistParts(diskset, requests.requests) - - # sort requests by size - requests.sortRequests() - - # partitioning algorithm in simplistic terms - # - # we want to allocate partitions such that the most specifically - # spelled out partitions get what they want first in order to ensure - # they don't get preempted. first conflict found returns an error - # which must be handled by the caller by saying that the partition - # add is impossible (XXX can we get an impossible situation after delete?) - # - # potentially confusing terms - # type == primary vs logical - # - # order to allocate: - # start and end cylinders given (note that start + size & !grow is equivalent) - # drive, partnum - # drive, type - # drive - # priority partition (/boot or /) - # size - - # run through with primary only constraints first - try: - fitConstrained(diskset, requests, 1, newParts) - except PartitioningError, msg: - raise PartitioningError, _("Could not allocate cylinder-based partitions as primary partitions.\n") + str(msg) - - try: - fitSized(diskset, requests, 1, newParts) - except PartitioningError, msg: - raise PartitioningError, _("Could not allocate partitions as primary partitions.\n") + str(msg) - - try: - fitConstrained(diskset, requests, 0, newParts) - except PartitioningError, msg: - raise PartitioningError, _("Could not allocate cylinder-based partitions.\n") + str(msg) - - # Don't need to handle the exception here since we leave the message alone. - fitSized(diskset, requests, 0, newParts) - - for request in requests.requests: - # set the unique identifier for raid and lvm devices - if request.type == REQUEST_RAID and not request.device: - request.device = str(request.uniqueID) - if request.type == REQUEST_VG and not request.device: - request.device = str(request.uniqueID) - # anything better we can use for the logical volume? - if request.type == REQUEST_LV and not request.device: - request.device = str(request.uniqueID) - - if not request.device: - raise PartitioningError, "Unsatisfied partition request\n%s" % request - - # get the sizes for raid devices, vgs, and logical volumes - for request in requests.requests: - if request.type == REQUEST_RAID: - request.size = request.getActualSize(requests, diskset) - elif request.type == REQUEST_VG: - request.size = request.getActualSize(requests, diskset) - elif request.type == REQUEST_LV: - if request.grow: - request.setSize(request.getStartSize()) - else: - request.size = request.getActualSize(requests, diskset) - elif request.preexist: - # we need to keep track of the max size of preexisting partitions - # FIXME: we should also get the max size for LVs at some point - part = partedUtils.get_partition_by_name(diskset.disks, request.device) - request.maxResizeSize = partedUtils.getMaxAvailPartSizeMB(part) - -## print("disk layout after everything is done") -## print(diskset.diskState()) - -def doPartitioning(diskset, requests, doRefresh = 1): - for request in requests.requests: - request.requestSize = request.size - request.currentDrive = None - - if doRefresh: - diskset.refreshDevices() - # XXX - handle delete requests - for delete in requests.deletes: - if isinstance(delete, partRequests.DeleteSpec): - deletePart(diskset, delete) - # FIXME: do we need to do anything with other types of deletes?? - - newParts = partlist() - - try: - processPartitioning(diskset, requests, newParts) - except PartitioningError, msg: - raise PartitioningError, "Partitioning failed: %s" % msg - - growParts(diskset, requests, newParts) - - newParts.reset() - - for req in requests.getBootableRequest() or []: - ret = bootRequestCheck(req, diskset) - if ret == BOOTALPHA_NOT_BSD: - raise PartitioningWarning, _("Boot partition %s doesn't belong to a BSD disk label. SRM won't be able to boot from this partition. Use a partition belonging to a BSD disk label or change this device disk label to BSD.") %(req.mountpoint,) - elif ret == BOOTALPHA_NO_RESERVED_SPACE: - raise PartitioningWarning, _("Boot partition %s doesn't belong to a disk with enough free space at its beginning for the bootloader to live on. Make sure that there's at least 5MB of free space at the beginning of the disk that contains /boot") %(req.mountpoint,) - elif ret == BOOTEFI_NOT_VFAT: - raise PartitioningError, _("Boot partition %s isn't a VFAT partition. EFI won't be able to boot from this partition.") %(req.mountpoint,) - elif ret == BOOTIPSERIES_TOO_HIGH: - raise PartitioningError, _("The boot partition must entirely be in the first 4GB of the disk. OpenFirmware won't be able to boot this installation.") - elif req == BOOT_NOT_EXT2: - raise PartitioningError, _("Boot partition %s is not a Linux filesystem, such as ext3. The system won't be able to boot from this partition.") %(req.mountpoint,) - elif ret != PARTITION_SUCCESS: - # more specific message? - raise PartitioningWarning, _("Boot partition %s may not meet booting constraints for your architecture.") %(req.mountpoint,) - - # now grow the logical partitions - growLogicalVolumes(diskset, requests) - - # make sure our logical volumes still fit - # - # XXXX should make all this used lvm.getVGFreeSpace() and - # lvm.getVGUsedSpace() at some point - # - - vgused = {} - for request in requests.requests: - if request.type == REQUEST_LV: - size = int(request.getActualSize(requests, diskset, True)) - if vgused.has_key(request.volumeGroup): - vgused[request.volumeGroup] = (vgused[request.volumeGroup] + - size) - else: - vgused[request.volumeGroup] = size - - for vg in vgused.keys(): - request = requests.getRequestByID(vg) - lvmLog.info("Used size vs. available for vg %s: %s %s", request.volumeGroupName, vgused[vg], request.getActualSize(requests, diskset)) - if vgused[vg] > request.getActualSize(requests, diskset): - raise PartitioningError, _("Adding this partition would not " - "leave enough disk space for already " - "allocated logical volumes in " - "%s." % (request.volumeGroupName)) - -# given clearpart specification execute it -# probably want to reset diskset and partition request lists before calling -# this the first time -def doClearPartAction(pomona, partitions, diskset): - type = partitions.autoClearPartType - cleardrives = partitions.autoClearPartDrives - initAll = partitions.reinitializeDisks - - if type == CLEARPART_TYPE_ALL: - linuxOnly = 0 - elif type == CLEARPART_TYPE_NONE: - return - else: - raise ValueError, "Invalid clear part type in doClearPartAction" - - drives = diskset.disks.keys() - drives.sort() - - for drive in drives: - # skip drives not in clear drive list - if (cleardrives and len(cleardrives) > 0 and not drive in cleardrives) or \ - drive in diskset.skippedDisks: - continue - disk = diskset.disks[drive] - part = disk.next_partition() - while part: - if (not part.is_active() or (part.type == parted.PARTITION_EXTENDED) or - (part.disk.type.name == "mac" and part.num == 1 and part.get_name() == "Apple")): - part = disk.next_partition(part) - continue - if part.fs_type: - ptype = partedUtils.get_partition_file_system_type(part) - else: - ptype = None - # we want to do the clearing if - # 1) clearAll is set - # 2) there's a fsystem on the partition and it's a "native" fs - # 3) there's not fsystem but the numeric id of partition is native - # 4) the ptable doesn't support numeric ids, but it appears to be - # a RAID or LVM device (#107319) - # 5) the drive contains protected partitions and initAll is set - if ((linuxOnly == 0) or (ptype and ptype.isLinuxNativeFS()) or - (initAll and - partedUtils.hasProtectedPartitions(drive, pomona)) or - (not ptype and - partedUtils.isLinuxNativeByNumtype(part.native_type)) or - ((part.native_type == -1) and # the ptable doesn't have types - ((part.is_flag_available(parted.PARTITION_RAID) and part.get_flag(parted.PARTITION_RAID)) or # this is a RAID - (part.is_flag_available(parted.PARTITION_LVM) and part.get_flag(parted.PARTITION_LVM)) # or an LVM - ))): - old = partitions.getRequestByDeviceName(partedUtils.get_partition_name(part)) - if old.getProtected(): - part = disk.next_partition(part) - continue - - partitions.deleteDependentRequests(old) - partitions.removeRequest(old) - - drive = partedUtils.get_partition_drive(part) - delete = partRequests.DeleteSpec(drive, part.geom.start, - part.geom.end) - partitions.addDelete(delete) - - part = disk.next_partition(part) - - # set the diskset up - try: - doPartitioning(diskset, partitions, doRefresh = 1) - except PartitioningError: # if we get an error here, it isn't overly relevant - pass - - for drive in drives: - if (cleardrives and len(cleardrives) > 0 and not drive in cleardrives) or \ - drive in diskset.skippedDisks: - continue - - disk = diskset.disks[drive] - ext = disk.extended_partition - # if the extended is empty, blow it away - if ext and len(partedUtils.get_logical_partitions(disk)) == 0: - delete = partRequests.DeleteSpec(drive, ext.geom.start, - ext.geom.end) - old = partitions.getRequestByDeviceName(partedUtils.get_partition_name(ext)) - partitions.removeRequest(old) - partitions.addDelete(delete) - deletePart(diskset, delete) - continue - -def doAutoPartition(pomona): - diskset = pomona.id.diskset - partitions = pomona.id.partitions - - if pomona.dir == DISPATCH_BACK: - diskset.refreshDevices() - partitions.setFromDisk(diskset) - partitions.setProtected(pomona.dispatch) - partitions.autoPartitionRequests = [] - return - - # if no auto partition info in instclass we bail - if len(partitions.autoPartitionRequests) < 1: - #return DISPATCH_NOOP - # XXX if we noop, then we fail later steps... let's just make it - # the workstation default. should instead just never get here - # if no autopart info - pomona.setDefaultPartitioning(partitions, doClear = 0) - - # reset drive and request info to original state - # XXX only do this if we're dirty -## id.diskset.refreshDevices() -## id.partrequests = PartitionRequests(id.diskset) - doClearPartAction(pomona, partitions, diskset) - - # XXX clearpartdrives is overloaded as drives we want to use for linux - drives = [] - initial_free = findFreespace(diskset) - initial_free_keys = initial_free.keys() - - if partitions.autoClearPartDrives: - for drive in filter (lambda d: d in initial_free_keys, partitions.autoClearPartDrives): - free = 0 - for f in initial_free[drive]: - size = f.geom.end - f.geom.start - # don't count any partition smaller than 1M - if (size > 2048): - free += size - for req in partitions.deletes: - if isinstance(req, partRequests.DeleteSpec) and req.drive == drive: - size = req.end - req.start - # don't count any partition smaller than 1M - if (size > 2048): - free += size - - # If there's less than 10M free, forget it. - if free > 20480: - drives.append(drive) - del initial_free - - for request in partitions.autoPartitionRequests: - if (isinstance(request, partRequests.PartitionSpec) and - request.device): - # get the preexisting partition they want to use - req = partitions.getRequestByDeviceName(request.device) - if not req or not req.type or req.type != REQUEST_PREEXIST: - pomona.intf.messageWindow(_("Requested Partition Does Not Exist"), - _("Unable to locate partition %s to use " - "for %s.\n\n" - "Press 'OK' to exit the installer.") - % (request.device, request.mountpoint), - custom_icon='error') - sys.exit(0) - - # now go through and set things from the request to the - # preexisting partition's request... ladeda - if request.mountpoint: - req.mountpoint = request.mountpoint - if request.uniqueID: # for raid to work - req.uniqueID = request.uniqueID - if request.fsopts: - req.fsopts = request.fsopts - if not request.format: - req.format = 0 - else: - req.format = 1 - req.fstype = request.fstype - # XXX whee! lots of cut and paste code lies below - elif (isinstance(request, partRequests.RaidRequestSpec) and - request.preexist == 1): - req = partitions.getRequestByDeviceName(request.device) - if not req or req.preexist == 0: - pomona.intf.messageWindow(_("Requested Raid Device Does Not Exist"), - _("Unable to locate raid device %s to use " - "for %s.\n\n" - "Press 'OK' to exit the installer.") - % (request.device, - request.mountpoint), - custom_icon='error') - sys.exit(0) - - # now go through and set things from the request to the - # preexisting partition's request... ladeda - if request.mountpoint: - req.mountpoint = request.mountpoint - if request.uniqueID: # for raid to work - req.uniqueID = request.uniqueID - if request.fsopts: - req.fsopts = request.fsopts - if not request.format: - req.format = 0 - else: - req.format = 1 - req.fstype = request.fstype - # XXX not copying the raid bits because they should be handled - # automagically (actually, people probably aren't specifying them) - - elif (isinstance(request, partRequests.VolumeGroupRequestSpec) and - request.preexist == 1): - # get the preexisting partition they want to use - req = partitions.getRequestByVolumeGroupName(request.volumeGroupName) - if not req or req.preexist == 0 or req.format == 1: - pomona.intf.messageWindow(_("Requested Volume Group Does Not Exist"), - _("Unable to locate volume group %s to use " - "for %s.\n\n" - "Press 'OK' to exit the installer.") - % (request.volumeGroupName, - request.mountpoint), - custom_icon='error') - sys.exit(0) - - oldid = None - # now go through and set things from the request to the - # preexisting partition's request... ladeda - if request.physicalVolumes: - req.physicalVolumes = request.physicalVolumes - if request.pesize: - req.pesize = request.pesize - if request.uniqueID: # for raid to work - oldid = req.uniqueID - req.uniqueID = request.uniqueID - if request.fsopts: - req.fsopts = request.fsopts - if not request.format: - req.format = 0 - else: - req.format = 1 - - # we also need to go through and remap everything which we - # previously found to our new id. yay! - if oldid is not None: - for lv in partitions.getLVMLVForVGID(oldid): - lv.volumeGroup = req.uniqueID - - - elif (isinstance(request, partRequests.LogicalVolumeRequestSpec) and - request.preexist == 1): - # get the preexisting partition they want to use - req = partitions.getRequestByLogicalVolumeName(request.logicalVolumeName) - if not req or req.preexist == 0: - pomona.intf.messageWindow(_("Requested Logical Volume Does Not Exist"), - _("Unable to locate logical volume %s to use " - "for %s.\n\n" - "Press 'OK' to exit the installer.") - % (request.logicalVolumeName, - request.mountpoint), - custom_icon='error') - sys.exit(0) - - # now go through and set things from the request to the - # preexisting partition's request... ladeda - if request.volumeGroup: - req.volumeGroup = request.volumeGroup - if request.mountpoint: - req.mountpoint = request.mountpoint - if request.uniqueID: # for raid to work - req.uniqueID = request.uniqueID - if request.fsopts: - req.fsopts = request.fsopts - if not request.format: - req.format = 0 - else: - req.format = 1 - req.fstype = request.fstype - else: - req = copy.copy(request) - - if req.type == REQUEST_NEW and not req.drive: - req.drive = drives - - # this is kind of a hack, but if we're doing autopart encryption - # and the request is a PV, encrypt it - if partitions.autoEncrypt and req.type == REQUEST_NEW and \ - isinstance(req.fstype, fsset.lvmPhysicalVolumeDummyFileSystem): - req.encryption = cryptodev.LUKSDevice(passphrase=partitions.encryptionPassphrase, format=1) - - # if this is a multidrive request, we need to create one per drive - if req.type == REQUEST_NEW and req.multidrive: - if not req.drive: - req.drive = diskset.disks.keys() - - for drive in req.drive: - r = copy.copy(req) - r.encryption = copy.deepcopy(req.encryption) - r.drive = [ drive ] - partitions.addRequest(r) - continue - - if (isinstance(req, partRequests.VolumeGroupRequestSpec)): - # if the number of physical volumes requested is zero, then - # add _all_ physical volumes we can find - if ((len(req.physicalVolumes) == 0) - or (not req.physicalVolumes)): - req.physicalVolumes = [] - for r in partitions.requests: - if isinstance(r.fstype, - fsset.lvmPhysicalVolumeDummyFileSystem): - valid = 0 - if ((not partitions.autoClearPartDrives) or - len(partitions.autoClearPartDrives) == 0): - valid = 1 - else: - if not isinstance(r, partRequests.RaidRequestSpec): - for d in r.drive: - if d in partitions.autoClearPartDrives: - valid = 1 - break - - if not isinstance(r, partRequests.RaidRequestSpec): - if not r.multidrive: - valid = 0 - - if valid: - req.physicalVolumes.append(r.uniqueID) - # FIXME: this is a hack so that autopartition'd vgs - # can have a unique name - if req.autoname == 1 and req.volumeGroupName == "lvm": - n = lvm.createSuggestedVGName(partitions, pomona.id.network) - req.volumeGroupName = n - - if (isinstance(req, partRequests.LogicalVolumeRequestSpec)): - # if the volgroup is set to a string, we probably need - # to find that volgroup and use it's id - if type(req.volumeGroup) == type(""): - r = None - if req.volumeGroup == "lvm": - for p in partitions.requests: - if isinstance(p, partRequests.VolumeGroupRequestSpec) and p.autoname == 1: - r = p - break - else: - r = partitions.getRequestByVolumeGroupName(req.volumeGroup) - if r is not None: - req.volumeGroup = r.uniqueID - else: - raise RuntimeError, "Unable to find the volume group for logical volume %s" %(req.logicalVolumeName,) - - partitions.addRequest(req) - - # Remove all preexisting VG requests that reference nonexistant PV - # requests. These VGs should only be present on installs where we're - # using preexisting partitions that already have LVM information. We - # need to do the same thing for preexisting RAID requests, as well. - removeReqs = [] - - for req in partitions.requests: - if isinstance(req, partRequests.VolumeGroupRequestSpec): - lst = req.physicalVolumes - elif isinstance(req, partRequests.RaidRequestSpec): - lst = req.raidmembers - else: - continue - - if len(filter (lambda id: partitions.getRequestByID(id) != None, lst)) == 0: - removeReqs.append(req) - - for req in removeReqs: - partitions.removeRequest(req) - - removeReqs = [] - - # Now that we've removed bad VGs, remove all LVs that would have - # resided on those VGs. - for req in filter (lambda r: isinstance(r, partRequests.LogicalVolumeRequestSpec), partitions.requests): - if partitions.getRequestByID(req.volumeGroup) == None: - removeReqs.append(req) - - for req in removeReqs: - partitions.removeRequest(req) - - # sanity checks for the auto partitioning requests; mostly only useful - # for kickstart as our installclass defaults SHOULD be sane - for req in partitions.requests: - errors = req.sanityCheckRequest(partitions) - if errors: - pomona.intf.messageWindow(_("Automatic Partitioning Errors"), - _("The following errors occurred with your " - "partitioning:\n\n%s\n\n" - "Press 'OK' to exit the installer.") % - (errors,), custom_icon='error') - sys.exit(0) - - try: - doPartitioning(diskset, partitions, doRefresh = 0) - except PartitioningWarning, msg: - pomona.intf.messageWindow(_("Warnings During Automatic Partitioning"), - _("Following warnings occurred during automatic " - "partitioning:\n\n%s") % (msg,), - custom_icon='warning') - except PartitioningError, msg: - # restore drives to original state - diskset.refreshDevices() - partitions.setFromDisk(diskset) - partitions.setProtected(pomona.dispatch) - pomona.dispatch.skipStep("partition", skip = 0) - pomona.intf.messageWindow(_("Error Partitioning"), - _("Could not allocate requested partitions: \n\n" - "%s.") % (msg,), custom_icon='error') - - # now do a full check of the requests - (errors, warnings) = partitions.sanityCheckAllRequests(diskset) - if warnings: - for warning in warnings: - lvmLog.warning(warning) - if errors: - errortxt = string.join(errors, '\n') - extra = _("\n\nPress 'OK' to choose a different partitioning option.") - - pomona.intf.messageWindow(_("Automatic Partitioning Errors"), - _("The following errors occurred with your " - "partitioning:\n\n%s\n\n" - "This can happen if there is not enough " - "space on your hard drive(s) for the " - "installation. %s") - % (errortxt, extra), - custom_icon='error') - return DISPATCH_BACK - -def autoCreatePartitionRequests(autoreq): - """Return a list of requests created with a shorthand notation. - - Mainly used by installclasses; make a list of tuples of the form - (mntpt, fstype, minsize, maxsize, grow, format, asvol) - mntpt = None for non-mountable, otherwise is mount point - fstype = None to use default, otherwise a string - minsize = smallest size - maxsize = max size, or None means no max - grow = 0 or 1, should partition be grown - format = 0 or 1, whether to format - asvol = 0 or 1, whether or not it should be a logical volume (ignored) - """ - - requests = [] - for (mntpt, fstype, minsize, maxsize, grow, format, asvol) in autoreq: - if fstype: - ptype = fsset.fileSystemTypeGet(fstype) - else: - ptype = fsset.fileSystemTypeGetDefault() - - newrequest = partRequests.PartitionSpec(ptype, - mountpoint = mntpt, - size = minsize, - maxSizeMB = maxsize, - grow = grow, - format = format) - - requests.append(newrequest) - - return requests - -def autoCreateLVMPartitionRequests(autoreq): - """Return a list of requests created with a shorthand notation using LVM. - - Mainly used by installclasses; make a list of tuples of the form - (mntpt, fstype, minsize, maxsize, grow, format) - mntpt = None for non-mountable, otherwise is mount point - fstype = None to use default, otherwise a string - minsize = smallest size - maxsize = max size, or None means no max - grow = 0 or 1, should partition be grown - format = 0 or 1, whether to format - asvol = 0 or 1, whether or not it should be a logical volume - """ - - requests = [] - nr = partRequests.PartitionSpec(fsset.fileSystemTypeGet("physical volume (LVM)"), - mountpoint = None, - size = 0, - maxSizeMB = None, - grow = 1, - format = 1, - multidrive = 1) - - requests.append(nr) - nr = partRequests.VolumeGroupRequestSpec(fstype = None, - vgname = "lvm", - physvols = [], - format = 1) - nr.autoname = 1 - requests.append(nr) - - volnum = 0 - for (mntpt, fstype, minsize, maxsize, grow, format, asvol) in autoreq: - if fstype: - ptype = fsset.fileSystemTypeGet(fstype) - else: - ptype = fsset.fileSystemTypeGetDefault() - - if not asvol: - newrequest = partRequests.PartitionSpec(ptype, - mountpoint = mntpt, - size = minsize, - maxSizeMB = maxsize, - grow = grow, - format = format) - else: - newrequest = partRequests.LogicalVolumeRequestSpec(ptype, - mountpoint = mntpt, - size = minsize, - maxSizeMB = maxsize, - grow = grow, - format = format, - lvname = "LogVol%02d" %(volnum,), - volgroup = "lvm") - volnum += 1 - - - requests.append(newrequest) - - return requests - -def getAutopartitionBoot(): - """Return the proper shorthand for the boot dir (arch dependent).""" - return [ ("/boot", None, 200, None, 0, 1, 0) ] - - -# XXX hack but these are common strings to TUI and GUI -PARTMETHOD_TYPE_DESCR_TEXT = N_("Automatic Partitioning sets partitions " - "based on the selected installation type. " - "You also " - "can customize the partitions once they " - "have been created.\n\n" - "The manual disk partitioning tool, Disk Druid, " - "allows you " - "to create partitions in an interactive " - "environment. You can set the file system " - "types, mount points, partition sizes, and more.") - -AUTOPART_DISK_CHOICE_DESCR_TEXT = N_("Before automatic partitioning can be " - "set up by the installation program, you " - "must choose how to use the space on " - "your hard drives.") - -CLEARPART_TYPE_ALL_DESCR_TEXT = N_("Remove all partitions on this system") -CLEARPART_TYPE_LINUX_DESCR_TEXT = N_("Remove all Linux partitions on this system") -CLEARPART_TYPE_NONE_DESCR_TEXT = N_("Keep all partitions and use existing free space") diff --git a/pkgs/core/pomona/src/backend.py b/pkgs/core/pomona/src/backend.py deleted file mode 100644 index 325fbe8..0000000 --- a/pkgs/core/pomona/src/backend.py +++ /dev/null @@ -1,127 +0,0 @@ -# -# backend.py: Interface for installation backends -# -# Paul Nasrat pnasrat@redhat.com -# Jeremy Katz katzj@redhat.com -# -# Copyright (c) 2005 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# general public license. -# -# 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., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -import shutil -import iutil -import os, sys -import logging -from constants import * - -import packages - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -from flags import flags -log = logging.getLogger("pomona") - -class PomonaBackend: - def __init__(self, instPath): - """Abstract backend class all backends should inherit from this - @param instPath: root path for the installation to occur""" - - self.instPath = instPath - self.modeText = "" - - # some backends may have a special case for rootfs formatting - self.skipFormatRoot = False - - def doPreSelection(self, intf, id, instPath): - pass - - def doPostSelection(self, pomona): - pass - - def doPreInstall(self, pomona): - pass - - def doPostInstall(self, pomona): - sys.stdout.flush() - - def doInstall(self, pomona): - log.warning("doInstall not implemented for backend!") - pass - - def postAction(self, pomona): - pass - - def kernelVersionList(self): - return [] - - def doInitialSetup(self, pomona): - pass - - def doRepoSetup(self, pomona): - log.warning("doRepoSetup not implemented for backend!") - pass - - def groupExists(self, group): - log.warning("groupExists not implemented for backend!") - pass - - def selectGroup(self, group, *args): - log.warning("selectGroup not implemented for backend!") - pass - - def deselectGroup(self, group, *args): - log.warning("deselectGroup not implemented for backend!") - pass - - def packageExists(self, pkg): - log.warning("packageExists not implemented for backend!") - pass - - def selectPackage(self, pkg, *args): - log.warning("selectPackage not implemented for backend!") - pass - - def deselectPackage(self, pkg, *args): - log.warning("deselectPackage not implemented for backend!") - pass - - def getDefaultGroups(self, pomona): - log.warning("getDefaultGroups not implemented for backend!") - pass - - def writeConfiguration(self): - log.warning("writeConfig not implemented for backend!") - pass - - def getRequiredMedia(self): - log.warning("getRequiredMedia not implmented for backend!") - pass - -def doRepoSetup(pomona): - pomona.backend.doInitialSetup(pomona) - if pomona.backend.doRepoSetup(pomona) == DISPATCH_BACK: - return DISPATCH_BACK - -def doPostSelection(pomona): - return pomona.backend.doPostSelection(pomona) - -def doPreInstall(pomona): - pomona.backend.doPreInstall(pomona) - -def doPostInstall(pomona): - pomona.backend.doPostInstall(pomona) - -def doInstall(pomona): - pomona.backend.doInstall(pomona) - -def writeConfiguration(pomona): - log.info("Writing main configuration") - pomona.id.write(pomona) - pomona.backend.writeConfiguration() diff --git a/pkgs/core/pomona/src/bootloader.py b/pkgs/core/pomona/src/bootloader.py deleted file mode 100644 index 755b3eb..0000000 --- a/pkgs/core/pomona/src/bootloader.py +++ /dev/null @@ -1,740 +0,0 @@ -# -# bootloader.py: pomona bootloader shims -# -# Erik Troan ewt@redhat.com -# Jeremy Katz katzj@redhat.com -# -# Copyright 2001-2006 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# general public license. -# -# 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., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -import isys -import partedUtils -import os -import sys -import iutil -import string -import crypt -import random -import shutil -import struct -from copy import copy -from flags import flags -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -import logging -log = logging.getLogger("pomona") - -from fsset import * - -import pyfire.executil - -dosFilesystems = ('FAT', 'fat16', 'fat32', 'ntfs', 'hpfs') - -def doesDualBoot(): - return 1 - -def checkForBootBlock(device): - fd = os.open(device, os.O_RDONLY) - buf = os.read(fd, 512) - os.close(fd) - if len(buf) >= 512 and struct.unpack("H", buf[0x1fe: 0x200]) == (0xaa55,): - return True - return False - -# takes a line like #boot=/dev/hda and returns /dev/hda -# also handles cases like quoted versions and other nonsense -def getBootDevString(line): - dev = string.split(line, '=')[1] - dev = string.strip(dev) - dev = string.replace(dev, '"', '') - dev = string.replace(dev, "'", "") - return dev - -# hack and a half -# there's no guarantee that data is written to the disk and grub -# reads both the filesystem and the disk. suck. -def syncDataToDisk(dev, mntpt, instRoot = "/"): - isys.sync() - isys.sync() - isys.sync() - -class BootyNoKernelWarning(Exception): - pass - -class KernelArguments: - - def get(self): - return self.args - - def set(self, args): - self.args = args - - def chandevget(self): - return self.cargs - - def chandevset(self, args): - self.cargs = args - - def append(self, args): - if self.args: - # don't duplicate the addition of an argument (#128492) - if self.args.find(args) != -1: - return - self.args = self.args + " " - self.args = self.args + "%s" % (args,) - - - def __init__(self): - newArgs = [] - # look for kernel arguments we know should be preserved and add them - ourargs = ["speakup_synth=", "apic", "noapic", "apm=", "ide=nodma", - "noht", "acpi=", "video=", "pci="] - f = open("/proc/cmdline") - cmdline = f.read()[:-1] - f.close() - cmdlineargs = cmdline.split(" ") - for arg in cmdlineargs: - for check in ourargs: - if arg.startswith(check): - newArgs.append(arg) - - self.args = " ".join(newArgs) - -class BootImages: - """A collection to keep track of boot images available on the system. - Examples would be: - ('linux', 'Red Hat Linux', 'ext2'), - ('Other', 'Other', 'fat32'), ... - """ - def __init__(self): - self.default = None - self.images = {} - - def getImages(self): - """returns dictionary of (label, longlabel, devtype) pairs - indexed by device""" - # return a copy so users can modify it w/o affecting us - return copy(self.images) - - def setImageLabel(self, dev, label, setLong = 0): - orig = self.images[dev] - if setLong: - self.images[dev] = (orig[0], label, orig[2]) - else: - self.images[dev] = (label, orig[1], orig[2]) - - def setDefault(self, default): - # default is a device - self.default = default - - def getDefault(self): - return self.default - - # XXX this has internal pomona-ish knowledge. ick - def setup(self, diskSet, fsset): - devices = {} - devs = self.availableBootDevices(diskSet, fsset) - for (dev, type) in devs: - devices[dev] = 1 - - # These partitions have disappeared - for dev in self.images.keys(): - if not devices.has_key(dev): - del self.images[dev] - - # These have appeared - for (dev, type) in devs: - if not self.images.has_key(dev): - if type in dosFilesystems and doesDualBoot(): - self.images[dev] = ("Other", "Other", type) - else: - self.images[dev] = (None, None, type) - - if not self.images.has_key(self.default): - entry = fsset.getEntryByMountPoint('/') - self.default = entry.device.getDevice() - (label, longlabel, type) = self.images[self.default] - if not label: - self.images[self.default] = ("linux", getProductName(), type) - - # XXX more internal pomona knowledge - def availableBootDevices(self, diskSet, fsset): - devs = [] - foundDos = 0 - for (dev, type) in diskSet.partitionTypes(): - if type in dosFilesystems and not foundDos and doesDualBoot(): - import isys - import partedUtils - - part = partedUtils.get_partition_by_name(diskSet.disks, dev) - if part.native_type not in partedUtils.dosPartitionTypes: - continue - - try: - bootable = checkForBootBlock(dev) - devs.append((dev, type)) - foundDos = 1 - except Exception, e: - #log("exception checking %s: %s" %(dev, e)) - pass - elif ((type == 'ntfs' or type =='hpfs') and not foundDos and doesDualBoot()): - devs.append((dev, type)) - # maybe questionable, but the first ntfs or fat is likely to - # be the correct one to boot with XP using ntfs - foundDos = 1 - - slash = fsset.getEntryByMountPoint('/') - if not slash or not slash.device or not slash.fsystem: - raise ValueError,("Trying to pick boot devices but do not have a " - "sane root partition. Aborting install.") - devs.append((slash.device.getDevice(), slash.fsystem.getName())) - - devs.sort() - return devs - -class bootloaderInfo: - def useGrub(self): - return self.useGrubVal - - def setForceLBA(self, val): - pass - - def setPassword(self, val, isCrypted = 1): - pass - - def getPassword(self): - pass - - def getDevice(self): - return self.device - - def setDevice(self, device): - self.device = device - - (dev, part) = getDiskPart(device) - if part is None: - self.defaultDevice = "mbr" - else: - self.defaultDevice = "partition" - - def createDriveList(self): - # create a drive list that we can use for drive mappings - # XXX has pomona internals knowledge - import isys - drives = isys.hardDriveDict().keys() - drives.sort(isys.compareDrives) - - # now filter out all of the drives without media present - drives = filter(lambda x: isys.mediaPresent(x), drives) - - return drives - - def updateDriveList(self, sortedList=[]): - self._drivelist = self.createDriveList() - - # If we're given a sort order, make sure the drives listed in it - # are put at the head of the drivelist in that order. All other - # drives follow behind in whatever order they're found. - if sortedList != []: - revSortedList = sortedList - revSortedList.reverse() - - for i in revSortedList: - try: - ele = self._drivelist.pop(self._drivelist.index(i)) - self._drivelist.insert(0, ele) - except: - pass - - def _getDriveList(self): - if self._drivelist is not None: - return self._drivelist - self.updateDriveList() - return self._drivelist - - def _setDriveList(self, val): - self._drivelist = val - drivelist = property(_getDriveList, _setDriveList) - - def __init__(self): - self.args = KernelArguments() - self.images = BootImages() - self.device = None - self.defaultDevice = None # XXX hack, used by kickstart - self.useGrubVal = 0 # only used on x86 - self.configfile = None - self.kernelLocation = "/boot/" - self.forceLBA32 = 0 - self.password = None - self.pure = None - self.above1024 = 0 - self._drivelist = None - -class x86BootloaderInfo(bootloaderInfo): - def setPassword(self, val, isCrypted = 1): - if not val: - self.password = val - self.pure = val - return - - if isCrypted and self.useGrubVal == 0: - #log("requested crypted password with lilo; ignoring") - self.pure = None - return - elif isCrypted: - self.password = val - self.pure = None - else: - salt = "$1$" - saltLen = 8 - - saltchars = string.letters + string.digits + './' - for i in range(saltLen): - salt += random.choice(saltchars) - - self.password = crypt.crypt(val, salt) - self.pure = val - - def getPassword (self): - return self.pure - - def setForceLBA(self, val): - self.forceLBA32 = val - - def getPhysicalDevices(self, device): - # This finds a list of devices on which the given device name resides. - # Accepted values for "device" are physical disks ("hda"), - # and real partitions on physical disks ("hda1"). - # - return [device] - - def writeGrub(self, instRoot, fsset, bl, kernelList, chainList, - defaultDev): - - images = bl.images.getImages() - rootDev = fsset.getEntryByMountPoint("/").device.getDevice() - - if not os.path.isdir(instRoot + '/boot/grub/'): - os.mkdir(instRoot + '/boot/grub', 0755) - - cf = '/boot/grub/grub.conf' - self.perms = 0600 - if os.access (instRoot + cf, os.R_OK): - self.perms = os.stat(instRoot + cf)[0] & 0777 - os.rename(instRoot + cf, instRoot + cf + '.backup') - - grubTarget = bl.getDevice() - target = "mbr" - if (grubTarget.startswith('rd/') or grubTarget.startswith('ida/') or - grubTarget.startswith('cciss/') or - grubTarget.startswith('sx8/') or - grubTarget.startswith('mapper/')): - if grubTarget[-1].isdigit(): - if grubTarget[-2] == 'p' or \ - (grubTarget[-2].isdigit() and grubTarget[-3] == 'p'): - type = "partition" - elif grubTarget[-1].isdigit() and not grubTarget.startswith('md'): - target = "partition" - - f = open(instRoot + cf, "w+") - - f.write("# grub.conf generated by pomona\n") - f.write("#\n") - - bootDev = fsset.getEntryByMountPoint("/boot") - grubPath = "/grub" - cfPath = "/" - if not bootDev: - bootDev = fsset.getEntryByMountPoint("/") - grubPath = "/boot/grub" - cfPath = "/boot/" - f.write("# NOTICE: You do not have a /boot partition. " - "This means that\n") - f.write("# all kernel and initrd paths are relative " - "to /, eg.\n") - else: - f.write("# NOTICE: You have a /boot partition. This means " - "that\n") - f.write("# all kernel and initrd paths are relative " - "to /boot/, eg.\n") - - bootDevs = self.getPhysicalDevices(bootDev.device.getDevice()) - bootDev = bootDev.device.getDevice() - - f.write('# root %s\n' % self.grubbyPartitionName(bootDevs[0])) - f.write("# kernel %svmlinuz-version ro " - "root=/dev/%s\n" % (cfPath, rootDev)) - f.write("# initrd %sinitramfs-version.img\n" % (cfPath)) - f.write("#boot=/dev/%s\n" % (grubTarget)) - - # keep track of which devices are used for the device.map - usedDevs = {} - - # get the default image to boot... first kernel image here - default = 0 - - f.write('default=%s\n' % (default)) - - # get the default timeout - timeout = 5 - f.write('timeout=%d\n' %(timeout,)) - - # we only want splashimage if they're not using a serial console - if os.access("%s/boot/grub/splash.xpm.gz" %(instRoot,), os.R_OK): - f.write('splashimage=%s%sgrub/splash.xpm.gz\n' - % (self.grubbyPartitionName(bootDevs[0]), cfPath)) - f.write("hiddenmenu\n") - - for dev in self.getPhysicalDevices(grubTarget): - usedDevs[dev] = 1 - - if self.password: - f.write('password --md5 %s\n' % (self.password)) - - for (kernelName, kernelVersion, kernelTag, kernelDesc) in kernelList: - kernelFile = "%s%skernel%s" % (cfPath, sname, kernelTag,) - - initrd = "/boot/initramfs-%s%s.img" % (kernelVersion, kernelTag,) - - f.write('title %s (%s - %s)\n' % (name, kernelDesc, kernelVersion)) - f.write('\troot %s\n' % self.grubbyPartitionName(bootDevs[0])) - - realroot = getRootDevName(initrd, fsset, rootDev, instRoot) - realroot = " root=%s" %(realroot,) - - f.write('\tkernel %s ro%s' % (kernelFile, realroot)) - self.args.append("quiet") - if self.args.get(): - f.write(' %s' % self.args.get()) - f.write('\n') - - if os.access (instRoot + initrd, os.R_OK): - # initrd is built in backend.postInstall - f.write('\tinitrd %sinitramfs-%s%s.img\n' % (cfPath, kernelVersion, kernelTag,)) - - for (label, longlabel, device) in chainList: - if ((not longlabel) or (longlabel == "")): - continue - f.write('title %s\n' % (longlabel)) - f.write('\trootnoverify %s\n' % self.grubbyPartitionName(device)) -# f.write('\tmakeactive\n') - f.write('\tchainloader +1') - f.write('\n') - usedDevs[device] = 1 - - f.close() - os.chmod(instRoot + "/boot/grub/grub.conf", self.perms) - - try: - # make symlink for /etc/grub.conf (config files belong in /etc) - if os.access (instRoot + "/etc/grub.conf", os.R_OK): - os.rename(instRoot + "/etc/grub.conf", instRoot + "/etc/grub.conf.backup") - os.symlink("../boot/grub/grub.conf", instRoot + "/etc/grub.conf") - except: - pass - - for dev in self.getPhysicalDevices(rootDev) + bootDevs: - usedDevs[dev] = 1 - - if os.access(instRoot + "/boot/grub/device.map", os.R_OK): - os.rename(instRoot + "/boot/grub/device.map", instRoot + "/boot/grub/device.map.backup") - - f = open(instRoot + "/boot/grub/device.map", "w+") - f.write("# this device map was generated by pomona\n") - devs = usedDevs.keys() - usedDevs = {} - for dev in devs: - drive = getDiskPart(dev)[0] - if usedDevs.has_key(drive): - continue - usedDevs[drive] = 1 - devs = usedDevs.keys() - devs.sort() - for drive in devs: - # XXX hack city. If they're not the sort of thing that'll - # be in the device map, they shouldn't still be in the list. - if not drive.startswith('md'): - f.write("(%s) /dev/%s\n" % (self.grubbyDiskName(drive), drive)) - f.close() - - args = "--stage2=/boot/grub/stage2 " - if self.forceLBA32: - args = "%s--force-lba " % (args,) - - sysconf = '/etc/sysconfig/grub' - if os.access (instRoot + sysconf, os.R_OK): - self.perms = os.stat(instRoot + sysconf)[0] & 0777 - os.rename(instRoot + sysconf, instRoot + sysconf + '.backup') - # if it's an absolute symlink, just get it out of our way - elif (os.path.islink(instRoot + sysconf) and - os.readlink(instRoot + sysconf)[0] == '/'): - os.rename(instRoot + sysconf, instRoot + sysconf + '.backup') - f = open(instRoot + sysconf, 'w+') - f.write("boot=/dev/%s\n" %(grubTarget,)) - # XXX forcelba never gets read back... - if self.forceLBA32: - f.write("forcelba=1\n") - else: - f.write("forcelba=0\n") - f.close() - - cmds = [] - for bootDev in bootDevs: - gtPart = self.getMatchingPart(bootDev, grubTarget) - gtDisk = self.grubbyPartitionName(getDiskPart(gtPart)[0]) - bPart = self.grubbyPartitionName(bootDev) - cmd = "root %s\n" % (bPart,) - - stage1Target = gtDisk - if target == "partition": - stage1Target = self.grubbyPartitionName(gtPart) - - cmd += "install %s%s/stage1 d %s %s/stage2 p %s%s/grub.conf" % \ - (args, grubPath, stage1Target, grubPath, bPart, grubPath) - cmds.append(cmd) - - log.info("GRUB commands:") - for cmd in cmds: - log.info("\t%s\n", cmd) - - if cfPath == "/": - syncDataToDisk(bootDev, "/boot", instRoot) - else: - syncDataToDisk(bootDev, "/", instRoot) - - # copy the stage files over into /boot - pyfire.executil.execWithRedirect("/usr/sbin/grub-install", - ["/usr/sbin/grub-install", "--just-copy"], - stdout = "/dev/tty5", stderr = "/dev/tty5", - root = instRoot) - - # really install the bootloader - for cmd in cmds: - p = os.pipe() - os.write(p[1], cmd + '\n') - os.close(p[1]) - import time - - # FIXME: hack to try to make sure everything is written - # to the disk - if cfPath == "/": - syncDataToDisk(bootDev, "/boot", instRoot) - else: - syncDataToDisk(bootDev, "/", instRoot) - - pyfire.executil.execWithRedirect("/usr/sbin/grub" , - [ "grub", "--batch", "--no-floppy", - "--device-map=/boot/grub/device.map" ], - stdin = p[0], - stdout = "/dev/tty5", stderr = "/dev/tty5", - root = instRoot) - os.close(p[0]) - - return "" - - def getMatchingPart(self, bootDev, target): - bootName, bootPartNum = getDiskPart(bootDev) - devices = self.getPhysicalDevices(target) - for device in devices: - name, partNum = getDiskPart(device) - if name == bootName: - return device - return devices[0] - - def grubbyDiskName(self, name): - return "hd%d" % self.drivelist.index(name) - - def grubbyPartitionName(self, dev): - (name, partNum) = getDiskPart(dev) - if partNum != None: - return "(%s,%d)" % (self.grubbyDiskName(name), partNum) - else: - return "(%s)" %(self.grubbyDiskName(name)) - - def write(self, instRoot, fsset, bl, kernelList, chainList, defaultDev, intf): - out = self.writeGrub(instRoot, fsset, bl, kernelList, chainList, defaultDev) - - def getArgList(self): - args = [] - - if self.forceLBA32: - args.append("--lba32") - if self.password: - args.append("--md5pass=%s" %(self.password)) - - # XXX add location of bootloader here too - - return args - - def __init__(self): - bootloaderInfo.__init__(self) - self.useGrubVal = 1 - self.kernelLocation = "/boot/" - self.configfile = "/etc/lilo.conf" - self.password = None - self.pure = None - -############### -# end of boot loader objects... these are just some utility functions used - -# return (disk, partition number) eg ('hda', 1) -def getDiskPart(dev): - cut = len(dev) - if (dev.startswith('rd/') or dev.startswith('ida/') or - dev.startswith('cciss/') or dev.startswith('sx8/') or - dev.startswith('mapper/')): - if dev[-2] == 'p': - cut = -1 - elif dev[-3] == 'p': - cut = -2 - else: - if dev[-2] in string.digits: - cut = -2 - elif dev[-1] in string.digits: - cut = -1 - - name = dev[:cut] - - # hack off the trailing 'p' from /dev/cciss/*, for example - if name[-1] == 'p': - for letter in name: - if letter not in string.letters and letter != "/": - name = name[:-1] - break - - if cut < 0: - partNum = int(dev[cut:]) - 1 - else: - partNum = None - - return (name, partNum) - -# hackery to determine if we should do root=LABEL=/ or whatnot -# as usual, knows too much about pomona -def getRootDevName(initrd, fsset, rootDev, instRoot): - if not os.access(instRoot + initrd, os.R_OK): - return "/dev/%s" % (rootDev,) - try: - rootEntry = fsset.getEntryByMountPoint("/") - if rootEntry.getUuid() is not None: - return "UUID=%s" %(rootEntry.getUuid(),) - elif rootEntry.getLabel() is not None and rootEntry.device.doLabel is not None: - return "LABEL=%s" %(rootEntry.getLabel(),) - return "/dev/%s" %(rootDev,) - except: - return "/dev/%s" %(rootDev,) - -# returns a product name to use for the boot loader string -def getProductName(): - # XXX Check /etc/ipfire-release here... - return "IPFire Linux" - -def bootloaderSetupChoices(pomona): - if pomona.dir == DISPATCH_BACK: - return - pomona.id.bootloader.updateDriveList() - - choices = pomona.id.fsset.bootloaderChoices(pomona.id.diskset, pomona.id.bootloader) - - pomona.id.bootloader.images.setup(pomona.id.diskset, pomona.id.fsset) - - if pomona.id.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 pomona.id.bootloader.defaultDevice not in keys: - log.warning("MBR not suitable as boot device; installing to partition") - pomona.id.bootloader.defaultDevice = "boot" - pomona.id.bootloader.setDevice(choices[pomona.id.bootloader.defaultDevice][0]) - elif choices and choices.has_key("mbr"): - pomona.id.bootloader.setDevice(choices["mbr"][0]) - elif choices and choices.has_key("boot"): - pomona.id.bootloader.setDevice(choices["boot"][0]) - - bootDev = pomona.id.fsset.getEntryByMountPoint("/") - if not bootDev: - bootDev = pomona.id.fsset.getEntryByMountPoint("/boot") - part = partedUtils.get_partition_by_name(pomona.id.diskset.disks, - bootDev.device.getDevice()) - if part and partedUtils.end_sector_to_cyl(part.geom.dev, part.geom.end) >= 1024: - pomona.id.bootloader.above1024 = 1 - -def writeBootloader(pomona): - def dosync(): - isys.sync() - isys.sync() - isys.sync() - - if pomona.id.bootloader.defaultDevice == -1: - log.error("No default boot device set") - return - - w = pomona.intf.waitWindow(_("Bootloader"), _("Installing bootloader...")) - - kernelList = [] - otherList = [] - root = pomona.id.fsset.getEntryByMountPoint('/') - if root: - rootDev = root.device.getDevice() - else: - rootDev = None - defaultDev = pomona.id.bootloader.images.getDefault() - - kernelLabel = None - kernelLongLabel = None - - for (dev, (label, longlabel, type)) in pomona.id.bootloader.images.getImages().items(): - if (dev == rootDev) or (rootDev is None and kernelLabel is None): - kernelLabel = label - kernelLongLabel = longlabel - elif dev == defaultDev: - otherList = [(label, longlabel, dev)] + otherList - else: - otherList.append((label, longlabel, dev)) - - if kernelLabel is None: - log.error("unable to find default image, bailing") - - defkern = None - for (kernelName, kernelVersion, kernelTag, kernelDesc) in pomona.backend.kernelVersionList(pomona): - if not defkern: - defkern = "%s%s" % (kernelName, kernelTag) - - if kernelTag == "-smp" and isys.smpAvailable(): - defkern = "%s%s" % (kernelName, kernelTag) - - kernelList.append((kernelName, kernelVersion, kernelTag, kernelDesc)) - - f = open(pomona.rootPath + "/etc/sysconfig/kernel", "w+") - f.write("# DEFAULTKERNEL specifies the default kernel package type\n") - f.write("DEFAULTKERNEL=%s\n" %(defkern,)) - f.close() - - dosync() - try: - pomona.id.bootloader.write(pomona.rootPath, pomona.id.fsset, pomona.id.bootloader, - kernelList, otherList, defaultDev, pomona.intf) - w.pop() - except BootyNoKernelWarning: - w.pop() - if pomona.intf: - pomona.intf.messageWindow(_("Warning"), - _("No kernel packages were installed on your " - "system. Your boot loader configuration " - "will not be changed.")) - dosync() - -# return instance of the appropriate bootloader for our arch -def getBootloader(): - return x86BootloaderInfo() diff --git a/pkgs/core/pomona/src/console.py b/pkgs/core/pomona/src/console.py index ed0bc59..7fbb49f 100644 --- a/pkgs/core/pomona/src/console.py +++ b/pkgs/core/pomona/src/console.py @@ -1,173 +1,17 @@ #!/usr/bin/python
-import os -import string -import locale -import gettext - -import pyfire.executil as executil -from pyfire.config import ConfigFile -import keyboard_models +from language import Language, LanguageWindow +from keyboard import Keyboard, KeyboardWindow
import gettext _ = lambda x: gettext.ldgettext("pomona", x) N_ = lambda x: x
-# Converts a single language into a "language search path". For example, -# de_DE.utf8@euro would become "de_DE.utf8@eueo de_DE.utf8 de_DE de" -def expandLangs(astring): - langs = [astring] - charset = None - # remove charset ... - if '.' in astring: - langs.append(string.split(astring, '.')[0]) - - if '@' in astring: - charset = string.split(astring, '@')[1] - - # also add 2 character language code ... - if len(astring) > 2: - if charset: - langs.append("%s@%s" %(astring[:2], charset)) - - langs.append(astring[:2]) - - return langs - -class Console(ConfigFile): - def __init__(self, filename): - ConfigFile.__init__(self, filename) - - # default to us and unicode enabled - self.info["KEYMAP"] = "us" - self.info["UNICODE"] = "yes" - - self._mods = keyboard_models.KeyboardModels() - - self.nativeLangNames = {} - self.locales = {} - - if os.environ.has_key("LANG"): - self.lang = self.fixLang(os.environ["LANG"]) - else: - self.lang = "en_US.UTF-8" - - # nick -> (name, short name, font, keyboard, timezone) mapping - search = ( '../lang-table', 'lang-table', '/usr/lib/pomona/lang-table', '/etc/lang-table') - for path in search: - if os.access(path, os.R_OK): - f = open(path, "r") - break - - for line in f.readlines(): - string.strip(line) - l = string.split(line, '\t') - - # throw out invalid lines - if len(l) < 6: - continue - - self.locales[l[3]] = (l[0], l[1], l[2], l[4], string.strip(l[5])) - self.nativeLangNames[l[0]] = _(l[0]) - - f.close() - - def availableLangs(self): - return self.nativeLangNames.keys() - - def setKeymap(self, keymap): - self.info["KEYMAP"] = keymap - - def getKeymap(self): - return self.info["KEYMAP"] - - def getDefaultKeymap(self): - return self.locales[self.canonLangNick(self.lang)][3] - - def getDefaultFont(self, nick): - return self.locales[self.canonLangNick(nick)][2] - - def getDefaultTimeZone(self): - return self.locales[self.canonLangNick(self.lang)][4] - - def _getKeyboardModels(self): - return self._mods.get_models() - - modelDict = property(_getKeyboardModels) - - def getKeymapName(self): - kbd = self.modelDict[self.getKeymap()] - if not kbd: - return "" - (name, layout, model, variant, options) = kbd - return name - - # Convert what might be a shortened form of a language's nick (en or - # en_US, for example) into the full version (en_US.UTF-8). If we - # don't find it, return our default of en_US.UTF-8. - def canonLangNick(self, nick): - for key in self.locales.keys(): - if nick in expandLangs(key): - return key - return "en_US.UTF-8" - - def getNickByName(self, name): - for k in self.locales.keys(): - row = self.locales[k] - if row[0] == name: - return k - - def fixLang(self, langToFix): - ret = None - for lang in self.locales.keys(): - if lang == langToFix: - (a, b, font, c, d) = self.locales[lang] - if font == "none": - ret = "en_US.UTF-8" - self.targetLang = lang - - if ret is None: - ret = langToFix - - return ret - - def getNativeLangName(self, lang): - return self.nativeLangNames[lang] - - def getLangNameByNick(self, nick): - return self.locales[self.canonLangNick(nick)][0] - - def getCurrentLangSearchList(self): - return expandLangs(self.lang) + ['C'] - - def setLanguage(self, nick): - self.info['LANG'] = os.environ["LANG"] = \ - self.lang = self.fixLang(self.canonLangNick(nick)) - os.environ["LC_NUMERIC"] = 'C' - - if self.locales[self.lang][2] == "none": - self.info['FONT'] = None - else: - self.info['FONT'] = self.locales[self.lang][2] - - try: - locale.setlocale(locale.LC_ALL, "") - except locale.Error: - pass - - def activate(self): - console_kbd = self.getKeymap() - if not console_kbd: - return +from constants import *
- # Call loadkeys to change the console keymap - if os.access("/bin/loadkeys", os.X_OK): - command = "/bin/loadkeys" - elif os.access("/usr/bin/loadkeys", os.X_OK): - command = "/usr/bin/loadkeys" - else: - command = "/bin/loadkeys" - argv = [ command, console_kbd ] +class Console: + def __init__(self, installer): + self.installer = installer
- if os.access(argv[0], os.X_OK) == 1: - executil.execWithRedirect(argv[0], argv, stdout="/dev/tty5", stderr="/dev/tty5") + self.language = Language(installer) + self.keyboard = Keyboard(installer) diff --git a/pkgs/core/pomona/src/constants.py b/pkgs/core/pomona/src/constants.py index c8ac4f9..9009486 100644 --- a/pkgs/core/pomona/src/constants.py +++ b/pkgs/core/pomona/src/constants.py @@ -4,72 +4,25 @@ import gettext _ = lambda x: gettext.ldgettext("pomona", x) N_ = lambda x: x
-version = "VERSION" -name = "NAME v%s" % version -sname = "SNAME" -iname = "PNAME" -bugurl = "http://bugtracker.ipfire.org/" -wikiurl = "http://wiki.ipfire.org/" -kernelVersion = "KVER" +PRODUCT_NAME = "IPFire" +PROCUCT_SNAME = "ipfire" +PRODUCT_VERSION = "3.0-prealpha2" +PRODUCT_SLOGAN = "Gluttony" +PRODUCT_URL = "http://www.ipfire.org/"
-HARDDISK_PATH = "/mnt/target" -SOURCE_PATH = "/mnt/source" -INFO_FILE = ".%sinfo" % (sname,) -IMAGE_FILE = "%s-%s.sfs" % (sname, version) -IMAGE_FILE_LS = "%s-%s.ls" % (sname, version) +SCREEN_ROOTLINE = _("Welcome to %s-v%s (%s)") % (PRODUCT_NAME, PRODUCT_VERSION, PRODUCT_SLOGAN,) +SCREEN_HELPLINE = _(" <F1> for help | <Tab> between elements | <Space> selects | <F12> next screen")
-REQUIRED_FILES = (IMAGE_FILE,) +LOGFILE = "/tmp/installer.log"
-DISPATCH_BACK = -1 DISPATCH_FORWARD = 1 -DISPATCH_NOOP = None - -CLEARPART_TYPE_ALL = 0 -CLEARPART_TYPE_NONE = -1 - -CB_UNDEF = -1 -CB_START = 0 -CB_STOP = 1 -CB_WAIT = 2 -CB_PROGRESS = 3 +DISPATCH_BACK = -1 +DISPATCH_NOOP = None
INSTALL_OK = 0 INSTALL_BACK = -1 INSTALL_NOOP = -2
-# different types of partition requests -# REQUEST_PREEXIST is a placeholder for a pre-existing partition on the system -# REQUEST_NEW is a request for a partition which will be automatically -# created based on various constraints on size, drive, etc -# REQUEST_RAID is a request for a raid device -# REQUEST_PROTECTED is a preexisting partition which can't change -# (harddrive install, harddrive with the isos on it) -# -REQUEST_PREEXIST = 1 -REQUEST_NEW = 2 -REQUEST_RAID = 4 -REQUEST_PROTECTED = 8 -REQUEST_VG = 16 # volume group -REQUEST_LV = 32 # logical volume - -# XXX this is made up and used by the size spinner; should just be set with -# a callback -MAX_PART_SIZE = 1024*1024*1024 - -lvmErrorOutput = "/tmp/lvmout" - -exceptionText = _("An unhandled exception has occurred. This " - "is most likely a bug. Please save a copy of " - "the detailed exception and file a bug report") -if not bugurl: - # this string will be combined with "An unhandled exception"... - # the leading space is not a typo. - exceptionText += _(" with the provider of this software.") -else: - # this string will be combined with "An unhandled exception"... - # the leading space is not a typo. - exceptionText += _(" against pomona at %s") %(bugurl,) - class Translator: """A simple class to facilitate on-the-fly translation for newt buttons""" def __init__(self, button, check): @@ -105,9 +58,3 @@ TEXT_YES_BUTTON = Translator(TEXT_YES_STR, TEXT_YES_CHECK) TEXT_NO_STR = N_("No") TEXT_NO_CHECK = "no" TEXT_NO_BUTTON = Translator(TEXT_NO_STR, TEXT_NO_CHECK) - -TEXT_EDIT_STR = N_("Edit") -TEXT_EDIT_CHECK = "edit" -TEXT_EDIT_BUTTON = Translator(TEXT_EDIT_STR, TEXT_EDIT_CHECK) - -TEXT_F12_CHECK = "F12" diff --git a/pkgs/core/pomona/src/cryptodev.py b/pkgs/core/pomona/src/cryptodev.py deleted file mode 100644 index 0efe94a..0000000 --- a/pkgs/core/pomona/src/cryptodev.py +++ /dev/null @@ -1,252 +0,0 @@ -# -# cryptodev.py -# -# 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/. -# -# Author(s): Dave Lehman dlehman@redhat.com -# - -import os -import iutil - -import logging -log = logging.getLogger("pomona") - -def isLuks(device): - if not device.startswith("/"): - device = "/dev/" + device - rc = iutil.execWithRedirect("cryptsetup", - ["isLuks", device], - stdout = "/dev/null", - stderr = "/dev/null", - searchPath = 1) - if rc: - return False - else: - return True - -def luksUUID(device): - if not device.startswith("/"): - device = "/dev/" + device - - if not isLuks(device): - return None - - uuid = iutil.execWithCapture("cryptsetup", ["luksUUID", device]) - uuid = uuid.strip() - return uuid - -class LUKSDevice: - """LUKSDevice represents an encrypted block device using LUKS/dm-crypt. - It requires an underlying block device and a passphrase to become - functional.""" - def __init__(self, device=None, passphrase=None, format=0): - self._device = None - self.passphrase = "" - self.name = "" - self.uuid = None - self.nameLocked = False - self.format = format - self.preexist = not format - self.packages = ["cryptsetup-luks"] - self.scheme = "LUKS" - - self.setDevice(device) - self.setPassphrase(passphrase) - if self.getUUID(): - name = "%s-%s" % (self.scheme.lower(), self.uuid) - self.setName(name, lock=True) - - def getScheme(self): - """Returns the name of the encryption scheme used by the device.""" - return self.scheme - - def setDevice(self, device): - if self._device == device: - return - - self._device = device - if device is not None: - # this will be temporary, but may be useful for debugging - name = "%s-%s" % (self.scheme.lower(), - os.path.basename(device)) - self.setName(name) - - def getDevice(self, encrypted=0): - if encrypted: - dev = self._device - else: - dev = "mapper/%s" % (self.name,) - - return dev - - def getUUID(self): - if self.format: - # self.format means we're going to reformat but haven't yet - # so we shouldn't act like there's anything worth seeing there - return - - if not self.uuid: - self.uuid = luksUUID(self.getDevice(encrypted=1)) - - return self.uuid - - def setName(self, name, lock=False): - """Set the name of the mapped device, eg: 'dmcrypt-sda3'""" - if self.name == name: - return - - if self.name and not self.getStatus(): - raise RuntimeError, "Cannot rename an active mapping." - - if self.nameLocked: - log.debug("Failed to change locked mapping name: %s" % - (self.name,)) - return - - self.name = name - if lock and name: - # don't allow anyone to lock the name as "" or None - self.nameLocked = True - - def setPassphrase(self, passphrase): - """Set the (plaintext) passphrase used to access the device.""" - self.passphrase = passphrase - - def crypttab(self): - """Return a crypttab formatted line describing this mapping.""" - format = "%-23s %-15s %s\n" - line = format % (self.name, - "UUID=%s" % (self.getUUID(),), - "none") - return line - - def getStatus(self): - """0 means active, 1 means inactive (or non-existent)""" - if not self.name: - return 1 - - rc = iutil.execWithRedirect("cryptsetup", - ["status", self.name], - stdout = "/dev/null", - stderr = "/dev/null", - searchPath = 1) - return rc - - def formatDevice(self): - """Write a LUKS header onto the device.""" - if not self.format: - return - - if not self.getStatus(): - log.debug("refusing to format active mapping %s" % (self.name,)) - return 1 - - if not self.passphrase: - raise RuntimeError, "Cannot create mapping without a passphrase." - - device = self.getDevice(encrypted=1) - if not device: - raise ValueError, "Cannot open mapping without a device." - - log.info("formatting %s as %s" % (device, self.getScheme())) - p = os.pipe() - os.write(p[1], "%s\n" % (self.passphrase,)) - os.close(p[1]) - - rc = iutil.execWithRedirect("cryptsetup", - ["-q", "luksFormat", - "/dev/%s" % (device,)], - stdin = p[0], - stdout = "/dev/null", - stderr = "/dev/tty5", - searchPath = 1) - self.format = 0 - return rc - - def openDevice(self): - if not self.getStatus(): - # already mapped - return 0 - - if not self.passphrase: - raise RuntimeError, "Cannot create mapping without a passphrase." - - device = self.getDevice(encrypted=1) - if not device: - raise ValueError, "Cannot open mapping without a device." - - uuid = self.getUUID() - if not uuid: - raise RuntimeError, "Device has no UUID." - - self.setName("%s-%s" % (self.scheme.lower(), uuid), lock=True) - - log.info("mapping %s device %s to %s" % (self.getScheme(), - device, - self.name)) - - p = os.pipe() - os.write(p[1], "%s\n" % (self.passphrase,)) - os.close(p[1]) - - rc = iutil.execWithRedirect("cryptsetup", - ["luksOpen", - "/dev/%s" % (device,), - self.name], - stdin = p[0], - stdout = "/dev/null", - stderr = "/dev/tty5", - searchPath = 1) - return rc - - def closeDevice(self): - if self.getStatus(): - # not mapped - return 0 - - log.info("unmapping %s device %s" % (self.getScheme(), self.name)) - rc = iutil.execWithRedirect("cryptsetup", - ["luksClose", self.name], - stdout = "/dev/null", - stderr = "/dev/tty5", - searchPath = 1) - return rc - - def addPassphrase(self, newpass): - if not newpass: - return 1 - - if newpass == self.passphrase: - return 0 - - p = os.pipe() - os.write(p[1], "%s\n%s" % (self.passphrase, newpass)) - os.close(p[1]) - - device = self.getDevice(encrypted=1) - log.info("adding new passphrase to %s device %s" % (self.getScheme(), - device)) - rc = iutil.execWithRedirect("cryptsetup", - ["-q", - "luksAddKey", - "/dev/%s" % (device,)], - stdin = p[0], - stdout = "/dev/null", - stderr = "/dev/tty5", - searchPath = 1) - - return rc diff --git a/pkgs/core/pomona/src/datastore.py b/pkgs/core/pomona/src/datastore.py new file mode 100644 index 0000000..eed9fa7 --- /dev/null +++ b/pkgs/core/pomona/src/datastore.py @@ -0,0 +1,13 @@ +#!/usr/bin/python + +import console +import storage +#import timezone + +class DataStore: + def __init__(self, installer): + self.installer = installer + + self.console = console.Console(self.installer) + self.storage = storage.Storage(self.installer) + #self.timezone = timezone.Timezone(self.installer) diff --git a/pkgs/core/pomona/src/dispatch.py b/pkgs/core/pomona/src/dispatch.py index c231719..26c404f 100644 --- a/pkgs/core/pomona/src/dispatch.py +++ b/pkgs/core/pomona/src/dispatch.py @@ -1,142 +1,32 @@ -# -# dispatch.py: install/upgrade master flow control -# -# Erik Troan ewt@redhat.com -# -# Copyright 2001-2006 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# general public license. -# -# 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., 675 Mass Ave, Cambridge, MA 02139, USA. -# +#!/usr/bin/python
-import string -from types import * -from constants import * -from autopart import doAutoPartition -from bootloader import writeBootloader, bootloaderSetupChoices -from packages import turnOnFilesystems, betaNagScreen, setupTimezone -from partitioning import partitionObjectsInitialize, partitioningComplete - -from packages import doMigrateFilesystems -from packages import doPostAction -from packages import copyPomonaLogs - -from flags import flags - -#from backend import doPostSelection, doRepoSetup -from backend import doPreInstall, doPostInstall, doInstall -from backend import writeConfiguration +from storage import storageInitialize +from storage.partitioning import doAutoPartition
-import logging -log = logging.getLogger("pomona") - -# -# items are one of -# -# ( name ) -# ( name, Function ) -# -# in the second case, the function is called directly from the dispatcher +from constants import * +from windows import *
-# All install steps take the pomona object as their sole argument. This -# gets passed in when we call the function. installSteps = [ - ("welcome", ), - ("betanag", betaNagScreen, ), - ("language", ), - ("keyboard", ), - ("partitionobjinit", partitionObjectsInitialize, ), - ("parttype", ), - ("autopartitionexecute", doAutoPartition, ), - ("partition", ), - ("partitiondone", partitioningComplete, ), - ("bootloadersetup", bootloaderSetupChoices, ), - ("bootloader", ), - ("bootloaderadvanced", ), - ("network", ), - ("timezone", ), - ("accounts", ), - #("reposetup", doRepoSetup, ), - #("tasksel", ), - #("group-selection", ), - #("postselection", doPostSelection, ), - ("confirminstall", ), - ("install", ), - ("migratefilesystems", doMigrateFilesystems, ), - ("enablefilesystems", turnOnFilesystems, ), - ("setuptime", setupTimezone, ), - ("preinstallconfig", doPreInstall, ), - ("installpackages", doInstall, ), - ("postinstallconfig", doPostInstall, ), - ("writeconfig", writeConfiguration, ), - ("instbootloader", writeBootloader, ), - ("copylogs", copyPomonaLogs, ), - #("postscripts", runPostScripts, ), - ("dopostaction", doPostAction, ), - ("complete", ), - ] - -class Dispatcher: - def gotoPrev(self): - self._setDir(DISPATCH_BACK) - self.moveStep() + ("welcome", welcomeWindow,), + ("experimental", experimentalWindow,), + ("console", [ "LanguageWindow", "KeyboardWindow",]), + ("storage", storageInitialize,), + ("partmethod", partmethodWindow,), + ("autopartition", autopartitionWindow,), + #("autopartitionexecute", doAutoPartition,), + ("partition", [ "PartitionWindow",]), + ("bootloader", bootloaderWindow,), + ("complete", finishedWindow,), + ]
- def gotoNext(self): - self._setDir(DISPATCH_FORWARD) - self.moveStep()
- def canGoBack(self): - # begin with the step before this one. If all steps are skipped, - # we can not go backwards from this screen - i = self.step - 1 - while i >= self.firstStep: - if not self.stepIsDirect(i) and not self.skipSteps.has_key(installSteps[i][0]): - return True - i = i - 1 - return False - - def setStepList(self, *steps): - # only remove non-permanently skipped steps from our skip list - for step, state in self.skipSteps.items(): - if state == 1: - del self.skipSteps[step] - - stepExists = {} - for step in installSteps: - name = step[0] - if not name in steps: - self.skipSteps[name] = 1 - - stepExists[name] = 1 - - for name in steps: - if not stepExists.has_key(name): - log.warning("step %s does not exist", name) - - def stepInSkipList(self, step): - if type(step) == type(1): - step = installSteps[step][0] - return self.skipSteps.has_key(step) +class Dispatcher: + def __init__(self, installer): + self.installer = installer
- def skipStep(self, stepToSkip, skip = 1, permanent = 0): - for step in installSteps: - name = step[0] - if name == stepToSkip: - if skip: - if permanent: - self.skipSteps[name] = 2 - elif not self.skipSteps.has_key(name): - self.skipSteps[name] = 1 - elif self.skipSteps.has_key(name): - # if marked as permanent then dont change - if self.skipSteps[name] != 2: - del self.skipSteps[name] - return - log.warning("step %s does not exist", stepToSkip) + self.step = None + self.skipSteps = {} + self.dir = DISPATCH_FORWARD
def stepIsDirect(self, step): """Takes a step number""" @@ -145,62 +35,22 @@ class Dispatcher: else: return False
- def moveStep(self): - if self.step == None: - self.step = self.firstStep - else: - self.step = self.step + self._getDir() - - if self.step >= len(installSteps): - return None - - while self.step >= self.firstStep and self.step < len(installSteps) \ - and (self.stepInSkipList(self.step) or self.stepIsDirect(self.step)): - if self.stepIsDirect(self.step) and not self.stepInSkipList(self.step): - (stepName, stepFunc) = installSteps[self.step] - log.info("moving (%d) to step %s" % (self._getDir(), stepName)) - rc = stepFunc(self.pomona) - if rc in [DISPATCH_BACK, DISPATCH_FORWARD]: - self._setDir(rc) - # if anything else, leave self.dir alone - - self.step = self.step + self._getDir() - if self.step == len(installSteps): - return None - - if (self.step < 0): - # pick the first step not in the skip list - self.step = 0 - while self.skipSteps.has_key(installSteps[self.step][0]): - self.step = self.step + 1 - elif self.step >= len(installSteps): - self.step = len(installSteps) - 1 - while self.skipSteps.has_key(installSteps[self.step][0]): - self.step = self.step - 1 - log.info("moving (%d) to step %s" % (self._getDir(), installSteps[self.step][0])) - - def currentStep(self): - if self.step == None: - self.gotoNext() - elif self.step >= len(installSteps): - return (None, None) - - stepInfo = installSteps[self.step] - step = stepInfo[0] - - return (step, self.pomona) - - def __init__(self, pomona): - self.pomona = pomona - self.pomona.dir = DISPATCH_FORWARD - self.step = None - self.skipSteps = {} - self.firstStep = 0 + def stepInSkipList(self, step): + return False # XXX
- def _getDir(self): - return self.pomona.dir + def nextStep(self): + while self.step <= len(installSteps) or self.step == None: + if self.step == None: + self.step = 0 + else: + self.step += self.dir
- def _setDir(self, dir): - self.pomona.dir = dir + if self.stepInSkipList(self.step): + continue + else: + break
- dir = property(_getDir,_setDir) + if self.step == len(installSteps): + return None + else: + return installSteps[self.step] diff --git a/pkgs/core/pomona/src/dmraid.py b/pkgs/core/pomona/src/dmraid.py deleted file mode 100644 index 5cee469..0000000 --- a/pkgs/core/pomona/src/dmraid.py +++ /dev/null @@ -1,302 +0,0 @@ -# -# dmraid.py - dmraid probing control -# -# Copyright (C) 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): Peter Jones pjones@redhat.com -# - -"""DMRaid probing control.""" -# XXX dmraid and md raid should be abstracted from the same thing. -pj -# XXX dmraid and lvm should use a common control mechanism (such as block.dm) -# for device-mapper. -pj - -import sys -import string -import block -import partedUtils -import raid -from flags import flags - -import logging -from pomona_log import logger, logFile - -logger.addLogger ("pomona.dmraid", minLevel=logging.DEBUG) -log = logging.getLogger("pomona.dmraid") -logger.addFileHandler (logFile, log) - -import isys - -# these arches can have their /boot on DMRAID and not have their -# boot loader blow up -# XXX This needs to be functional so it can test if drives sit on particular -# controlers. -pj -dmraidBootArches = [ "i386", "x86_64" ] - -dmNameUpdates = {} - -class DmDriveCache: - def __init__(self): - self.cache = {} - - def _addMapDevs(self, name, devs, obj): - isys.cachedDrives["mapper/" + name] = obj - log.debug("adding %s to isys cache" % ("mapper/" + name,)) - for dev in devs: - disk = dev.split('/')[-1] - if isys.cachedDrives.has_key(disk): - self.cache.setdefault(obj.name, {}) - self.cache[obj.name][obj.name] = obj - log.debug("adding %s to dm cache" % (disk,)) - self.cache[obj.name][disk] = isys.cachedDrives[disk] - log.debug("removing %s from isys cache" % (disk,)) - del isys.cachedDrives[disk] - - def add(self, obj): - if isinstance(obj, block.MultiPath): - return self._addMapDevs(obj.name, obj.bdevs, obj) - else: - members = [] - for m in obj.members: - if isinstance(m, block.RaidDev): - members.append(m.rd.device.path) - return self._addMapDevs(obj.name, members, obj) - - def remove(self, name): - objname = "mapper/" + name - if isys.cachedDrives.has_key(objname): - obj = isys.cachedDrives[objname] - log.debug("removing %s from isys cache" % (objname,)) - del isys.cachedDrives[objname] - if self.cache.has_key(obj.name): - del self.cache[obj.name][obj.name] - for k,v in self.cache[obj.name].items(): - log.debug("adding %s to isys cache" % (name,)) - isys.cachedDrives[k] = v - log.debug("removing %s from dm cache" % (obj,)) - del self.cache[obj.name] - - def rename(self, obj, newname): - oldname = 'mapper/' + obj.name - if isys.cachedDrives.has_key(oldname): - dmNameUpdates[obj.name] = newname - self.remove(oldname) - # XXX why doesn't setting the property work? - obj.set_name(newname) - self.add(obj) - - def __contains__(self, name): - return self.cache.has_key(name) - -cacheDrives = DmDriveCache() - -class DegradedRaidWarning(Warning): - def __init__(self, *args): - self.args = args - def __str__(self): - return self.args and ('%s' % self.args[0]) or repr(self) - -def scanForRaid(drives, degradedOk=False): - """Scans for dmraid devices on drives. - - drives is a list of device names. - Returns a list of (raidSet, parentRaidSet, devices, level, totalDisks) - tuples. - """ - - log.debug("scanning for dmraid on drives %s" % (drives,)) - - probeDrives = [] - for d in drives: - probeDrives.append("/dev/%s" % (d,)) - - dmsets = [] - def nonDegraded(rs): - log.debug("got raidset %s (%s)" % (rs, string.join(rs.member_devpaths))) - log.debug(" valid: %s found_devs: %s total_devs: %s" % (rs.valid, rs.rs.found_devs, rs.rs.total_devs)) - - if not rs.valid and not degradedOk: - log.warning("raid %s (%s) is degraded" % (rs, rs.name)) - #raise DegradedRaidWarning, rs - return False - return True - - raidsets = filter(nonDegraded, block.getRaidSets(probeDrives) or []) - def updateName(rs): - if dmNameUpdates.has_key(rs.name): - rs.set_name(dmNameUpdates[rs.name]) - cacheDrives.add(rs) - return rs - - return reduce(lambda x,y: x + [updateName(y),], raidsets, []) - -def renameRaidSet(rs, name): - cacheDrives.rename(rs, name) - -def startAllRaid(driveList): - """Do a raid start on raid devices.""" - - if not flags.dmraid: - return [] - log.debug("starting all dmraids on drives %s" % (driveList,)) - - try: - dmList = scanForRaid(driveList) - except Exception, e: - log.error("error scanning dmraid, disabling: %s" %(e,)) - flags.dmraid = 0 - dmList = [] - - newDmList = [] - for rs in dmList: - rs.prefix = '/dev/mapper/' - log.debug("starting raid %s with mknod=True" % (rs,)) - try: - rs.activate(mknod=True) - newDmList.append(rs) - except Exception, e: - log.error("Activating raid %s failed: " % (rs.rs,)) - log.error(" table: %s" % (rs.rs.table,)) - log.error(" exception: %s" % (e,)) - try: - rs.deactivate() - del rs - except: - pass - - return newDmList - -def stopAllRaid(dmList): - """Do a raid stop on each of the raid device tuples given.""" - - if not flags.dmraid: - return - log.debug("stopping all dmraids") - for rs in dmList: - log.debug("stopping raid %s" % (rs,)) - if rs.name in cacheDrives: - cacheDrives.remove(rs.name) - - rs.deactivate() - #block.removeDeviceMap(map) - -def isRaid6(raidlevel): - """Return whether raidlevel is a valid descriptor of RAID6.""" - return False - -def isRaid5(raidlevel): - """Return whether raidlevel is a valid descriptor of RAID5.""" - return False - -def isRaid1(raidlevel): - """Return whether raidlevel is a valid descriptor of RAID1.""" - return raid.isRaid1(raidlevel) - -def isRaid0(raidlevel): - """Return whether raidlevel is a valid descriptor of RAID1.""" - return raid.isRaid0(raidlevel) - -def get_raid_min_members(raidlevel): - """Return the minimum number of raid members required for raid level""" - return raid.get_raid_min_members(raidlevel) - -def get_raid_max_spares(raidlevel, nummembers): - """Return the maximum number of raid spares for raidlevel.""" - return raid.get_raid_max_spares(raidlevel, nummembers) - -def register_raid_device(dmname, newdevices, newlevel, newnumActive): - """Register a new RAID device in the dmlist.""" - raise NotImplementedError - -def lookup_raid_device(dmname): - """Return the requested RAID device information.""" - for rs, parent, devices, level, nrDisks, totalDisks in \ - partedUtils.DiskSet.dmList: - if dmname == rs.name: - return (rs.name, devices, level, totalDisks) - raise KeyError, "dm device not found" - -def scanForMPath(drives): - log.debug("scanning for multipath on drives %s" % (drives,)) - mpaths = [] - - probeDrives = [] - for d in drives: - probeDrives.append("/dev/%s" % (d,)) - - import block as _block - - log.debug("loading bdevid modules from: '%s'" % (_block.getBdevidPath(),)) - - _block.load("scsi") - mpaths = _block.getMPaths(probeDrives) - log.debug("mpaths: %s" % (mpaths,)) - - def updateName(mp): - if dmNameUpdates.has_key(mp.name): - mp.set_name(dmNameUpdates[mp.name]) - cacheDrives.add(mp) - return mp - - return reduce(lambda x,y: x + [updateName(y),], mpaths, []) - -def renameMPath(mpath, name): - cacheDrives.rename(mpath, name) - -def startMPath(mpath): - if flags.mpath == 0: - return - mpath.prefix = '/dev/mapper/' - log.debug("starting mpath %s with mknod=True" % (mpath,)) - mpath.activate(mknod=True) - -def startAllMPath(driveList): - """Start all of the MPaths of the specified drives.""" - - if not flags.mpath: - return [] - log.debug("starting all mpaths on drives %s" % (driveList,)) - - try: - mpList = scanForMPath(driveList) - except Exception, e: - log.error("error scanning mpaths, disabling: %s" %(e,)) - flags.mpath = 0 - mpList = [] - - for mp in mpList: - startMPath(mp) - return mpList - -def stopMPath(mp): - if flags.mpath == 0: - return - - log.debug("stopping mpath %s" % (mp,)) - if mp.name in cacheDrives: - cacheDrives.remove(mp.name) - - mp.deactivate() - #block.removeDeviceMap(map) - -def stopAllMPath(mpList): - """Do a mpath stop on each of the mpath device tuples given.""" - - if not flags.mpath: - return - log.debug("stopping all mpaths") - for mp in mpList: - stopMPath(mp) diff --git a/pkgs/core/pomona/src/errors.py b/pkgs/core/pomona/src/errors.py deleted file mode 100644 index 6708b1d..0000000 --- a/pkgs/core/pomona/src/errors.py +++ /dev/null @@ -1,159 +0,0 @@ -# -# errors.py: exception classes used throughout pomona -# -# Copyright (C) 2002, 2007, 2008 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 -# Chris Lumens clumens@redhat.com -# Matt Wilson msw@redhat.com -# Jeremy Katz katzj@redhat.com -# Mike Fulbright msf@redhat.com -# - -import string -import os -from constants import lvmErrorOutput - -"""Exceptions for use in lvm operations.""" - -class LvmError(Exception): - """An error occurred with lvm.""" - def __init__(self, command, name=None): - self.command = command - self.name = name - self.log = self.getLvmOutput() - - def getLvmOutput(self): - if not os.access(lvmErrorOutput, os.R_OK): - return "" - f = open(lvmErrorOutput, "r") - lines = reduce(lambda x,y: x + [string.strip(y),], f.readlines(), []) - lines = string.join(reduce(lambda x,y: x + [" %s" % (y,)], \ - lines, []), "\n") - return lines - - def __str__(self): - s = "" - if not self.name is None: - s = " for device %s" % (self.name,) - return "%s failed%s\nLog:\n%s" % (self.command, s, self.log) - -class LVCreateError(LvmError): - def __init__(self, vgname, lvname, size): - self.vgname = vgname - self.lvname = lvname - self.size = size - self.log = self.getLvmOutput() - - def __str__(self): - return "lvcreate of %d Megabyte lv "%s" on vg "%s" failed\n" \ - "Log:\n%s" % ( \ - self.size, self.lvname, self.vgname, self.log) - -class LVRemoveError(LvmError): - def __init__(self, vgname, lvname): - self.vgname = vgname - self.lvname = lvname - self.log = self.getLvmOutput() - - def __str__(self): - return "lvremove of lv "%s" from vg "%s" failed\nLog:\n%s" % ( \ - self.lvname, self.vgname, self.log) - -class LVResizeError(LvmError): - def __init__(self, vgname, lvname): - self.vgname = vgname - self.lvname = lvname - self.log = self.getLvmOutput() - - def __str__(self): - return "lvresize of lv "%s" from vg "%s" failed\nLog:\n%s" % ( \ - self.lvname, self.vgname, self.log) - -class VGCreateError(LvmError): - def __init__(self, vgname, PESize, nodes): - self.vgname = vgname - self.PESize = PESize - self.nodes = nodes - self.log = self.getLvmOutput() - - def __str__(self): - nodes = string.join(self.nodes, ' ') - return "vgcreate failed creating vg "%s" (PESize=%dkB) on PVs: %s\n" \ - "Log:\n%s" % ( \ - self.vgname, self.PESize, nodes, self.log) - -class VGRemoveError(LvmError): - def __init__(self, vgname): - self.vgname = vgname - self.log = self.getLvmOutput() - - def __str__(self): - return "vgremove of vg "%s" failed\nLog:\n%s" % ( \ - self.vgname, self.log) - -class PVRemoveError(LvmError): - def __init__(self, pvname): - self.pvname = pvname - self.log = self.getLvmOutput() - - def __str__(self): - return "pvremove of pv "%s" failed\nLog:\n%s" % ( \ - self.pvname, self.log) - -class PVCreateError(LvmError): - def __init__(self, pvname): - self.pvname = pvname - self.log = self.getLvmOutput() - - def __str__(self): - return "pvcreate of pv "%s" failed\nLog:\n%s" % ( \ - self.pvname, self.log) - -"""Exceptions for use in partitioning.""" - -class PartitioningError(Exception): - """A critical error which must be resolved to continue the installation.""" - def __init__(self, message=""): - self.message = str(message) - - def __str__ (self): - return self.message - -class PartitioningWarning(Exception): - """A warning which may be ignored and still complete the installation.""" - def __init__(self, message=""): - self.message = str(message) - - def __str__ (self): - return self.message - -class LabelError(Exception): - """The device could not be labeled.""" - def __init__(self, message=""): - self.message = str(message) - - def __str__(self): - return self.message - -"""Exceptions for use in package selection.""" - -class NoSuchGroup(Exception): - def __init__ (self, value): - self.value = value - - def __str__ (self): - return self.value diff --git a/pkgs/core/pomona/src/exception.py b/pkgs/core/pomona/src/exception.py index 3a018a8..36fd2b0 100644 --- a/pkgs/core/pomona/src/exception.py +++ b/pkgs/core/pomona/src/exception.py @@ -1,19 +1,17 @@ +#!/usr/bin/python
-import bdb -import os, sys, signal, types -from cPickle import Pickler -from string import joinfields +import os +import signal +import string +import sys import traceback +import types
-import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -import logging -log = logging.getLogger("pomona") +from cPickle import Pickler
dumpHash = {}
-def dumpClass(instance, fd, level=0, parentkey="", skipList=[]): +def dumpClass(instance, fd, level=0, parentkey=""): # protect from loops try: if not dumpHash.has_key(instance): @@ -26,11 +24,11 @@ def dumpClass(instance, fd, level=0, parentkey="", skipList=[]): return
if (instance.__class__.__dict__.has_key("__str__") or - instance.__class__.__dict__.has_key("__repr__")): + instance.__class__.__dict__.has_key("__repr__")): fd.write("%s\n" % (instance,)) return - fd.write("%s instance, containing members:\n" % - (instance.__class__.__name__)) + + fd.write("%s instance, containing members:\n" % (instance.__class__.__name__)) pad = ' ' * ((level) * 2)
for key, value in instance.__dict__.items(): @@ -39,12 +37,6 @@ def dumpClass(instance, fd, level=0, parentkey="", skipList=[]): else: curkey = key
- # Don't dump objects that are in our skip list, though ones that are - # None are probably okay. - if eval("instance.%s is not None" % key) and \ - eval("id(instance.%s)" % key) in skipList: - continue - if type(value) == types.ListType: fd.write("%s%s: [" % (pad, curkey)) first = 1 @@ -54,10 +46,11 @@ def dumpClass(instance, fd, level=0, parentkey="", skipList=[]): else: first = 0 if type(item) == types.InstanceType: - dumpClass(item, fd, level + 1, skipList=skipList) + dumpClass(item, fd, level + 1,) else: fd.write("%s" % (item,)) fd.write("]\n") + elif type(value) == types.DictType: fd.write("%s%s: {" % (pad, curkey)) first = 1 @@ -71,28 +64,19 @@ def dumpClass(instance, fd, level=0, parentkey="", skipList=[]): else: fd.write("%s: " % (k,)) if type(v) == types.InstanceType: - dumpClass(v, fd, level + 1, parentkey = curkey, skipList=skipList) + dumpClass(v, fd, level + 1, parentkey = curkey) else: fd.write("%s" % (v,)) fd.write("}\n") + elif type(value) == types.InstanceType: fd.write("%s%s: " % (pad, curkey)) - dumpClass(value, fd, level + 1, parentkey=curkey, skipList=skipList) + dumpClass(value, fd, level + 1, parentkey=curkey) + else: fd.write("%s%s: %s\n" % (pad, curkey, value))
-def dumpException(out, text, tb, pomona): - skipList = [] - idSkipList = [] - - # Catch attributes that do not exist at the time we do the exception dump - # and ignore them. - for k in skipList: - try: - eval("idSkipList.append(id(%s))" % k) - except: - pass - +def dumpException(out, text, tb, installer): p = Pickler(out)
out.write(text) @@ -111,7 +95,7 @@ def dumpException(out, text, tb, pomona):
try: out.write("\n\n") - dumpClass(pomona, out, skipList=idSkipList) + dumpClass(installer, out) except: out.write("\nException occurred during state dump:\n") traceback.print_exc(None, out) @@ -139,31 +123,29 @@ def formatException(type, value, tb): lst.extend(traceback.format_exception_only(type, value)) return lst
-def handleException(pomona, (type, value, tb)): - if isinstance(value, bdb.BdbQuit): - sys.exit(1) - +def handleException(installer, (type, value, tb)): # restore original exception handler sys.excepthook = sys.__excepthook__
+ installer.log.error("Exception occured. Read more in /tmp/instdump.txt.") + # get traceback information list = formatException(type, value, tb) - text = joinfields(list, "") + text = string.joinfields(list, "")
- # save to local storage first + # save to local storage out = open("/tmp/instdump.txt", "w") - dumpException(out, text, tb, pomona) + dumpException(out, text, tb, installer) out.close()
- win = pomona.intf.exceptionWindow(text, "/tmp/instdump.txt") + win = installer.intf.exceptionWindow(text, "/tmp/instdump.txt") if not win: - pomona.intf.__del__() + installer.intf.__del__() os.kill(os.getpid(), signal.SIGKILL)
while 1: win.run() - rc = win.getrc()
- if rc == 0: - pomona.intf.__del__() + if win.getrc() == 0: + installer.intf.__del__() os.kill(os.getpid(), signal.SIGKILL) diff --git a/pkgs/core/pomona/src/flags.py b/pkgs/core/pomona/src/flags.py deleted file mode 100644 index 69b3768..0000000 --- a/pkgs/core/pomona/src/flags.py +++ /dev/null @@ -1,67 +0,0 @@ -# -# flags.py: global pomona flags -# -# Copyright 2001 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -import os -import shlex -from constants import * - -# A lot of effort, but it only allows a limited set of flags to be referenced -class Flags: - def __getattr__(self, attr): - if self.__dict__['flags'].has_key(attr): - return self.__dict__['flags'][attr] - raise AttributeError, attr - - def __setattr__(self, attr, val): - if self.__dict__['flags'].has_key(attr): - self.__dict__['flags'][attr] = val - else: - raise AttributeError, attr - - def createCmdlineDict(self): - cmdlineDict = {} - cmdline = open("/proc/cmdline", "r").read() - lst = shlex.split(cmdline) - - for i in lst: - try: - (key, val) = i.split("=", 1) - except: - key = i - val = True - - cmdlineDict[key] = val - - return cmdlineDict - - def __init__(self): - self.__dict__['flags'] = {} - self.__dict__['flags']['expert'] = 0 - self.__dict__['flags']['debug'] = 0 - self.__dict__['flags']['cmdline'] = self.createCmdlineDict() - self.__dict__['flags']['network'] = False - self.__dict__['flags']['mpath'] = 1 - self.__dict__['flags']['dmraid'] = 1 - - for line in os.popen("tty"): - line = line.strip() - if line.startswith("/dev/tty"): - self.__dict__['flags']['virtpconsole'] = False - else: - self.__dict__['flags']['virtpconsole'] = True - - if self.__dict__['flags']['cmdline'].has_key("debug"): - self.__dict__['flags']['debug'] = self.__dict__['flags']['cmdline']['debug'] - -global flags -flags = Flags() diff --git a/pkgs/core/pomona/src/fsset.py b/pkgs/core/pomona/src/fsset.py deleted file mode 100644 index dcc80f3..0000000 --- a/pkgs/core/pomona/src/fsset.py +++ /dev/null @@ -1,2876 +0,0 @@ -# -# fsset.py: filesystem management -# -# Copyright (C) 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): Matt Wilson msw@redhat.com -# Jeremy Katz katzj@redhat.com -# - -import math -import string -import isys -import iutil -import os -import resource -import posix -import stat -import errno -import parted -import sys -import struct -import partitions -import partedUtils -import raid -import lvm -import time -import types -from flags import flags -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -import logging -log = logging.getLogger("pomona") - -class SuspendError(Exception): - pass - -class OldSwapError(Exception): - pass - -class ResizeError(Exception): - pass - -defaultMountPoints = ['/', '/boot', '/home', '/tmp', '/usr', '/var', '/usr/local', '/opt'] - -fileSystemTypes = {} - -def fileSystemTypeGetDefault(): - if fileSystemTypeGet('ext4').isSupported(): - return fileSystemTypeGet('ext4') - elif fileSystemTypeGet('ext3').isSupported(): - return fileSystemTypeGet('ext3') - elif fileSystemTypeGet('ext2').isSupported(): - return fileSystemTypeGet('ext2') - else: - raise ValueError, "You have neither ext4, ext3 or ext2 support in your kernel!" - - -def fileSystemTypeGet(key): - return fileSystemTypes[key] - -def fileSystemTypeRegister(klass): - fileSystemTypes[klass.getName()] = klass - -def fileSystemTypeGetTypes(): - return fileSystemTypes.copy() - -def getUsableLinuxFs(): - rc = [] - for fsType in fileSystemTypes.keys(): - if fileSystemTypes[fsType].isMountable() and \ - fileSystemTypes[fsType].isLinuxNativeFS(): - rc.append(fsType) - - # make sure the default is first in the list, kind of ugly - default = fileSystemTypeGetDefault() - defaultName = default.getName() - if defaultName in rc: - del rc[rc.index(defaultName)] - rc.insert(0, defaultName) - return rc - -def devify(device): - if device in ["proc", "devpts", "sysfs", "tmpfs"] or device.find(":") != -1: - return device - elif device == "sys": - return "sysfs" - elif device == "shm": - return "tmpfs" - elif device == "spufs": - return "spufs" - elif device != "none" and device[0] != '/': - return "/dev/" + device - else: - return device - -class FileSystemType: - kernelFilesystems = {} - lostAndFoundContext = None - - def __init__(self): - self.deviceArguments = {} - self.formattable = 0 - self.checked = 0 - self.name = "" - self.linuxnativefs = 0 - self.partedFileSystemType = None - self.partedPartitionFlags = [] - self.maxSizeMB = 8 * 1024 * 1024 - self.supported = -1 - self.defaultOptions = "defaults" - self.migratetofs = None - self.extraFormatArgs = [] - self.maxLabelChars = 16 - self.packages = [] - self.needProgram = [] - self.resizable = False - self.supportsFsProfiles = False - self.fsProfileSpecifier = None - self.fsprofile = None - self.bootable = False - - def createLabel(self, mountpoint, maxLabelChars, kslabel = None): - # If a label was specified in the kickstart file, return that as the - # label. - if kslabel: - return kslabel - - if len(mountpoint) > maxLabelChars: - return mountpoint[0:maxLabelChars] - else: - return mountpoint - - def isBootable(self): - return self.bootable - - def isResizable(self): - return self.resizable - def resize(self, entry, size, progress, chroot='/'): - pass - def getMinimumSize(self, device): - log.warning("Unable to determinine minimal size for %s", device) - return 1 - - def isKernelFS(self): - """Returns True if this is an in-kernel pseudo-filesystem.""" - return False - - def mount(self, device, mountpoint, readOnly=0, bindMount=0, - instroot=""): - if not self.isMountable(): - return - iutil.mkdirChain("%s/%s" %(instroot, mountpoint)) - log.debug("mounting %s on %s/%s as %s" %(device, instroot, - mountpoint, self.getMountName())) - isys.mount(device, "%s/%s" %(instroot, mountpoint), - fstype = self.getMountName(), - readOnly = readOnly, bindMount = bindMount, - options = self.defaultOptions) - - def umount(self, device, path): - isys.umount(path, removeDir = 0) - - def getName(self, quoted = 0): - """Return the name of the filesystem. Set quoted to 1 if this - should be quoted (ie, it's not for display).""" - if quoted: - if self.name.find(" ") != -1: - return ""%s"" %(self.name,) - return self.name - - def getMountName(self, quoted = 0): - return self.getName(quoted) - - def getNeededPackages(self): - return self.packages - - def registerDeviceArgumentFunction(self, klass, function): - self.deviceArguments[klass] = function - - def formatDevice(self, entry, progress, chroot='/'): - if self.isFormattable(): - raise RuntimeError, "formatDevice method not defined" - - def migrateFileSystem(self, device, message, chroot='/'): - if self.isMigratable(): - raise RuntimeError, "migrateFileSystem method not defined" - - def labelDevice(self, entry, chroot): - pass - - def clobberDevice(self, entry, chroot): - pass - - def isFormattable(self): - return self.formattable - - def isLinuxNativeFS(self): - return self.linuxnativefs - - def setFsProfile(self, fsprofile=None): - if not self.supportsFsProfiles: - raise RuntimeError, "%s does not support profiles" % (self,) - self.fsprofile = fsprofile - - def getFsProfileArgs(self): - if not self.supportsFsProfiles: - raise RuntimeError, "%s does not support profiles" % (self,) - args = None - if self.fsprofile: - args = [] - if self.fsProfileSpecifier: - args.extend(self.fsProfileSpecifier) - args.extend(self.fsprofile) - return args - - def readProcFilesystems(self): - f = open("/proc/filesystems", 'r') - if not f: - pass - lines = f.readlines() - for line in lines: - fields = string.split(line) - if fields[0] == "nodev": - fsystem = fields[1] - else: - fsystem = fields[0] - FileSystemType.kernelFilesystems[fsystem] = None - - def isMountable(self): - if not FileSystemType.kernelFilesystems: - self.readProcFilesystems() - - return FileSystemType.kernelFilesystems.has_key(self.getMountName()) or self.getName() == "auto" - - def isSupported(self): - # check to ensure we have the binaries they need - for p in self.needProgram: - if len(filter(lambda d: os.path.exists("%s/%s" %(d, p)), - os.environ["PATH"].split(":"))) == 0: - return False - - if self.supported == -1: - return self.isMountable() - return self.supported - - def isChecked(self): - return self.checked - - def getDeviceArgs(self, device): - deviceArgsFunction = self.deviceArguments.get(device.__class__) - if not deviceArgsFunction: - return [] - return deviceArgsFunction(device) - - def getPartedFileSystemType(self): - return self.partedFileSystemType - - def getPartedPartitionFlags(self): - return self.partedPartitionFlags - - # note that this returns the maximum size of a filesystem in megabytes - def getMaxSizeMB(self): - return self.maxSizeMB - - def getDefaultOptions(self, mountpoint): - return self.defaultOptions - - def getMigratableFSTargets(self): - retval = [] - if not self.migratetofs: - return retval - - for fs in self.migratetofs: - if fileSystemTypeGet(fs).isSupported(): - retval.append(fs) - - return retval - - def isMigratable(self): - if len(self.getMigratableFSTargets()) > 0: - return 1 - else: - return 0 - - -class reiserfsFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.partedFileSystemType = parted.file_system_type_get("reiserfs") - self.formattable = 1 - self.checked = 1 - self.linuxnativefs = 1 - self.bootable = True - # this is totally, 100% unsupported. Boot with "linux reiserfs" - # at the boot: prompt will let you make new reiserfs filesystems - # in the installer. Bugs filed when you use this will be closed - # WONTFIX. - if flags.cmdline.has_key("reiserfs"): - self.supported = -1 - else: - self.supported = 0 - - self.name = "reiserfs" - self.packages = [ "reiserfs-utils" ] - self.needProgram = [ "mkreiserfs", "reiserfstune" ] - - self.maxSizeMB = 8 * 1024 * 1024 - - def formatDevice(self, entry, progress, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - - p = os.pipe() - os.write(p[1], "y\n") - os.close(p[1]) - - rc = iutil.execWithRedirect("mkreiserfs", - [devicePath], - stdin = p[0], - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - - if rc: - raise SystemError - - def labelDevice(self, entry, chroot): - devicePath = entry.device.setupDevice(chroot) - label = self.createLabel(entry.mountpoint, self.maxLabelChars, - kslabel = entry.label) - rc = iutil.execWithRedirect("reiserfstune", - ["--label", label, devicePath], - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - if rc: - raise SystemError - entry.setLabel(label) - -fileSystemTypeRegister(reiserfsFileSystem()) - -class xfsFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.partedFileSystemType = parted.file_system_type_get("xfs") - self.formattable = 1 - self.checked = 1 - self.linuxnativefs = 1 - self.name = "xfs" - self.maxSizeMB = 16 * 1024 * 1024 - self.maxLabelChars = 12 - self.supported = -1 - if not os.path.exists("/sbin/mkfs.xfs") and not os.path.exists("/usr/sbin/mkfs.xfs"): - self.supported = 0 - - self.packages = [ "xfsprogs" ] - self.needProgram = [ "mkfs.xfs", "xfs_admin" ] - - def formatDevice(self, entry, progress, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - - rc = iutil.execWithRedirect("mkfs.xfs", ["-f", devicePath], - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - - if rc: - raise SystemError - - def labelDevice(self, entry, chroot): - devicePath = entry.device.setupDevice(chroot) - label = self.createLabel(entry.mountpoint, self.maxLabelChars, - kslabel = entry.label) - rc = iutil.execWithRedirect("xfs_admin", - ["-L", label, devicePath], - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - if rc: - raise SystemError - entry.setLabel(label) - -fileSystemTypeRegister(xfsFileSystem()) - -class jfsFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.partedFileSystemType = parted.file_system_type_get("jfs") - self.formattable = 1 - self.checked = 1 - self.linuxnativefs = 1 - self.maxLabelChars = 16 - self.bootable = True - # this is totally, 100% unsupported. Boot with "linux jfs" - # at the boot: prompt will let you make new reiserfs filesystems - # in the installer. Bugs filed when you use this will be closed - # WONTFIX. - if flags.cmdline.has_key("jfs"): - self.supported = -1 - else: - self.supported = 0 - - self.name = "jfs" - self.packages = [ "jfsutils" ] - self.needProgram = [ "mkfs.jfs", "jfs_tune" ] - - self.maxSizeMB = 8 * 1024 * 1024 - - def labelDevice(self, entry, chroot): - devicePath = entry.device.setupDevice(chroot) - label = self.createLabel(entry.mountpoint, self.maxLabelChars, - kslabel = entry.label) - rc = iutil.execWithRedirect("jfs_tune", - ["-L", label, devicePath], - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - if rc: - raise SystemError - entry.setLabel(label) - - def formatDevice(self, entry, progress, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - - rc = iutil.execWithRedirect("mkfs.jfs", - ["-q", devicePath], - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - - if rc: - raise SystemError - -fileSystemTypeRegister(jfsFileSystem()) - -class extFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.partedFileSystemType = None - self.formattable = 1 - self.checked = 1 - self.linuxnativefs = 1 - self.maxSizeMB = 8 * 1024 * 1024 - self.packages = [ "e2fsprogs" ] - self.supportsFsProfiles = True - self.fsProfileSpecifier = "-T" - self.resizable = True - self.bootable = True - - def resize(self, entry, size, progress, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - - log.info("checking %s prior to resize" %(devicePath,)) - w = None - if progress: - w = progress(_("Checking"), - _("Checking filesystem on %s...") %(devicePath), - 100, pulse = True) - - rc = iutil.execWithPulseProgress("e2fsck", ["-f", "-p", "-C", "0", devicePath], - stdout="/tmp/resize.out", - stderr="/tmp/resize.out", - progress = w) - if rc >= 4: - raise ResizeError, ("Check of %s failed" %(devicePath,), devicePath) - if progress: - w.pop() - w = progress(_("Resizing"), - _("Resizing filesystem on %s...") %(devicePath), - 100, pulse = True) - - log.info("resizing %s" %(devicePath,)) - rc = iutil.execWithPulseProgress("resize2fs", - ["-p", devicePath, "%sM" %(size,)], - stdout="/tmp/resize.out", - stderr="/tmp/resize.out", - progress = w) - if progress: - w.pop() - if rc: - raise ResizeError, ("Resize of %s failed" %(devicePath,), devicePath) - - def getMinimumSize(self, device): - """Return the minimum filesystem size in megabytes""" - devicePath = "/dev/%s" % (device,) - - # FIXME: it'd be nice if we didn't have to parse this out ourselves - buf = iutil.execWithCapture("dumpe2fs", - ["-h", devicePath], - stderr = "/dev/tty5") - blocks = free = bs = 0 - for l in buf.split("\n"): - if l.startswith("Free blocks"): - try: - free = l.split()[2] - free = int(free) - except Exception, e: - log.warning("error determining free blocks on %s: %s" %(devicePath, e)) - free = 0 - elif l.startswith("Block size"): - try: - bs = l.split()[2] - bs = int(bs) - except Exception, e: - log.warning("error determining block size of %s: %s" %(devicePath, e)) - bs = 0 - elif l.startswith("Block count"): - try: - blocks = l.split()[2] - blocks = int(blocks) - except Exception, e: - log.warning("error determining block count of %s: %s" %(devicePath, e)) - blocks = 0 - - if free == 0 or bs == 0: - log.warning("Unable to determinine minimal size for %s", devicePath) - return 1 - - used = math.ceil((blocks - free) * bs / 1024.0 / 1024.0) - log.info("used size of %s is %s" %(devicePath, used)) - # FIXME: should we bump this beyond the absolute minimum? - return used - - def labelDevice(self, entry, chroot): - devicePath = entry.device.setupDevice(chroot) - label = self.createLabel(entry.mountpoint, self.maxLabelChars, - kslabel = entry.label) - - rc = iutil.execWithRedirect("e2label", - [devicePath, label], - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - if rc: - raise SystemError - entry.setLabel(label) - - def formatDevice(self, entry, progress, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - devArgs = self.getDeviceArgs(entry.device) - args = [ "mke2fs", devicePath ] - - fsProfileArgs = self.getFsProfileArgs() - if fsProfileArgs: - args.extend(fsProfileArgs) - args.extend(devArgs) - args.extend(self.extraFormatArgs) - - log.info("Format command: %s\n" % str(args)) - - rc = ext2FormatFilesystem(args, "/dev/tty5", - progress, - entry.mountpoint) - if rc: - raise SystemError - - def clobberDevice(self, entry, chroot): - device = entry.device.setupDevice(chroot) - isys.ext2Clobber(device) - - # this is only for ext3 filesystems, but migration is a method - # of the ext2 fstype, so it needs to be here. FIXME should be moved - def setExt3Options(self, entry, message, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - - # if no journal, don't turn off the fsck - if not isys.ext2HasJournal(devicePath): - return - - rc = iutil.execWithRedirect("tune2fs", - ["-c0", "-i0", - "-ouser_xattr,acl", devicePath], - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - -class ext2FileSystem(extFileSystem): - def __init__(self): - extFileSystem.__init__(self) - self.name = "ext2" - self.partedFileSystemType = parted.file_system_type_get("ext2") - self.migratetofs = ['ext3'] - - def migrateFileSystem(self, entry, message, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - - if not entry.fsystem or not entry.origfsystem: - raise RuntimeError, ("Trying to migrate fs w/o fsystem or " - "origfsystem set") - if entry.fsystem.getName() != "ext3": - raise RuntimeError, ("Trying to migrate ext2 to something other " - "than ext3") - - # if journal already exists skip - if isys.ext2HasJournal(devicePath): - log.info("Skipping migration of %s, has a journal already.\n" % devicePath) - return - - rc = iutil.execWithRedirect("tune2fs", - ["-j", devicePath ], - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - - if rc: - raise SystemError - - # XXX this should never happen, but appears to have done - # so several times based on reports in bugzilla. - # At least we can avoid leaving them with a system which won't boot - if not isys.ext2HasJournal(devicePath): - log.warning("Migration of %s attempted but no journal exists after " - "running tune2fs.\n" % (devicePath)) - if message: - rc = message(_("Error"), - _("An error occurred migrating %s to ext3. It is " - "possible to continue without migrating this " - "file system if desired.\n\n" - "Would you like to continue without migrating %s?") - % (devicePath, devicePath), type = "yesno") - if rc == 0: - sys.exit(0) - entry.fsystem = entry.origfsystem - else: - extFileSystem.setExt3Options(self, entry, message, chroot) - - -fileSystemTypeRegister(ext2FileSystem()) - -class ext3FileSystem(extFileSystem): - def __init__(self): - extFileSystem.__init__(self) - self.name = "ext3" - self.extraFormatArgs = [ "-t", "ext3" ] - self.partedFileSystemType = parted.file_system_type_get("ext3") - if flags.cmdline.has_key("ext4"): - self.migratetofs = ['ext4dev'] - - def formatDevice(self, entry, progress, chroot='/'): - extFileSystem.formatDevice(self, entry, progress, chroot) - extFileSystem.setExt3Options(self, entry, progress, chroot) - - def migrateFileSystem(self, entry, message, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - - if not entry.fsystem or not entry.origfsystem: - raise RuntimeError, ("Trying to migrate fs w/o fsystem or " - "origfsystem set") - if entry.fsystem.getName() != "ext4dev": - raise RuntimeError, ("Trying to migrate ext3 to something other " - "than ext4") - - # This is only needed as long as ext4 is actually "ext4dev" - rc = iutil.execWithRedirect("tune2fs", - ["-E", "test_fs", devicePath ], - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - if rc: - raise SystemError - -fileSystemTypeRegister(ext3FileSystem()) - -class ext4FileSystem(extFileSystem): - def __init__(self): - extFileSystem.__init__(self) - self.name = "ext4" - self.partedFileSystemType = parted.file_system_type_get("ext3") - self.extraFormatArgs = [ "-t", "ext4" ] - self.bootable = False - - def formatDevice(self, entry, progress, chroot='/'): - extFileSystem.formatDevice(self, entry, progress, chroot) - extFileSystem.setExt3Options(self, entry, progress, chroot) - -fileSystemTypeRegister(ext4FileSystem()) - -class btrfsFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.formattable = 1 - self.checked = 1 - self.linuxnativefs = 1 - self.bootable = False - self.maxLabelChars = 256 - - self.name = "btrfs" - self.packages = [ "btrfs-progs" ] - self.needProgram = [ "mkfs.btrfs", "btrfsctl" ] - - # Bigger, really, depending on machine - self.maxSizeMB = 16 * 1024 * 1024 - - # We'll sneakily label it here, too. - def formatDevice(self, entry, progress, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - label = self.createLabel(entry.mountpoint, self.maxLabelChars, - kslabel = entry.label) - - rc = iutil.execWithRedirect("mkfs.btrfs", ["-L", label, devicePath], - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - - if rc: - raise SystemError - entry.setLabel(label) - - def labelDevice(self, entry, chroot): - # We did this on the initial format; no standalone labeler yet - pass - - def resize(self, entry, size, progress, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - log.info("resizing %s" %(devicePath,)) - - w = None - if progress: - w = progress(_("Resizing"), - _("Resizing filesystem on %s...") %(devicePath), - 100, pulse = True) - - rc = iutil.execWithPulseProgress("btrfsctl", - ["-r", "%sM" %(size,), devicePath], - stdout="/tmp/resize.out", - stderr="/tmp/resize.out", - progress = w) - if progress: - w.pop() - if rc: - raise ResizeError, ("Resize of %s failed: %s" %(devicePath, rc), devicePath) - - -fileSystemTypeRegister(btrfsFileSystem()) - -class raidMemberDummyFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.partedFileSystemType = parted.file_system_type_get("ext2") - self.partedPartitionFlags = [ parted.PARTITION_RAID ] - self.formattable = 1 - self.checked = 0 - self.linuxnativefs = 1 - self.name = "software RAID" - self.maxSizeMB = 8 * 1024 * 1024 - self.supported = 1 - - if len(raid.availRaidLevels) == 0: - self.supported = 0 - - self.packages = [ "mdadm" ] - - def formatDevice(self, entry, progress, chroot='/'): - # mkraid did all we need to format this partition... - pass - -fileSystemTypeRegister(raidMemberDummyFileSystem()) - -class lvmPhysicalVolumeDummyFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.partedFileSystemType = parted.file_system_type_get("ext2") - self.partedPartitionFlags = [ parted.PARTITION_LVM ] - self.formattable = 1 - self.checked = 0 - self.linuxnativefs = 1 - self.name = "physical volume (LVM)" - self.maxSizeMB = 8 * 1024 * 1024 - self.supported = 1 - self.packages = [ "lvm2" ] - - def isMountable(self): - return 0 - - def formatDevice(self, entry, progress, chroot='/'): - # already done by the pvcreate during volume creation - pass - -fileSystemTypeRegister(lvmPhysicalVolumeDummyFileSystem()) - -class lvmVolumeGroupDummyFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.partedFileSystemType = parted.file_system_type_get("ext2") - self.formattable = 1 - self.checked = 0 - self.linuxnativefs = 0 - self.name = "volume group (LVM)" - self.supported = 0 - self.maxSizeMB = 8 * 1024 * 1024 - self.packages = [ "lvm2" ] - - def isMountable(self): - return 0 - - def formatDevice(self, entry, progress, chroot='/'): - # the vgcreate already did this - pass - -fileSystemTypeRegister(lvmVolumeGroupDummyFileSystem()) - -class swapFileSystem(FileSystemType): - enabledSwaps = {} - - def __init__(self): - FileSystemType.__init__(self) - self.partedFileSystemType = parted.file_system_type_get("linux-swap") - self.formattable = 1 - self.name = "swap" - self.maxSizeMB = 8 * 1024 * 1024 - self.linuxnativefs = 1 - self.supported = 1 - self.maxLabelChars = 15 - - def mount(self, device, mountpoint, readOnly=0, bindMount=0, - instroot = None): - pagesize = resource.getpagesize() - buf = None - if pagesize > 2048: - num = pagesize - else: - num = 2048 - try: - fd = os.open(device, os.O_RDONLY) - buf = os.read(fd, num) - except: - pass - finally: - try: - os.close(fd) - except: - pass - - if buf is not None and len(buf) == pagesize: - sig = buf[pagesize - 10:] - if sig == 'SWAP-SPACE': - raise OldSwapError - if sig == 'S1SUSPEND\x00' or sig == 'S2SUSPEND\x00': - raise SuspendError - - isys.swapon (device) - - def umount(self, device, path): - # unfortunately, turning off swap is bad. - raise RuntimeError, "unable to turn off swap" - - def formatDevice(self, entry, progress, chroot='/'): - file = entry.device.setupDevice(chroot) - rc = iutil.execWithRedirect ("mkswap", - ['-v1', file], - stdout = "/dev/tty5", - stderr = "/dev/tty5", - searchPath = 1) - if rc: - raise SystemError - - def labelDevice(self, entry, chroot): - file = entry.device.setupDevice(chroot) - devName = entry.device.getDevice() - # we'll keep the SWAP-* naming for all devs but Compaq SMART2 - # nodes (#176074) - if devName[0:6] == "cciss/": - swapLabel = "SW-%s" % (devName) - elif devName.startswith("mapper/"): - swapLabel = "SWAP-%s" % (devName[7:],) - else: - swapLabel = "SWAP-%s" % (devName) - label = self.createLabel(swapLabel, self.maxLabelChars) - rc = iutil.execWithRedirect ("mkswap", - ['-v1', "-L", label, file], - stdout = "/dev/tty5", - stderr = "/dev/tty5", - searchPath = 1) - if rc: - raise SystemError - entry.setLabel(label) - - def clobberDevice(self, entry, chroot): - pagesize = resource.getpagesize() - dev = entry.device.setupDevice(chroot) - try: - fd = os.open(dev, os.O_RDWR) - buf = "\0x00" * pagesize - os.write(fd, buf) - except: - pass - finally: - try: - os.close(fd) - except: - pass - -fileSystemTypeRegister(swapFileSystem()) - -class FATFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.partedFileSystemType = parted.file_system_type_get("fat32") - self.formattable = 1 - self.checked = 0 - self.maxSizeMB = 1024 * 1024 - self.name = "vfat" - self.packages = [ "dosfstools" ] - self.defaultOptions = "umask=0077,shortname=winnt" - - def formatDevice(self, entry, progress, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - devArgs = self.getDeviceArgs(entry.device) - args = [ devicePath ] - args.extend(devArgs) - - rc = iutil.execWithRedirect("mkdosfs", args, - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - if rc: - raise SystemError - - def labelDevice(self, entry, chroot): - devicePath = entry.device.setupDevice(chroot) - label = self.createLabel(entry.mountpoint, self.maxLabelChars, - kslabel = entry.label) - - rc = iutil.execWithRedirect("dosfslabel", - [devicePath, label], - stdout = "/dev/tty5", - stderr = "/dev/tty5", - searchPath = 1) - if rc: - msg = iutil.execWithCapture("dosfslabel", [devicePath], - stderr="/dev/tty5") - raise SystemError, "dosfslabel failed on device %s: %s" % (devicePath, msg) - - newLabel = iutil.execWithCapture("dosfslabel", [devicePath], - stderr = "/dev/tty5") - newLabel = newLabel.strip() - if label != newLabel: - raise SystemError, "dosfslabel failed on device %s" % (devicePath,) - entry.setLabel(label) - -fileSystemTypeRegister(FATFileSystem()) - -class NTFSFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.partedFileSystemType = parted.file_system_type_get("ntfs") - self.formattable = 0 - self.checked = 0 - self.name = "ntfs" - if len(filter(lambda d: os.path.exists("%s/ntfsresize" %(d,)), - os.environ["PATH"].split(":"))) > 0: - self.resizable = True - - def resize(self, entry, size, progress, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - log.info("resizing %s to %sM" %(devicePath, size)) - w = None - if progress: - w = progress(_("Resizing"), - _("Resizing filesystem on %s...") %(devicePath), - 100, pulse = True) - - p = os.pipe() - os.write(p[1], "y\n") - os.close(p[1]) - - # FIXME: we should call ntfsresize -c to ensure that we can resize - # before starting the operation - - rc = iutil.execWithPulseProgress("ntfsresize", ["-v", - "-s", "%sM" %(size,), - devicePath], - stdin = p[0], - stdout = "/tmp/resize.out", - stderr = "/tmp/resize.out", - progress = w) - if progress: - w.pop() - if rc: - raise ResizeError, ("Resize of %s failed" %(devicePath,), devicePath) - - def getMinimumSize(self, device): - """Return the minimum filesystem size in megabytes""" - devicePath = "/dev/%s" % (device,) - - buf = iutil.execWithCapture("ntfsresize", ["-m", devicePath], - stderr = "/dev/tty5") - for l in buf.split("\n"): - if not l.startswith("Minsize"): - continue - try: - min = l.split(":")[1].strip() - return int(min) + 250 - except Exception, e: - log.warning("Unable to parse output for minimum size on %s: %s" %(device, e)) - - log.warning("Unable to discover minimum size of filesystem on %s" %(device,)) - return 1 - - -fileSystemTypeRegister(NTFSFileSystem()) - -class hfsFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.partedFileSystemType = parted.file_system_type_get("hfs") - self.formattable = 1 - self.checked = 0 - self.name = "hfs" - self.supported = 0 - self.needProgram = [ "hformat" ] - - def isMountable(self): - return 0 - - def formatDevice(self, entry, progress, chroot='/'): - devicePath = entry.device.setupDevice(chroot) - devArgs = self.getDeviceArgs(entry.device) - args = [ devicePath ] - args.extend(devArgs) - - rc = iutil.execWithRedirect("hformat", args, - stdout = "/dev/tty5", - stderr = "/dev/tty5", searchPath = 1) - if rc: - raise SystemError - -fileSystemTypeRegister(hfsFileSystem()) - -class HfsPlusFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.partedFileSystemType = parted.file_system_type_get("hfs+") - self.formattable = 0 - self.checked = 0 - self.name = "hfs+" - -fileSystemTypeRegister(HfsPlusFileSystem()) - -class networkFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.formattable = 0 - self.checked = 0 - self.name = "nfs" - - def isMountable(self): - return 0 - -fileSystemTypeRegister(networkFileSystem()) - -class nfsv4FileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.formattable = 0 - self.checked = 0 - self.name = "nfs4" - - def isMountable(self): - return 0 - -fileSystemTypeRegister(nfsv4FileSystem()) - -class ForeignFileSystem(FileSystemType): - def __init__(self): - FileSystemType.__init__(self) - self.formattable = 0 - self.checked = 0 - self.name = "foreign" - - def formatDevice(self, entry, progress, chroot='/'): - return - -fileSystemTypeRegister(ForeignFileSystem()) - -class PseudoFileSystem(FileSystemType): - def __init__(self, name): - FileSystemType.__init__(self) - self.formattable = 0 - self.checked = 0 - self.name = name - self.supported = 0 - - def isKernelFS(self): - return True - -class SpuFileSystem(PseudoFileSystem): - def __init__(self): - PseudoFileSystem.__init__(self, "spufs") - -fileSystemTypeRegister(SpuFileSystem()) - -class ProcFileSystem(PseudoFileSystem): - def __init__(self): - PseudoFileSystem.__init__(self, "proc") - -fileSystemTypeRegister(ProcFileSystem()) - -class SysfsFileSystem(PseudoFileSystem): - def __init__(self): - PseudoFileSystem.__init__(self, "sysfs") - -fileSystemTypeRegister(SysfsFileSystem()) - -class DevptsFileSystem(PseudoFileSystem): - def __init__(self): - PseudoFileSystem.__init__(self, "devpts") - self.defaultOptions = "gid=5,mode=620" - - def isMountable(self): - return 0 - -fileSystemTypeRegister(DevptsFileSystem()) - -class DevshmFileSystem(PseudoFileSystem): - def __init__(self): - PseudoFileSystem.__init__(self, "tmpfs") - - def isMountable(self): - return 0 - -fileSystemTypeRegister(DevshmFileSystem()) - -class AutoFileSystem(PseudoFileSystem): - def __init__(self): - PseudoFileSystem.__init__(self, "auto") - - def mount(self, device, mountpoint, readOnly=0, bindMount=0, - instroot = None): - errNum = 0 - errMsg = "cannot mount auto filesystem on %s of this type" % device - - if not self.isMountable(): - return - iutil.mkdirChain("%s/%s" %(instroot, mountpoint)) - - fs = isys.readFSType(device) - if fs is not None: - try: - isys.mount (device, mountpoint, fstype = fs, readOnly = - readOnly, bindMount = bindMount) - return - except SystemError, (num, msg): - errNum = num - errMsg = msg - - raise SystemError (errNum, errMsg) - - def umount(self, device, path): - isys.umount(path, removeDir = 0) - -fileSystemTypeRegister(AutoFileSystem()) - -class BindFileSystem(PseudoFileSystem): - def __init__(self): - PseudoFileSystem.__init__(self, "bind") - - def isMountable(self): - return 1 - -fileSystemTypeRegister(BindFileSystem()) - -class FileSystemSet: - def __init__(self): - self.messageWindow = None - self.progressWindow = None - self.waitWindow = None - self.mountcount = 0 - self.migratedfs = 0 - self.reset() - self.volumesCreated = 0 - - def isActive(self): - return self.mountcount != 0 - - def registerMessageWindow(self, method): - self.messageWindow = method - - def registerProgressWindow(self, method): - self.progressWindow = method - - def registerWaitWindow(self, method): - self.waitWindow = method - - def reset (self): - self.entries = [] - proc = FileSystemSetEntry(Device(device="proc"), '/proc', - fileSystemTypeGet("proc")) - self.add(proc) - sys = FileSystemSetEntry(Device(device="sys"), '/sys', - fileSystemTypeGet("sysfs")) - self.add(sys) - pts = FileSystemSetEntry(Device(device="devpts"), '/dev/pts', - fileSystemTypeGet("devpts"), "gid=5,mode=620") - self.add(pts) - shm = FileSystemSetEntry(Device(device="shm"), '/dev/shm', - fileSystemTypeGet("tmpfs")) - self.add(shm) - - def verify (self): - for entry in self.entries: - if type(entry.__dict__) != type({}): - raise RuntimeError, "fsset internals inconsistent" - - def add (self, newEntry): - # Should object A be sorted after object B? Take mountpoints and - # device names into account so bind mounts are sorted correctly. - def comesAfter (a, b): - mntA = a.mountpoint - mntB = b.mountpoint - devA = a.device.getDevice() - devB = b.device.getDevice() - - if not mntB: - return False - if mntA and mntA != mntB and mntA.startswith(mntB): - return True - if devA and devA != mntB and devA.startswith(mntB): - return True - return False - - def samePseudo (a, b): - return isinstance(a.fsystem, PseudoFileSystem) and isinstance (b.fsystem, PseudoFileSystem) and \ - not isinstance (a.fsystem, BindFileSystem) and not isinstance (b.fsystem, BindFileSystem) and \ - a.fsystem.getName() == b.fsystem.getName() - - def sameEntry (a, b): - return a.device.getDevice() == b.device.getDevice() and a.mountpoint == b.mountpoint - - # Remove preexisting duplicate entries - pseudo filesystems are - # duplicate if they have the same filesystem type as an existing one. - # Otherwise, they have to have the same device and mount point - # (required to check for bind mounts). - for existing in self.entries: - if samePseudo (newEntry, existing) or sameEntry (newEntry, existing): - self.remove(existing) - - # XXX debuggin' -## log.info ("fsset at %s\n" -## "adding entry for %s\n" -## "entry object %s, class __dict__ is %s", -## self, entry.mountpoint, entry, -## isys.printObject(entry.__dict__)) - - insertAt = 0 - - # Special case for /. - if newEntry.mountpoint == "/": - self.entries.insert(insertAt, newEntry) - return - - # doesn't matter where these get added, so just put them at the end - if not newEntry.mountpoint or not newEntry.mountpoint.startswith("/") or self.entries == []: - self.entries.append(newEntry) - return - - for entry in self.entries: - if comesAfter(newEntry, entry): - insertAt = self.entries.index(entry)+1 - - self.entries.insert(insertAt, newEntry) - - def remove (self, entry): - self.entries.remove(entry) - - def getEntryByMountPoint(self, mount): - for entry in self.entries: - if entry.mountpoint == mount: - return entry - return None - - def getEntryByDeviceName(self, dev): - for entry in self.entries: - if entry.device.getDevice() == dev: - return entry - - # getDevice() will return the mapped device if using LUKS - if entry.device.device == dev: - return entry - - return None - - def copy (self): - new = FileSystemSet() - for entry in self.entries: - new.add (entry) - return new - - def fstab (self): - format = "%-23s %-23s %-7s %-15s %d %d\n" - fstab = """ -# -# /etc/fstab -# Created by pomona on %s -# -# Accessible filesystems, by reference, are maintained under '/dev/disk' -# See man pages fstab(5), findfs(8), mount(8) and/or vol_id(8) for more info -# -""" % time.asctime() - - for entry in self.entries: - if entry.mountpoint: - if entry.getUuid() and entry.device.doLabel is not None: - device = "UUID=%s" %(entry.getUuid(),) - elif entry.getLabel() and entry.device.doLabel is not None: - device = "LABEL=%s" % (entry.getLabel(),) - else: - device = devify(entry.device.getDevice()) - fstab = fstab + entry.device.getComment() - fstab = fstab + format % (device, entry.mountpoint, - entry.fsystem.getMountName(), - entry.getOptions(), entry.fsck, - entry.order) - return fstab - - def mtab (self): - format = "%s %s %s %s 0 0\n" - mtab = "" - for entry in self.entries: - if not entry.isMounted(): - continue - if entry.mountpoint: - # swap doesn't end up in the mtab - if entry.fsystem.getName() == "swap": - continue - options = entry.getOptions() - if options: - options = "rw," + options - else: - options = "rw" - mtab = mtab + format % (devify(entry.device.getDevice()), - entry.mountpoint, - entry.fsystem.getName(), - options) - return mtab - - def raidtab(self): - # set up raidtab... - raidtab = "" - for entry in self.entries: - if entry.device.getName() == "RAIDDevice": - raidtab = raidtab + entry.device.raidTab() - - return raidtab - - def mdadmConf(self): - """Make the mdadm.conf file with mdadm command. - - This creates a conf file with active arrays. In other words - the arrays that we don't want included must be inactive. - """ - activeArrays = iutil.execWithCapture("mdadm", ["--detail", "--scan"]) - if len(activeArrays) == 0: - return - - cf = """ -# mdadm.conf written out by pomona -DEVICE partitions -MAILADDR root - -%s -""" % activeArrays - return cf - - def crypttab(self): - """set up /etc/crypttab""" - crypttab = "" - for entry in self.entries: - if entry.device.crypto: - crypttab += entry.device.crypto.crypttab() - - return crypttab - - def write (self, prefix): - f = open (prefix + "/etc/fstab", "w") - f.write (self.fstab()) - f.close () - - cf = self.mdadmConf() - - if cf: - f = open (prefix + "/etc/mdadm.conf", "w") - f.write (cf) - f.close () - - crypttab = self.crypttab() - if crypttab: - f = open(prefix + "/etc/crypttab", "w") - f.write(crypttab) - f.close() - - # touch mtab - open (prefix + "/etc/mtab", "w+") - f.close () - - def mkDevRoot(self, instPath): - root = self.getEntryByMountPoint("/") - dev = "%s/dev/%s" % (instPath, root.device.getDevice()) - if not os.path.exists("%s/dev/root" %(instPath,)) and os.path.exists(dev): - rdev = os.stat(dev).st_rdev - os.mknod("%s/dev/root" % (instPath,), stat.S_IFBLK | 0600, rdev) - - # return the "boot" device - def getBootDev(self): - mntDict = {} - bootDev = None - for entry in self.entries: - mntDict[entry.mountpoint] = entry.device - - # FIXME: this ppc stuff feels kind of crufty -- the abstraction - # here needs a little bit of work - if mntDict.has_key("/boot"): - bootDev = mntDict['/boot'] - elif mntDict.has_key("/"): - bootDev = mntDict['/'] - - return bootDev - - def bootloaderChoices(self, diskSet, bl): - ret = {} - bootDev = self.getBootDev() - - if bootDev is None: - log.warning("no boot device set") - return ret - - if bootDev.getName() == "RAIDDevice": - ret['boot'] = (bootDev.device, N_("RAID Device")) - return ret - - ret['boot'] = (bootDev.device, N_("First sector of boot partition")) - ret['mbr'] = (bl.drivelist[0], N_("Master Boot Record (MBR)")) - return ret - - # set active partition on disks - # if an active partition is set, leave it alone; if none set - # set either our boot partition or the first partition on the drive active - def setActive(self, diskset): - dev = self.getBootDev() - - if dev is None: - return - - bootDev = dev.device - - if dev.getName() != "RAIDDevice": - part = partedUtils.get_partition_by_name(diskset.disks, bootDev) - drive = partedUtils.get_partition_drive(part) - - for drive in diskset.disks.keys(): - foundActive = 0 - bootPart = None - if partedUtils.hasGptLabel(diskset, drive): - continue - disk = diskset.disks[drive] - part = disk.next_partition() - while part: - if not part.is_active(): - part = disk.next_partition(part) - continue - - if not part.is_flag_available(parted.PARTITION_BOOT): - foundActive = 1 - part = None - continue - - if part.get_flag(parted.PARTITION_BOOT): - foundActive = 1 - part = None - continue - - if not bootPart: - bootPart = part - - if partedUtils.get_partition_name(part) == bootDev: - bootPart = part - - part = disk.next_partition(part) - - if bootPart and not foundActive: - bootPart.set_flag(parted.PARTITION_BOOT, 1) - - if bootPart: - del bootPart - - def resizeFilesystems (self, diskset, chroot = '/', shrink = False, grow = False): - todo = [] - for entry in self.entries: - if not entry.fsystem or not entry.fsystem.isResizable(): - continue - if entry.fsystem.isFormattable() and entry.getFormat(): - continue - if entry.resizeTargetSize is None: - continue - if shrink and not (entry.resizeTargetSize < entry.resizeOrigSize): - continue - if grow and not (entry.resizeTargetSize > entry.resizeOrigSize): - continue - todo.append(entry) - if len(todo) == 0: - return - - # we have to have lvm activated to be able to do resizes of LVs - lvmActive = lvm.vgcheckactive() - devicesActive = diskset.devicesOpen - - if not devicesActive: - # should this not be diskset.openDevices() ? - diskset.startMPath() - diskset.startDmRaid() - diskset.startMdRaid() - - if not lvmActive: - lvm.vgscan() - lvm.vgactivate() - - for entry in todo: - entry.fsystem.resize(entry, entry.resizeTargetSize, - self.progressWindow, chroot) - if not lvmActive: - lvm.vgdeactivate() - - if not devicesActive: - # should this not be diskset.closeDevices() ? - diskset.stopMPath() - diskset.stopDmRaid() - diskset.stopMdRaid() - - def shrinkFilesystems (self, diskset, chroot): - self.resizeFilesystems(diskset, chroot, shrink = True) - def growFilesystems (self, diskset, chroot): - self.resizeFilesystems(diskset, chroot, grow = True) - - def formatSwap (self, chroot, forceFormat=False): - formatted = [] - notformatted = [] - - for entry in self.entries: - if (not entry.fsystem or not entry.fsystem.getName() == "swap" or - entry.isMounted()): - continue - if not entry.getFormat(): - if not forceFormat: - notformatted.append(entry) - continue - try: - self.formatEntry(entry, chroot) - formatted.append(entry) - except SystemError: - if self.messageWindow: - self.messageWindow(_("Error"), - _("An error occurred trying to " - "initialize swap on device %s. This " - "problem is serious, and the install " - "cannot continue.\n\n" - "Press <Enter> to exit the installer.") - % (entry.device.getDevice(),)) - sys.exit(0) - - for entry in formatted: - try: - self.labelEntry(entry, chroot) - except SystemError: - # should be OK, fall back to by device - pass - - # find if there's a label on the ones we're not formatting - for entry in notformatted: - dev = entry.device.getDevice() - if not dev or dev == "none": - continue - try: - label = isys.readFSLabel(dev) - except: - continue - if label: - entry.setLabel(label) - - def turnOnSwap (self, chroot, upgrading=False): - def swapErrorDialog (msg, format_button_text, entry): - buttons = [_("Skip"), format_button_text, _("_Exit installer")] - ret = self.messageWindow(_("Error"), msg, type="custom", - custom_buttons=buttons, - custom_icon="warning") - if ret == 0: - self.entries.remove(entry) - elif ret == 1: - self.formatEntry(entry, chroot) - entry.mount(chroot) - self.mountcount = self.mountcount + 1 - else: - sys.exit(0) - - for entry in self.entries: - if (entry.fsystem and entry.fsystem.getName() == "swap" - and not entry.isMounted()): - try: - entry.mount(chroot) - self.mountcount = self.mountcount + 1 - except OldSwapError: - if self.messageWindow: - msg = _("The swap device:\n\n /dev/%s\n\n" - "is a version 0 Linux swap partition. If you " - "want to use this device, you must reformat as " - "a version 1 Linux swap partition. If you skip " - "it, the installer will ignore it during the " - "installation.") % (entry.device.getDevice()) - - swapErrorDialog(msg, _("Reformat"), entry) - except SuspendError: - if self.messageWindow: - if upgrading: - msg = _("The swap device:\n\n /dev/%s\n\n" - "in your /etc/fstab file is currently in " - "use as a software suspend partition, " - "which means your system is hibernating. " - "To perform an upgrade, please shut down " - "your system rather than hibernating it.") \ - % (entry.device.getDevice()) - else: - msg = _("The swap device:\n\n /dev/%s\n\n" - "in your /etc/fstab file is currently in " - "use as a software suspend partition, " - "which means your system is hibernating. " - "If you are performing a new install, " - "make sure the installer is set " - "to format all swap partitions.") \ - % (entry.device.getDevice()) - - # choose your own adventure swap partitions... - msg = msg + _("\n\nChoose Skip if you want the " - "installer to ignore this partition during " - "the upgrade. Choose Format to reformat " - "the partition as swap space.") - - swapErrorDialog(msg, _("Format"), entry) - else: - sys.exit(0) - except SystemError, (num, msg): - if self.messageWindow: - if upgrading and not entry.getLabel(): - err = _("Error enabling swap device %s: %s\n\n" - "Devices in /etc/fstab should be specified " - "by label, not by device name.\n\nPress " - "OK to exit the installer.") % (entry.device.getDevice(), msg) - elif upgrading: - err = _("Error enabling swap device %s: %s\n\n" - "The /etc/fstab on your upgrade partition " - "does not reference a valid swap " - "partition.\n\nPress OK to exit the " - "installer") % (entry.device.getDevice(), msg) - else: - err = _("Error enabling swap device %s: %s\n\n" - "This most likely means this swap " - "partition has not been initialized.\n\n" - "Press OK to exit the installer.") % (entry.device.getDevice(), msg) - - self.messageWindow(_("Error"), err) - sys.exit(0) - - def labelEntry(self, entry, chroot, ignoreExisting = False): - label = entry.device.getLabel() - if label and not ignoreExisting: - entry.setLabel(label) - entry.device.doLabel = 1 - - if entry.device.doLabel is not None: - entry.fsystem.labelDevice(entry, chroot) - - def formatEntry(self, entry, chroot): - if entry.mountpoint: - log.info("formatting %s as %s" %(entry.mountpoint, entry.fsystem.name)) - entry.fsystem.clobberDevice(entry, chroot) - entry.fsystem.formatDevice(entry, self.progressWindow, chroot) - - def getMigratableEntries(self): - retval = [] - for entry in self.entries: - if entry.origfsystem and entry.origfsystem.isMigratable(): - retval.append(entry) - - return retval - - def formattablePartitions(self): - list = [] - for entry in self.entries: - if entry.fsystem.isFormattable(): - list.append (entry) - return list - - def createLogicalVolumes (self, chroot='/'): - vgs = {} - # first set up the volume groups - for entry in self.entries: - if entry.fsystem.name == "volume group (LVM)": - entry.device.setupDevice(chroot) - vgs[entry.device.name] = entry.device - - # then set up the logical volumes - for entry in self.entries: - if isinstance(entry.device, LogicalVolumeDevice): - vg = None - if vgs.has_key(entry.device.vgname): - vg = vgs[entry.device.vgname] - entry.device.setupDevice(chroot, vgdevice = vg) - self.volumesCreated = 1 - - - def makeFilesystems (self, chroot='/', skiprootfs=False): - formatted = [] - notformatted = [] - for entry in self.entries: - if (not entry.fsystem.isFormattable() or not entry.getFormat() - or entry.isMounted()): - notformatted.append(entry) - continue - # FIXME: this is a bit of a hack, but works - if (skiprootfs and entry.mountpoint == '/'): - formatted.append(entry) - continue - try: - self.formatEntry(entry, chroot) - formatted.append(entry) - except SystemError: - if self.messageWindow: - self.messageWindow(_("Error"), - _("An error occurred trying to " - "format %s. This problem is " - "serious, and the install cannot " - "continue.\n\n" - "Press <Enter> to exit the installer.") - % (entry.device.getDevice(),)) - sys.exit(0) - - for entry in formatted: - try: - self.labelEntry(entry, chroot) - except SystemError: - # should be OK, we'll still use the device name to mount. - pass - - # go through and have labels for the ones we don't format - for entry in notformatted: - dev = entry.device.getDevice() - if not dev or dev == "none": - continue - if not entry.mountpoint or entry.mountpoint == "swap": - continue - try: - label = isys.readFSLabel(dev) - except: - continue - if label: - entry.setLabel(label) - else: - self.labelEntry(entry, chroot) - - def haveMigratedFilesystems(self): - return self.migratedfs - - def migrateFilesystems (self, pomona): - if self.migratedfs: - return - - for entry in self.entries: - if not entry.origfsystem: - continue - - if not entry.origfsystem.isMigratable() or not entry.getMigrate(): - continue - try: - entry.origfsystem.migrateFileSystem(entry, self.messageWindow, - pomona.rootPath) - except SystemError: - if self.messageWindow: - self.messageWindow(_("Error"), - _("An error occurred trying to " - "migrate %s. This problem is " - "serious, and the install cannot " - "continue.\n\n" - "Press <Enter> to exit the installer.") - % (entry.device.getDevice(),)) - sys.exit(0) - - # we need to unmount and remount so that we're mounted as the - # new fstype as we want to use the new filesystem type during - # the upgrade for ext3->ext4 migrations - if self.isActive(): - self.umountFilesystems(pomona.rootPath, swapoff = False) - self.mountFilesystems(pomona) - - self.migratedfs = 1 - - def mountFilesystems(self, pomona, raiseErrors = 0, readOnly = 0, skiprootfs = 0): - protected = pomona.id.partitions.protectedPartitions() - - for entry in self.entries: - # Don't try to mount a protected partition, since it will already - # have been mounted as the installation source. - if protected and entry.device.getDevice() in protected and os.path.ismount("/mnt/isodir"): - continue - - if not entry.fsystem.isMountable() or (skiprootfs and entry.mountpoint == '/'): - continue - - try: - log.info("trying to mount %s on %s" %(entry.device.setupDevice(), entry.mountpoint,)) - entry.mount(pomona.rootPath, readOnly = readOnly) - self.mountcount = self.mountcount + 1 - except OSError, (num, msg): - if self.messageWindow: - if num == errno.EEXIST: - self.messageWindow(_("Invalid mount point"), - _("An error occurred when trying " - "to create %s. Some element of " - "this path is not a directory. " - "This is a fatal error and the " - "install cannot continue.\n\n" - "Press <Enter> to exit the " - "installer.") % (entry.mountpoint,)) - else: - self.messageWindow(_("Invalid mount point"), - _("An error occurred when trying " - "to create %s: %s. This is " - "a fatal error and the install " - "cannot continue.\n\n" - "Press <Enter> to exit the " - "installer.") % (entry.mountpoint, - msg)) - log.error("OSError: (%d) %s" % (num, msg) ) - sys.exit(0) - except SystemError, (num, msg): - if raiseErrors: - raise SystemError, (num, msg) - if self.messageWindow: - if not entry.fsystem.isLinuxNativeFS(): - ret = self.messageWindow(_("Unable to mount filesystem"), - _("An error occurred mounting " - "device %s as %s. You may " - "continue installation, but " - "there may be problems.") % - (entry.device.getDevice(), - entry.mountpoint), - type="custom", custom_icon="warning", - custom_buttons=[_("_Exit installer"), - _("_Continue")]) - - if ret == 0: - sys.exit(0) - else: - continue - else: - if pomona.id.getUpgrade() and not (entry.getLabel() or entry.getUuid()): - errStr = _("Error mounting device %s as %s: " - "%s\n\n" - "Devices in /etc/fstab should be specified " - "by label or UUID, not by device name." - "\n\n" - "Press OK to exit the installer.") % (entry.device.getDevice(), entry.mountpoint, msg) - else: - errStr = _("Error mounting device %s as %s: " - "%s\n\n" - "Press OK to exit the installer.") % (entry.device.getDevice(), entry.mountpoint, msg) - - self.messageWindow(_("Error"), errStr) - - log.error("SystemError: (%d) %s" % (num, msg) ) - sys.exit(0) - - self.makeLVMNodes(pomona.rootPath) - - def makeLVMNodes(self, instPath, trylvm1 = 0): - # XXX hack to make the device node exist for the root fs if - # it's a logical volume so that mkinitrd can create the initrd. - root = self.getEntryByMountPoint("/") - if not root: - if self.messageWindow: - self.messageWindow(_("Error"), - _("Error finding / entry.\n\n" - "This is most likely means that " - "your fstab is incorrect." - "\n\n" - "Press OK to exit the installer.")) - sys.exit(0) - - rootlvm1 = 0 - if trylvm1: - dev = root.device.getDevice() - # lvm1 major is 58 - if os.access("%s/dev/%s" %(instPath, dev), os.R_OK) and posix.major(os.stat("%s/dev/%s" %(instPath, dev)).st_rdev) == 58: - rootlvm1 = 1 - - if isinstance(root.device, LogicalVolumeDevice) or rootlvm1: - # now make sure all of the device nodes exist. *sigh* - rc = lvm.vgmknodes() - - rootDev = "/dev/%s" % (root.device.getDevice(),) - rootdir = instPath + os.path.dirname(rootDev) - if not os.path.isdir(rootdir): - os.makedirs(rootdir) - - if root.device.crypto is None: - dmdev = "/dev/mapper/" + root.device.getDevice().replace("-","--").replace("/", "-") - else: - dmdev = "/dev/" + root.device.getDevice() - - if os.path.exists(instPath + dmdev): - os.unlink(instPath + dmdev) - if not os.path.isdir(os.path.dirname(instPath + dmdev)): - os.makedirs(os.path.dirname(instPath + dmdev)) - iutil.copyDeviceNode(dmdev, instPath + dmdev) - - # unlink existing so that we dtrt on upgrades - if os.path.exists(instPath + rootDev) and not root.device.crypto: - os.unlink(instPath + rootDev) - if not os.path.isdir(rootdir): - os.makedirs(rootdir) - - if root.device.crypto is None: - os.symlink(dmdev, instPath + rootDev) - - if not os.path.isdir("%s/etc/lvm" %(instPath,)): - os.makedirs("%s/etc/lvm" %(instPath,)) - - def filesystemSpace(self, chroot='/'): - space = [] - for entry in self.entries: - if not entry.isMounted(): - continue - # we can't put swap files on swap partitions; that's nonsense - if entry.mountpoint == "swap": - continue - path = "%s/%s" % (chroot, entry.mountpoint) - try: - space.append((entry.mountpoint, isys.pathSpaceAvailable(path))) - except SystemError: - log.error("failed to get space available in filesystemSpace() for %s" %(entry.mountpoint,)) - - def spaceSort(a, b): - (m1, s1) = a - (m2, s2) = b - - if (s1 > s2): - return -1 - elif s1 < s2: - return 1 - - return 0 - - space.sort(spaceSort) - return space - - def hasDirtyFilesystems(self, mountpoint): - ret = [] - - for entry in self.entries: - # XXX - multifsify, virtualize isdirty per fstype - if entry.fsystem.getName() != "ext2": continue - if entry.getFormat(): continue - if isinstance(entry.device.getDevice(), BindMountDevice): continue - - try: - if isys.ext2IsDirty(entry.device.getDevice()): - log.info("%s is a dirty ext2 partition" % entry.device.getDevice()) - ret.append(entry.device.getDevice()) - except Exception, e: - log.error("got an exception checking %s for being dirty, hoping it's not" %(entry.device.getDevice(),)) - - return ret - - def umountFilesystems(self, instPath, ignoreErrors = 0, swapoff = True): - # Unmount things bind mounted into the instPath here because they're - # not tracked by self.entries. - if os.path.ismount("%s/dev" % instPath): - isys.umount("%s/dev" % instPath, removeDir=0) - - # take a slice so we don't modify self.entries - reverse = self.entries[:] - reverse.reverse() - - for entry in reverse: - if entry.mountpoint == "swap" and not swapoff: - continue - entry.umount(instPath) - entry.device.cleanupDevice(instPath) - -class FileSystemSetEntry: - def __init__ (self, device, mountpoint, - fsystem=None, options=None, - origfsystem=None, migrate=0, - order=-1, fsck=-1, format=0, - fsprofile=None): - if not fsystem: - fsystem = fileSystemTypeGet("ext2") - self.device = device - self.mountpoint = mountpoint - self.fsystem = fsystem - self.origfsystem = origfsystem - self.migrate = migrate - self.resizeTargetSize = None - self.resizeOrigSize = None - self.options = options - self.mountcount = 0 - self.label = None - if fsck == -1: - self.fsck = fsystem.isChecked() - else: - self.fsck = fsck - if order == -1: - if mountpoint == '/': - self.order = 1 - elif self.fsck: - self.order = 2 - else: - self.order = 0 - else: - self.order = order - if format and not fsystem.isFormattable(): - raise RuntimeError, ("file system type %s is not formattable, " - "but has been added to fsset with format " - "flag on" % fsystem.getName()) - self.format = format - self.fsprofile = fsprofile - - def mount(self, chroot='/', devPrefix='/dev', readOnly = 0): - device = self.device.setupDevice(chroot, devPrefix=devPrefix) - - self.fsystem.mount(device, "%s" % (self.mountpoint,), - readOnly = readOnly, - bindMount = isinstance(self.device, - BindMountDevice), - instroot = chroot) - - self.mountcount = self.mountcount + 1 - - def umount(self, chroot='/'): - if self.mountcount > 0: - try: - self.fsystem.umount(self.device, "%s/%s" % (chroot, - self.mountpoint)) - self.mountcount = self.mountcount - 1 - except RuntimeError: - pass - - def setFileSystemType(self, fstype): - self.fsystem = fstype - - def getMountPoint(self): - return self.mountpoint - - def getOptions(self): - options = self.options - if not options: - options = self.fsystem.getDefaultOptions(self.mountpoint) - return options + self.device.getDeviceOptions() - - def setFormat (self, state): - if self.migrate and state: - raise ValueError, "Trying to set format bit on when migrate is set!" - self.format = state - - def getFormat (self): - return self.format - - def setMigrate (self, state): - if self.format and state: - raise ValueError, "Trying to set migrate bit on when format is set!" - - self.migrate = state - - def getMigrate (self): - return self.migrate - - def setResizeTarget (self, targetsize, size): - if not self.fsystem.isResizable() and targetsize is not None: - raise ValueError, "Can't set a resize target for a non-resizable filesystem" - self.resizeTargetSize = targetsize - self.resizeOrigSize = size - - def getResizeTarget (self): - return self.resizeTargetSize - - def isMounted (self): - return self.mountcount > 0 - - def getLabel (self): - return self.label - - def getUuid (self): - return isys.readFSUuid(self.device.getDevice()) - - def setLabel (self, label): - self.label = label - - def __str__(self): - if not self.mountpoint: - mntpt = "None" - else: - mntpt = self.mountpoint - - str = ("fsentry -- device: %(device)s mountpoint: %(mountpoint)s\n" - " fsystem: %(fsystem)s format: %(format)s\n" - " ismounted: %(mounted)s options: '%(options)s'\n" - " label: %(label)s fsprofile: %(fsprofile)s\n"% - {"device": self.device.getDevice(), "mountpoint": mntpt, - "fsystem": self.fsystem.getName(), "format": self.format, - "mounted": self.mountcount, "options": self.getOptions(), - "label": self.label, "fsprofile": self.fsprofile}) - return str - - -class Device: - def __init__(self, device = "none", encryption=None): - self.device = device - self.label = None - self.isSetup = 0 - self.doLabel = 1 - self.deviceOptions = "" - if encryption: - self.crypto = encryption - # mount by device since the name is based only on UUID - self.doLabel = None - if device not in ("none", None): - self.crypto.setDevice(device) - else: - self.crypto = None - - def getComment (self): - return "" - - def getDevice (self, asBoot = 0): - if self.crypto: - return self.crypto.getDevice() - else: - return self.device - - def setupDevice (self, chroot='/', devPrefix='/dev/'): - return self.device - - def cleanupDevice (self, chroot, devPrefix='/dev/'): - if self.crypto: - self.crypto.closeDevice() - - def solidify (self): - pass - - def getName(self): - return self.__class__.__name__ - - def getLabel(self): - try: - return isys.readFSLabel(self.setupDevice()) - except: - return "" - - def setAsNetdev(self): - """Ensure we're set up so that _netdev is in our device options.""" - if "_netdev" not in self.deviceOptions: - self.deviceOptions += ",_netdev" - - def isNetdev(self): - """Check to see if we're set as a netdev""" - if "_netdev" in self.deviceOptions: - return True - return False - - def getDeviceOptions(self): - return self.deviceOptions - -class DevDevice(Device): - """Device with a device node rooted in /dev that we just always use - the pre-created device node for.""" - def __init__(self, dev): - Device.__init__(self, device=dev) - - def getDevice(self, asBoot = 0): - return self.device - - def setupDevice(self, chroot='/', devPrefix='/dev'): - #We use precreated device but we have to make sure that the device exists - path = '/dev/%s' % (self.getDevice(),) - return path - -class RAIDDevice(Device): - # XXX usedMajors does not take in account any EXISTING md device - # on the system for installs. We need to examine all partitions - # to investigate which minors are really available. - usedMajors = {} - - # members is a list of Device based instances that will be - # a part of this raid device - def __init__(self, level, members, minor=-1, spares=0, existing=0, - chunksize = 64, encryption=None): - Device.__init__(self, encryption=encryption) - self.level = level - self.members = members - self.spares = spares - self.numDisks = len(members) - spares - self.isSetup = existing - self.doLabel = None - if chunksize is not None: - self.chunksize = chunksize - else: - self.chunksize = 256 - - if len(members) < spares: - raise RuntimeError, ("you requested more spare devices " - "than online devices!") - - if level == 5: - if self.numDisks < 3: - raise RuntimeError, "RAID 5 requires at least 3 online members" - - # there are 32 major md devices, 0...31 - if minor == -1 or minor is None: - for I in range(32): - if not RAIDDevice.usedMajors.has_key(I): - minor = I - break - - if minor == -1: - raise RuntimeError, ("Unable to allocate minor number for " - "raid device") - - RAIDDevice.usedMajors[minor] = None - self.device = "md" + str(minor) - self.minor = minor - - if self.crypto: - self.crypto.setDevice(self.device) - - # make sure the list of raid members is sorted - self.members.sort(cmp=lambda x,y: cmp(x.getDevice(),y.getDevice())) - - def __del__ (self): - del RAIDDevice.usedMajors[self.minor] - - def ext2Args (self): - if self.level == 5: - return [ '-R', 'stride=%d' % ((self.numDisks - 1) * 16) ] - elif self.level == 0: - return [ '-R', 'stride=%d' % (self.numDisks * 16) ] - return [] - - def mdadmLine (self, devPrefix="/dev"): - levels = { 0: "raid0", - 1: "raid1", - 4: "raid5", - 5: "raid5", - 6: "raid6", - 10: "raid10" } - - # If we can't find the device for some reason, revert to old behavior. - try: - (dev, devices, level, numActive) = raid.lookup_raid_device (self.device) - except KeyError: - devices = [] - - # First loop over all the devices that make up the RAID trying to read - # the superblock off each. If we read a superblock, return a line that - # can go into the mdadm.conf. If we fail, fall back to the old method - # of using the super-minor. - for d in devices: - try: - (major, minor, uuid, level, nrDisks, totalDisks, mdMinor) = \ - isys.raidsb(d) - return "ARRAY %s/%s level=%s num-devices=%d uuid=%s\n" \ - %(devPrefix, self.device, levels[level], nrDisks, uuid) - except ValueError: - pass - - return "ARRAY %s/%s super-minor=%s\n" %(devPrefix, self.device, - self.minor) - - def raidTab (self, devPrefix='/dev'): - entry = "" - entry = entry + "raiddev %s/%s\n" % (devPrefix, - self.device,) - entry = entry + "raid-level %d\n" % (self.level,) - entry = entry + "nr-raid-disks %d\n" % (self.numDisks,) - entry = entry + "chunk-size %s\n" %(self.chunksize,) - entry = entry + "persistent-superblock 1\n" - entry = entry + "nr-spare-disks %d\n" % (self.spares,) - i = 0 - for device in [m.getDevice() for m in self.members[:self.numDisks]]: - entry = entry + " device %s/%s\n" % (devPrefix, - device) - entry = entry + " raid-disk %d\n" % (i,) - i = i + 1 - i = 0 - for device in [m.getDevice() for m in self.members[self.numDisks:]]: - entry = entry + " device %s/%s\n" % (devPrefix, - device) - entry = entry + " spare-disk %d\n" % (i,) - i = i + 1 - return entry - - def setupDevice (self, chroot="/", devPrefix='/dev'): - if not self.isSetup: - memberDevs = [] - for pd in self.members: - memberDevs.append(pd.setupDevice(chroot, devPrefix=devPrefix)) - if pd.isNetdev(): self.setAsNetdev() - - args = ["--create", "/dev/%s" %(self.device,), - "--run", "--chunk=%s" %(self.chunksize,), - "--level=%s" %(self.level,), - "--raid-devices=%s" %(self.numDisks,)] - - if self.spares > 0: - args.append("--spare-devices=%s" %(self.spares,),) - - args.extend(memberDevs) - log.info("going to run: %s" %(["mdadm"] + args,)) - iutil.execWithRedirect ("mdadm", args, - stderr="/dev/tty5", stdout="/dev/tty5", - searchPath = 1) - raid.register_raid_device(self.device, - [m.getDevice() for m in self.members], - self.level, self.numDisks) - self.isSetup = 1 - else: - isys.raidstart(self.device, self.members[0].getDevice()) - - if self.crypto: - self.crypto.formatDevice() - self.crypto.openDevice() - node = "%s/%s" % (devPrefix, self.crypto.getDevice()) - else: - node = "%s/%s" % (devPrefix, self.device) - - return node - - def getDevice (self, asBoot = 0): - if not asBoot and self.crypto: - return self.crypto.getDevice() - elif not asBoot: - return self.device - else: - return self.members[0].getDevice(asBoot=asBoot) - - def solidify(self): - return - -ext2 = fileSystemTypeGet("ext2") -ext2.registerDeviceArgumentFunction(RAIDDevice, RAIDDevice.ext2Args) - -class VolumeGroupDevice(Device): - def __init__(self, name, physvols, pesize = 32768, existing = 0): - """Creates a VolumeGroupDevice. - - name is the name of the volume group - physvols is a list of Device objects which are the physical volumes - pesize is the size of physical extents in kilobytes - existing is whether this vg previously existed. - """ - - Device.__init__(self) - self.physicalVolumes = physvols - self.isSetup = existing - self.name = name - self.device = name - self.isSetup = existing - - self.physicalextentsize = pesize - - def setupDevice (self, chroot="/", devPrefix='/dev/'): - nodes = [] - for volume in self.physicalVolumes: - # XXX the lvm tools are broken and will only work for /dev - node = volume.setupDevice(chroot, devPrefix="/dev") - if volume.isNetdev(): self.setAsNetdev() - - # XXX I should check if the pv is set up somehow so that we - # can have preexisting vgs and add new pvs to them. - if not self.isSetup: - lvm.pvcreate(node) - nodes.append(node) - - if not self.isSetup: - lvm.vgcreate(self.name, self.physicalextentsize, nodes) - self.isSetup = 1 - else: - lvm.vgscan() - lvm.vgactivate() - - return "/dev/%s" % (self.name,) - - def solidify(self): - return - -class LogicalVolumeDevice(Device): - # note that size is in megabytes! - def __init__(self, vgname, size, lvname, vg, existing = 0, encryption=None): - Device.__init__(self, encryption=encryption) - self.vgname = vgname - self.size = size - self.name = lvname - self.isSetup = 0 - self.isSetup = existing - self.doLabel = None - self.vg = vg - - # these are attributes we might want to expose. or maybe not. - # self.chunksize - # self.stripes - # self.stripesize - # self.extents - # self.readaheadsectors - - def setupDevice(self, chroot="/", devPrefix='/dev', vgdevice = None): - if self.crypto: - self.crypto.setDevice("mapper/%s-%s" % (self.vgname, self.name)) - - if not self.isSetup: - lvm.lvcreate(self.name, self.vgname, self.size) - self.isSetup = 1 - - if vgdevice and vgdevice.isNetdev(): - self.setAsNetdev() - - if self.crypto: - self.crypto.formatDevice() - self.crypto.openDevice() - - return "/dev/%s" % (self.getDevice(),) - - def getDevice(self, asBoot = 0): - if self.crypto and not asBoot: - device = self.crypto.getDevice() - else: - device = "%s/%s" % (self.vgname, self.name) - - return device - - def solidify(self): - return - - -class PartitionDevice(Device): - def __init__(self, partition, encryption=None): - if type(partition) != types.StringType: - raise ValueError, "partition must be a string" - Device.__init__(self, device=partition, encryption=encryption) - - (disk, pnum) = getDiskPart(partition) - - def getDevice(self, asBoot = 0): - if self.crypto and not asBoot: - return self.crypto.getDevice() - else: - return self.device - - def setupDevice(self, chroot="/", devPrefix='/dev'): - path = '%s/%s' % (devPrefix, self.device) - if self.crypto: - self.crypto.formatDevice() - self.crypto.openDevice() - path = "%s/%s" % (devPrefix, self.crypto.getDevice()) - return path - -class PartedPartitionDevice(PartitionDevice): - def __init__(self, partition): - Device.__init__(self) - self.device = None - self.partition = partition - - def getDevice(self, asBoot = 0): - if not self.partition: - return self.device - - return partedUtils.get_partition_name(self.partition) - - def solidify(self): - # drop reference on the parted partition object and note - # the current minor number allocation - self.device = self.getDevice() - self.partition = None - -class BindMountDevice(Device): - def __init__(self, directory): - Device.__init__(self) - self.device = directory - - def setupDevice(self, chroot="/", devPrefix="/tmp"): - return chroot + self.device - -class SwapFileDevice(Device): - def __init__(self, file): - Device.__init__(self) - self.device = file - self.size = 0 - - def setSize (self, size): - self.size = size - - def setupDevice (self, chroot="/", devPrefix='/dev'): - file = os.path.normpath(chroot + self.getDevice()) - if not os.access(file, os.R_OK): - if self.size: - # make sure the permissions are set properly - fd = os.open(file, os.O_CREAT, 0600) - os.close(fd) - isys.ddfile(file, self.size, None) - else: - raise SystemError, (0, "swap file creation necessary, but " - "required size is unknown.") - return file - -# This is a device that describes a swap file that is sitting on -# the loopback filesystem host for partitionless installs. -# The piggypath is the place where the loopback file host filesystem -# will be mounted -class PiggybackSwapFileDevice(SwapFileDevice): - def __init__(self, piggypath, file): - SwapFileDevice.__init__(self, file) - self.piggypath = piggypath - - def setupDevice(self, chroot="/", devPrefix='/dev'): - return SwapFileDevice.setupDevice(self, self.piggypath, devPrefix) - -class LoopbackDevice(Device): - def __init__(self, hostPartition, hostFs): - Device.__init__(self) - self.host = "/dev/" + hostPartition - self.hostfs = hostFs - self.device = "loop1" - - def setupDevice(self, chroot="/", devPrefix='/dev/'): - if not self.isSetup: - isys.mount(self.host[5:], "/mnt/loophost", fstype = "vfat") - self.device = allocateLoopback("/mnt/loophost/redhat.img") - if not self.device: - raise SystemError, "Unable to allocate loopback device" - self.isSetup = 1 - path = '%s/%s' % (devPrefix, self.getDevice()) - else: - path = '%s/%s' % (devPrefix, self.getDevice()) - path = os.path.normpath(path) - return path - - def getComment (self): - return "# LOOP1: %s %s /redhat.img\n" % (self.host, self.hostfs) - -def makeDevice(dev): - cryptoDev = partitions.lookup_cryptodev(dev) - if cryptoDev and cryptoDev.getDevice() == dev: - dev = cryptoDev.getDevice(encrypted=True) - - if dev.startswith('md'): - try: - (mdname, devices, level, numActive) = raid.lookup_raid_device(dev) - # convert devices to Device instances and sort out encryption - devList = [] - for dev in devices: - cryptoMem = partitions.lookup_cryptodev(dev) - if cryptoMem and cryptoMem.getDevice() == dev: - dev = cryptoMem.getDevice(encrypted=True) - - devList.append(PartitionDevice(dev, encryption=cryptoMem)) - - device = RAIDDevice(level, devList, - minor=int(mdname[2:]), - spares=len(devices) - numActive, - existing=1, encryption=cryptoDev) - except KeyError: - device = PartitionDevice(dev, encryption=cryptoDev) - else: - device = PartitionDevice(dev, encryption=cryptoDev) - return device - -# XXX fix RAID -def readFstab(pomona): - def createMapping(dict): - mapping = {} - dupes = [] - - for device, info in dict.items(): - if not mapping.has_key(info): - mapping[info] = device - elif not info in dupes: - dupes.append(info) - - return (mapping, dupes) - - def showError(label, intf): - if intf: - intf.messageWindow(_("Duplicate Labels"), - _("Multiple devices on your system are " - "labelled %s. Labels across devices must be " - "unique for your system to function " - "properly.\n\n" - "Please fix this problem and restart the " - "installation process.") %(label,), - type="custom", custom_icon="error", - custom_buttons=[_("_Exit installer")]) - sys.exit(0) - else: - log.warning("Duplicate labels for %s, but no intf so trying " - "to continue" %(label,)) - - path = pomona.rootPath + '/etc/fstab' - intf = pomona.intf - fsset = FileSystemSet() - - # first, we look at all the disks on the systems and get any ext2/3 - # labels off of the filesystem. - # temporary, to get the labels - diskset = partedUtils.DiskSet(pomona) - diskset.openDevices() - labels = diskset.getInfo() - uuids = diskset.getInfo(readFn=lambda d: isys.readFSUuid(d)) - - (labelToDevice, labelDupes) = createMapping(labels) - (uuidToDevice, uuidDupes) = createMapping(uuids) - - loopIndex = {} - - f = open (path, "r") - lines = f.readlines () - f.close() - - for line in lines: - fields = string.split (line) - - if not fields: continue - - if line[0] == "#": - # skip all comments - continue - - # all valid fstab entries have 6 fields; if the last two are missing - # they are assumed to be zero per fstab(5) - if len(fields) < 4: - continue - elif len(fields) == 4: - fields.append(0) - fields.append(0) - elif len(fields) == 5: - fields.append(0) - elif len(fields) > 6: - continue - if string.find(fields[3], "noauto") != -1: continue - - # shenanigans to handle ext3,ext2 format in fstab - fstotry = fields[2] - if fstotry.find(","): - fstotry = fstotry.split(",") - else: - fstotry = [ fstotry ] - fsystem = None - for fs in fstotry: - # if we don't support mounting the filesystem, continue - if not fileSystemTypes.has_key(fs): - continue - fsystem = fileSystemTypeGet(fs) - break - # "none" is valid as an fs type for bind mounts (#151458) - if fsystem is None and (string.find(fields[3], "bind") == -1): - continue - - label = None - if fields[0] == "none": - device = Device() - elif ((string.find(fields[3], "bind") != -1) and - fields[0].startswith("/")): - # it's a bind mount, they're Weird (tm) - device = BindMountDevice(fields[0]) - fsystem = fileSystemTypeGet("bind") - elif len(fields) >= 6 and fields[0].startswith('LABEL='): - label = fields[0][6:] - if label in labelDupes: - showError(label, intf) - - if labelToDevice.has_key(label): - device = makeDevice(labelToDevice[label]) - else: - log.warning ("fstab file has LABEL=%s, but this label " - "could not be found on any file system", label) - # bad luck, skip this entry. - continue - elif len(fields) >= 6 and fields[0].startswith('UUID='): - uuid = fields[0][5:] - if uuid in uuidDupes: - showError(uuid, intf) - - if uuidToDevice.has_key(uuid): - device = makeDevice(uuidToDevice[uuid]) - else: - log.warning ("fstab file has UUID=%s, but this UUID" - "could not be found on any file system", uuid) - # bad luck, skip this entry. - continue - elif fields[2] == "swap" and not fields[0].startswith('/dev/'): - # swap files - file = fields[0] - - if file.startswith('/initrd/loopfs/'): - file = file[14:] - device = PiggybackSwapFileDevice("/mnt/loophost", file) - else: - device = SwapFileDevice(file) - elif fields[0].startswith('/dev/loop'): - # look up this loop device in the index to find the - # partition that houses the filesystem image - # XXX currently we assume /dev/loop1 - if loopIndex.has_key(device): - (dev, fs) = loopIndex[device] - device = LoopbackDevice(dev, fs) - elif fields[0].startswith('/dev/'): - # Older installs may have lines starting with things like /dev/proc - # so watch out for that on upgrade. - if fsystem is not None and isinstance(fsystem, PseudoFileSystem): - device = Device(device = fields[0][5:]) - else: - device = makeDevice(fields[0][5:]) - else: - device = Device(device = fields[0]) - - # if they have a filesystem being mounted as auto, we need - # to sniff around a bit to figure out what it might be - # if we fail at all, though, just ignore it - if fsystem == "auto" and device.getDevice() != "none": - try: - tmp = partedUtils.sniffFilesystemType("/dev/%s" %(device.setupDevice(),)) - if tmp is not None: - fsystem = tmp - except: - pass - - entry = FileSystemSetEntry(device, fields[1], fsystem, fields[3], - origfsystem=fsystem) - if label: - entry.setLabel(label) - fsset.add(entry) - return fsset - -def allocateLoopback(file): - found = 1 - for i in range(8): - path = "/dev/loop%d" % (i,) - try: - isys.losetup(path, file) - found = 1 - except SystemError: - continue - break - if found: - return path - return None - -def ext2FormatFilesystem(argList, messageFile, windowCreator, mntpoint): - if windowCreator: - w = windowCreator(_("Formatting"), - _("Formatting %s file system...") % (mntpoint,), 100) - else: - w = None - - fd = os.open(messageFile, os.O_RDWR | os.O_CREAT | os.O_APPEND) - p = os.pipe() - childpid = os.fork() - if not childpid: - os.close(p[0]) - os.dup2(p[1], 1) - os.dup2(fd, 2) - os.close(p[1]) - os.close(fd) - - env = os.environ - configs = [ "/tmp/updates/mke2fs.conf", - "/etc/mke2fs.conf", - ] - for config in configs: - if os.access(config, os.R_OK): - env['MKE2FS_CONFIG'] = config - break - - os.execvpe(argList[0], argList, env) - log.critical("failed to exec %s", argList) - os._exit(1) - - os.close(p[1]) - - # ignoring SIGCHLD would be cleaner then ignoring EINTR, but - # we can't use signal() in this thread? - - s = 'a' - while s and s != '\b': - try: - s = os.read(p[0], 1) - except OSError, args: - (num, str) = args - if (num != 4): - raise IOError, args - - os.write(fd, s) - - num = '' - while s: - try: - s = os.read(p[0], 1) - os.write(fd, s) - - if s != '\b': - try: - num = num + s - except: - pass - else: - if num and len(num): - l = string.split(num, '/') - try: - val = (int(l[0]) * 100) / int(l[1]) - except (IndexError, TypeError): - pass - else: - w and w.set(val) - num = '' - except OSError, args: - (errno, str) = args - if (errno != 4): - raise IOError, args - - try: - (pid, status) = os.waitpid(childpid, 0) - except OSError, (num, msg): - log.critical("exception from waitpid while formatting: %s %s" %(num, msg)) - status = None - os.close(fd) - - w and w.pop() - - # *shrug* no clue why this would happen, but hope that things are fine - if status is None: - return 0 - - if os.WIFEXITED(status) and (os.WEXITSTATUS(status) == 0): - return 0 - - return 1 - -# copy and paste job from booty/bootloaderInfo.py... -def getDiskPart(dev): - cut = len(dev) - if (dev.startswith('rd/') or dev.startswith('ida/') or - dev.startswith('cciss/') or dev.startswith('sx8/') or - dev.startswith('mapper/') or dev.startswith('mmcblk')): - if dev[-2] == 'p': - cut = -1 - elif dev[-3] == 'p': - cut = -2 - else: - if dev[-2] in string.digits: - cut = -2 - elif dev[-1] in string.digits: - cut = -1 - - name = dev[:cut] - - # hack off the trailing 'p' from /dev/cciss/*, for example - if name[-1] == 'p': - for letter in name: - if letter not in string.letters and letter != "/": - name = name[:-1] - break - - if cut < 0: - partNum = int(dev[cut:]) - 1 - else: - partNum = None - - return (name, partNum) diff --git a/pkgs/core/pomona/src/installer.py b/pkgs/core/pomona/src/installer.py deleted file mode 100644 index 89230eb..0000000 --- a/pkgs/core/pomona/src/installer.py +++ /dev/null @@ -1,291 +0,0 @@ -#!/usr/bin/python -############################################################################### -# # -# IPFire.org - A linux based firewall # -# Copyright (C) 2008 Michael Tremer & Christian Schmidt # -# # -# 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 3 of the License, or # -# (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program. If not, see http://www.gnu.org/licenses/. # -# # -############################################################################### - -import os -import sys -import re -import signal -import warnings -from optparse import OptionParser - -import isys -import users -import iutil -import dispatch -from flags import flags -from constants import * - -from tui import InstallInterface -from pakfireinstall import PakfireBackend -from instdata import InstallData -from autopart import getAutopartitionBoot, autoCreatePartitionRequests - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -# Make sure messages sent through python's warnings module get logged. -def PomonaShowWarning(message, category, filename, lineno, file=sys.stderr): - log.warning("%s" % warnings.formatwarning(message, category, filename, lineno)) - -warnings.showwarning = PomonaShowWarning - -def parseOptions(): - - op = OptionParser() - - # Method of operation - op.add_option("-d", "--debug", dest="debug", action="store_true", default=False) - op.add_option("--expert", action="store_true", default=False) - op.add_option("-t", "--test", action="store_true", default=False) - - op.add_option("-m", "--method", default=None) - - # Language - op.add_option("--keymap") - op.add_option("--kbdtype") - op.add_option("--lang") - - # Obvious - op.add_option("--loglevel") - op.add_option("--syslog") - - return op.parse_args() - -def setupLoggingFromOpts(opts): - if opts.loglevel and logLevelMap.has_key(opts.loglevel): - log.setHandlersLevel(logLevelMap[opts.loglevel]) - - if opts.syslog: - if opts.syslog.find(":") != -1: - (host, port) = opts.syslog.split(":") - logger.addSysLogHandler(log, host, port=int(port)) - else: - logger.addSysLogHandler(log, opts.syslog) - -def checkMemory(): - if iutil.memInstalled() < isys.MIN_RAM: - from snack import SnackScreen, ButtonChoiceWindow - - screen = SnackScreen() - ButtonChoiceWindow(screen, _("Fatal Error"), - _("You do not have enough RAM to install %s " - "on this machine.\n" - "\n" - "Press <return> to reboot your system.\n") - % (name,), buttons = (_("OK"),)) - screen.finish() - sys.exit(0) - -class Pomona: - def __init__(self): - self.intf = None - self.id = None - self.rootPath = HARDDISK_PATH - self.dispatch = dispatch.Dispatcher(self) - - self.backend = PakfireBackend(self.rootPath) - - def setDefaultPartitioning(self, partitions, clear = CLEARPART_TYPE_ALL, doClear = 1): - autorequests = [ ("/", None, 1024, None, 1, 1, 1) ] - - bootreq = getAutopartitionBoot() - if bootreq: - autorequests.extend(bootreq) - - (minswap, maxswap) = iutil.swapSuggestion() - autorequests.append((None, "swap", minswap, maxswap, 1, 1, 1)) - - if doClear: - partitions.autoClearPartType = clear - partitions.autoClearPartDrives = [] - - partitions.autoPartitionRequests = autoCreatePartitionRequests(autorequests) - - def setZeroMbr(self, zeroMbr): - self.id.partitions.zeroMbr = zeroMbr - - def setKeyboard(self, kb): - self.id.console.setKeymap(kb) - - def setTimezoneInfo(self, timezone, asUtc = 0, asArc = 0): - self.id.timezone.setTimezoneInfo(timezone, asUtc, asArc) - - def setLanguage(self, lang): - self.id.console.setLanguage(lang) - -if __name__ == "__main__": - pomona = Pomona() - - # Set up logging - import logging - from pomona_log import logger, logLevelMap - - log = logging.getLogger("pomona") - stdoutLog = logging.getLogger("pomona.stdout") - if os.access("/dev/tty3", os.W_OK): - logger.addFileHandler("/dev/tty3", log) - - log.info("pomona called with cmdline = %s" %(sys.argv,)) - - # Set up environment - if not os.environ.has_key("LANG"): - os.environ["LANG"] = "en_US.UTF-8" - os.environ['HOME'] = '/tmp' - os.environ['LC_NUMERIC'] = 'C' - - signal.signal(signal.SIGINT, signal.SIG_DFL) - signal.signal(signal.SIGSEGV, isys.handleSegv) - - # Reading command line options - (opts, args) = parseOptions() - - setupLoggingFromOpts(opts) - - if opts.expert: - flags.expert = 1 - - if opts.test: - flags.test = 1 - - if opts.debug: - flags.debug = True - import pdb - pdb.set_trace() - - log.info (_("Starting text installation...")) - - checkMemory() - - pomona.intf = InstallInterface() - - pomona.id = InstallData(pomona) - pomona.id.reset(pomona) - pomona.setDefaultPartitioning(pomona.id.partitions, CLEARPART_TYPE_ALL) - - if flags.expert: - pomona.dispatch.setStepList( - "language", - "keyboard", - "welcome", - "betanag", - "installtype", - "partitionobjinit", - "parttype", - "autopartitionexecute", - "partition", - "partitiondone", - "bootloadersetup", - "bootloader", - "networkdevicecheck", - "network", - "timezone", - "accounts", - "reposetup", - "basepkgsel", - "tasksel", - "postselection", - "confirminstall", - "install", - "enablefilesystems", - "migratefilesystems", - "setuptime", - "preinstallconfig", - "installpackages", - "postinstallconfig", - "writeconfig", - "firstboot", - "instbootloader", - "dopostaction", - "postscripts", - "writexconfig", - "writeksconfig", - "writeregkey", - "methodcomplete", - "copylogs", - "setfilecon", - "complete" - ) - else: - pomona.dispatch.setStepList( - "language", - "keyboard", - "welcome", - "betanag", - "installtype", - "partitionobjinit", - "parttype", - "autopartitionexecute", - "partition", - "partitiondone", - "bootloadersetup", - "bootloader", - "networkdevicecheck", - "network", - "timezone", - "accounts", - "reposetup", - "basepkgsel", - "tasksel", - "postselection", - "confirminstall", - "install", - "enablefilesystems", - "migratefilesystems", - "setuptime", - "preinstallconfig", - "installpackages", - "postinstallconfig", - "writeconfig", - "firstboot", - "instbootloader", - "dopostaction", - "postscripts", - "writexconfig", - "writeksconfig", - "writeregkey", - "methodcomplete", - "copylogs", - "setfilecon", - "complete" - ) - - users.createLuserConf(pomona.rootPath) - - if opts.lang: - pomona.dispatch.skipStep("language", permanent = 1) - pomona.setLanguage(opts.lang) - pomona.id.timezone.setTimezoneInfo(pomona.id.console.getDefaultTimeZone()) - - if opts.keymap: - pomona.dispatch.skipStep("keyboard", permanent = 1) - pomona.setKeyboard(opts.keymap) - - from exception import handleException - sys.excepthook = lambda type, value, tb, pomona=pomona: handleException(pomona, (type, value, tb)) - - try: - pomona.intf.run(pomona) - except SystemExit, code: - pomona.intf.shutdown() - except: - handleException(pomona, sys.exc_info()) - - del pomona.intf diff --git a/pkgs/core/pomona/src/instdata.py b/pkgs/core/pomona/src/instdata.py deleted file mode 100644 index d1762e7..0000000 --- a/pkgs/core/pomona/src/instdata.py +++ /dev/null @@ -1,65 +0,0 @@ -# -# instdata.py - central store for all configuration data needed to install -# -# Erik Troan ewt@redhat.com -# -# Copyright 2001-2002 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -import os -import string -import console -import network -import timezone -import fsset -import bootloader -import partitions -import partedUtils -import users -from flags import * -from constants import * - -import logging -log = logging.getLogger("pomona") - -# Collector class for all data related to an install. - -class InstallData: - def reset(self, pomona): - # Reset everything except the console settings (language, keyboard) - - self.network = network.Network(pomona.rootPath + "/etc/sysconfig/network") - self.timezone = timezone.Timezone() - self.timezone.setTimezoneInfo(self.console.getDefaultTimeZone()) - self.users = None - self.rootPassword = { "password": "" } - self.fsset.reset() - self.diskset = partedUtils.DiskSet(pomona) - self.partitions = partitions.Partitions(pomona) - self.bootloader = bootloader.getBootloader() - self.rootParts = None - - def setInstallProgressClass(self, c): - self.instProgress = c - - def write(self, pomona): - self.console.write() - self.timezone.write(pomona.rootPath) - self.network.write() - - self.users = users.Users() - - # User should already exist, just without a password. - self.users.setRootPassword(self.rootPassword["password"], algo="sha512") - - def __init__(self, pomona): - self.console = console.Console(pomona.rootPath + "/etc/sysconfig/console") - self.fsset = fsset.FileSystemSet() - self.reset(pomona) diff --git a/pkgs/core/pomona/src/isys/Makefile b/pkgs/core/pomona/src/isys/Makefile index e462c0f..680ae05 100644 --- a/pkgs/core/pomona/src/isys/Makefile +++ b/pkgs/core/pomona/src/isys/Makefile @@ -20,41 +20,31 @@
include ../Makefile.inc
-CFLAGS += -I$(PYTHONINCLUDE) -I/usr/include -I.. -I. +OBJECTS = isys.o mount.o
-OBJECTS = devices.o imount.o smp.o linkdetect.o \ - lang.o isofs.o vio.o eddsupport.o str.o \ - wireless.o ethtool.o +CFLAGS += -I$(PYTHONINCLUDE) +LDFLAGS = +LIBS =
-SOBJECTS = $(patsubst %.o,%.lo,$(OBJECTS)) -SOURCES = $(patsubst %.o,%.c,$(OBJECTS)) isys.c -LOADLIBES = -lpci -lpopt -lext2fs -lz -lpci -lblkid -PYMODULES = _isys.so +all: depend _isys.so
-all: depend $(PYMODULES) libisys.a +depend: $(patsubst %.o,%.c,$(OBJECTS)) + $(CPP) -M $(CFLAGS) $(patsubst %.o,%.c,$(OBJECTS)) > depend
-%.lo: %.c - $(CC) -c $(CFLAGS) -fPIC -o $@ $< +%.o: %.c + $(CC) -c $(CFLAGS) -o $@ $<
-_isys.so: isys.lo $(SOBJECTS) - $(CC) -shared -g -fPIC -o $@ isys.lo $(SOBJECTS) $(LOADLIBES) $(LDFLAGS) +_isys.so: $(OBJECTS) + $(CC) -shared $(CFLAGS) $(LDFLAGS) $(LIBS) -o $@ $(OBJECTS)
-libisys.a: libisys.a($(OBJECTS)) - -filtertest: filtertest.o libisys.a +install: _isys.so isys.py + cp -vf _isys.so isys.py $(PYTHONLIBDIR)
clean: - rm -f *.o *.so *.lo *.a *.pyc $(TARGET) $(SOBJECTS) - rm -f $(OBJECTS) - rm -f depend - -install: all - -mkdir -p $(PYTHONLIBDIR) - install -s $(PYMODULES) $(PYTHONLIBDIR) - install -m 644 isys.py $(PYTHONLIBDIR) + rm -vf $(OBJECTS) depend _isys.so *.py[co]
-depend: - $(CPP) -M $(CFLAGS) $(SOURCES) > depend +test: _isys.so + python -c "import isys"
ifeq (depend,$(wildcard depend)) include depend diff --git a/pkgs/core/pomona/src/isys/devices.c b/pkgs/core/pomona/src/isys/devices.c deleted file mode 100644 index 69a0020..0000000 --- a/pkgs/core/pomona/src/isys/devices.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * devices.c - various hardware probing functionality - * - * 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/. - * - * Author(s): Bill Nottingham notting@redhat.com - */ - -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/types.h> - -#include "devices.h" - -/* for 'disks', to filter out weird stuff */ -#define MINIMUM_INTERESTING_SIZE 32*1024 /* 32MB */ - -/* from genhd.h, kernel side */ -#define GENHD_FL_REMOVABLE 1 -#define GENHD_FL_DRIVERFS 2 -#define GENHD_FL_MEDIA_CHANGE_NOTIFY 4 -#define GENHD_FL_CD 8 -#define GENHD_FL_UP 16 -#define GENHD_FL_SUPPRESS_PARTITION_INFO 32 -#define GENHD_FL_FAIL 64 - - -struct device **getDevices(enum deviceType type) { - struct device **ret = NULL; - struct device *new; - int numdevices = 0; - int rc; - - if (type & (DEVICE_DISK | DEVICE_CDROM)) { - DIR *dir; - struct dirent *ent; - - dir = opendir("/sys/block"); - - if (!dir) goto storagedone; - - while ((ent = readdir(dir))) { - char path[64]; - char buf[64]; - int fd, caps, devtype; - - snprintf(path, 64, "/sys/block/%s/capability", ent->d_name); - fd = open(path, O_RDONLY); - if (fd == -1) - continue; - if (read(fd, buf, 64) <= 0) { - close(fd); - continue; - } - close(fd); - caps = strtol(buf, NULL, 16); - if (caps & GENHD_FL_CD) - devtype = DEVICE_CDROM; - else - devtype = DEVICE_DISK; - if (!(devtype & type)) - continue; - - if (devtype == DEVICE_DISK && !(caps & GENHD_FL_REMOVABLE)) { - int size; - - snprintf(path, 64, "/sys/block/%s/size", ent->d_name); - fd = open(path, O_RDONLY); - if (fd == -1) - continue; - if (read(fd, buf, 64) <= 0) { - close(fd); - continue; - } - close(fd); - size = atoi(buf); - if (size < MINIMUM_INTERESTING_SIZE) - continue; - } - - new = calloc(1, sizeof(struct device)); - new->device = strdup(ent->d_name); - /* FIXME */ - rc = asprintf(&new->description,"Storage device %s",new->device); - new->type = devtype; - if (caps & GENHD_FL_REMOVABLE) { - new->priv.removable = 1; - } - ret = realloc(ret, (numdevices+2) * sizeof(struct device)); - ret[numdevices] = new; - ret[numdevices+1] = NULL; - numdevices++; - } - } -storagedone: - - if (type & DEVICE_NETWORK) { - DIR *dir; - struct dirent *ent; - - dir = opendir("/sys/class/net"); - - if (!dir) goto netdone; - - while ((ent = readdir(dir))) { - char path[64]; - int fd, type; - char buf[64]; - - snprintf(path, 64, "/sys/class/net/%s/type", ent->d_name); - fd = open(path, O_RDONLY); - if (fd == -1) - continue; - if (read(fd, buf, 64) <= 0) { - close(fd); - continue; - } - close(fd); - type = atoi(buf); - if (type != 1) - continue; - - new = calloc(1, sizeof(struct device)); - new->device = strdup(ent->d_name); - /* FIXME */ - snprintf(path, 64, "/sys/class/net/%s/address", ent->d_name); - fd = open(path, O_RDONLY); - if (fd != -1) { - if (read(fd, buf, 64) > 0) { - int i; - for (i = (strlen(buf)-1); isspace(buf[i]); i--) buf[i] = '\0'; - new->priv.hwaddr = strdup(buf); - } - } - - if (new->priv.hwaddr) - rc = asprintf(&new->description, "Ethernet device %s - %s", - new->device, new->priv.hwaddr); - else - rc = asprintf(&new->description, "Ethernet device %s", new->device); - - ret = realloc(ret, (numdevices+2) * sizeof(struct device)); - ret[numdevices] = new; - ret[numdevices+1] = NULL; - numdevices++; - } - } -netdone: - return ret; -} - diff --git a/pkgs/core/pomona/src/isys/devices.h b/pkgs/core/pomona/src/isys/devices.h deleted file mode 100644 index 9428a77..0000000 --- a/pkgs/core/pomona/src/isys/devices.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * devices.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 DEVICES_H -#define DEVICES_H - -enum deviceType { - DEVICE_ANY = ~0, - DEVICE_NETWORK = (1 << 0), - DEVICE_DISK = (1 << 1), - DEVICE_CDROM = (1 << 2) -}; - -struct device { - char *device; - char *description; - enum deviceType type; - union { - char *hwaddr; - int removable; - } priv; -}; - -struct device **getDevices(enum deviceType type); - -#endif diff --git a/pkgs/core/pomona/src/isys/eddsupport.c b/pkgs/core/pomona/src/isys/eddsupport.c deleted file mode 100644 index 9fb38af..0000000 --- a/pkgs/core/pomona/src/isys/eddsupport.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * eddsupport.c - handling of mapping disk drives in Linux to disk drives - * according to the BIOS using the edd kernel module - * - * Copyright (C) 2004 Dell, Inc. All rights reserved. - * 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): Rezwanul_Kabir@Dell.com - * Jeremy Katz katzj@redhat.com - */ - -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/stat.h> -#include <sys/reboot.h> -#include <sys/types.h> -#include <linux/types.h> - - -#include "eddsupport.h" -#include "devices.h" -#include "isys.h" - -#define EDD_DIR "/sys/firmware/edd" -#define SIG_FILE "mbr_signature" -#define MBRSIG_OFFSET 0x1b8 - -#define HASH_TABLE_SIZE 17 - - -struct diskMapEntry{ - uint32_t key; - char *diskname; - struct diskMapEntry *next; -}; - -struct diskMapTable { - struct diskMapEntry **table; - int tableSize; -}; - -static struct diskMapTable *mbrSigToName = NULL; -static int diskHashInit = 0; - - - -static struct diskMapTable* initializeHashTable(int); -static int insertHashItem(struct diskMapTable *, struct diskMapEntry *); -static struct diskMapEntry* lookupHashItem(struct diskMapTable *, uint32_t); -static int addToHashTable(struct diskMapTable *, uint32_t , char *); -static struct device ** createDiskList(); -static int mapBiosDisks(struct device ** , const char *); -static int readDiskSig(char *, uint32_t *); -static int readMbrSig(char *, uint32_t *); - -/* This is the top level function that creates a disk list present in the - * system, checks to see if unique signatures exist on the disks at offset - * 0x1b8. If a unique signature exists then it will map BIOS disks to their - * corresponding hd/sd device names. Otherwise, we'll avoid mapping drives. - */ - -int probeBiosDisks() { - struct device ** devices = NULL; - - devices = createDiskList(); - if(!devices){ -#ifdef STANDALONE - fprintf(stderr, "No disks!\n"); -#endif - return -1; - } - - if(!mapBiosDisks(devices, EDD_DIR)){ -#ifdef STANDALONE - fprintf(stderr, "WARNING: couldn't map BIOS disks\n"); -#endif - return -1; - } - return 0; -} - - -static struct device ** createDiskList(){ - return getDevices (DEVICE_DISK); -} - -static int readDiskSig(char *device, uint32_t *disksig) { - int fd, rc; - - fd = open(device, O_RDONLY); - if (fd < 0) { -#ifdef STANDALONE - fprintf(stderr, "Error opening device %s: %s\n ", device, - strerror(errno)); -#endif - return -errno; - } - - rc = lseek(fd, MBRSIG_OFFSET, SEEK_SET); - if (rc < 0){ - close(fd); - -#ifdef STANDALONE - fprintf(stderr, "Error seeking to MBRSIG_OFFSET in %s: %s\n", - device, strerror(errno)); -#endif - return -1; - } - - rc = read(fd, disksig, sizeof(uint32_t)); - if (rc < sizeof(uint32_t)) { - close(fd); - -#ifdef STANDALONE - fprintf(stderr, "Failed to read signature from %s\n", device); -#endif - return -1; - } - - close(fd); - return 0; -} - -static int mapBiosDisks(struct device** devices,const char *path) { - DIR *dirHandle; - struct dirent *entry; - char * sigFileName; - uint32_t mbrSig, biosNum, currentSig; - struct device **currentDev, **foundDisk; - int i, rc, ret; - - dirHandle = opendir(path); - if(!dirHandle){ -#ifdef STANDALONE - fprintf(stderr, "Failed to open directory %s: %s\n", path, - strerror(errno)); -#endif - return 0; - } - - mbrSigToName = initializeHashTable(HASH_TABLE_SIZE); - if(!mbrSigToName){ -#ifdef STANDALONE - fprintf(stderr, "Error initializing mbrSigToName table\n"); -#endif - closedir(dirHandle); - return 0; - } - - while ((entry = readdir(dirHandle)) != NULL) { - if(!strncmp(entry->d_name,".",1) || !strncmp(entry->d_name,"..",2)) { - continue; - } - ret = sscanf((entry->d_name+9), "%x", &biosNum); - - sigFileName = malloc(strlen(path) + strlen(entry->d_name) + 20); - sprintf(sigFileName, "%s/%s/%s", path, entry->d_name, SIG_FILE); - if (readMbrSig(sigFileName, &mbrSig) == 0) { - for (currentDev = devices, i = 0, foundDisk=NULL; - (*currentDev) != NULL && i<2; - currentDev++) { - if (!(*currentDev)->device) - continue; - - if ((rc=readDiskSig((*currentDev)->device, ¤tSig)) < 0) { - if (rc == -ENOMEDIUM) - continue; - closedir(dirHandle); - return 0; - } - - if (mbrSig == currentSig) { - foundDisk=currentDev; - i++; - } - } - - if (i==1) { - if(!addToHashTable(mbrSigToName, (uint32_t)biosNum, - (*foundDisk)->device)) { - closedir(dirHandle); - return 0; - } - } - } - } - closedir(dirHandle); - return 1; -} - - -static int readMbrSig(char *filename, uint32_t *int_sig){ - FILE* fh; - - fh = fopen(filename,"r"); - if(fh == NULL) { -#ifdef STANDALONE - fprintf(stderr, "Error opening mbr_signature file %s: %s\n", filename, - strerror(errno)); -#endif - return -1; - } - fseek(fh, 0, SEEK_SET); - if (fscanf(fh, "%x", int_sig) != 1) { -#ifdef STANDALONE - fprintf(stderr, "Error reading %s\n", filename); -#endif - fclose(fh); - return -1; - } - - fclose(fh); - return 0; -} - - -static struct diskMapTable* initializeHashTable(int size) { - struct diskMapTable *hashTable; - - hashTable = malloc(sizeof(struct diskMapTable)); - hashTable->tableSize = size; - hashTable->table = malloc(sizeof(struct diskMapEntry *) * size); - memset(hashTable->table,0,(sizeof(struct diskMapEntry *) * size)); - return hashTable; -} - - -static int insertHashItem(struct diskMapTable *hashTable, - struct diskMapEntry *hashItem) { - int index; - - index = (hashItem->key) % (hashTable->tableSize); - - if(hashTable->table[index] == NULL){ - hashTable->table[index] = hashItem; - return index; - } else { - hashItem->next = hashTable->table[index]; - hashTable->table[index] = hashItem; - return index; - } -} - - -static struct diskMapEntry * lookupHashItem(struct diskMapTable *hashTable, - uint32_t itemKey) { - int index; - struct diskMapEntry *hashItem; - - index = itemKey % (hashTable->tableSize); - for (hashItem = hashTable->table[index]; - (hashItem != NULL) && (hashItem->key != itemKey); - hashItem = hashItem->next) { - ; - } - return hashItem; -} - - -static int addToHashTable(struct diskMapTable *hashTable, - uint32_t itemKey, char *diskName) { - int index; - struct diskMapEntry *diskSigToNameEntry; - - diskSigToNameEntry = malloc(sizeof(struct diskMapEntry)); - diskSigToNameEntry->next = NULL; - diskSigToNameEntry->key = itemKey; - diskSigToNameEntry->diskname = diskName; - - if ((index = insertHashItem(hashTable, diskSigToNameEntry)) < 0){ -#ifdef STANDALONE - fprintf(stderr, "Unable to insert item\n"); -#endif - return 0; - } else { - return 1; - } -} - - -char * getBiosDisk(char *biosStr) { - uint32_t biosNum; - struct diskMapEntry * disk; - int ret; - - if (diskHashInit == 0) { - probeBiosDisks(); - diskHashInit = 1; - } - - if (mbrSigToName == NULL) - return NULL; - - ret = sscanf(biosStr,"%x",&biosNum); - disk = lookupHashItem(mbrSigToName, biosNum); - if (disk) return disk->diskname; - - return NULL; -} diff --git a/pkgs/core/pomona/src/isys/eddsupport.h b/pkgs/core/pomona/src/isys/eddsupport.h deleted file mode 100644 index 77fc4c4..0000000 --- a/pkgs/core/pomona/src/isys/eddsupport.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * eddsupport.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 EDDSUPPORT_H -#define EDDSUPPORT_H - -int probeBiosDisks(); -char* getBiosDisk(char *); - -#endif - - diff --git a/pkgs/core/pomona/src/isys/ethtool.c b/pkgs/core/pomona/src/isys/ethtool.c deleted file mode 100644 index 42a06dc..0000000 --- a/pkgs/core/pomona/src/isys/ethtool.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * ethtool.c - setting of basic ethtool options - * - * Copyright (C) 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): Jeremy Katz katzj@redhat.com - */ - -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> - -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <net/if.h> - -#include <linux/sockios.h> -#include "net.h" - -static int set_intf_up(struct ifreq ifr, int sock) { - if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) { - return (-1); - } - ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); - if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) { - fprintf(stderr, "failed to bring up interface %s: %s", ifr.ifr_name, - strerror(errno)); - return -1; - } - return (0); -} - -int setEthtoolSettings(char * dev, ethtool_speed speed, - ethtool_duplex duplex) { - int sock, err; - struct ethtool_cmd ecmd; - struct ifreq ifr; - - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - perror("Unable to create socket"); - return -1; - } - - /* Setup our control structures. */ - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, dev); - - if (set_intf_up(ifr, sock) == -1) { - fprintf(stderr, "unable to bring up interface %s: %s", dev, - strerror(errno)); - return -1; - } - - ecmd.cmd = ETHTOOL_GSET; - ifr.ifr_data = (caddr_t)&ecmd; - err = ioctl(sock, SIOCETHTOOL, &ifr); - if (err < 0) { - perror("Unable to get settings via ethtool. Not setting"); - return -1; - } - - if (speed != ETHTOOL_SPEED_UNSPEC) - ecmd.speed = speed; - if (duplex != ETHTOOL_DUPLEX_UNSPEC) - ecmd.duplex = duplex; - if ((duplex != ETHTOOL_DUPLEX_UNSPEC) || (speed != ETHTOOL_SPEED_UNSPEC)) - ecmd.autoneg = AUTONEG_DISABLE; - - ecmd.cmd = ETHTOOL_SSET; - ifr.ifr_data = (caddr_t)&ecmd; - err = ioctl(sock, SIOCETHTOOL, &ifr); - if (err < 0) { - // perror("Unable to set settings via ethtool. Not setting"); - return -1; - } - - return 0; -} diff --git a/pkgs/core/pomona/src/isys/imount.c b/pkgs/core/pomona/src/isys/imount.c deleted file mode 100644 index ec5ad5e..0000000 --- a/pkgs/core/pomona/src/isys/imount.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * imount.c - * - * Copyright (C) 2007, 2008 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 <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/mount.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "imount.h" -#include "sundries.h" - -#define _(foo) foo - -static int mkdirIfNone(char * directory); - -static int readFD(int fd, char **buf) { - char *p; - size_t size = 4096; - int s, filesize = 0; - - *buf = calloc(4096, sizeof (char)); - if (*buf == NULL) - abort(); - - do { - p = &(*buf)[filesize]; - s = read(fd, p, 4096); - if (s < 0) - break; - - filesize += s; - if (s == 0) - break; - - size += s; - *buf = realloc(*buf, size); - if (*buf == NULL) - abort(); - } while (1); - - if (filesize == 0 && s < 0) { - free(*buf); - *buf = NULL; - return -1; - } - - return filesize; -} - -int doPwMount(char *dev, char *where, char *fs, char *options, char **err) { - int rc, child, status, pipefd[2]; - char *opts = NULL, *device; - - if (mkdirChain(where)) - return IMOUNT_ERR_ERRNO; - - if (strstr(fs, "nfs")) { - if (options) { - if (asprintf(&opts, "%s,nolock", options) == -1) { - fprintf(stderr, "%s: %d: %s\n", __func__, __LINE__, - strerror(errno)); - fflush(stderr); - abort(); - } - } else { - opts = strdup("nolock"); - } - device = strdup(dev); - } else { - if ((options && strstr(options, "bind") == NULL) && - strncmp(dev, "LABEL=", 6) && strncmp(dev, "UUID=", 5) && - *dev != '/') { - if (asprintf(&device, "/dev/%s", dev) == -1) { - fprintf(stderr, "%s: %d: %s\n", __func__, __LINE__, - strerror(errno)); - fflush(stderr); - abort(); - } - } else { - device = strdup(dev); - } - if (options) - opts = strdup(options); - } - - if (pipe(pipefd)) - return IMOUNT_ERR_ERRNO; - - if (!(child = fork())) { - int fd; - - close(pipefd[0]); - - /* Close stdin entirely, redirect stdout to tty5, and redirect stderr - * to a pipe so we can put error messages into exceptions. We'll - * only use these messages should mount also return an error code. - */ - fd = open("/dev/tty5", O_RDONLY); - close(STDIN_FILENO); - dup2(fd, STDIN_FILENO); - close(fd); - - fd = open("/dev/tty5", O_WRONLY); - close(STDOUT_FILENO); - dup2(fd, STDOUT_FILENO); - - dup2(pipefd[1], STDERR_FILENO); - - if (opts) { - fprintf(stdout, "Running... /bin/mount -n -t %s -o %s %s %s\n", - fs, opts, device, where); - rc = execl("/bin/mount", - "/bin/mount", "-n", "-t", fs, "-o", opts, device, where, NULL); - exit(1); - } - else { - fprintf(stdout, "Running... /bin/mount -n -t %s %s %s\n", - fs, device, where); - rc = execl("/bin/mount", "/bin/mount", "-n", "-t", fs, device, where, NULL); - exit(1); - } - } - - close(pipefd[1]); - - if (err != NULL) - rc = readFD(pipefd[0], err); - - close(pipefd[0]); - waitpid(child, &status, 0); - - free(opts); - free(device); - if (!WIFEXITED(status) || (WIFEXITED(status) && WEXITSTATUS(status))) - return IMOUNT_ERR_OTHER; - - return 0; -} - -int doMultiMount(char *dev, char *where, char **fstypes, char *options, char **err) { - int retval = 0, i; - - for (i = 0; fstypes[i]; i++) { - /* If we made a previous call to mount and it returned an error message, - * get rid of it now. We only want to preserve the error from the last - * fstype. - */ - if (err && *err && **err) { - free(*err); - *err = NULL; - } - - retval = doPwMount(dev, where, fstypes[i], options, err); - if (!retval) - return retval; - } - - return retval; -} - -int mkdirChain(char * origChain) { - char * chain; - char * chptr; - - chain = alloca(strlen(origChain) + 1); - strcpy(chain, origChain); - chptr = chain; - - while ((chptr = strchr(chptr, '/'))) { - *chptr = '\0'; - if (mkdirIfNone(chain)) { - *chptr = '/'; - return IMOUNT_ERR_ERRNO; - } - - *chptr = '/'; - chptr++; - } - - if (mkdirIfNone(chain)) - return IMOUNT_ERR_ERRNO; - - return 0; -} - -static int mkdirIfNone(char * directory) { - int rc, mkerr; - char * chptr; - - /* If the file exists it *better* be a directory -- I'm not going to - actually check or anything */ - if (!access(directory, X_OK)) return 0; - - /* if the path is '/' we get ENOFILE not found" from mkdir, rather - then EEXIST which is weird */ - for (chptr = directory; *chptr; chptr++) - if (*chptr != '/') break; - if (!*chptr) return 0; - - rc = mkdir(directory, 0755); - mkerr = errno; - - if (!rc || mkerr == EEXIST) return 0; - - return IMOUNT_ERR_ERRNO; -} diff --git a/pkgs/core/pomona/src/isys/imount.h b/pkgs/core/pomona/src/isys/imount.h deleted file mode 100644 index 56f6dea..0000000 --- a/pkgs/core/pomona/src/isys/imount.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * imount.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_IMOUNT -#define H_IMOUNT - -#define IMOUNT_ERR_ERRNO 1 -#define IMOUNT_ERR_OTHER 2 - -#include <sys/mount.h> /* for umount() */ - -#define IMOUNT_RDONLY 1 -#define IMOUNT_BIND 2 -#define IMOUNT_REMOUNT 4 - -int doPwMount(char *dev, char *where, char *fs, char *options, char **err); -int doMultiMount(char *dev, char *where, char **fstypes, char *options, char **err); -int mkdirChain(char * origChain); - -#endif diff --git a/pkgs/core/pomona/src/isys/isofs.c b/pkgs/core/pomona/src/isys/isofs.c deleted file mode 100644 index c444dce..0000000 --- a/pkgs/core/pomona/src/isys/isofs.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * isofs.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 <fcntl.h> -#include <string.h> -#include <unistd.h> - -#define BLOCK_SIZE 2048 - -/* returns 1 if file is an ISO, 0 otherwise */ -int fileIsIso(const char * file) { - int blkNum; - char magic[5]; - int fd; - - fd = open(file, O_RDONLY); - if (fd < 0) - return 0; - - for (blkNum = 16; blkNum < 100; blkNum++) { - if (lseek(fd, blkNum * BLOCK_SIZE + 1, SEEK_SET) < 0) { - close(fd); - return 0; - } - - if (read(fd, magic, sizeof(magic)) != sizeof(magic)) { - close(fd); - return 0; - } - - if (!strncmp(magic, "CD001", 5)) { - close(fd); - return 1; - } - } - - close(fd); - return 0; -} diff --git a/pkgs/core/pomona/src/isys/isys.c b/pkgs/core/pomona/src/isys/isys.c index f56e713..08684fa 100644 --- a/pkgs/core/pomona/src/isys/isys.c +++ b/pkgs/core/pomona/src/isys/isys.c @@ -1,245 +1,24 @@ -/* - * isys.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 <Python.h> - -#include <stdio.h> -#include <dirent.h> -#include <errno.h> -#define u32 __u32 -#include <ext2fs/ext2fs.h> -#include <fcntl.h> -#include <popt.h> -/* Need to tell loop.h what the actual dev_t type is. */ -#undef dev_t -#define dev_t unsigned short -#include <linux/loop.h> -#undef dev_t -#define dev_t dev_t -#include <sys/ioctl.h> -#include <sys/mount.h> -#include <sys/stat.h> -#include <sys/sysmacros.h> -#include <sys/time.h> -#include <sys/utsname.h> -#include <sys/vfs.h> -#include <unistd.h> -#include <resolv.h> -#include <scsi/scsi.h> -#include <scsi/scsi_ioctl.h> -#include <sys/vt.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <linux/fb.h> -#include <libintl.h> -#ifdef USESELINUX -#include <selinux/selinux.h> -#endif -#include <libgen.h> -#include <linux/major.h> -#include <linux/raid/md_u.h> -#include <linux/raid/md_p.h> -#include <signal.h> -#include <execinfo.h>
-#include <blkid/blkid.h> +#include <Python.h>
#include "isys.h" -#include "imount.h" -#include "smp.h" -#include "lang.h" -#include "eddsupport.h" -#include "imount.h" +#include "mount.h"
-#ifndef CDROMEJECT -#define CDROMEJECT 0x5309 -#endif
static PyObject * doMount(PyObject * s, PyObject * args); static PyObject * doUMount(PyObject * s, PyObject * args); -static PyObject * smpAvailable(PyObject * s, PyObject * args); -static PyObject * htAvailable(PyObject * s, PyObject * args); -static PyObject * doSwapon(PyObject * s, PyObject * args); -static PyObject * doSwapoff(PyObject * s, PyObject * args); -static PyObject * doLoSetup(PyObject * s, PyObject * args); -static PyObject * doUnLoSetup(PyObject * s, PyObject * args); -static PyObject * doLoChangeFd(PyObject * s, PyObject * args); -static PyObject * doDdFile(PyObject * s, PyObject * args); -static PyObject * doWipeRaidSuperblock(PyObject * s, PyObject * args); -static PyObject * doGetRaidSuperblock(PyObject * s, PyObject * args); -static PyObject * doGetRaidChunkSize(PyObject * s, PyObject * args); -static PyObject * doDevSpaceFree(PyObject * s, PyObject * args); -static PyObject * doResetResolv(PyObject * s, PyObject * args); -static PyObject * doLoadKeymap(PyObject * s, PyObject * args); -static PyObject * doClobberExt2 (PyObject * s, PyObject * args); -static PyObject * doReadE2fsLabel(PyObject * s, PyObject * args); -static PyObject * doExt2Dirty(PyObject * s, PyObject * args); -static PyObject * doExt2HasJournal(PyObject * s, PyObject * args); -static PyObject * doEjectCdrom(PyObject * s, PyObject * args); -static PyObject * doVtActivate(PyObject * s, PyObject * args); -static PyObject * doisPseudoTTY(PyObject * s, PyObject * args); -static PyObject * doisVioConsole(PyObject * s); -static PyObject * doSync(PyObject * s, PyObject * args); -static PyObject * doisIsoImage(PyObject * s, PyObject * args); -static PyObject * getFramebufferInfo(PyObject * s, PyObject * args); -static PyObject * printObject(PyObject * s, PyObject * args); -static PyObject * doProbeBiosDisks(PyObject * s, PyObject * args); -static PyObject * doGetBiosDisk(PyObject * s, PyObject * args); -static PyObject * doSegvHandler(PyObject *s, PyObject *args); -static PyObject * doGetBlkidData(PyObject * s, PyObject * args); -static PyObject * doGetDeviceByToken(PyObject *s, PyObject *args);
static PyMethodDef isysModuleMethods[] = { - { "ejectcdrom", (PyCFunction) doEjectCdrom, METH_VARARGS, NULL }, - { "e2dirty", (PyCFunction) doExt2Dirty, METH_VARARGS, NULL }, - { "e2hasjournal", (PyCFunction) doExt2HasJournal, METH_VARARGS, NULL }, - { "e2fslabel", (PyCFunction) doReadE2fsLabel, METH_VARARGS, NULL }, - { "e2fsclobber", (PyCFunction) doClobberExt2, METH_VARARGS, NULL }, - { "devSpaceFree", (PyCFunction) doDevSpaceFree, METH_VARARGS, NULL }, - { "getraidsb", (PyCFunction) doGetRaidSuperblock, METH_VARARGS, NULL }, - { "wiperaidsb", (PyCFunction) doWipeRaidSuperblock, METH_VARARGS, NULL }, - { "getraidchunk", (PyCFunction) doGetRaidChunkSize, METH_VARARGS, NULL }, - { "lochangefd", (PyCFunction) doLoChangeFd, METH_VARARGS, NULL }, - { "losetup", (PyCFunction) doLoSetup, METH_VARARGS, NULL }, - { "unlosetup", (PyCFunction) doUnLoSetup, METH_VARARGS, NULL }, - { "ddfile", (PyCFunction) doDdFile, METH_VARARGS, NULL }, { "mount", (PyCFunction) doMount, METH_VARARGS, NULL }, - { "smpavailable", (PyCFunction) smpAvailable, METH_VARARGS, NULL }, - { "htavailable", (PyCFunction) htAvailable, METH_VARARGS, NULL }, { "umount", (PyCFunction) doUMount, METH_VARARGS, NULL }, - { "resetresolv", (PyCFunction) doResetResolv, METH_VARARGS, NULL }, - { "swapon", (PyCFunction) doSwapon, METH_VARARGS, NULL }, - { "swapoff", (PyCFunction) doSwapoff, METH_VARARGS, NULL }, - { "loadKeymap", (PyCFunction) doLoadKeymap, METH_VARARGS, NULL }, - { "vtActivate", (PyCFunction) doVtActivate, METH_VARARGS, NULL}, - { "isPseudoTTY", (PyCFunction) doisPseudoTTY, METH_VARARGS, NULL}, - { "isVioConsole", (PyCFunction) doisVioConsole, METH_NOARGS, NULL}, - { "sync", (PyCFunction) doSync, METH_VARARGS, NULL}, - { "isisoimage", (PyCFunction) doisIsoImage, METH_VARARGS, NULL}, - { "fbinfo", (PyCFunction) getFramebufferInfo, METH_VARARGS, NULL}, - { "printObject", (PyCFunction) printObject, METH_VARARGS, NULL}, - { "biosDiskProbe", (PyCFunction) doProbeBiosDisks, METH_VARARGS,NULL}, - { "getbiosdisk",(PyCFunction) doGetBiosDisk, METH_VARARGS,NULL}, - { "handleSegv", (PyCFunction) doSegvHandler, METH_VARARGS, NULL }, - { "getblkid", (PyCFunction) doGetBlkidData, METH_VARARGS, NULL }, - { "getdevicebytoken", (PyCFunction) doGetDeviceByToken, METH_VARARGS, NULL }, - { NULL, NULL, 0, NULL } -} ; - -static PyObject * doDdFile(PyObject * s, PyObject * args) { - int fd; - int megs; - char * ptr; - int i; - - if (!PyArg_ParseTuple(args, "ii", &fd, &megs)) return NULL; - - ptr = calloc(1024 * 256, 1); - - while (megs--) { - for (i = 0; i < 4; i++) { - if (write(fd, ptr, 1024 * 256) != 1024 * 256) { - PyErr_SetFromErrno(PyExc_SystemError); - free(ptr); - return NULL; - } - sync(); - } - } - - free(ptr); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * doUnLoSetup(PyObject * s, PyObject * args) { - int loopfd; - - if (!PyArg_ParseTuple(args, "i", &loopfd)) return NULL; - if (ioctl(loopfd, LOOP_CLR_FD, 0)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -/* XXX - msw */ -#ifndef LOOP_CHANGE_FD -#define LOOP_CHANGE_FD 0x4C06 -#endif - -static PyObject * doLoChangeFd(PyObject * s, PyObject * args) { - int loopfd; - int targfd; - - if (!PyArg_ParseTuple(args, "ii", &loopfd, &targfd)) - return NULL; - if (ioctl(loopfd, LOOP_CHANGE_FD, targfd)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * doLoSetup(PyObject * s, PyObject * args) { - int loopfd; - int targfd; - struct loop_info loopInfo; - char * loopName; - - if (!PyArg_ParseTuple(args, "iis", &loopfd, &targfd, &loopName)) - return NULL; - if (ioctl(loopfd, LOOP_SET_FD, targfd)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - memset(&loopInfo, 0, sizeof(loopInfo)); - strncpy(loopInfo.lo_name, basename(loopName), 63); - - if (ioctl(loopfd, LOOP_SET_STATUS, &loopInfo)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * doUMount(PyObject * s, PyObject * args) { - char * fs; - - if (!PyArg_ParseTuple(args, "s", &fs)) return NULL; +};
- if (umount(fs)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } +void init_isys(void) { + PyObject * m, * d;
- Py_INCREF(Py_None); - return Py_None; + m = Py_InitModule("_isys", isysModuleMethods); + d = PyModule_GetDict(m); }
static PyObject * doMount(PyObject * s, PyObject * args) { @@ -250,8 +29,8 @@ static PyObject * doMount(PyObject * s, PyObject * args) { &flags)) return NULL;
rc = doPwMount(device, mntpoint, fs, flags, &err); - if (rc == IMOUNT_ERR_ERRNO) - PyErr_SetFromErrno(PyExc_SystemError); + if (rc == MOUNT_ERR_ERRNO) + PyErr_SetFromErrno(PyExc_SystemError); else if (rc) { PyObject *tuple = PyTuple_New(2);
@@ -260,510 +39,24 @@ static PyObject * doMount(PyObject * s, PyObject * args) { PyErr_SetObject(PyExc_SystemError, tuple); }
- if (rc) return NULL; - - Py_INCREF(Py_None); - return Py_None; -} - -#define BOOT_SIGNATURE 0xaa55 /* boot signature */ -#define BOOT_SIG_OFFSET 510 /* boot signature offset */ - -int swapoff(const char * path); -int swapon(const char * path, int priorty); - -static PyObject * doSwapoff (PyObject * s, PyObject * args) { - char * path; - - if (!PyArg_ParseTuple(args, "s", &path)) return NULL; - - if (swapoff (path)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * doSwapon (PyObject * s, PyObject * args) { - char * path; - - if (!PyArg_ParseTuple(args, "s", &path)) return NULL; - - if (swapon (path, 0)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * smpAvailable(PyObject * s, PyObject * args) { - if (!PyArg_ParseTuple(args, "")) return NULL; - - return Py_BuildValue("i", detectSMP()); -} - -static PyObject * htAvailable(PyObject * s, PyObject * args) { - if (!PyArg_ParseTuple(args, "")) return NULL; - - return Py_BuildValue("i", detectHT()); -} - -void init_isys(void) { - PyObject * m, * d; - - m = Py_InitModule("_isys", isysModuleMethods); - d = PyModule_GetDict(m); - - PyDict_SetItemString(d, "MIN_RAM", PyInt_FromLong(MIN_RAM)); - PyDict_SetItemString(d, "EARLY_SWAP_RAM", PyInt_FromLong(EARLY_SWAP_RAM)); -} - -static PyObject * doResetResolv(PyObject * s, PyObject * args) { - if (!PyArg_ParseTuple(args, "")) { + if (rc) return NULL; - } - - /* reinit the resolver so DNS changes take affect */ - res_init();
Py_INCREF(Py_None); return Py_None; }
-static PyObject * doWipeRaidSuperblock(PyObject * s, PyObject * args) { - int fd; - unsigned long size; - struct mdp_super_t * sb; - - if (!PyArg_ParseTuple(args, "i", &fd)) return NULL; - - if (ioctl(fd, BLKGETSIZE, &size)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - /* put the size in 1k blocks */ - size >>= 1; - - if (lseek64(fd, ((off64_t) 512) * (off64_t) MD_NEW_SIZE_SECTORS(size), SEEK_SET) < 0) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - sb = malloc(sizeof(mdp_super_t)); - sb = memset(sb, '\0', sizeof(mdp_super_t)); - - if (write(fd, sb, sizeof(sb)) != sizeof(sb)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - return Py_None; -} - -static PyObject * doGetRaidSuperblock(PyObject * s, PyObject * args) { - int fd; - unsigned long size; - mdp_super_t sb; - char uuid[36]; - - if (!PyArg_ParseTuple(args, "i", &fd)) return NULL; - - if (ioctl(fd, BLKGETSIZE, &size)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - /* put the size in 1k blocks */ - size >>= 1; - - if (lseek64(fd, ((off64_t) 512) * (off64_t) MD_NEW_SIZE_SECTORS(size), SEEK_SET) < 0) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - if (sb.md_magic != MD_SB_MAGIC) { - PyErr_SetString(PyExc_ValueError, "bad md magic on device"); - return NULL; - } - - sprintf(uuid, "%08x:%08x:%08x:%08x", sb.set_uuid0, sb.set_uuid1, - sb.set_uuid2, sb.set_uuid3); - - return Py_BuildValue("(iisiiii)", sb.major_version, sb.minor_version, - uuid, sb.level, sb.nr_disks, sb.raid_disks, - sb.md_minor); -} - -static PyObject * doGetRaidChunkSize(PyObject * s, PyObject * args) { - int fd; - unsigned long size; - mdp_super_t sb; - - if (!PyArg_ParseTuple(args, "i", &fd)) return NULL; - - if (ioctl(fd, BLKGETSIZE, &size)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - /* put the size in 1k blocks */ - size >>= 1; - - if (lseek64(fd, ((off64_t) 512) * (off64_t) MD_NEW_SIZE_SECTORS(size), SEEK_SET) < 0) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - if (sb.md_magic != MD_SB_MAGIC) { - PyErr_SetString(PyExc_ValueError, "bad md magic on device"); - return NULL; - } - - return Py_BuildValue("i", sb.chunk_size / 1024); -} - -static int get_bits(unsigned long long v) { - int b = 0; - - if ( v & 0xffffffff00000000LLU ) { b += 32; v >>= 32; } - if ( v & 0xffff0000LLU ) { b += 16; v >>= 16; } - if ( v & 0xff00LLU ) { b += 8; v >>= 8; } - if ( v & 0xf0LLU ) { b += 4; v >>= 4; } - if ( v & 0xcLLU ) { b += 2; v >>= 2; } - if ( v & 0x2LLU ) b++; - - return v ? b + 1 : b; -} - -static PyObject * doDevSpaceFree(PyObject * s, PyObject * args) { - char * path; - struct statfs sb; - unsigned long long size; - - if (!PyArg_ParseTuple(args, "s", &path)) return NULL; - - if (statfs(path, &sb)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - /* Calculate a saturated addition to prevent oveflow. */ - if ( get_bits(sb.f_bfree) + get_bits(sb.f_bsize) <= 64 ) - size = (unsigned long long)sb.f_bfree * sb.f_bsize; - else - size = ~0LLU; - - return PyLong_FromUnsignedLongLong(size>>20); -} - -static PyObject * doLoadKeymap (PyObject * s, PyObject * args) { - char * keymap; - int ret; - - if (!PyArg_ParseTuple(args, "s", &keymap)) return NULL; - - ret = isysLoadKeymap (keymap); - if (ret) { - errno = -ret; - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * doClobberExt2 (PyObject * s, PyObject * args) { - char * device; - ext2_filsys fsys; - struct ext2_super_block sb; - int rc; - - if (!PyArg_ParseTuple(args, "s", &device)) return NULL; - - rc = ext2fs_open(device, EXT2_FLAG_FORCE, 0, 0, unix_io_manager, &fsys); - - if (rc) { - Py_INCREF(Py_None); - return Py_None; - } - - memset(&sb, 0, sizeof(struct ext2_super_block)); - rc = ext2fs_initialize (device, 0, &sb, unix_io_manager, &fsys); - if (rc) { - Py_INCREF(Py_None); - return Py_None; - } - - ext2fs_close(fsys); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * doReadE2fsLabel(PyObject * s, PyObject * args) { - char * device; - ext2_filsys fsys; - char buf[50]; - int rc; - - if (!PyArg_ParseTuple(args, "s", &device)) return NULL; - - rc = ext2fs_open(device, EXT2_FLAG_FORCE, 0, 0, unix_io_manager, - &fsys); - if (rc) { - Py_INCREF(Py_None); - return Py_None; - } - - memset(buf, 0, sizeof(buf)); - strncpy(buf, fsys->super->s_volume_name, - sizeof(fsys->super->s_volume_name)); - - ext2fs_close(fsys); - - return Py_BuildValue("s", buf); -} - -static PyObject * doExt2Dirty(PyObject * s, PyObject * args) { - char * device; - ext2_filsys fsys; - int rc; - int clean; - - if (!PyArg_ParseTuple(args, "s", &device)) return NULL; - - rc = ext2fs_open(device, EXT2_FLAG_FORCE, 0, 0, unix_io_manager, - &fsys); - if (rc) { - Py_INCREF(Py_None); - return Py_None; - } - - clean = fsys->super->s_state & EXT2_VALID_FS; - - ext2fs_close(fsys); - - return Py_BuildValue("i", !clean); -} -static PyObject * doExt2HasJournal(PyObject * s, PyObject * args) { - char * device; - ext2_filsys fsys; - int rc; - int hasjournal; - - if (!PyArg_ParseTuple(args, "s", &device)) return NULL; - rc = ext2fs_open(device, EXT2_FLAG_FORCE, 0, 0, unix_io_manager, - &fsys); - if (rc) { - Py_INCREF(Py_None); - return Py_None; - } - - hasjournal = fsys->super->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL; - - ext2fs_close(fsys); - - return Py_BuildValue("i", hasjournal); -} - -static PyObject * doEjectCdrom(PyObject * s, PyObject * args) { - int fd; - - if (!PyArg_ParseTuple(args, "i", &fd)) return NULL; - - if (ioctl(fd, CDROMEJECT, 1)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * doVtActivate(PyObject * s, PyObject * args) { - int vtnum; - - if (!PyArg_ParseTuple(args, "i", &vtnum)) return NULL; - - if (ioctl(0, VT_ACTIVATE, vtnum)) { - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * doisPseudoTTY(PyObject * s, PyObject * args) { - int fd; - struct stat sb; - - if (!PyArg_ParseTuple(args, "i", &fd)) return NULL; - fstat(fd, &sb); - - /* XXX close enough for now */ - return Py_BuildValue("i", ((major(sb.st_rdev) >= 136) && (major(sb.st_rdev) <= 143))); -} - -static PyObject * doisVioConsole(PyObject * s) { - return Py_BuildValue("i", isVioConsole()); -} - -static PyObject * doSync(PyObject * s, PyObject * args) { - int fd; - - if (!PyArg_ParseTuple(args, "", &fd)) return NULL; - sync(); - - Py_INCREF(Py_None); - return Py_None; -} - -int fileIsIso(const char * file); - -static PyObject * doisIsoImage(PyObject * s, PyObject * args) { - char * fn; - int rc; - - if (!PyArg_ParseTuple(args, "s", &fn)) return NULL; - - rc = fileIsIso(fn); - - return Py_BuildValue("i", rc); -} - -static PyObject * getFramebufferInfo(PyObject * s, PyObject * args) { - int fd; - struct fb_var_screeninfo fb; - - fd = open("/dev/fb0", O_RDONLY); - if (fd == -1) { - Py_INCREF(Py_None); - return Py_None; - } - - if (ioctl(fd, FBIOGET_VSCREENINFO, &fb)) { - close(fd); - PyErr_SetFromErrno(PyExc_SystemError); - return NULL; - } - - close(fd); - - return Py_BuildValue("(iii)", fb.xres, fb.yres, fb.bits_per_pixel); -} - -static PyObject * printObject (PyObject * o, PyObject * args) { - PyObject * obj; - char buf[256]; - - if (!PyArg_ParseTuple(args, "O", &obj)) - return NULL; - - snprintf(buf, 256, "<%s object at %lx>", obj->ob_type->tp_name, - (long) obj); - - return PyString_FromString(buf); -} - -static PyObject * doProbeBiosDisks(PyObject * s, PyObject * args) { - if (!PyArg_ParseTuple(args, "")) return NULL; - - - return Py_BuildValue("i", probeBiosDisks()); -} - -static PyObject * doGetBiosDisk(PyObject * s, PyObject * args) { - char *mbr_sig; - char *diskname; - - if (!PyArg_ParseTuple(args, "s", &mbr_sig)) return NULL; - - if ((diskname = getBiosDisk(mbr_sig))) - return Py_BuildValue("s", diskname); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject * doSegvHandler(PyObject *s, PyObject *args) { - void *array[20]; - size_t size; - char **strings; - size_t i; - - signal(SIGSEGV, SIG_DFL); /* back to default */ - - size = backtrace (array, 20); - strings = backtrace_symbols (array, size); - - printf ("Anaconda received SIGSEGV!. Backtrace:\n"); - for (i = 0; i < size; i++) - printf ("%s\n", strings[i]); - - free (strings); - exit(1); -} - -static PyObject *doGetDeviceByToken(PyObject *s, PyObject *args) { - blkid_cache cache; - char *token, *value, *dev; - - if (!PyArg_ParseTuple(args, "ss", &token, &value)) return NULL; - - blkid_get_cache(&cache, NULL); - - dev = blkid_get_devname(cache, token, value); - if (dev == NULL) { - Py_INCREF(Py_None); - return Py_None; - } else { - return Py_BuildValue("s", dev); - } -} - -static PyObject * doGetBlkidData(PyObject * s, PyObject * args) { - char * dev, * key; - blkid_cache cache; - blkid_dev bdev = NULL; - blkid_tag_iterate titer; - const char * type, * data; - - if (!PyArg_ParseTuple(args, "ss", &dev, &key)) return NULL; +static PyObject * doUMount(PyObject * s, PyObject * args) { + char * fs;
- blkid_get_cache(&cache, NULL); + if (!PyArg_ParseTuple(args, "s", &fs)) + return NULL;
- bdev = blkid_get_dev(cache, dev, BLKID_DEV_NORMAL); - if (bdev == NULL) - goto out; - titer = blkid_tag_iterate_begin(bdev); - while (blkid_tag_next(titer, &type, &data) >= 0) { - if (!strcmp(type, key)) { - blkid_tag_iterate_end(titer); - return Py_BuildValue("s", data); - } + if (umount(fs)) { + PyErr_SetFromErrno(PyExc_SystemError); + return NULL; } - blkid_tag_iterate_end(titer);
- out: Py_INCREF(Py_None); return Py_None; } - -/* vim:set shiftwidth=4 softtabstop=4: */ diff --git a/pkgs/core/pomona/src/isys/isys.h b/pkgs/core/pomona/src/isys/isys.h index 9f6a2bb..4757e4c 100644 --- a/pkgs/core/pomona/src/isys/isys.h +++ b/pkgs/core/pomona/src/isys/isys.h @@ -1,35 +1,5 @@ -/* - * isys.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_ISYS #define H_ISYS
-#define MIN_RAM 32000 -#define EARLY_SWAP_RAM 64000 - -int insmod(char * modName, char * path, char ** args); -int rmmod(char * modName); - -/* returns 0 for true, !0 for false */ -int fileIsIso(const char * file); - -/* returns 1 if on an iSeries vio console, 0 otherwise */ -int isVioConsole(void);
#endif diff --git a/pkgs/core/pomona/src/isys/isys.py b/pkgs/core/pomona/src/isys/isys.py index 7104c6c..ffc2c97 100644 --- a/pkgs/core/pomona/src/isys/isys.py +++ b/pkgs/core/pomona/src/isys/isys.py @@ -1,297 +1,11 @@ -# -# isys.py - installer utility functions and glue for C module -# -# Copyright (C) 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): Matt Wilson msw@redhat.com -# Erik Troan ewt@redhat.com -# Jeremy Katz katzj@redhat.com -# +#!/usr/bin/python
import _isys -import string -import os -import os.path -import socket -import stat -import posix -import sys -import iutil -import warnings -import resource -import re -import struct -import pyfire.hal
-import logging -log = logging.getLogger("pomona") -import warnings +import os +import string
mountCount = {} -raidCount = {} - -MIN_RAM = _isys.MIN_RAM -EARLY_SWAP_RAM = _isys.EARLY_SWAP_RAM - -## Get the amount of free space available under a directory path. -# @param path The directory path to check. -# @return The amount of free space available, in -def pathSpaceAvailable(path): - return _isys.devSpaceFree(path) - - -mdadmOutput = "/tmp/mdadmout" - -## An error occured when running mdadm. -class MdadmError(Exception): - ## The constructor. - # @param args The arguments passed to the mdadm command. - # @param name The the name of the RAID device used in the mdadm command. - def __init__(self, args, name=None): - self.args = args - self.name = name - self.log = self.getCmdOutput() - - ## Get the output of the last mdadm command run. - # @return The formatted output of the mdadm command which caused an error. - def getCmdOutput(self): - f = open(mdadmOutput, "r") - lines = reduce(lambda x,y: x + [string.strip(y),], f.readlines(), []) - lines = string.join(reduce(lambda x,y: x + [" %s" % (y,)], \ - lines, []), "\n") - return lines - - def __str__(self): - s = "" - if not self.name is None: - s = " for device %s" % (self.name,) - command = "mdadm " + string.join(self.args, " ") - return "'%s' failed%s\nLog:\n%s" % (command, s, self.log) - -def _mdadm(*args): - try: - lines = iutil.execWithCapture("mdadm", args, stderr = mdadmOutput) - lines = string.split(lines, '\n') - lines = reduce(lambda x,y: x + [y.strip(),], lines, []) - return lines - except: - raise MdadmError, args - -def _getRaidInfo(drive): - log.info("mdadm -E %s" % (drive,)) - try: - lines = _mdadm("-E", drive) - except MdadmError: - ei = sys.exc_info() - ei[1].name = drive - raise ei[0], ei[1], ei[2] - - info = { - 'major': "-1", - 'minor': "-1", - 'uuid' : "", - 'level': -1, - 'nrDisks': -1, - 'totalDisks': -1, - 'mdMinor': -1, - } - - for line in lines: - vals = string.split(string.strip(line), ' : ') - if len(vals) != 2: - continue - if vals[0] == "Version": - vals = string.split(vals[1], ".") - info['major'] = vals[0] - info['minor'] = vals[1] - elif vals[0] == "UUID": - info['uuid'] = vals[1] - elif vals[0] == "Raid Level": - info['level'] = int(vals[1][4:]) - elif vals[0] == "Raid Devices": - info['nrDisks'] = int(vals[1]) - elif vals[0] == "Total Devices": - info['totalDisks'] = int(vals[1]) - elif vals[0] == "Preferred Minor": - info['mdMinor'] = int(vals[1]) - else: - continue - - if info['uuid'] == "": - raise ValueError, info - - return info - -def _stopRaid(mdDevice): - log.info("mdadm --stop %s" % (mdDevice,)) - try: - _mdadm("--stop", mdDevice) - except MdadmError: - ei = sys.exc_info() - ei[1].name = mdDevice - raise ei[0], ei[1], ei[2] - -def raidstop(mdDevice): - log.info("stopping raid device %s" %(mdDevice,)) - if raidCount.has_key (mdDevice): - if raidCount[mdDevice] > 1: - raidCount[mdDevice] = raidCount[mdDevice] - 1 - return - del raidCount[mdDevice] - - devInode = "/dev/%s" % mdDevice - - try: - _stopRaid(devInode) - except: - pass - -def _startRaid(mdDevice, mdMinor, uuid): - log.info("mdadm -A --uuid=%s --super-minor=%s %s" % (uuid, mdMinor, mdDevice)) - try: - _mdadm("-A", "--uuid=%s" % (uuid,), "--super-minor=%s" % (mdMinor,), \ - mdDevice) - except MdadmError: - ei = sys.exc_info() - ei[1].name = mdDevice - raise ei[0], ei[1], ei[2] - -def raidstart(mdDevice, aMember): - log.info("starting raid device %s" %(mdDevice,)) - if raidCount.has_key(mdDevice) and raidCount[mdDevice]: - raidCount[mdDevice] = raidCount[mdDevice] + 1 - return - - raidCount[mdDevice] = 1 - - mdInode = "/dev/%s" % mdDevice - mbrInode = "/dev/%s" % aMember - - if os.path.exists(mdInode): - minor = os.minor(os.stat(mdInode).st_rdev) - else: - minor = int(mdDevice[2:]) - try: - info = _getRaidInfo(mbrInode) - if info.has_key('mdMinor'): - minor = info['mdMinor'] - _startRaid(mdInode, minor, info['uuid']) - except: - pass - -## Remove the superblock from a RAID device. -# @param device The complete path to the RAID device name to wipe. -def wipeRaidSB(device): - try: - fd = os.open(device, os.O_WRONLY) - except OSError, e: - log.warning("error wiping raid device superblock for %s: %s", device, e) - return - - try: - _isys.wiperaidsb(fd) - finally: - os.close(fd) - return - -## Get the raw superblock from a RAID device. -# @param The basename of a RAID device to check. This device node does not -# need to exist to begin with. -# @return A RAID superblock in its raw on-disk format. -def raidsb(mdDevice): - return raidsbFromDevice("/dev/%s" % mdDevice) - -## Get the superblock from a RAID device. -# @param The full path to a RAID device name to check. This device node must -# already exist. -# @return A tuple of the contents of the RAID superblock, or ValueError on -# error. -def raidsbFromDevice(device): - try: - info = _getRaidInfo(device) - return (info['major'], info['minor'], info['uuid'], info['level'], - info['nrDisks'], info['totalDisks'], info['mdMinor']) - except: - raise ValueError - -def getRaidChunkFromDevice(device): - fd = os.open(device, os.O_RDONLY) - rc = 64 - try: - rc = _isys.getraidchunk(fd) - finally: - os.close(fd) - return rc - -## Set up an already existing device node to be used as a loopback device. -# @param device The full path to a device node to set up as a loopback device. -# @param file The file to mount as loopback on device. -# @param readOnly Should this loopback device be used read-only? -def losetup(device, file, readOnly = 0): - if readOnly: - mode = os.O_RDONLY - else: - mode = os.O_RDWR - targ = os.open(file, mode) - loop = os.open(device, mode) - try: - _isys.losetup(loop, targ, file) - finally: - os.close(loop) - os.close(targ) - -def lochangefd(device, file): - loop = os.open(device, os.O_RDONLY) - targ = os.open(file, os.O_RDONLY) - try: - _isys.lochangefd(loop, targ) - finally: - os.close(loop) - os.close(targ) - -## Disable a previously setup loopback device. -# @param device The full path to an existing loopback device node. -def unlosetup(device): - loop = os.open(device, os.O_RDONLY) - try: - _isys.unlosetup(loop) - finally: - os.close(loop) - -def ddfile(file, megs, pw = None): - buf = '\x00' * (1024 * 256) - - fd = os.open(file, os.O_RDWR | os.O_CREAT) - - total = megs * 4 # we write out 1/4 of a meg each time through - - if pw: - (fn, title, text) = pw - win = fn(title, text, total - 1) - - for n in range(total): - os.write(fd, buf) - if pw: - win.set(n) - - if pw: - win.pop() - - os.close(fd)
## Mount a filesystem, similar to the mount system call. # @param device The device to mount. If bindMount is 1, this should be an @@ -331,7 +45,7 @@ def mount(device, location, fstype = "ext2", readOnly = 0, bindMount = 0, remoun
flags = ",".join(opts)
- log.debug("isys.py:mount()- going to mount %s on %s with options %s" %(device, location, flags)) + #log.debug("isys.py:mount()- going to mount %s on %s with options %s" %(device, location, flags)) rc = _isys.mount(fstype, device, location, flags)
if not rc: @@ -363,348 +77,3 @@ def umount(what, removeDir = 1): del mountCount[what]
return rc - -## Get the SMP status of the system. -# @return True if this is an SMP system, False otherwise. -def smpAvailable(): - return _isys.smpavailable() - -htavailable = _isys.htavailable - -## Disable swap. -# @param path The full path of the swap device to disable. -def swapoff(path): - return _isys.swapoff (path) - -## Enable swap. -# @param path The full path of the swap device to enable. -def swapon(path): - return _isys.swapon (path) - -## Load a keyboard layout for text mode installs. -# @param keymap The keyboard layout to load. This must be one of the values -# from rhpl.KeyboardModels. -def loadKeymap(keymap): - return _isys.loadKeymap (keymap) - -cachedDrives = None - -## Clear the drive dict cache. -# This method clears the drive dict cache. If the drive state changes (by -# loading and unloading modules, attaching removable devices, etc.) then this -# function must be called before any of the *DriveDict or *DriveList functions. -# If not, those functions will return information that does not reflect the -# current machine state. -def flushDriveDict(): - global cachedDrives - cachedDrives = None - -def driveDict(klassArg): - import parted - global cachedDrives - if cachedDrives is None: - new = {} - for dev in pyfire.hal.get_devices_by_type("storage"): - if dev['device'] is None: # none devices make no sense - continue - - device = dev['device'].replace('/dev/','') - # we can't actually use the sg devices, so ignore them - if device.startswith("sg"): - log.info("ignoring sg device %s" %(device,)) - continue - - # we can't actually use the st devices, so ignore them - if device.startswith("st"): - log.info("ignoring st device %s" %(device,)) - continue - - # we want to ignore md devices as they're not hard disks in our pov - if device.startswith("md"): - continue - - if dev['storage.drive_type'] != 'disk': - new[device] = dev - continue - try: - if not mediaPresent(device): - new[device] = dev - continue - - if device.startswith("sd"): - peddev = parted.PedDevice.get(dev['device']) - model = peddev.model - - del peddev - new[device] = dev - except Exception, e: - log.debug("exception checking disk blacklist on %s: %s" % \ - (device, e)) - cachedDrives = new - - ret = {} - for key,dev in cachedDrives.items(): - if dev['storage.drive_type'] == klassArg: - ret[key] = dev - return ret - -## Get all the hard drives attached to the system. -# This method queries the drive dict cache for all hard drives. If the cache -# is empty, this will cause all disk devices to be probed. If the status of -# the devices has changed, flushDriveDict must be called first. -# -# @see flushDriveDict -# @see driveDict -# @return A dict of all the hard drive descriptions, keyed on device name. -def hardDriveDict(): - ret = {} - dict = driveDict("disk") - for item in dict.keys(): - try: - ret[item] = dict[item]['description'] - except AttributeError: - ret[item] = "" - return ret - -## Get all the removable drives attached to the system. -# This method queries the drive dict cache for all removable drives. If the cache -# is empty, this will cause all disk devices to be probed. If the status of -# the devices has changed, flushDriveDict must be run called first. -# -# @see flushDriveDict -# @see driveDict -# @return A dict of all the removable drive descriptions, keyed on device name. -def removableDriveDict(): - ret = {} - dict = driveDict("disk") - for item in dict.keys(): - if dict[item]['storage.removable'] != 0: - try: - ret[item] = dict[item]['description'] - except AttributeError: - ret[item] = "" - return ret - -## Get all CD/DVD drives attached to the system. -# This method queries the drive dict cache for all hard drives. If the cache -# is empty, this will cause all disk devices to be probed. If the status of -# the devices has changed, flushDriveDict must be called first. -# -# @see flushDriveDict -# @see driveDict -# @return A sorted list of all the CD/DVD drives, without any leading /dev/. -def cdromList(): - list = driveDict("cdrom").keys() - list.sort() - return list - -## Get all tape drives attached to the system. -# This method queries the drive dict cache for all hard drives. If the cache -# is empty, this will cause all disk devices to be probed. If the status of -# the devices has changed, flushDriveDict must be called first. -# -# @see flushDriveDict -# @see driveDict -# @return A sorted list of all the tape drives, without any leading /dev/. -def tapeDriveList(): - list = driveDict("tape").keys() - list.sort() - return list - -## Calculate the broadcast address of a network. -# @param ip An IPv4 address as a string. -# @param nm A corresponding netmask as a string. -# @return A tuple of network address and broadcast address strings. -def inet_calcNetBroad(ip, nm): - (ipaddr,) = struct.unpack('I', socket.inet_pton(socket.AF_INET, ip)) - ipaddr = socket.ntohl(ipaddr) - - (nmaddr,) = struct.unpack('I', socket.inet_pton(socket.AF_INET, nm)) - nmaddr = socket.ntohl(nmaddr) - - netaddr = ipaddr & nmaddr - bcaddr = netaddr | (~nmaddr) - - nw = socket.inet_ntop(socket.AF_INET, struct.pack('!I', netaddr)) - bc = socket.inet_ntop(socket.AF_INET, struct.pack('!I', bcaddr)) - - return (nw, bc) - -def doProbeBiosDisks(): - return _isys.biosDiskProbe() - -def doGetBiosDisk(mbrSig): - return _isys.getbiosdisk(mbrSig) - -biosdisks = {} -for d in range(80, 80 + 15): - disk = doGetBiosDisk("%d" %(d,)) - #print "biosdisk of %s is %s" %(d, disk) - if disk is not None: - biosdisks[disk] = d - -def compareDrives(first, second): - if biosdisks.has_key(first) and biosdisks.has_key(second): - one = biosdisks[first] - two = biosdisks[second] - if (one < two): - return -1 - elif (one > two): - return 1 - - if first.startswith("hd"): - type1 = 0 - elif first.startswith("sd"): - type1 = 1 - elif (first.startswith("vd") or first.startswith("xvd")): - type1 = -1 - else: - type1 = 2 - - if second.startswith("hd"): - type2 = 0 - elif second.startswith("sd"): - type2 = 1 - elif (second.startswith("vd") or second.startswith("xvd")): - type2 = -1 - else: - type2 = 2 - - if (type1 < type2): - return -1 - elif (type1 > type2): - return 1 - else: - len1 = len(first) - len2 = len(second) - - if (len1 < len2): - return -1 - elif (len1 > len2): - return 1 - else: - if (first < second): - return -1 - elif (first > second): - return 1 - - return 0 - -def readFSUuid(device): - if not os.path.exists(device): - device = "/dev/%s" % device - - label = _isys.getblkid(device, "UUID") - return label - -def readFSLabel(device): - if not os.path.exists(device): - device = "/dev/%s" % device - - label = _isys.getblkid(device, "LABEL") - return label - -def readFSType(device): - if not os.path.exists(device): - device = "/dev/%s" % device - - fstype = _isys.getblkid(device, "TYPE") - if fstype is None: - # FIXME: libblkid doesn't show physical volumes as having a filesystem - # so let's sniff for that.(#409321) - try: - fd = os.open(device, os.O_RDONLY) - buf = os.read(fd, 2048) - except: - return fstype - finally: - try: - os.close(fd) - except: - pass - - - if fstype == "ext4": - return "ext4dev" - return fstype - -def ext2Clobber(device): - _isys.e2fsclobber(device) - -def ext2IsDirty(device): - label = _isys.e2dirty(device) - return label - -def ext2HasJournal(device): - hasjournal = _isys.e2hasjournal(device); - return hasjournal - -def ejectCdrom(device): - fd = os.open(device, os.O_RDONLY|os.O_NONBLOCK) - - # this is a best effort - try: - _isys.ejectcdrom(fd) - except SystemError, e: - log.warning("error ejecting cdrom (%s): %s" %(device, e)) - pass - - os.close(fd) - -def driveUsesModule(device, modules): - """Returns true if a drive is using a prticular module. Only works - for SCSI devices right now.""" - - if not isinstance(modules, ().__class__) and not \ - isinstance(modules, [].__class__): - modules = [modules] - - if device[:2] == "hd": - return False - rc = False - if os.access("/tmp/scsidisks", os.R_OK): - sdlist=open("/tmp/scsidisks", "r") - sdlines = sdlist.readlines() - sdlist.close() - for l in sdlines: - try: - # each line has format of: <device> <module> - (sddev, sdmod) = string.split(l) - - if sddev == device: - if sdmod in modules: - rc = True - break - except: - pass - return rc - -## Check if a removable media drive (CD, USB key, etc.) has media present. -# @param device The basename of the device node. -# @return True if media is present in device, False otherwise. -def mediaPresent(device): - try: - fd = os.open("/dev/%s" % device, os.O_RDONLY) - except OSError, (errno, strerror): - # error 123 = No medium found - if errno == 123: - return False - else: - return True - else: - os.close(fd) - return True - -def vtActivate(num): - _isys.vtActivate (num) - -def isPsudoTTY(fd): - return _isys.isPseudoTTY(fd) - -## Flush filesystem buffers. -def sync(): - return _isys.sync () - -handleSegv = _isys.handleSegv -printObject = _isys.printObject -isVioConsole = _isys.isVioConsole diff --git a/pkgs/core/pomona/src/isys/lang.c b/pkgs/core/pomona/src/isys/lang.c deleted file mode 100644 index e16bf3a..0000000 --- a/pkgs/core/pomona/src/isys/lang.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * lang.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 <alloca.h> -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <unistd.h> - -#include <linux/keyboard.h> -#ifdef NR_KEYS -#undef NR_KEYS -#define NR_KEYS 128 -#endif - -#include "linux/kd.h" - -#include "cpio.h" -#include "isys.h" -#include "lang.h" -#include "stubs.h" - -int isysLoadFont(void) { - unsigned char font[65536]; - struct console_font_op cfo; - unsigned short map[E_TABSZ]; - struct unimapdesc d; - struct unimapinit u; - struct unipair desc[2048]; - gzFile stream; - int rc; - -#if defined (__s390__) || defined (__s390x__) - return 0; -#endif - stream = gunzip_open("/etc/screenfont.gz"); - if (!stream) - return -EACCES; - - gunzip_read(stream, &cfo, sizeof(cfo)); - gunzip_read(stream, font, sizeof(font)); - gunzip_read(stream, map, sizeof(map)); - gunzip_read(stream, &d.entry_ct, sizeof(d.entry_ct)); - d.entries = desc; - gunzip_read(stream, desc, d.entry_ct * sizeof(desc[0])); - gunzip_close(stream); - - cfo.data = font; - cfo.op = KD_FONT_OP_SET; - - rc = ioctl(1, KDFONTOP, &cfo); - if (rc) return rc; - rc = ioctl(1, PIO_UNIMAPCLR, &u); - if (rc) return rc; - rc = ioctl(1, PIO_UNIMAP, &d); - if (rc) return rc; - rc = ioctl(1, PIO_UNISCRNMAP, map); - if (rc) return rc; - /* activate the font map */ - fprintf(stderr, "\033(K"); - return 0; -} - -int isysSetUnicodeKeymap(void) { - int console; - -#if defined (__s390__) || defined (__s390x__) - return 0; -#endif - console = open("/dev/console", O_RDWR); - if (console < 0) - return -EACCES; - - /* place keyboard in unicode mode */ - ioctl(console, KDSKBMODE, K_UNICODE); - close(console); - return 0; -} - -/* the file pointer must be at the beginning of the section already! */ -int loadKeymap(gzFile stream) { - int console; - int kmap, key; - struct kbentry entry; - int keymaps[MAX_NR_KEYMAPS]; - int count = 0; - unsigned int magic; - short keymap[NR_KEYS]; - struct stat sb; - -#if defined (__s390__) || defined (__s390x__) - return 0; -#endif - if (isVioConsole()) - return 0; - if (!access("/proc/xen", R_OK)) /* xen can't load keymaps */ - return 0; - - /* assume that if we're already on a pty loading a keymap is silly */ - fstat(0, &sb); - if (major(sb.st_rdev) == 3 || major(sb.st_rdev) == 136) - return 0; - - if (gunzip_read(stream, &magic, sizeof(magic)) != sizeof(magic)) - return -EIO; - - if (magic != KMAP_MAGIC) return -EINVAL; - - if (gunzip_read(stream, keymaps, sizeof(keymaps)) != sizeof(keymaps)) - return -EINVAL; - - console = open("/dev/console", O_RDWR); - if (console < 0) - return -EACCES; - - for (kmap = 0; kmap < MAX_NR_KEYMAPS; kmap++) { - if (!keymaps[kmap]) continue; - - if (gunzip_read(stream, keymap, sizeof(keymap)) != sizeof(keymap)) { - close(console); - return -EIO; - } - - count++; - for (key = 0; key < NR_KEYS; key++) { - entry.kb_index = key; - entry.kb_table = kmap; - entry.kb_value = keymap[key]; - if (KTYP(entry.kb_value) != KT_SPEC) { - if (ioctl(console, KDSKBENT, &entry)) { - int ret = errno; - close(console); - return ret; - } - } - } - } - close(console); - return 0; -} - -int isysLoadKeymap(char * keymap) { - int num = -1; - int rc; - gzFile f; - struct kmapHeader hdr; - struct kmapInfo * infoTable; - char buf[16384]; /* I hope this is big enough */ - int i; - - f = gunzip_open("/etc/keymaps.gz"); - if (!f) return -EACCES; - - if (gunzip_read(f, &hdr, sizeof(hdr)) != sizeof(hdr)) { - gunzip_close(f); - return -EINVAL; - } - - i = hdr.numEntries * sizeof(*infoTable); - infoTable = alloca(i); - if (gunzip_read(f, infoTable, i) != i) { - gunzip_close(f); - return -EIO; - } - - for (i = 0; i < hdr.numEntries; i++) - if (!strcmp(infoTable[i].name, keymap)) { - num = i; - break; - } - - if (num == -1) { - gunzip_close(f); - return -ENOENT; - } - - for (i = 0; i < num; i++) { - if (gunzip_read(f, buf, infoTable[i].size) != infoTable[i].size) { - gunzip_close(f); - return -EIO; - } - } - - rc = loadKeymap(f); - - gunzip_close(f); - - return rc; -} diff --git a/pkgs/core/pomona/src/isys/lang.h b/pkgs/core/pomona/src/isys/lang.h deleted file mode 100644 index 8632bc6..0000000 --- a/pkgs/core/pomona/src/isys/lang.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 ISYS_LANG_H -#define ISYS_LANG_H - -#include "stubs.h" - -/* define ask johnsonm@redhat.com where this came from */ -#define KMAP_MAGIC 0x8B39C07F -#define KMAP_NAMELEN 40 /* including '\0' */ - -struct kmapHeader { - int magic; - int numEntries; -}; - -struct kmapInfo { - int size; - char name[KMAP_NAMELEN]; -}; - -int loadKeymap(gzFile stream); -int isysLoadFont(void); -int isysLoadKeymap(char * keymap); -int isysSetUnicodeKeymap(void); - -#endif diff --git a/pkgs/core/pomona/src/isys/linkdetect.c b/pkgs/core/pomona/src/isys/linkdetect.c deleted file mode 100644 index 1f2fbd6..0000000 --- a/pkgs/core/pomona/src/isys/linkdetect.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * linkdetect.c - simple link detection - * - * pulls code from mii-tool.c in net-toools and ethtool so - * that we can do everything that jgarzik says we should check - * - * Copyright (C) 2002, 2003 Red Hat, Inc. All rights reserved. - * Portions Copyright (C) 2000 David A. Hinds -- dhinds@pcmcia.sourceforge.org - * - * 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 <sys/ioctl.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#include <sys/socket.h> -#include <sys/types.h> -#include <net/if.h> - -#include <linux/sockios.h> -#include <linux/mii.h> -#include <linux/ethtool.h> -#include "net.h" - -static struct ifreq ifr; - -static int mdio_read(int skfd, int location) -{ - void *data = &ifr.ifr_data; - struct mii_ioctl_data *mii = data; - mii->reg_num = location; - if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0) { -#ifdef STANDALONE - fprintf(stderr, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name, - strerror(errno)); -#endif - return -1; - } - return mii->val_out; -} - -/* we don't need writing right now */ -#if 0 -static void mdio_write(int skfd, int location, int value) -{ - struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&ifr.ifr_data; - mii->reg_num = location; - mii->val_in = value; - if (ioctl(skfd, SIOCSMIIREG, &ifr) < 0) { -#ifdef STANDALONE - fprintf(stderr, "SIOCSMIIREG on %s failed: %s\n", ifr.ifr_name, - strerror(errno)); -#endif - } -} -#endif - - - -static int get_mii_link_status(int sock) { - int i, mii_val[32]; - - if (ioctl(sock, SIOCGMIIPHY, &ifr) < 0) { - if (errno != ENODEV) -#ifdef STANDALONE - fprintf(stderr, "SIOCGMIIPHY on '%s' failed: %s\n", - ifr.ifr_name, strerror(errno)); -#endif - return -1; - } - - /* Some bits in the BMSR are latched, but we can't rely on being - the only reader, so only the current values are meaningful */ - mdio_read(sock, MII_BMSR); - for (i = 0; i < 8; i++) - mii_val[i] = mdio_read(sock, i); - - if (mii_val[MII_BMCR] == 0xffff) { -#ifdef STANDALONE - fprintf(stderr, " No MII transceiver present!.\n"); -#endif - return -1; - } - - if (mii_val[MII_BMSR] & BMSR_LSTATUS) - return 1; - else - return 0; -} - -static int get_ethtool_link_status(int sock) { - struct ethtool_value edata; - int rc; - - edata.cmd = ETHTOOL_GLINK; - ifr.ifr_data = (caddr_t)&edata; - rc = ioctl(sock, SIOCETHTOOL, &ifr); - if (rc == 0) { - return edata.data; - } else if (errno != EOPNOTSUPP) { -#ifdef STANDALONE - fprintf(stderr, "Cannot get link status (%d): %s\n", errno, strerror(errno)); -#endif - } - - return -1; -} - - - -int get_link_status(char * devname) { - int sock, rc; - - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { -#ifdef STANDALONE - fprintf(stderr, "Error creating socket: %s\n", strerror(errno)); -#endif - return -1; - } - - /* Setup our control structures. */ - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, devname); - - /* check for link with both ethtool and mii registers. ethtool is - * supposed to be the One True Way (tm), but it seems to not work - * with much yet :/ */ - - rc = get_ethtool_link_status(sock); -#ifdef STANDALONE - printf("ethtool link status of %s is: %d\n", devname, rc); -#endif - if (rc == 1) { - close(sock); - return 1; - } - - rc = get_mii_link_status(sock); -#ifdef STANDALONE - printf("MII link status of %s is: %d\n", devname, rc); -#endif - if (rc == 1) { - close(sock); - return 1; - } - - return 0; -} - -#ifdef STANDALONE -/* hooray for stupid test programs! */ -int main(int argc, char **argv) { - char * dev; - - if (argc >= 2) - dev = argv[1]; - else - dev = strdup("eth0"); - - printf("link status of %s is %d\n", dev, get_link_status(dev)); - return 0; -} -#endif diff --git a/pkgs/core/pomona/src/isys/mount.c b/pkgs/core/pomona/src/isys/mount.c new file mode 100644 index 0000000..6b0f175 --- /dev/null +++ b/pkgs/core/pomona/src/isys/mount.c @@ -0,0 +1,186 @@ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mount.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <fcntl.h> + +#include "mount.h" + +static int mkdirIfNone(char * directory); + +static int readFD(int fd, char **buf) { + char *p; + size_t size = 4096; + int s, filesize = 0; + + *buf = calloc(4096, sizeof (char)); + if (*buf == NULL) + abort(); + + do { + p = &(*buf)[filesize]; + s = read(fd, p, 4096); + if (s < 0) + break; + + filesize += s; + if (s == 0) + break; + + size += s; + *buf = realloc(*buf, size); + if (*buf == NULL) + abort(); + } while (1); + + if (filesize == 0 && s < 0) { + free(*buf); + *buf = NULL; + return -1; + } + + return filesize; +} + +int doPwMount(char *dev, char *where, char *fs, char *options, char **err) { + int rc, child, status, pipefd[2]; + char *opts = NULL, *device; + + if (mkdirChain(where)) + return MOUNT_ERR_ERRNO; + + if (strstr(fs, "nfs")) { + if (options) { + if (asprintf(&opts, "%s,nolock", options) == -1) { + fprintf(stderr, "%s: %d: %s\n", __func__, __LINE__, + strerror(errno)); + fflush(stderr); + abort(); + } + } else { + opts = strdup("nolock"); + } + device = strdup(dev); + } else { + if ((options && strstr(options, "bind") == NULL) && + strncmp(dev, "LABEL=", 6) && strncmp(dev, "UUID=", 5) && + *dev != '/') { + if (asprintf(&device, "/dev/%s", dev) == -1) { + fprintf(stderr, "%s: %d: %s\n", __func__, __LINE__, + strerror(errno)); + fflush(stderr); + abort(); + } + } else { + device = strdup(dev); + } + if (options) + opts = strdup(options); + } + + if (pipe(pipefd)) + return MOUNT_ERR_ERRNO; + + if (!(child = fork())) { + int fd; + + close(pipefd[0]); + + /* Close stdin entirely, redirect stdout to tty5, and redirect stderr + * to a pipe so we can put error messages into exceptions. We'll + * only use these messages should mount also return an error code. + */ + fd = open("/dev/tty5", O_RDONLY); + close(STDIN_FILENO); + dup2(fd, STDIN_FILENO); + close(fd); + + fd = open("/dev/tty5", O_WRONLY); + close(STDOUT_FILENO); + dup2(fd, STDOUT_FILENO); + + dup2(pipefd[1], STDERR_FILENO); + + if (opts) { + rc = execl("/bin/mount", + "/bin/mount", "-n", "-t", fs, "-o", opts, device, where, NULL); + exit(1); + } + else { + rc = execl("/bin/mount", "/bin/mount", "-n", "-t", fs, device, where, NULL); + exit(1); + } + } + + close(pipefd[1]); + + if (err != NULL) + rc = readFD(pipefd[0], err); + + close(pipefd[0]); + waitpid(child, &status, 0); + + free(opts); + free(device); + if (!WIFEXITED(status) || (WIFEXITED(status) && WEXITSTATUS(status))) + return MOUNT_ERR_OTHER; + + return 0; +} + +int mkdirChain(char * origChain) { + char * chain; + char * chptr; + + chain = alloca(strlen(origChain) + 1); + strcpy(chain, origChain); + chptr = chain; + + while ((chptr = strchr(chptr, '/'))) { + *chptr = '\0'; + if (mkdirIfNone(chain)) { + *chptr = '/'; + return MOUNT_ERR_ERRNO; + } + + *chptr = '/'; + chptr++; + } + + if (mkdirIfNone(chain)) + return MOUNT_ERR_ERRNO; + + return 0; +} + +static int mkdirIfNone(char * directory) { + int rc, mkerr; + char * chptr; + + /* If the file exists it *better* be a directory -- I'm not going to + actually check or anything */ + if (!access(directory, X_OK)) + return 0; + + /* if the path is '/' we get ENOFILE not found" from mkdir, rather + then EEXIST which is weird */ + for (chptr = directory; *chptr; chptr++) + if (*chptr != '/') + break; + if (!*chptr) + return 0; + + rc = mkdir(directory, 0755); + mkerr = errno; + + if (!rc || mkerr == EEXIST) + return 0; + + return MOUNT_ERR_ERRNO; +} diff --git a/pkgs/core/pomona/src/isys/mount.h b/pkgs/core/pomona/src/isys/mount.h new file mode 100644 index 0000000..b505322 --- /dev/null +++ b/pkgs/core/pomona/src/isys/mount.h @@ -0,0 +1,13 @@ + +#ifndef H_MOUNT +#define H_MOUNT + +#define MOUNT_ERR_ERRNO 1 +#define MOUNT_ERR_OTHER 2 + +#include <sys/mount.h> /* for umount() */ + +int doPwMount(char *dev, char *where, char *fs, char *options, char **err); +int mkdirChain(char * origChain); + +#endif diff --git a/pkgs/core/pomona/src/isys/net.h b/pkgs/core/pomona/src/isys/net.h deleted file mode 100644 index 7843286..0000000 --- a/pkgs/core/pomona/src/isys/net.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 ISYSNET_H -#define ISYSNET_H - -#include <linux/types.h> -#include <linux/ethtool.h> - -/* type definitions so that the kernel-ish includes can be shared */ -#ifndef uint8_t -# define uint8_t unsigned char -#endif -#ifndef uint16_t -# define uint16_t unsigned short int -#endif -#ifndef uint32_t -# define uint32_t unsigned int -#endif -#ifndef uint64_t -# define uint64_t unsigned long long int -#endif -typedef uint64_t u64; -typedef uint32_t u32; -typedef uint16_t u16; -typedef uint8_t u8; - -/* returns 1 for link, 0 for no link, -1 for unknown */ -int get_link_status(char *ifname); - -typedef enum ethtool_speed_t { ETHTOOL_SPEED_UNSPEC = -1, - ETHTOOL_SPEED_10 = SPEED_10, - ETHTOOL_SPEED_100 = SPEED_100, - ETHTOOL_SPEED_1000 = SPEED_1000 } ethtool_speed; -typedef enum ethtool_duplex_t { ETHTOOL_DUPLEX_UNSPEC = -1, - ETHTOOL_DUPLEX_HALF = DUPLEX_HALF, - ETHTOOL_DUPLEX_FULL = DUPLEX_FULL } ethtool_duplex; - -/* set ethtool settings */ -int setEthtoolSettings(char * dev, ethtool_speed speed, ethtool_duplex duplex); - -#endif diff --git a/pkgs/core/pomona/src/isys/smp.c b/pkgs/core/pomona/src/isys/smp.c deleted file mode 100644 index 7fee3db..0000000 --- a/pkgs/core/pomona/src/isys/smp.c +++ /dev/null @@ -1,488 +0,0 @@ -/* - * smp.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/. - */ - -/* -[_Anarchy_(alan@lightning.swansea.uk.linux.org)] you should do one check - though - if the board seems to be SMP and the CPU in /proc/cpuinfo is non - intel dont install an SMP kernel - thats a dual pentium board with a cyrix - or similar single cpu in it -*/ - - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <string.h> -#include <errno.h> -#include <stdint.h> -#include <sys/types.h> - -/* - * Copyright (c) 1996, by Steve Passe - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. The name of the developer may NOT be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - * - * $Id$ - */ - -/* - * mptable.c - */ - -#define VMAJOR 2 -#define VMINOR 0 -#define VDELTA 12 - -/* - * this will cause the raw mp table to be dumped to /tmp/mpdump - * -#define RAW_DUMP - */ - -#define MP_SIG 0x5f504d5f /* _MP_ */ -#define EXTENDED_PROCESSING_READY -#define OEM_PROCESSING_READY_NOT - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/types.h> - -#define LINUX 1 -#if LINUX -typedef uint32_t vm_offset_t; -#else -#include <machine/types.h> -#endif - -/* EBDA is @ 40:0e in real-mode terms */ -#define EBDA_POINTER 0x040e /* location of EBDA pointer */ - -/* CMOS 'top of mem' is @ 40:13 in real-mode terms */ -#define TOPOFMEM_POINTER 0x0413 /* BIOS: base memory size */ - -#define DEFAULT_TOPOFMEM 0xa0000 - -#define BIOS_BASE 0xf0000 -#define BIOS_BASE2 0xe0000 -#define BIOS_SIZE 0x10000 -#define ONE_KBYTE 1024 - -#define GROPE_AREA1 0x80000 -#define GROPE_AREA2 0x90000 -#define GROPE_SIZE 0x10000 - -/* MP Floating Pointer Structure */ -typedef struct MPFPS { - char signature[ 4 ]; - int32_t pap; - u_char length; - u_char spec_rev; - u_char checksum; - u_char mpfb1; - u_char mpfb2; - u_char mpfb3; - u_char mpfb4; - u_char mpfb5; -} mpfps_t; - -/* MP Configuration Table Header */ -typedef struct MPCTH { - char signature[ 4 ]; - uint16_t base_table_length; - u_char spec_rev; - u_char checksum; - char oem_id[ 8 ]; - char product_id[ 12 ]; - int32_t oem_table_pointer; - uint16_t oem_table_size; - uint16_t entry_count; - int32_t apic_address; - uint16_t extended_table_length; - u_char extended_table_checksum; - u_char reserved; -} mpcth_t; - -typedef struct PROCENTRY { - u_char type; - u_char apicID; - u_char apicVersion; - u_char cpuFlags; - uint32_t cpuSignature; - uint32_t featureFlags; - uint32_t reserved1; - uint32_t reserved2; -} ProcEntry; - -#define PROCENTRY_FLAG_EN 0x01 - -static int seekEntry( vm_offset_t addr ); -static void apic_probe( vm_offset_t* paddr, int* where ); -static void readEntry( void* entry, int size ); - -/* global data */ -static int pfd; /* physical /dev/mem fd */ -static int verbose = 0; -static int grope = 0; - -static int readType() { - u_char type; - - if ( read( pfd, &type, sizeof( u_char ) ) != sizeof( u_char ) ) { -/* perror( "type read" ); */ -/* fprintf( stderr, "\npfd: %d", pfd ); */ -/* fflush( stderr ); */ -/* exit( 1 ); */ - return -1; - } - - if ( lseek( pfd, -1, SEEK_CUR ) < 0 ) { -/* perror( "type seek" ); */ -/* exit( 1 ); */ - return -1; - } - - return (int)type; -} - -#define MODE_SMP_CHECK 1 - -static int groupForSMP(int mode) { - vm_offset_t paddr; - int where; - mpfps_t mpfps; - int rc = 0; - int ncpus = 0; - - /* open physical memory for access to MP structures */ - if ( (pfd = open( "/dev/mem", O_RDONLY )) < 0 ) { - return 0; - } - - /* probe for MP structures */ - apic_probe( &paddr, &where ); - if ( where <= 0 ) - return 0; - - if (seekEntry( paddr )) - return 0; - readEntry( &mpfps, sizeof( mpfps_t ) ); - - if (mpfps.mpfb1) - /* old style */ - rc = 1; - else { - /* go to the config table */ - mpcth_t cth; - int count, i; - - paddr = (vm_offset_t) mpfps.pap; - if (seekEntry( paddr )) - return 0; - readEntry( &cth, sizeof( cth ) ); - /* if we don't have any entries, the kernel sure - won't be able to set up mp. Needs at least one entry - for smp kernel */ - if (cth.entry_count <= 1) { - close (pfd); - return 0; - } - - count = cth.entry_count; - for (i = 0; i < count; i++) { - if ( readType() == 0 ) { - ProcEntry entry; - readEntry( &entry, sizeof( entry ) ); - if (entry.cpuFlags & PROCENTRY_FLAG_EN) - ncpus++; - } - } - if (ncpus > 1) - rc = 1; - } - - close (pfd); - return rc; -} - -/* - * set PHYSICAL address of MP floating pointer structure - */ -#define NEXT(X) ((X) += 4) -static void -apic_probe( vm_offset_t* paddr, int* where ) { - /* - * c rewrite of apic_probe() by Jack F. Vogel - */ - - unsigned int x; - uint16_t segment; - vm_offset_t target; - uint32_t buffer[ BIOS_SIZE / sizeof( int32_t ) ]; - - if ( verbose ) - printf( "\n" ); - - /* search Extended Bios Data Area, if present */ - if ( verbose ) - printf( " looking for EBDA pointer @ 0x%04x, ", EBDA_POINTER ); - if (seekEntry( (vm_offset_t)EBDA_POINTER )) { - *where = 0; - *paddr = (vm_offset_t)0; - return; - } - readEntry( &segment, 2 ); - if ( segment ) { /* search EBDA */ - target = (vm_offset_t)segment << 4; - if ( verbose ) - printf( "found, searching EBDA @ 0x%08x\n", target ); - if (seekEntry( target )) { - *where = 0; - *paddr = (vm_offset_t)0; - return; - } - readEntry( buffer, ONE_KBYTE ); - - for ( x = 0; x < ONE_KBYTE / sizeof ( uint32_t ); NEXT(x) ) { - if ( buffer[ x ] == MP_SIG ) { - *where = 1; - *paddr = (x * sizeof( uint32_t )) + target; - return; - } - } - - } - else { - if ( verbose ) - printf( "NOT found\n" ); - } - - /* read CMOS for real top of mem */ - if (seekEntry( (vm_offset_t)TOPOFMEM_POINTER )) { - *where = 0; - *paddr = (vm_offset_t)0; - return; - } - readEntry( &segment, 2 ); - --segment; /* less ONE_KBYTE */ - target = segment * 1024; - if ( verbose ) - printf( " searching CMOS 'top of mem' @ 0x%08x (%dK)\n", - target, segment ); - seekEntry( target ); - readEntry( buffer, ONE_KBYTE ); - - for ( x = 0; x < ONE_KBYTE / sizeof ( uint32_t ); NEXT(x) ) { - if ( buffer[ x ] == MP_SIG ) { - *where = 2; - *paddr = (x * sizeof( uint32_t )) + target; - return; - } - } - - /* we don't necessarily believe CMOS, check base of the last 1K of 640K */ - if ( target != (DEFAULT_TOPOFMEM - 1024)) { - target = (DEFAULT_TOPOFMEM - 1024); - if ( verbose ) - printf( " searching default 'top of mem' @ 0x%08x (%dK)\n", - target, (target / 1024) ); - seekEntry( target ); - readEntry( buffer, ONE_KBYTE ); - - for ( x = 0; x < ONE_KBYTE / sizeof ( uint32_t ); NEXT(x) ) { - if ( buffer[ x ] == MP_SIG ) { - *where = 3; - *paddr = (x * sizeof( uint32_t )) + target; - return; - } - } - } - - /* search the BIOS */ - if ( verbose ) - printf( " searching BIOS @ 0x%08x\n", BIOS_BASE ); - seekEntry( BIOS_BASE ); - readEntry( buffer, BIOS_SIZE ); - - for ( x = 0; x < BIOS_SIZE / sizeof( uint32_t ); NEXT(x) ) { - if ( buffer[ x ] == MP_SIG ) { - *where = 4; - *paddr = (x * sizeof( uint32_t )) + BIOS_BASE; - return; - } - } - - /* search the extended BIOS */ - if ( verbose ) - printf( " searching extended BIOS @ 0x%08x\n", BIOS_BASE2 ); - seekEntry( BIOS_BASE2 ); - readEntry( buffer, BIOS_SIZE ); - - for ( x = 0; x < BIOS_SIZE / sizeof( uint32_t ); NEXT(x) ) { - if ( buffer[ x ] == MP_SIG ) { - *where = 5; - *paddr = (x * sizeof( uint32_t )) + BIOS_BASE2; - return; - } - } - - if ( grope ) { - /* search additional memory */ - target = GROPE_AREA1; - if ( verbose ) - printf( " groping memory @ 0x%08x\n", target ); - seekEntry( target ); - readEntry( buffer, GROPE_SIZE ); - - for ( x = 0; x < GROPE_SIZE / sizeof( uint32_t ); NEXT(x) ) { - if ( buffer[ x ] == MP_SIG ) { - *where = 6; - *paddr = (x * sizeof( uint32_t )) + GROPE_AREA1; - return; - } - } - - target = GROPE_AREA2; - if ( verbose ) - printf( " groping memory @ 0x%08x\n", target ); - seekEntry( target ); - readEntry( buffer, GROPE_SIZE ); - - for ( x = 0; x < GROPE_SIZE / sizeof( uint32_t ); NEXT(x) ) { - if ( buffer[ x ] == MP_SIG ) { - *where = 7; - *paddr = (x * sizeof( uint32_t )) + GROPE_AREA2; - return; - } - } - } - - *where = 0; - *paddr = (vm_offset_t)0; -} - -/* - * - */ -static int seekEntry( vm_offset_t addr ) { - if ( lseek( pfd, (off_t)addr, SEEK_SET ) < 0 ) { - return 1; - } - return 0; -} - -/* - * - */ -static void readEntry( void* entry, int size ) { - if ( read( pfd, entry, size ) != size ) { - return; - perror( "readEntry" ); - exit( 1 ); - } -} - -static int intelDetectSMP(void) { - return groupForSMP(MODE_SMP_CHECK); -} - -/* ---- end mptable mess ---- */ - -static inline unsigned int cpuid_ebx(int op) { - unsigned int eax, ebx; - - __asm__("pushl %%ebx; cpuid; movl %%ebx,%1; popl %%ebx" - : "=a" (eax), "=g" (ebx) - : "0" (op) - : "cx", "dx"); - return ebx; -} - -/* XXX: rewrite using /proc/cpuinfo info if it there. Only fall - back to inline asm if it is not */ -int detectHT(void) { - FILE *f; - int htflag = 0; - uint32_t ebx = 0; - int smp_num_siblings = 0; - - f = fopen("/proc/cpuinfo", "r"); - if (f) { - char buff[1024]; - - while (fgets (buff, 1024, f) != NULL) { - if (!strncmp (buff, "flags\t\t:", 8)) { - if (strstr(buff, " ht ") || - /* buff includes \n, so back up 4 bytes from the end - and check there too to catch the end case */ - !strncmp(buff + strlen(buff) - 4, " ht", 3)) { - htflag = 1; - } - break; - } - } - fclose(f); - } - if (!htflag) - return 0; - - ebx = cpuid_ebx(1); - smp_num_siblings = (ebx & 0xff0000) >> 16; - - if (smp_num_siblings >= 2) - return 1; - return 0; -} - -int detectSMP(void) -{ - static int isSMP = -1; - - if (isSMP != -1) - return isSMP; - -#if defined (__i386__) - return isSMP = intelDetectSMP(); -#else - #error unknown architecture -#endif -} diff --git a/pkgs/core/pomona/src/isys/smp.h b/pkgs/core/pomona/src/isys/smp.h deleted file mode 100644 index 651fa33..0000000 --- a/pkgs/core/pomona/src/isys/smp.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * smp.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 SMP_H -#define SMP_H - -int detectSMP(void); -int detectHT(void); - -#endif /* SMP_H */ diff --git a/pkgs/core/pomona/src/isys/str.c b/pkgs/core/pomona/src/isys/str.c deleted file mode 100644 index cf05473..0000000 --- a/pkgs/core/pomona/src/isys/str.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * str.c - String helper functions that don't need string.h or ctype.h - * - * Copyright (C) 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): David Cantrell dcantrell@redhat.com - */ - -#include <stdio.h> -#include <stdlib.h> - -#include "str.h" - -/** - * Called by str2upper() or str2lower() to do the actual work. - * - * @param str String to convert. - * @param lower Lower bound for the character range (e.g., a - z). - * @param upper Upper bound for the character range (e.g., a - z). - * @param shift Shift value (32 for lowercase, -32 for uppercase). - * @return Pointer to str. - */ -char *str2case(char *str, char lower, char upper, int shift) { - char *tmp; - - if (str == NULL) - return NULL; - - /* man ascii(7) */ - tmp = str; - while (*tmp != '\0') { - if (*tmp >= lower && *tmp <= upper) - *tmp += shift; - - tmp++; - } - - return str; -} - -/** - * Convert given string to uppercase. Modifies the argument in the caller's - * stack. If you must ask simply "why?" for this function, it's so we don't - * need toupper() and the same for loop all over the place. - * - * LIMITATIONS: Only deals with ASCII character set. - * - * @param str String to convert to uppercase. - * @return Pointer to str. - */ -char *str2upper(char *str) { - return str2case(str, 'a', 'z', -32); -} - -/** - * Convert given string to lowercase. Modifies the argument in the caller's - * stack. If you must ask simply "why?" for this function, it's so we don't - * need tolower() and the same for loop all over the place. - * - * LIMITATIONS: Only deals with ASCII character set. - * - * @param str String to convert to lowercase. - * @return Pointer to str. - */ -char *str2lower(char *str) { - return str2case(str, 'A', 'Z', 32); -} - -/** - * Pretty much an exact copy of index(3) from the C library. - * @param str String to scan. - * @param ch Character to scan for. - * @return Position of ch in str, NULL if not found. - */ -char *strindex(char *str, int ch) { - if (str == NULL) - return NULL; - - do { - if (*str == ch) - return str; - else - str++; - } while (*str != '\0'); - - return NULL; -} - -/** - * Return number of occurrences of a character in a string. - * @param str String to scan. - * @param ch Character to scan for. - * @return Number of occurrences of ch in str. - */ -int strcount(char *str, int ch) { - int retval = 0; - char *tmp = str; - - if (tmp == NULL) - return retval; - - do { - if ((tmp = strindex(tmp, ch)) != NULL) { - tmp++; - retval++; - } - } while (tmp != NULL); - - return retval; -} - -/* vim:set shiftwidth=4 softtabstop=4: */ diff --git a/pkgs/core/pomona/src/isys/str.h b/pkgs/core/pomona/src/isys/str.h deleted file mode 100644 index d296021..0000000 --- a/pkgs/core/pomona/src/isys/str.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * str.c - String helper functions, the header file - * - * Copyright (C) 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): David Cantrell dcantrell@redhat.com - */ - -/* Function prototypes */ -char *str2case(char *str, char lower, char upper, int shift); -char *str2upper(char *str); -char *str2lower(char *str); -int strcount(char *str, int ch); -char *strindex(char *str, int ch); - -/* vim:set shiftwidth=4 softtabstop=4: */ diff --git a/pkgs/core/pomona/src/isys/stubs.h b/pkgs/core/pomona/src/isys/stubs.h deleted file mode 100644 index ddf5c8d..0000000 --- a/pkgs/core/pomona/src/isys/stubs.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * stubs.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/. - */ - -/* we use gzlib when linked against dietlibc, but otherwise, we should use - zlib. it would make more sense to do the defines in the other direction, - but that causes symbol wackiness because both gunzip_open and gzip_open in - gzlib are gzopen from zlib -*/ - -#ifndef ISYS_STUB -#define ISYS_STUB - -#ifndef GZLIB -#include <zlib.h> - -#define gunzip_open(x) gzopen(x, "r") -#define gunzip_dopen gzdopen(x, "r") -#define gunzip_close gzclose -#define gunzip_read gzread -#define gzip_write gzwrite -#define gzip_open(x, y, z) gzopen(x, "w") - -#else -#include "gzlib/gzlib.h" - -#endif - -#endif diff --git a/pkgs/core/pomona/src/isys/sundries.h b/pkgs/core/pomona/src/isys/sundries.h deleted file mode 100644 index 1fb67b8..0000000 --- a/pkgs/core/pomona/src/isys/sundries.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * sundries.h: Support function prototypes. Functions are in sundries.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 <sys/types.h> -#include <fcntl.h> -#include <limits.h> -#include <signal.h> -#include <stdarg.h> -#include <stdlib.h> -#if !defined(bool_t) && !defined(__GLIBC__) -#include <rpc/types.h> -#endif - -extern int mount_quiet; -extern int verbose; -extern int sloppy; - -#define streq(s, t) (strcmp ((s), (t)) == 0) - - -/* String list data structure. */ -typedef struct string_list -{ - char *hd; - struct string_list *tl; -} *string_list; - -#define car(p) ((p) -> hd) -#define cdr(p) ((p) -> tl) - -string_list cons (char *a, const string_list); - -/* Functions in sundries.c that are used in mount.c and umount.c */ -void block_signals (int how); -char *canonicalize (const char *path); -char *realpath (const char *path, char *resolved_path); -void error (const char *fmt, ...); -int matching_type (const char *type, string_list types); -string_list parse_list (char *strings); -void *xmalloc (size_t size); -char *xstrdup (const char *s); -char *xstrndup (const char *s, int n); -char *xstrconcat2 (const char *, const char *); -char *xstrconcat3 (const char *, const char *, const char *); -char *xstrconcat4 (const char *, const char *, const char *, const char *); - -/* Here is some serious cruft. */ -#ifdef __GNUC__ -#if __GNUC__ > 2 || (defined(__GNUC_MINOR__) && __GNUC__ == 2 && __GNUC_MINOR__ >= 5) -void die (int errcode, const char *fmt, ...) __attribute__ ((noreturn)); -#else /* GNUC < 2.5 */ -void volatile die (int errcode, const char *fmt, ...); -#endif /* GNUC < 2.5 */ -#else /* !__GNUC__ */ -void die (int errcode, const char *fmt, ...); -#endif /* !__GNUC__ */ - -#ifdef HAVE_NFS -int nfsmount (const char *spec, const char *node, int *flags, - char **orig_opts, char **opt_args, int running_bg); -#endif - -/* exit status - bits below are ORed */ -#define EX_USAGE 1 /* incorrect invocation or permission */ -#define EX_SYSERR 2 /* out of memory, cannot fork, ... */ -#define EX_SOFTWARE 4 /* internal mount bug or wrong version */ -#define EX_USER 8 /* user interrupt */ -#define EX_FILEIO 16 /* problems writing, locking, ... mtab/fstab */ -#define EX_FAIL 32 /* mount failure */ -#define EX_SOMEOK 64 /* some mount succeeded */ - -#define EX_BG 256 /* retry in background (internal only) */ diff --git a/pkgs/core/pomona/src/isys/vio.c b/pkgs/core/pomona/src/isys/vio.c deleted file mode 100644 index 55f497f..0000000 --- a/pkgs/core/pomona/src/isys/vio.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * vio.c - probing for vio devices on the iSeries (viocd and viodasd) - * - * Copyright (C) 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): Jeremy Katz katzj@redhat.com - */ - -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#if defined(__powerpc__) -static int readFD (int fd, char **buf) -{ - char *p; - size_t size = 4096; - int s, filesize; - - *buf = malloc (size); - if (*buf == 0) - return -1; - - filesize = 0; - do { - p = &(*buf) [filesize]; - s = read (fd, p, 4096); - if (s < 0) - break; - filesize += s; - if (s == 0) - break; - size += 4096; - *buf = realloc (*buf, size); - } while (1); - - if (filesize == 0 && s < 0) { - free (*buf); - *buf = NULL; - return -1; - } - - return filesize; -} -#endif - -int isVioConsole(void) { -#if !defined(__powerpc__) - return 0; -#else - int fd, i; - char *buf, *start; - char driver[50], device[50]; - static int isviocons = -1; - - if (isviocons != -1) - return isviocons; - - fd = open("/proc/tty/drivers", O_RDONLY); - if (fd < 0) { - fprintf(stderr, "failed to open /proc/tty/drivers!\n"); - return 0; - } - i = readFD(fd, &buf); - if (i < 1) { - close(fd); - fprintf(stderr, "error reading /proc/tty/drivers!\n"); - return 0; - } - close(fd); - buf[i] = '\0'; - - isviocons = 0; - start = buf; - while (start && *start) { - if (sscanf(start, "%s %s", (char *) &driver, (char *) &device) == 2) { - if (!strcmp(driver, "vioconsole") && !strcmp(device, "/dev/tty")) { - isviocons = 1; - break; - } - } - start = strchr(start, '\n'); - if (start) - start++; - } - free(buf); - return isviocons; -#endif -} diff --git a/pkgs/core/pomona/src/isys/wireless.c b/pkgs/core/pomona/src/isys/wireless.c deleted file mode 100644 index ed43d97..0000000 --- a/pkgs/core/pomona/src/isys/wireless.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * wireless.c - wireless card manipulation - * Some portions from wireless_tools - * copyright (c) 1997-2003 Jean Tourrilhes jt@hpl.hp.com - * - * 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 <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <unistd.h> - -#include <sys/socket.h> -#include <sys/types.h> - -#include <linux/types.h> -#include <linux/if.h> -#include <linux/wireless.h> - -static struct iwreq get_wreq(char * ifname) { - struct iwreq wreq; - - memset(&wreq, 0, sizeof(wreq)); - strncpy(wreq.ifr_name, ifname, IFNAMSIZ); - return wreq; -} - -static int get_socket() { - int sock; - - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { -#ifdef STANDALONE - fprintf(stderr, "Error creating socket: %s\n", strerror(errno)); -#endif - return -1; - } - - return sock; -} - -int is_wireless_interface(char * ifname) { - int sock = get_socket(); - struct iwreq wreq = get_wreq(ifname); - - int rc = ioctl(sock, SIOCGIWNAME, &wreq); - close(sock); - - if (rc < 0) { - return 0; - } - - return 1; -} - -/* set the essid for ifname to essid. if essid is NULL, do automatically */ -int set_essid(char * ifname, char * essid) { - int sock; - struct iwreq wreq; - - memset(&wreq, 0, sizeof (wreq)); - - if (strlen(essid) > IW_ESSID_MAX_SIZE) { - fprintf(stderr, "essid too long\n"); - return -1; - } - - sock = get_socket(); - wreq = get_wreq(ifname); - - if (essid) { - wreq.u.essid.flags = 1; - wreq.u.essid.pointer = (caddr_t) essid; - wreq.u.essid.length = strlen(essid) + 1; - } else { - wreq.u.essid.flags = 0; - wreq.u.essid.pointer = (caddr_t) NULL; - wreq.u.essid.length = 0; - } - - int rc = ioctl(sock, SIOCSIWESSID, &wreq); - close(sock); - - if (rc < 0) { - fprintf(stderr, "failed to set essid: %s\n", strerror(errno)); - return -1; - } - - return 0; -} - -char * get_essid(char * ifname) { - int sock; - struct iwreq wreq; - - memset(&wreq, 0, sizeof (wreq)); - - sock = get_socket(); - wreq = get_wreq(ifname); - - wreq.u.essid.pointer = (caddr_t) malloc(IW_ESSID_MAX_SIZE + 1); - wreq.u.essid.length = IW_ESSID_MAX_SIZE + 1; - wreq.u.essid.flags = 0; - int rc = ioctl(sock, SIOCGIWESSID, &wreq); - close(sock); - - if (rc < 0) { - fprintf(stderr, "failed to get essid for %s: %s\n", ifname, - strerror(errno)); - return NULL; - } - - return wreq.u.essid.pointer; -} - -/* based off iw_in_key from wireless-tools/iwlib.c */ -static int parse_wep_key(char * in, unsigned char * key) { - int len = 0; - - if (!strncmp(in, "s:", 2)) { - /* the key is a string */ - len = strlen(in + 2); - memmove(key, in + 2, len); - } else { - char *buff, *hex, *out, *p; - - /* hexadecimal digits, straight from iwlib.c */ - buff = malloc(IW_ENCODING_TOKEN_MAX + strlen(in) + 1); - if(buff == NULL) { - fprintf(stderr, "Malloc failed (string too long ?)\n"); - return(-1); - } - /* Preserve original buffers (both in & out) */ - hex = buff + IW_ENCODING_TOKEN_MAX; - strcpy(hex, in); - out = buff; - /* Parse */ - p = strtok(hex, "-:;.,"); - while((p != (char *) NULL) && (len < IW_ENCODING_TOKEN_MAX)) { - int temph, templ, count, l; - - /* Get each char separatly (and not by two) so that we don't - * get confused by 'enc' (=> '0E'+'0C') and similar */ - count = sscanf(p, "%1X%1X", &temph, &templ); - if(count < 1) - return(-1); /* Error -> non-hex char */ - /* Fixup odd strings such as '123' is '01'+'23' and not '12'+'03'*/ - l = strlen(p); - if(l % 2) - count = 1; - /* Put back two chars as one byte */ - if(count == 2) - templ |= temph << 4; - else - templ = temph; - out[len++] = (unsigned char) (templ & 0xFF); - /* Check where to get next char from */ - if(l > count) /* Token not finished yet */ - p += count; - else - p = strtok((char *) NULL, "-:;.,"); - } - memcpy(key, out, len); - free(buff); - } - - return len; -} - -int set_wep_key(char * ifname, char * key) { - int sock; - struct iwreq wreq; - unsigned char thekey[IW_ENCODING_TOKEN_MAX]; - - if (strlen(key) > IW_ENCODING_TOKEN_MAX) { - fprintf(stderr, "wep key too long\n"); - return -1; - } - - sock = get_socket(); - wreq = get_wreq(ifname); - - if (key) { - int len = parse_wep_key(key, thekey); - if (len > 0) { - wreq.u.data.flags = IW_ENCODE_ENABLED; - wreq.u.data.length = len; - wreq.u.data.pointer = (caddr_t) thekey; - } - } else { - wreq.u.data.flags = IW_ENCODE_DISABLED; - wreq.u.data.pointer = (caddr_t) NULL; - wreq.u.data.length = 0; - } - - int rc = ioctl(sock, SIOCSIWENCODE, &wreq); - close(sock); - - if (rc < 0) { - fprintf(stderr, "failed to set wep key: %s\n", strerror(errno)); - return -1; - } - - return 0; -} - -enum { MODE_AUTO, MODE_ADHOC, MODE_MANAGED, MODE_MASTER, MODE_REPEATER, - MODE_SECONDARY, MODE_MONITOR }; - -int set_managed(char * ifname) { - int sock = get_socket(); - struct iwreq wreq = get_wreq(ifname); - - wreq.u.mode = MODE_MANAGED; - int rc = ioctl(sock, SIOCSIWMODE, &wreq); - close(sock); - - if (rc < 0) { - fprintf(stderr, "failed to set managed mode: %s\n", strerror(errno)); - return -1; - } - - return 0; -} - -#ifdef STANDALONE -int main(int argc, char **argv) { - if (argc < 4) { - fprintf(stderr, "Usage: %s [interface] [essid] [key]\n", argv[0]); - exit(1); - } - - if (!is_wireless_interface(argv[1])) { - fprintf(stderr, "%s isn't a wireless interface!\n", argv[1]); - exit(2); - } - - /* if (set_essid(argv[1], NULL) < 0) { - fprintf(stderr, "Unable to set essid to %s\n", argv[2]); - exit(3); - } - exit(0);*/ - - if (set_essid(argv[1], argv[2]) < 0) { - fprintf(stderr, "Unable to set essid to %s\n", argv[2]); - exit(3); - } - - /* if (set_wep_key(argv[1], NULL) < 0) { - fprintf(stderr, "Unable to set wepkey to %s\n", argv[2]); - exit(4); - } - exit(0);*/ - - if (set_wep_key(argv[1], argv[3]) < 0) { - fprintf(stderr, "Unable to set wepkey to %s\n", argv[2]); - exit(4); - } - - return 0; -} -#endif diff --git a/pkgs/core/pomona/src/isys/wireless.h b/pkgs/core/pomona/src/isys/wireless.h deleted file mode 100644 index 82cb4d4..0000000 --- a/pkgs/core/pomona/src/isys/wireless.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * wireless.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 WIRELESS_H -#define WIRELESS_H - -int is_wireless_interface(char * ifname); -int set_essid(char * ifname, char * essid); -char * get_essid(char * ifname); -int set_wep_key(char * ifname, char * key); -int set_managed(char * ifname); - -#endif diff --git a/pkgs/core/pomona/src/iutil.py b/pkgs/core/pomona/src/iutil.py deleted file mode 100644 index 569ea8d..0000000 --- a/pkgs/core/pomona/src/iutil.py +++ /dev/null @@ -1,333 +0,0 @@ -# -# iutil.py - generic install utility functions -# -# 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): Erik Troan ewt@redhat.com -# - -import os, string, stat -import os.path -from errno import * -import warnings -import subprocess -from flags import flags - -import logging -log = logging.getLogger("pomona") - -## Run an external program and redirect the output to a file. -# @param command The command to run. -# @param argv A list of arguments. -# @param stdin The file descriptor to read stdin from. -# @param stdout The file descriptor to redirect stdout to. -# @param stderr The file descriptor to redirect stderr to. -# @param searchPath Should command be searched for in $PATH? -# @param root The directory to chroot to before running command. -# @return The return code of command. -def execWithRedirect(command, argv, stdin = 0, stdout = 1, stderr = 2, - searchPath = 0, root = '/'): - def chroot (): - os.chroot(root) - - if not searchPath and not os.access (command, os.X_OK): - raise RuntimeError, command + " can not be run" - - argv = list(argv) - if type(stdin) == type("string"): - if os.access(stdin, os.R_OK): - stdin = open(stdin) - else: - stdin = 0 - if type(stdout) == type("string"): - stdout = open(stdout, "w") - if type(stderr) == type("string"): - stderr = open(stderr, "w") - - if stdout is not None and type(stdout) != int: - stdout.write("Running... %s\n" %([command] + argv,)) - - try: - proc = subprocess.Popen([command] + argv, stdin=stdin, stdout=stdout, - stderr=stderr, preexec_fn=chroot, cwd=root) - ret = proc.wait() - except OSError, (errno, msg): - errstr = "Error running %s: %s" % (command, msg) - log.error (errstr) - raise RuntimeError, errstr - - return ret - -## Run an external program and capture standard out. -# @param command The command to run. -# @param argv A list of arguments. -# @param stdin The file descriptor to read stdin from. -# @param stderr The file descriptor to redirect stderr to. -# @param root The directory to chroot to before running command. -# @return The output of command from stdout. -def execWithCapture(command, argv, stdin = 0, stderr = 2, root='/'): - def chroot(): - os.chroot(root) - - argv = list(argv) - if type(stdin) == type("string"): - if os.access(stdin, os.R_OK): - stdin = open(stdin) - else: - stdin = 0 - if type(stderr) == type("string"): - stderr = open(stderr, "w") - - try: - pipe = subprocess.Popen([command] + argv, stdin=stdin, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - preexec_fn=chroot, cwd=root) - except OSError, (errno, msg): - log.error ("Error running " + command + ": " + msg) - raise RuntimeError, "Error running " + command + ": " + msg - - rc = pipe.stdout.read() - pipe.wait() - return rc - -def execWithPulseProgress(command, argv, stdin = 0, stdout = 1, stderr = 2, - progress = None, root = '/'): - def chroot(): - os.chroot(root) - - argv = list(argv) - if type(stdin) == type("string"): - if os.access(stdin, os.R_OK): - stdin = open(stdin) - else: - stdin = 0 - if type(stdout) == type("string"): - stdout = open(stdout, "w") - if type(stderr) == type("string"): - stderr = open(stderr, "w") - if stdout is not None and type(stdout) != int: - stdout.write("Running... %s\n" %([command] + argv,)) - - p = os.pipe() - childpid = os.fork() - if not childpid: - os.close(p[0]) - os.dup2(p[1], 1) - os.dup2(stderr.fileno(), 2) - os.dup2(stdin, 0) - os.close(stdin) - os.close(p[1]) - stderr.close() - - os.execvp(command, [command] + argv) - os._exit(1) - - os.close(p[1]) - - while 1: - try: - s = os.read(p[0], 1) - except OSError, args: - (num, str) = args - if (num != 4): - raise IOError, args - - stdout.write(s) - if progress: progress.pulse() - - if len(s) < 1: - break - - try: - (pid, status) = os.waitpid(childpid, 0) - except OSError, (num, msg): - log.critical("exception from waitpid: %s %s" %(num, msg)) - - progress and progress.pop() - - # *shrug* no clue why this would happen, but hope that things are fine - if status is None: - return 0 - - if os.WIFEXITED(status): - return os.WEXITSTATUS(status) - - return 1 - -## Run a shell. -def execConsole(): - try: - proc = subprocess.Popen(["/bin/sh"]) - proc.wait() - except OSError, (errno, msg): - raise RuntimeError, "Error running /bin/sh: " + msg - -## Get the size of a directory and all its subdirectories. -# @param dir The name of the directory to find the size of. -# @return The size of the directory in kilobytes. -def getDirSize(dir): - def getSubdirSize(dir): - # returns size in bytes - mydev = os.lstat(dir)[stat.ST_DEV] - - dsize = 0 - for f in os.listdir(dir): - curpath = '%s/%s' % (dir, f) - sinfo = os.lstat(curpath) - if stat.S_ISDIR(sinfo[stat.ST_MODE]): - if mydev == sinfo[stat.ST_DEV]: - dsize += getSubdirSize(curpath) - elif stat.S_ISREG(sinfo[stat.ST_MODE]): - dsize += sinfo[stat.ST_SIZE] - else: - pass - - return dsize - return getSubdirSize(dir)/1024 - -## Get the amount of RAM not used by /tmp. -# @return The amount of available memory in kilobytes. -def memAvailable(): - tram = memInstalled() - - ramused = getDirSize("/tmp") - return tram - ramused - -## Get the amount of RAM installed in the machine. -# @return The amount of installed memory in kilobytes. -def memInstalled(): - f = open("/proc/meminfo", "r") - lines = f.readlines() - f.close() - - for l in lines: - if l.startswith("MemTotal:"): - fields = string.split(l) - mem = fields[1] - break - - return int(mem) - -## Suggest the size of the swap partition that will be created. -# @param quiet Should size information be logged? -# @return A tuple of the minimum and maximum swap size, in megabytes. -def swapSuggestion(quiet=0): - mem = memInstalled()/1024 - mem = ((mem/16)+1)*16 - if not quiet: - log.info("Detected %sM of memory", mem) - - if mem <= 256: - minswap = 256 - maxswap = 512 - else: - if mem > 2000: - minswap = 1000 - maxswap = 2000 + mem - else: - minswap = mem - maxswap = 2*mem - - if not quiet: - log.info("Swap attempt of %sM to %sM", minswap, maxswap) - - return (minswap, maxswap) - -## Create a directory path. Don't fail if the directory already exists. -# @param dir The directory path to create. -def mkdirChain(dir): - try: - os.makedirs(dir, 0755) - except OSError, (errno, msg): - try: - if errno == EEXIST and stat.S_ISDIR(os.stat(dir).st_mode): - return - except: - pass - - log.error("could not create directory %s: %s" % (dir, msg)) - -## Get the total amount of swap memory. -# @return The total amount of swap memory in kilobytes, or 0 if unknown. -def swapAmount(): - f = open("/proc/meminfo", "r") - lines = f.readlines() - f.close() - - for l in lines: - if l.startswith("SwapTotal:"): - fields = string.split(l) - return int(fields[1]) - return 0 - -## Copy a device node. -# Copies a device node by looking at the device type, major and minor device -# numbers, and doing a mknod on the new device name. -# -# @param src The name of the source device node. -# @param dest The name of the new device node to create. -def copyDeviceNode(src, dest): - filestat = os.lstat(src) - mode = filestat[stat.ST_MODE] - if stat.S_ISBLK(mode): - type = stat.S_IFBLK - elif stat.S_ISCHR(mode): - type = stat.S_IFCHR - else: - # XXX should we just fallback to copying normally? - raise RuntimeError, "Tried to copy %s which isn't a device node" % (src,) - - os.mknod(dest, mode | type, filestat.st_rdev) - -# Architecture checking functions - -def isX86(bits=None): - arch = os.uname()[4] - - # x86 platforms include: - # i*86 - # athlon* - # x86_64 - # amd* - # ia32e - if bits is None: - if (arch.startswith('i') and arch.endswith('86')) or \ - arch.startswith('athlon') or arch.startswith('amd') or \ - arch == 'x86_64' or arch == 'ia32e': - return True - elif bits == 32: - if arch.startswith('i') and arch.endswith('86'): - return True - elif bits == 64: - if arch.startswith('athlon') or arch.startswith('amd') or \ - arch == 'x86_64' or arch == 'ia32e': - return True - - return False - -def getArch(): - if isX86(bits=32): - return 'i386' - elif isX86(bits=64): - return 'x86_64' - else: - return os.uname()[4] - -def isConsoleOnVirtualTerminal(): - # XXX PJFIX is there some way to ask the kernel this instead? - return not flags.serial diff --git a/pkgs/core/pomona/src/keyboard.py b/pkgs/core/pomona/src/keyboard.py new file mode 100644 index 0000000..3044626 --- /dev/null +++ b/pkgs/core/pomona/src/keyboard.py @@ -0,0 +1,131 @@ +#!/usr/bin/python + +import os + +from snack import ListboxChoiceWindow + +import gettext +_ = lambda x: gettext.ldgettext("pomona", x) + +from constants import * + +def gkn(str): + idx = str.find("|") + if idx == -1: + return str + return str[idx + 1:] + +class KeyboardModels: + def __init__(self): + self._modelDict = { + 'ar-azerty' : [N_('keyboard|Arabic (azerty)'), 'us,ara', 'pc105', 'azerty', 'grp:shifts_toggle,grp_led:scroll'], + 'ar-azerty-digits' : [N_('keyboard|Arabic (azerty/digits)'), 'us,ara', 'pc105', 'azerty_digits', 'grp:shifts_toggle,grp_led:scroll'], + 'ar-digits' : [N_('keyboard|Arabic (digits)'), 'us,ara', 'pc105', 'digits', 'grp:shifts_toggle,grp_led:scroll'], + 'ar-qwerty' : [N_('keyboard|Arabic (qwerty)'), 'us,ara', 'pc105', 'qwerty', 'grp:shifts_toggle,grp_led:scroll'], + 'ar-qwerty-digits' : [N_('keyboard|Arabic (qwerty/digits)'), 'us,ara', 'pc105', 'qwerty_digits', 'grp:shifts_toggle,grp_led:scroll'], + 'be-latin1' : [N_('keyboard|Belgian (be-latin1)'), 'be', 'pc105', '', ''], + 'ben' : [N_('keyboard|Bengali (Inscript)'), 'us,in', 'pc105', 'ben', 'grp:shifts_toggle,grp_led:scroll'], + 'ben-probhat' : [N_('keyboard|Bengali (Probhat)'), 'us,in', 'pc105', 'ben_probhat', 'grp:shifts_toggle,grp_led:scroll'], + 'bg_bds-utf8' : [N_('keyboard|Bulgarian'), 'us,bg', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], + 'bg_pho-utf8' : [N_('keyboard|Bulgarian (Phonetic)'), 'us,bg', 'pc105', ',phonetic', 'grp:shifts_toggle,grp_led:scroll'], + 'br-abnt2' : [N_('keyboard|Brazilian (ABNT2)'), 'br', 'abnt2', '', ''], + 'cf' : [N_('keyboard|French Canadian'), 'ca(fr)', 'pc105', '', ''], + 'croat' : [N_('keyboard|Croatian'), 'hr', 'pc105', '', '' ], + 'cz-us-qwertz' : [N_('keyboard|Czech'), 'us,cz', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], + 'cz-lat2' : [N_('keyboard|Czech (qwerty)'), 'cz', 'pc105', 'qwerty', ''], + 'de' : [N_('keyboard|German'), 'de', 'pc105', '', ''], + 'de-latin1' : [N_('keyboard|German (latin1)'), 'de', 'pc105', '', ''], + 'de-latin1-nodeadkeys' : [N_('keyboard|German (latin1 w/ no deadkeys)'), 'de', 'pc105', 'nodeadkeys', ''], + 'dev' : [N_('keyboard|Devanagari (Inscript)'), 'us,dev', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], + 'dvorak' : [N_('keyboard|Dvorak'), 'us', 'pc105', 'dvorak', ''], + 'dk' : [N_('keyboard|Danish'), 'dk', 'pc105', '', ''], + 'dk-latin1' : [N_('keyboard|Danish (latin1)'), 'dk', 'pc105', '', ''], + 'es' : [N_('keyboard|Spanish'), 'es', 'pc105', '', ''], + 'et' : [N_('keyboard|Estonian'), 'ee', 'pc105', '', ''], + 'fi' : [N_('keyboard|Finnish'), 'fi', 'pc105', '', ''], + 'fi-latin1' : [N_('keyboard|Finnish (latin1)'), 'fi', 'pc105', '', ''], + 'fr' : [N_('keyboard|French'), 'fr', 'pc105', '', ''], + 'fr-latin9' : [N_('keyboard|French (latin9)'), 'fr', 'pc105', 'latin9', ''], + 'fr-latin1' : [N_('keyboard|French (latin1)'), 'fr', 'pc105', '', ''], + 'fr-pc' : [N_('keyboard|French (pc)'), 'fr', 'pc105', '', ''], + 'fr_CH' : [N_('keyboard|Swiss French'), 'fr_CH', 'pc105', '', ''], + 'fr_CH-latin1' : [N_('keyboard|Swiss French (latin1)'), 'ch', 'pc105', 'fr', ''], + 'gr' : [N_('keyboard|Greek'), 'us,gr', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], + 'guj' : [N_('keyboard|Gujarati (Inscript)'), 'us,in', 'pc105', 'guj', 'grp:shifts_toggle,grp_led:scroll'], + 'gur' : [N_('keyboard|Punjabi (Inscript)'), 'us,gur', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], + 'hu' : [N_('keyboard|Hungarian'), 'hu', 'pc105', '', ''], + 'hu101' : [N_('keyboard|Hungarian (101 key)'), 'hu', 'pc105', 'qwerty', ''], + 'is-latin1' : [N_('keyboard|Icelandic'), 'is', 'pc105', '', ''], + 'it' : [N_('keyboard|Italian'), 'it', 'pc105', '', ''], + 'it-ibm' : [N_('keyboard|Italian (IBM)'), 'it', 'pc105', '', ''], + 'it2' : [N_('keyboard|Italian (it2)'), 'it', 'pc105', '', ''], + 'jp106' : [N_('keyboard|Japanese'), 'jp', 'jp106', '', ''], + 'ko' : [N_('keyboard|Korean'), 'kr', 'pc105', '', ''], + 'la-latin1' : [N_('keyboard|Latin American'), 'latam', 'pc105', '', ''], + 'mk-utf' : [N_('keyboard|Macedonian'), 'us,mkd', 'pc105', '','grp:shifts_toggle,grp_led:scroll'], + 'nl' : [N_('keyboard|Dutch'), 'nl', 'pc105', '', ''], + 'no' : [N_('keyboard|Norwegian'), 'no', 'pc105', '', ''], + 'pl2' : [N_('keyboard|Polish'), 'pl', 'pc105', '', ''], + 'pt-latin1' : [N_('keyboard|Portuguese'), 'pt', 'pc105', '', ''], + 'ro_win' : [N_('keyboard|Romanian'), 'ro', 'pc105', '', ''], + 'ru' : [N_('keyboard|Russian'), 'us,ru', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], + 'sr-cy' : [N_('keyboard|Serbian'), 'cs', 'pc105', '', ''], + 'sr-latin' : [N_('keyboard|Serbian (latin)'), 'cs', 'pc105', 'latin', ''], + 'sv-latin1' : [N_('keyboard|Swedish'), 'se', 'pc105', '', ''], + 'sg' : [N_('keyboard|Swiss German'), 'ch', 'pc105', 'de_nodeadkeys', ''], + 'sg-latin1' : [N_('keyboard|Swiss German (latin1)'), 'ch', 'pc105', 'de_nodeadkeys', ''], + 'sk-qwerty' : [N_('keyboard|Slovak (qwerty)'), 'sk', 'pc105', '', 'qwerty'], + 'slovene' : [N_('keyboard|Slovenian'), 'si', 'pc105', '', ''], + 'tml-inscript' : [N_('keyboard|Tamil (Inscript)'), 'us,in', 'pc105', 'tam', 'grp:shifts_toggle,grp_led:scroll'], + 'tml-uni' : [N_('keyboard|Tamil (Typewriter)'), 'us,in', 'pc105', 'tam_TAB', 'grp:shifts_toggle,grp_led:scroll'], + 'trq' : [N_('keyboard|Turkish'), 'tr', 'pc105', '', ''], + 'uk' : [N_('keyboard|United Kingdom'), 'gb', 'pc105', '', ''], + 'ua-utf' : [N_('keyboard|Ukrainian'), 'us,ua', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], + 'us-acentos' : [N_('keyboard|U.S. International'), 'us', 'pc105', 'intl', ''], + 'us' : [N_('keyboard|U.S. English'), 'us+inet', 'pc105', '', ''], + } + + def getAllModels(self): + ret = [] + for model in self._modelDict.values(): + ret.append(gkn(_(model[0]))) + return ret + +class Keyboard: + def __init__(self, installer): + self.installer = installer + + self.models = KeyboardModels() + + def getKeymap(self): + return gkn(self.models._modelDict["us"][0]) # XXX + + def setKeymap(self, keymap): + self.installer.log.debug("Set keymap to "%s"" % keymap) + + +class KeyboardWindow: + def __call__(self, installer): + #if flags.virtpconsole: + # return INSTALL_NOOP + + keyboard = installer.ds.console.keyboard + + keyboards = keyboard.models.getAllModels() + keyboards.sort() + + default = keyboard.getKeymap() + + (button, choice) = ListboxChoiceWindow(installer.intf.screen, + _("Keyboard Selection"), + _("Which model keyboard is attached to this computer?"), + keyboards, buttons = [TEXT_OK_BUTTON, TEXT_BACK_BUTTON], + width = 30, scroll = 1, height = 8, default = default) + + if button == TEXT_BACK_CHECK: + return INSTALL_BACK + + keyboard.setKeymap(keyboards[choice]) + #keyboard.activate() + + return INSTALL_OK diff --git a/pkgs/core/pomona/src/keyboard_models.py b/pkgs/core/pomona/src/keyboard_models.py deleted file mode 100644 index 76c0e41..0000000 --- a/pkgs/core/pomona/src/keyboard_models.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/python -tt -# -# keyboard_models.py - keyboard model list -# -# Brent Fox bfox@redhat.com -# Mike Fulbright msf@redhat.com -# Jeremy Katz katzj@redhat.com -# -# Copyright 2002-2007 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, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) -N_ = lambda x: x - -def gkn(str): - idx = str.find("|") - if idx == -1: - return str - return str[idx + 1:] - -class KeyboardModels: - def get_models(self): - return self.modelDict - - def __init__(self): - # NOTE: to add a keyboard model to this dict, copy the comment - # above all of them, and then the key should be the console layout - # name. val is [N_('keyboard|Keyboard Name'), xlayout, kbmodel, - # variant, options] - self._modelDict = { - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'ar-azerty' : [N_('keyboard|Arabic (azerty)'), 'us,ara', 'pc105', 'azerty', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'ar-azerty-digits' : [N_('keyboard|Arabic (azerty/digits)'), 'us,ara', 'pc105', 'azerty_digits', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'ar-digits' : [N_('keyboard|Arabic (digits)'), 'us,ara', 'pc105', 'digits', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'ar-qwerty' : [N_('keyboard|Arabic (qwerty)'), 'us,ara', 'pc105', 'qwerty', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'ar-qwerty-digits' : [N_('keyboard|Arabic (qwerty/digits)'), 'us,ara', 'pc105', 'qwerty_digits', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'be-latin1' : [N_('keyboard|Belgian (be-latin1)'), 'be', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'ben' : [N_('keyboard|Bengali (Inscript)'), 'us,in', 'pc105', 'ben', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'ben-probhat' : [N_('keyboard|Bengali (Probhat)'), 'us,in', 'pc105', 'ben_probhat', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'bg_bds-utf8' : [N_('keyboard|Bulgarian'), 'us,bg', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'bg_pho-utf8' : [N_('keyboard|Bulgarian (Phonetic)'), 'us,bg', 'pc105', ',phonetic', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'br-abnt2' : [N_('keyboard|Brazilian (ABNT2)'), 'br', 'abnt2', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'cf' : [N_('keyboard|French Canadian'), 'ca(fr)', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'croat' : [N_('keyboard|Croatian'), 'hr', 'pc105', '', '' ], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'cz-us-qwertz' : [N_('keyboard|Czech'), 'us,cz', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'cz-lat2' : [N_('keyboard|Czech (qwerty)'), 'cz', 'pc105', 'qwerty', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'de' : [N_('keyboard|German'), 'de', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'de-latin1' : [N_('keyboard|German (latin1)'), 'de', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'de-latin1-nodeadkeys' : [N_('keyboard|German (latin1 w/ no deadkeys)'), 'de', 'pc105', 'nodeadkeys', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'dev' : [N_('keyboard|Devanagari (Inscript)'), 'us,dev', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'dvorak' : [N_('keyboard|Dvorak'), 'us', 'pc105', 'dvorak', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'dk' : [N_('keyboard|Danish'), 'dk', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'dk-latin1' : [N_('keyboard|Danish (latin1)'), 'dk', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'es' : [N_('keyboard|Spanish'), 'es', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'et' : [N_('keyboard|Estonian'), 'ee', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'fi' : [N_('keyboard|Finnish'), 'fi', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'fi-latin1' : [N_('keyboard|Finnish (latin1)'), 'fi', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'fr' : [N_('keyboard|French'), 'fr', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'fr-latin9' : [N_('keyboard|French (latin9)'), 'fr', 'pc105', 'latin9', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'fr-latin1' : [N_('keyboard|French (latin1)'), 'fr', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'fr-pc' : [N_('keyboard|French (pc)'), 'fr', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'fr_CH' : [N_('keyboard|Swiss French'), 'fr_CH', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'fr_CH-latin1' : [N_('keyboard|Swiss French (latin1)'), 'ch', 'pc105', 'fr', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'gr' : [N_('keyboard|Greek'), 'us,gr', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'guj' : [N_('keyboard|Gujarati (Inscript)'), 'us,in', 'pc105', 'guj', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'gur' : [N_('keyboard|Punjabi (Inscript)'), 'us,gur', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'hu' : [N_('keyboard|Hungarian'), 'hu', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'hu101' : [N_('keyboard|Hungarian (101 key)'), 'hu', 'pc105', 'qwerty', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'is-latin1' : [N_('keyboard|Icelandic'), 'is', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'it' : [N_('keyboard|Italian'), 'it', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'it-ibm' : [N_('keyboard|Italian (IBM)'), 'it', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'it2' : [N_('keyboard|Italian (it2)'), 'it', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'jp106' : [N_('keyboard|Japanese'), 'jp', 'jp106', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'ko' : [N_('keyboard|Korean'), 'kr', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'la-latin1' : [N_('keyboard|Latin American'), 'latam', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'mk-utf' : [N_('keyboard|Macedonian'), 'us,mkd', 'pc105', '','grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'nl' : [N_('keyboard|Dutch'), 'nl', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'no' : [N_('keyboard|Norwegian'), 'no', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'pl2' : [N_('keyboard|Polish'), 'pl', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'pt-latin1' : [N_('keyboard|Portuguese'), 'pt', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'ro_win' : [N_('keyboard|Romanian'), 'ro', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'ru' : [N_('keyboard|Russian'), 'us,ru', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'sr-cy' : [N_('keyboard|Serbian'), 'cs', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'sr-latin' : [N_('keyboard|Serbian (latin)'), 'cs', 'pc105', 'latin', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'sv-latin1' : [N_('keyboard|Swedish'), 'se', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'sg' : [N_('keyboard|Swiss German'), 'ch', 'pc105', 'de_nodeadkeys', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'sg-latin1' : [N_('keyboard|Swiss German (latin1)'), 'ch', 'pc105', 'de_nodeadkeys', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'sk-qwerty' : [N_('keyboard|Slovak (qwerty)'), 'sk', 'pc105', '', 'qwerty'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'slovene' : [N_('keyboard|Slovenian'), 'si', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'tml-inscript' : [N_('keyboard|Tamil (Inscript)'), 'us,in', 'pc105', 'tam', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'tml-uni' : [N_('keyboard|Tamil (Typewriter)'), 'us,in', 'pc105', 'tam_TAB', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'trq' : [N_('keyboard|Turkish'), 'tr', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'uk' : [N_('keyboard|United Kingdom'), 'gb', 'pc105', '', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'ua-utf' : [N_('keyboard|Ukrainian'), 'us,ua', 'pc105', '', 'grp:shifts_toggle,grp_led:scroll'], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'us-acentos' : [N_('keyboard|U.S. International'), 'us', 'pc105', 'intl', ''], - # Translators: the word before the bar is just context and - # doesn't need to be translated. Only after will be translated. - 'us' : [N_('keyboard|U.S. English'), 'us+inet', 'pc105', '', ''], - } - - def _get_models(self): - ret = {} - for (key, item) in self._modelDict.items(): - ret[key] = [gkn(_(item[0])), item[1], item[2], item[3], item[4]] - return ret - - modelDict = property(_get_models) - -def get_supported_models(): - models = KeyboardModels() - maps = models.modelDict.keys() - maps.sort() - for map in maps: - print map - -if __name__ == "__main__": - get_supported_models() diff --git a/pkgs/core/pomona/src/language.py b/pkgs/core/pomona/src/language.py new file mode 100644 index 0000000..bdbe5d4 --- /dev/null +++ b/pkgs/core/pomona/src/language.py @@ -0,0 +1,109 @@ +#/usr/bin/python + +import os +import locale +import string + +from snack import ListboxChoiceWindow + +import gettext +_ = lambda x: gettext.ldgettext("pomona", x) + +from constants import * + +# Converts a single language into a "language search path". For example, +# de_DE.utf8@euro would become "de_DE.utf8@euro de_DE.utf8 de_DE de" +def expandLangs(astring): + langs = [astring] + charset = None + # remove charset ... + if '.' in astring: + langs.append(string.split(astring, '.')[0]) + + if '@' in astring: + charset = string.split(astring, '@')[1] + + # also add 2 character language code ... + if len(astring) > 2: + if charset: + langs.append("%s@%s" %(astring[:2], charset)) + + langs.append(astring[:2]) + + return langs + +class Language: + def __init__(self, installer): + self.installer = installer + + self.languages = {} + + # nick -> (name, short name, font, keyboard, timezone) mapping + search = ('lang-table', '../lang-table', '/usr/lib/pomona/lang-table', '/etc/lang-table') + for path in search: + if os.access(path, os.R_OK): + f = open(path, "r") + break + + for line in f.readlines(): + line = line.strip() #string.strip(line) + l = line.split("\t") #.split(line, '\t') + + # throw out invalid lines + if len(l) < 6: + continue + + (name, short, font, locale, keyboard, timezone) = l + self.languages[short] = (name, _(name), font, locale, timezone) + + f.close() + + def getAllLanguages(self): + ret = [] + for (name, name2, font, locale, timezone) in self.languages.values(): + ret.append(name2) + return ret + + def getLanguage(self): + return "English" # XXX + + def setLanguage(self, lang): + self.installer.log.debug("Set language to "%s"" % lang) + os.environ["LC_NUMERIC"] = 'C' + #XXX os.environ["LANG"] = "de_DE.utf8" + + try: + locale.setlocale(locale.LC_ALL, "") + except locale.Error: + pass + + +class LanguageWindow: + def __call__(self, installer): + language = installer.ds.console.language + + languages = language.getAllLanguages() + languages.sort() + + current = language.getLanguage() + + (button, choice) = ListboxChoiceWindow(installer.intf.screen, + _("Language Selection"), + _("What language would you like to use during the " + "installation process?"), languages, + buttons = [TEXT_OK_BUTTON, TEXT_BACK_BUTTON], + width = 30, default = _(current), scroll = 1, + height = min((8, len(languages)))) + + if button == TEXT_BACK_CHECK: + return INSTALL_BACK + + language.setLanguage(languages[choice]) + #installer.ds.timezone.setTimezoneInfo(id.console.getDefaultTimeZone()) + + return INSTALL_OK + + +if __name__ == "__main__": + language = Language(None) + print language.getAllLanguages() diff --git a/pkgs/core/pomona/src/log.py b/pkgs/core/pomona/src/log.py new file mode 100644 index 0000000..aee3e5d --- /dev/null +++ b/pkgs/core/pomona/src/log.py @@ -0,0 +1,45 @@ +#!/usr/bin/python + +import time + +from constants import * + +class Logger: + def __init__(self): + self.logfile = open(LOGFILE, "w+") + + self.logline = "%s %8s: %s\n" # time, group, message + + def critical(self, msg): + self.logfile.write(self.logline % (self.time(), "CRITICAL", msg,)) + self.flush() + + def info(self, msg): + self.logfile.write(self.logline % (self.time(), "INFO", msg,)) + self.flush() + + def debug(self, msg): + self.logfile.write(self.logline % (self.time(), "DEBUG", msg,)) + self.flush() + + def error(self, msg): + self.logfile.write(self.logline % (self.time(), "ERROR", msg,)) + self.flush() + + def warning(self, msg): + self.logfile.write(self.logline % (self.time(), "WARNING", msg,)) + self.flush() + + def stdout(self, msg): + self.logfile.write(self.logline % (self.time(), "STDOUT", msg,)) + self.flush() + print msg + + def time(self): + return time.strftime("%d %b %Y %H:%M:%S") + + def __del__(self): + self.logfile.close() + + def flush(self): + self.logfile.flush() diff --git a/pkgs/core/pomona/src/lvm.py b/pkgs/core/pomona/src/lvm.py deleted file mode 100644 index e5b2fd9..0000000 --- a/pkgs/core/pomona/src/lvm.py +++ /dev/null @@ -1,613 +0,0 @@ -# -# lvm.py - lvm probing control -# -# 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): Jeremy Katz katzj@redhat.com -# - -import os -import sys -import iutil -import string -import math -import isys -import re - -from flags import flags - -import logging -log = logging.getLogger("pomona") - -from constants import * - -MAX_LV_SLOTS=256 - -lvmDevicePresent = 0 - -from errors import * - -def has_lvm(): - global lvmDevicePresent - - if not (os.access("/usr/sbin/lvm", os.X_OK) or - os.access("/sbin/lvm", os.X_OK)): - return - - f = open("/proc/devices", "r") - lines = f.readlines() - f.close() - - for line in lines: - try: - (dev, name) = line[:-1].split(' ', 2) - except: - continue - if name == "device-mapper": - lvmDevicePresent = 1 - break - return lvmDevicePresent -# now check to see if lvm is available -has_lvm() - -if lvmDevicePresent == 1: - log.info("LVM is enabled.") -else: - log.info("LVM is disabled.") - -def lvmExec(*args): - try: - return iutil.execWithRedirect("lvm", args, stdout = lvmErrorOutput, - stderr = lvmErrorOutput, searchPath = 1) - except Exception, e: - log.error("error running lvm command: %s" %(e,)) - raise LvmError, args[0] - -def lvmCapture(*args): - try: - lvmout = iutil.execWithCapture("lvm", args, stderr = lvmErrorOutput) - lines = [] - for line in lvmout.split("\n"): - lines.append(line.strip().split(':')) - return lines - except Exception, e: - log.error("error running lvm command: %s" %(e,)) - raise LvmError, args[0] - -def vgscan(): - """Runs vgscan.""" - global lvmDevicePresent - - if lvmDevicePresent == 0: - return - - rc = lvmExec("vgscan", "-v") - if rc: - log.error("running vgscan failed: %s" %(rc,)) -# lvmDevicePresent = 0 - -def vgmknodes(volgroup=None): - # now make the device nodes - args = ["vgmknodes", "-v"] - if volgroup: - args.append(volgroup) - rc = lvmExec(*args) - if rc: - log.error("running vgmknodes failed: %s" %(rc,)) -# lvmDevicePresent = 0 - -def vgcheckactive(volgroup = None): - """Check if volume groups are active - - volgroup - optional parameter to inquire about a specific volume group. - """ - global lvmDevicePresent - if lvmDevicePresent == 0: - return False - - args = ["lvs", "--noheadings", "--units", "b", "--nosuffix", - "--separator", ":", "--options", "vg_name,lv_name,attr"] - for line in lvmCapture(*args): - try: - (vg, lv, attr) = line - except: - continue - - log.info("lv %s/%s, attr is %s" %(vg, lv, attr)) - if attr.find("a") == -1: - continue - - if volgroup is None or volgroup == vg: - return True - - return False - -def vgactivate(volgroup = None): - """Activate volume groups by running vgchange -ay. - - volgroup - optional single volume group to activate - """ - global lvmDevicePresent - if lvmDevicePresent == 0: - return - - args = ["vgchange", "-ay", "-v"] - if volgroup: - args.append(volgroup) - rc = lvmExec(*args) - if rc: - log.error("running vgchange failed: %s" %(rc,)) -# lvmDevicePresent = 0 - vgmknodes(volgroup) - -def vgdeactivate(volgroup = None): - """Deactivate volume groups by running vgchange -an. - - volgroup - optional single volume group to deactivate - """ - global lvmDevicePresent - if lvmDevicePresent == 0: - return - - args = ["vgchange", "-an", "-v"] - if volgroup: - args.append(volgroup) - rc = lvmExec(*args) - if rc: - log.error("running vgchange failed: %s" %(rc,)) -# lvmDevicePresent = 0 - -def lvcreate(lvname, vgname, size): - """Creates a new logical volume. - - lvname - name of logical volume to create. - vgname - name of volume group lv will be in. - size - size of lv, in megabytes. - """ - global lvmDevicePresent - if lvmDevicePresent == 0: - return - writeForceConf() - vgscan() - - args = ["lvcreate", "-v", "-L", "%dM" %(size,), "-n", lvname, "-An", vgname] - try: - rc = lvmExec(*args) - except: - rc = 1 - if rc: - raise LVCreateError(vgname, lvname, size) - unlinkConf() - -def lvremove(lvname, vgname): - """Removes a logical volume. - - lvname - name of logical volume to remove. - vgname - name of volume group lv is in. - """ - global lvmDevicePresent - if lvmDevicePresent == 0: - return - - args = ["lvremove", "-f", "-v"] - dev = "/dev/%s/%s" %(vgname, lvname) - args.append(dev) - - try: - rc = lvmExec(*args) - except: - rc = 1 - if rc: - raise LVRemoveError(vgname, lvname) - -def lvresize(lvname, vgname, size): - global lvmDevicePresent - if lvmDevicePresent == 0: - return - - args = ["lvresize", "-An", "-L", "%dM" %(size,), "-v", "--force", - "/dev/%s/%s" %(vgname, lvname,)] - - try: - rc = lvmExec(*args) - except: - rc = 1 - if rc: - raise LVResizeError(vgname, lvname) - - -def vgcreate(vgname, PESize, nodes): - """Creates a new volume group." - - vgname - name of volume group to create. - PESize - Physical Extent size, in kilobytes. - nodes - LVM Physical Volumes on which to put the new VG. - """ - global lvmDevicePresent - if lvmDevicePresent == 0: - return - - # rescan now that we've recreated pvs. ugh. - writeForceConf() - vgscan() - - args = ["vgcreate", "-v", "-An", "-s", "%sk" % (PESize,), vgname ] - args.extend(nodes) - - try: - rc = lvmExec(*args) - except: - rc = 1 - if rc: - raise VGCreateError(vgname, PESize, nodes) - unlinkConf() - -def vgremove(vgname): - """Removes a volume group. Deactivates the volume group first - - vgname - name of volume group. - """ - global lvmDevicePresent - if lvmDevicePresent == 0: - return - - # find the Physical Volumes which make up this Volume Group, so we - # can prune and recreate them. - pvs = [] - for pv in pvlist(): - if pv[1] == vgname: - pvs.append(pv[0]) - - # we'll try to deactivate... if it fails, we'll probably fail on - # the removal too... but it's worth a shot - try: - vgdeactivate(vgname) - except: - pass - - args = ["vgremove", "-v", vgname] - - log.info(string.join(args, ' ')) - try: - rc = lvmExec(*args) - except: - rc = 1 - if rc: - raise VGRemoveError, vgname - - # now iterate all the PVs we've just freed up, so we reclaim the metadata - # space. This is an LVM bug, AFAICS. - for pvname in pvs: - args = ["pvremove", "-ff", "-y", "-v", pvname] - - log.info(string.join(args, ' ')) - try: - rc = lvmExec(*args) - except: - rc = 1 - if rc: - raise PVRemoveError, pvname - - args = ["pvcreate", "-ff", "-y", "-v", pvname] - - log.info(string.join(args, ' ')) - try: - rc = lvmExec(*args) - except: - rc = 1 - if rc: - raise PVCreateError, pvname - wipeOtherMetadataFromPV(pvname) - -def pvcreate(node): - """Initializes a new Physical Volume." - - node - path to device node on which to create the new PV." - """ - global lvmDevicePresent - if lvmDevicePresent == 0: - return - - # rescan now that we've recreated pvs. ugh. - writeForceConf() - - args = ["pvcreate", "-ff", "-y", "-v", node ] - - try: - rc = lvmExec(*args) - except: - rc = 1 - if rc: - raise PVCreateError, node - unlinkConf() - wipeOtherMetadataFromPV(node) - -def lvlist(): - global lvmDevicePresent - if lvmDevicePresent == 0: - return [] - - lvs = [] - # field names for "options" are in LVM2.2.01.01/lib/report/columns.h - args = ["lvdisplay", "-C", "--noheadings", "--units", "b", - "--nosuffix", "--separator", ":", "--options", - "vg_name,lv_name,lv_size,origin" - ] - lvscanout = iutil.execWithCapture("lvm", args, stderr = "/dev/tty6") - for line in lvmCapture(*args): - try: - (vg, lv, size, origin) = line - size = long(math.floor(long(size) / (1024 * 1024))) - if origin == '': - origin = None - except: - continue - - logmsg = "lv is %s/%s, size of %s" % (vg, lv, size) - if origin: - logmsg += ", snapshot from %s" % (origin,) - log.info(logmsg) - lvs.append( (vg, lv, size, origin) ) - - return lvs - -def pvlist(): - global lvmDevicePresent - if lvmDevicePresent == 0: - return [] - - pvs = [] - args = ["pvdisplay", "-C", "--noheadings", "--units", "b", - "--nosuffix", "--separator", ":", "--options", - "pv_name,vg_name,dev_size" - ] - for line in lvmCapture(*args): - try: - (dev, vg, size) = line - size = long(math.floor(long(size) / (1024 * 1024))) - except: - continue - - if dev.startswith("/dev/dm-"): - from block import dm - try: - sb = os.stat(dev) - (major, minor) = (os.major(sb.st_rdev), os.minor(sb.st_rdev)) - for map in dm.maps(): - if map.dev.major == major and map.dev.minor == minor: - dev = "/dev/mapper/%s" % map.name - break - except: - pass - - log.info("pv is %s in vg %s, size is %s" %(dev, vg, size)) - pvs.append( (dev, vg, size) ) - - return pvs - -def vglist(): - global lvmDevicePresent - if lvmDevicePresent == 0: - return [] - - vgs = [] - args = ["vgdisplay", "-C", "--noheadings", "--units", "b", - "--nosuffix", "--separator", ":", "--options", - "vg_name,vg_size,vg_extent_size,vg_free" - ] - for line in lvmCapture(*args): - try: - (vg, size, pesize, free) = line - size = long(math.floor(long(size) / (1024 * 1024))) - pesize = long(pesize)/1024 - free = math.floor(long(free) / (1024 * 1024)) - except: - continue - log.info("vg %s, size is %s, pesize is %s" %(vg, size, pesize)) - vgs.append( (vg, size, pesize, free) ) - return vgs - -def partialvgs(): - global lvmDevicePresent - if lvmDevicePresent == 0: - return [] - - vgs = [] - args = ["vgdisplay", "-C", "-P", "--noheadings", "--units", "b", - "--nosuffix", "--separator", ":"] - for line in lvmCapture(*args): - try: - (vg, numpv, numlv, numsn, attr, size, free) = line - except: - continue - if attr.find("p") != -1: - log.info("vg %s, attr is %s" %(vg, attr)) - vgs.append(vg) - - return vgs - -# FIXME: this is a hack. we really need to have a --force option. -def unlinkConf(): - lvmroot = "/etc/lvm" - if os.path.exists("%s/lvm.conf" %(lvmroot,)): - os.unlink("%s/lvm.conf" %(lvmroot,)) - -def writeForceConf(): - """Write out an /etc/lvm/lvm.conf that doesn't do much (any?) filtering""" - - lvmroot = "/etc/lvm" - try: - os.unlink("/etc/lvm/.cache") - except: - pass - if not os.path.isdir(lvmroot): - os.mkdir(lvmroot) - - unlinkConf() - - f = open("%s/lvm.conf" %(lvmroot,), "w+") - f.write(""" -# anaconda hacked lvm.conf to avoid filtering breaking things -devices { - sysfs_scan = 0 - md_component_detection = 1 -} -""") - -# FIXME: another hack. we need to wipe the raid metadata since pvcreate -# doesn't -def wipeOtherMetadataFromPV(node): - try: - isys.wipeRaidSB(node) - except Exception, e: - log.critical("error wiping raidsb from %s: %s", node, e) - - - -def getPossiblePhysicalExtents(floor=0): - """Returns a list of integers representing the possible values for - the physical extent of a volume group. Value is in KB. - - floor - size (in KB) of smallest PE we care about. - """ - - possiblePE = [] - curpe = 8 - while curpe <= 16384*1024: - if curpe >= floor: - possiblePE.append(curpe) - curpe = curpe * 2 - - return possiblePE - -def clampLVSizeRequest(size, pe, roundup=0): - """Given a size and a PE, returns the actual size of logical volumne. - - size - size (in MB) of logical volume request - pe - PE size (in KB) - roundup - round sizes up or not - """ - - if roundup: - func = math.ceil - else: - func = math.floor - return (long(func((size*1024L)/pe))*pe)/1024 - -def clampPVSize(pvsize, pesize): - """Given a PV size and a PE, returns the usable space of the PV. - Takes into account both overhead of the physical volume and 'clamping' - to the PE size. - - pvsize - size (in MB) of PV request - pesize - PE size (in KB) - """ - - # we want Kbytes as a float for our math - pvsize *= 1024.0 - return long((math.floor(pvsize / pesize) * pesize) / 1024) - -def getMaxLVSize(pe): - """Given a PE size in KB, returns maximum size (in MB) of a logical volume. - - pe - PE size in KB - """ - # LVM2, size limited by number of sectors - return (16*1024*1024) #Max is 16TiB - -def safeLvmName(str): - tmp = string.strip(str) - tmp = tmp.replace("/", "_") - tmp = re.sub("[^0-9a-zA-Z._]", "", str) - tmp = tmp.lstrip("_") - - return tmp - -def createSuggestedVGName(partitions, network): - """Given list of partition requests, come up with a reasonable VG name - - partitions - list of requests - """ - - # try to create a volume group name incorporating the hostname - hn = network.hostname - if hn is not None and hn != '': - if hn == 'localhost' or hn == 'localhost.localdomain': - vgtemplate = "VolGroup" - elif hn.find('.') != -1: - hn = safeLvmName(hn) - vgtemplate = "vg_%s" % (hn.split('.')[0].lower(),) - else: - hn = safeLvmName(hn) - vgtemplate = "vg_%s" % (hn.lower(),) - else: - vgtemplate = "VolGroup" - - if not partitions.isVolumeGroupNameInUse(vgtemplate): - return vgtemplate - else: - i = 0 - while 1: - tmpname = "%s%02d" % (vgtemplate, i,) - if not partitions.isVolumeGroupNameInUse(tmpname): - break - - i += 1 - if i > 99: - tmpname = "" - - return tmpname - -def createSuggestedLVName(logreqs): - """Given list of LV requests, come up with a reasonable LV name - - partitions - list of LV requests for this VG - """ - - i = 0 - - lnames = [] - for lv in logreqs: - lnames.append(lv.logicalVolumeName) - - while 1: - tmpname = "LogVol%02d" % (i,) - if (logreqs is None) or (tmpname not in lnames): - break - - i += 1 - if i > 99: - tmpname = "" - - return tmpname - -def getVGUsedSpace(vgreq, requests, diskset): - vgused = 0 - for request in requests.requests: - if request.type == REQUEST_LV and request.volumeGroup == vgreq.uniqueID: - size = int(request.getActualSize(requests, diskset)) - vgused = vgused + size - - - return vgused - -def getVGFreeSpace(vgreq, requests, diskset): - used = getVGUsedSpace(vgreq, requests, diskset) - log.debug("used space is %s" % (used,)) - - total = vgreq.getActualSize(requests, diskset) - log.debug("actual space is %s" % (total,)) - return total - used diff --git a/pkgs/core/pomona/src/network.py b/pkgs/core/pomona/src/network.py deleted file mode 100644 index 5f5cce1..0000000 --- a/pkgs/core/pomona/src/network.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/python - -import socket -import string - -import pyfire.net - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -def networkDeviceCheck(pomona): - devs = pomona.id.network.available() - if not devs: - pomona.dispatch.skipStep("network") - -class Network(pyfire.net.Network): - def __init__(self, filename): - pyfire.net.Network.__init__(self) - - self.settings = pyfire.net.NetworkSettings(filename) - -class IPError(Exception): - pass - -class IPMissing(Exception): - pass - -# sanity check an IP string. -def sanityCheckIPString(ip_string): - if ip_string.strip() == "": - raise IPMissing, _("IP address is missing.") - - if ip_string.find(':') == -1 and ip_string.find('.') > 0: - family = socket.AF_INET - errstr = _("IPv4 addresses must contain four numbers between 0 and 255, separated by periods.") - elif ip_string.find(':') > 0 and ip_string.find('.') == -1: - family = socket.AF_INET6 - errstr = _("'%s' is not a valid IPv6 address.") % ip_string - else: - raise IPError, _("'%s' is an invalid IP address.") % ip_string - - try: - socket.inet_pton(family, ip_string) - except socket.error: - raise IPError, errstr - -def sanityCheckHostname(hostname): - if len(hostname) < 1: - return None - - if len(hostname) > 255: - return _("Hostname must be 255 or fewer characters in length.") - - validStart = string.ascii_letters + string.digits - validAll = validStart + ".-" - - if string.find(validStart, hostname[0]) == -1: - return _("Hostname must start with a valid character in the ranges " - "'a-z', 'A-Z', or '0-9'") - - for i in range(1, len(hostname)): - if string.find(validAll, hostname[i]) == -1: - return _("Hostnames can only contain the characters 'a-z', 'A-Z', '0-9', '-', or '.'") - - return None diff --git a/pkgs/core/pomona/src/packages.py b/pkgs/core/pomona/src/packages.py deleted file mode 100644 index 27dac7e..0000000 --- a/pkgs/core/pomona/src/packages.py +++ /dev/null @@ -1,195 +0,0 @@ -# -# packages.py: package management - mainly package installation -# -# Erik Troan ewt@redhat.com -# Matt Wilson msw@redhat.com -# Michael Fulbright msf@redhat.com -# Jeremy Katz katzj@redhat.com -# -# Copyright 2001-2006 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -import iutil -import isys -import os -import sys -import fsset -import shutil -import time -import lvm -from flags import flags -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -import logging -log = logging.getLogger("pomona") - -def doPostAction(pomona): - pomona.backend.postAction(pomona) - -def copyPomonaLogs(pomona): - log.info("Copying pomona logs") - for (fn, dest) in (("/root/pomona.log", "pomona.log"), - ("/tmp/syslog", "pomona.syslog")): - if os.access(fn, os.R_OK): - try: - shutil.copyfile(fn, "%s/var/log/%s" %(pomona.rootPath, dest)) - os.chmod("%s/var/log/%s" %(pomona.rootPath, dest), 0600) - except: - pass - -def doMigrateFilesystems(pomona): - if pomona.dir == DISPATCH_BACK: - return DISPATCH_NOOP - - if pomona.id.fsset.haveMigratedFilesystems(): - return DISPATCH_NOOP - - pomona.id.fsset.migrateFilesystems (pomona) - -def turnOnFilesystems(pomona): - def handleResizeError(e, dev): - if os.path.exists("/tmp/resize.out"): - details = open("/tmp/resize.out", "r").read() - else: - details = "%s" %(e,) - pomona.intf.detailedMessageWindow(_("Resizing Failed"), - _("There was an error encountered " - "resizing the device %s.") %(dev,), - details, - type = "custom", - custom_buttons = [_("_Exit installer")]) - sys.exit(1) - - if pomona.dir == DISPATCH_BACK: - log.info("unmounting filesystems") - pomona.id.fsset.umountFilesystems(pomona.rootPath) - return - - if not pomona.id.fsset.isActive(): - # turn off any swaps that we didn't turn on - # needed for live installs - iutil.execWithRedirect("swapoff", ["-a"], - stdout = "/dev/tty5", stderr="/dev/tty5", - searchPath = 1) - pomona.id.partitions.doMetaDeletes(pomona.id.diskset) - pomona.id.fsset.setActive(pomona.id.diskset) - try: - pomona.id.fsset.shrinkFilesystems(pomona.id.diskset, pomona.rootPath) - except fsset.ResizeError, (e, dev): - handleResizeError(e, dev) - - if not pomona.id.fsset.isActive(): - pomona.id.diskset.savePartitions() - # this is somewhat lame, but we seem to be racing with - # device node creation sometimes. so wait for device nodes - # to settle - w = pomona.intf.waitWindow(_("Activating"), _("Activating new partitions. Please wait...")) - time.sleep(1) - rc = iutil.execWithRedirect("/sbin/udevadm", [ "settle" ], - stdout = "/dev/tty5", - stderr = "/dev/tty5", - searchPath = 1) - w.pop() - - pomona.id.partitions.doEncryptionRetrofits() - - try: - pomona.id.partitions.doMetaResizes(pomona.id.diskset) - except lvm.LVResizeError, e: - handleResizeError("%s" %(e,), "%s/%s" %(e.vgname, e.lvname)) - - try: - pomona.id.fsset.growFilesystems(pomona.id.diskset, pomona.rootPath) - except fsset.ResizeError, (e, dev): - handleResizeError(e, dev) - - if not pomona.id.fsset.volumesCreated: - try: - pomona.id.fsset.createLogicalVolumes(pomona.rootPath) - except SystemError, e: - log.error("createLogicalVolumes failed with %s", str(e)) - pomona.intf.messageWindow(_("LVM operation failed"), - str(e)+"\n\n"+_("The installer will now exit..."), - type="custom", custom_icon="error", custom_buttons=[_("_Reboot")]) - sys.exit(0) - - pomona.id.fsset.formatSwap(pomona.rootPath) - pomona.id.fsset.turnOnSwap(pomona.rootPath) - pomona.id.fsset.makeFilesystems(pomona.rootPath, - pomona.backend.skipFormatRoot) - pomona.id.fsset.mountFilesystems(pomona,0,0, - pomona.backend.skipFormatRoot) - -def setupTimezone(pomona): - # we don't need this on going backwards - if pomona.dir == DISPATCH_BACK: - return - - os.environ["TZ"] = pomona.id.timezone.tz - tzfile = "/usr/share/zoneinfo/" + pomona.id.timezone.tz - if not os.access(tzfile, os.R_OK): - log.error("unable to set timezone") - else: - try: - shutil.copyfile(tzfile, "/etc/localtime") - except OSError, (errno, msg): - log.error("Error copying timezone (from %s): %s" %(tzfile, msg)) - - args = [ "--hctosys" ] - if pomona.id.timezone.utc: - args.append("-u") - - try: - iutil.execWithRedirect("/usr/sbin/hwclock", args, stdin = None, - stdout = "/dev/tty5", stderr = "/dev/tty5") - except RuntimeError: - log.error("Failed to set clock") - -def betaNagScreen(pomona): - if pomona.dir == DISPATCH_BACK: - return DISPATCH_NOOP - - ### Check if we run a pre-release version - if not version.find("alpha") and \ - not version.find("beta") and \ - not version.find("rc"): - return DISPATCH_NOOP - - while 1: - rc = pomona.intf.messageWindow( _("Warning! This is pre-release software!"), - _("Thank you for downloading this " - "pre-release of %s.\n\n" - "This is not a final " - "release and is not intended for use " - "on production systems. The purpose of " - "this release is to collect feedback " - "from testers, and it is not suitable " - "for day to day usage.\n\n" - "To report feedback, please visit:\n\n" - " %s\n\n" - "and file a report against '%s'.\n") - % (name, bugurl, name), - type="custom", custom_icon="warning", - custom_buttons=[_("_Exit"), _("_Install anyway")]) - - if not rc: - msg = _("Your system will now be rebooted...") - buttons = [_("_Back"), _("_Reboot")] - rc = pomona.intf.messageWindow(_("Rebooting System"), - msg, - type="custom", custom_icon="warning", - custom_buttons=buttons) - if rc: - sys.exit(0) - else: - break diff --git a/pkgs/core/pomona/src/pakfireinstall.py b/pkgs/core/pomona/src/pakfireinstall.py deleted file mode 100644 index ada57f0..0000000 --- a/pkgs/core/pomona/src/pakfireinstall.py +++ /dev/null @@ -1,265 +0,0 @@ -# -# Copyright (c) 2005-2007 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# general public license. -# -# 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., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -import sys -import os -import os.path -import shutil -import warnings -import locale -import signal -import subprocess -import time - -import urlgrabber.progress -import urlgrabber.grabber -from urlgrabber.grabber import URLGrabber, URLGrabError -from backend import PomonaBackend -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -import logging -log = logging.getLogger("pomona") - -import urlparse -urlparse.uses_fragment.append('media') - -import iutil -import isys -import pyfire - -def size_string(size): - def number_format(s): - return locale.format("%s", s, 1) - - if size > 1024 * 1024: - size = size / (1024*1024) - return _("%s MB") %(number_format(size),) - elif size > 1024: - size = size / 1024 - return _("%s KB") %(number_format(size),) - else: - if size == 1: - return _("%s Byte") %(number_format(size),) - else: - return _("%s Bytes") %(number_format(size),) - -class PomonaCallback: - def __init__(self, pomona): - self.messageWindow = pomona.intf.messageWindow - self.waitWindow = pomona.intf.waitWindow - self.progress = pomona.id.instProgress - self.progressWindow = pomona.intf.progressWindow - - self.initWindow = None - - self.lastprogress = 0 - self.incr = 20 - - self.text = "" - - self.window = None - self.windowType = None - - def setSize(self, totalSize): - self.totalSize = totalSize - self.doneSize = 0 - self.lastprogress = 0 - self.incr = totalSize / 100 - - def callback(self, what, amount=0, title=None, text=None): - # first time here means we should pop the window telling - # user to wait until we get here - if self.initWindow is not None: - self.initWindow.pop() - self.initWindow = None - - if what == CB_START: - if self.totalSize == 0: - self.window = self.waitWindow(title, text, width=55) - self.text = text - self.windowType = "wait" - else: - self.window = self.progressWindow(title, text, self.totalSize) - self.windowType = "progress" - - elif what == CB_STOP: - self.window.pop() - - elif what == CB_PROGRESS: - if self.windowType == "progress": - if amount > self.lastprogress + self.incr: - self.window.set(amount) - self.lastprogress = amount - elif self.windowType == "wait": - self.window.set_text(self.text + " " + amount) - -class PomonaPakfire: - def __init__(self, pomona): - self.pomona = pomona - - def run(self, cb, intf, id): - self.extractFiles(cb, intf, id) - - def extractFiles(self, cb, intf, id): - filename = os.path.join(SOURCE_PATH, IMAGE_FILE) - filename_ls = os.path.join(SOURCE_PATH, IMAGE_FILE_LS) - - # XXX Temporarily disabled - #fd = open(filename_ls, 'r') - filesize = 1000 - #while fd.readline(): - # filesize += 1 - #fd.close() - cb.setSize(filesize) - - filesize = int(os.path.getsize(filename)) - log.info("Source file %s has size of %dKB" % (filename, filesize / 1024,)) - - command = "unsquashfs -n -i -f -d %s %s 2>/dev/tty5" % (HARDDISK_PATH, filename,) - - extractor = subprocess.Popen(command, shell=True, - stdout=subprocess.PIPE, - stdin=subprocess.PIPE) - - cb.callback(CB_START, title=_("Base system"), text=_("Installing base system...")) - - buf = extractor.stdout.readline() - tot = 0 - while buf != "": - tot += 1 - cb.callback(CB_PROGRESS, amount=tot) - buf = extractor.stdout.readline() - - cb.callback(CB_STOP) - -class PakfireBackend(PomonaBackend): - def __init__(self, instPath): - PomonaBackend.__init__(self, instPath) - - def selectBestKernel(self): - """Find the best kernel package which is available and select it.""" - pass ## XXX todo? - - def selectFSPackages(self, fsset, diskset): - for entry in fsset.entries: - map(self.selectPackage, entry.fsystem.getNeededPackages()) - - def doPostSelection(self, pomona): - pass - - def doPreInstall(self, pomona): - if pomona.dir == DISPATCH_BACK: - return DISPATCH_BACK - - self.pompak = PomonaPakfire(pomona) - - def doInstall(self, pomona): - log.info("Preparing to install files") - - cb = PomonaCallback(pomona) - - cb.initWindow = pomona.intf.waitWindow(_("Install Starting"), - _("Starting install process. This may take several minutes...")) - time.sleep(2) - - self.pompak.run(cb, pomona.intf, pomona.id) - - if cb.initWindow is not None: - cb.initWindow.pop() - - pomona.id.instProgress = None - - def doPostInstall(self, pomona): - w = pomona.intf.waitWindow(_("Post Install"), - _("Performing post install configuration...")) - - # we need to have a /dev after install and now that udev is - # handling /dev, it gets to be more fun. so just bind mount the - # installer /dev - isys.mount("/dev", "%s/dev" %(pomona.rootPath,), bindMount = 1) - - # write out the fstab - pomona.id.fsset.write(pomona.rootPath) - # rootpath mode doesn't have this file around - if os.access("/tmp/modprobe.conf", os.R_OK): - shutil.copyfile("/tmp/modprobe.conf", - pomona.rootPath + "/etc/modprobe.conf") - - ### XXX pomona.id.network.write(pomona.rootPath) - - for (kernelName, kernelVersion, kernelTag, kernelDesc) in self.kernelVersionList(pomona): - initrd = "/boot/initramfs-%s%s.img" % (kernelVersion, kernelTag,) - log.info("mkinitramfs: creating %s" % initrd) - pyfire.executil.execWithRedirect("/sbin/mkinitramfs", - ["/sbin/mkinitramfs", "-v", "-f", "%s" % initrd, - "%s%s" % (kernelVersion, kernelTag,), ], - stdout = "/dev/tty5", stderr = "/dev/tty5", - root = pomona.rootPath) - - PomonaBackend.doPostInstall(self, pomona) - w.pop() - - def kernelVersionList(self, pomona): - kernelVersions = [] - - tag2desc = { "-smp" : _("Symmetric multiprocessing"), - "-xen" : _("Xen guest"), } - - kernelName = "%skernel-%s" % (sname, kernelVersion) - - for kernelTag in [ "", "-smp", "-xen", ]: - filename = "%s%s" % (kernelName, kernelTag) - if os.access(pomona.rootPath + "/boot/" + filename, os.R_OK): - if not kernelTag == "": - kernelDesc = tag2desc[kernelTag] - else: - kernelDesc = _("Normal Boot") - kernelVersions.append((kernelName, kernelVersion, kernelTag, kernelDesc)) - - return kernelVersions - -class PakfireProgress: - def __init__(self, intf, text, total): - window = intf.progressWindow(_("Installation Progress"), text, total, 0.01) - self.window = window - - self.current = 0 - self.incr = 1 - self.total = total - self.popped = False - - def set_incr(self, incr): - self.incr = incr - - def progressbar(self, current, total, name=None): - if not self.popped: - self.window.set(float(current)/total * self.incr + self.current) - else: - warnings.warn("PakfireProgress.progressbar called when popped", - RuntimeWarning, stacklevel=2) - - def pop(self): - self.window.pop() - self.popped = True - - def next_task(self, current = None): - if current: - self.current = current - else: - self.current += self.incr - if not self.popped: - self.window.set(self.current) - else: - warnings.warn("PakfireProgress.set called when popped", - RuntimeWarning, stacklevel=2) diff --git a/pkgs/core/pomona/src/partErrors.py b/pkgs/core/pomona/src/partErrors.py deleted file mode 100644 index 0c3f461..0000000 --- a/pkgs/core/pomona/src/partErrors.py +++ /dev/null @@ -1,33 +0,0 @@ -# -# partErrors.py: partitioning error exceptions -# -# Matt Wilson msw@redhat.com -# Jeremy Katz katzj@redhat.com -# Mike Fulbright msf@redhat.com -# -# Copyright 2002 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -"""Exceptions for use in partitioning.""" - -class PartitioningError(Exception): - """A critical error which must be resolved to continue the installation.""" - def __init__ (self, value): - self.value = value - - def __str__ (self): - return self.value - -class PartitioningWarning(Exception): - """A warning which may be ignored and still complete the installation.""" - def __init__ (self, value): - self.value = value - - def __str__ (self): - return self.value diff --git a/pkgs/core/pomona/src/partIntfHelpers.py b/pkgs/core/pomona/src/partIntfHelpers.py deleted file mode 100644 index 2d2833f..0000000 --- a/pkgs/core/pomona/src/partIntfHelpers.py +++ /dev/null @@ -1,547 +0,0 @@ -# -# partIntfHelpers.py: partitioning interface helper 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): Matt Wilson msw@redhat.com -# Jeremy Katz katzj@redhat.com -# Mike Fulbright msf@redhat.com -# Harald Hoyer harald@redhat.de -# - -"""Helper functions shared between partitioning interfaces.""" - -import string -from constants import * -import partedUtils -import parted -import fsset -import iutil -import partRequests - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -def sanityCheckVolumeGroupName(volname): - """Make sure that the volume group name doesn't contain invalid chars.""" - badNames = ['lvm', 'root', '.', '..' ] - - if not volname: - return _("Please enter a volume group name.") - - # ripped the value for this out of linux/include/lvm.h - if len(volname) > 128: - return _("Volume Group Names must be less than 128 characters") - - if volname in badNames: - return _("Error - the volume group name %s is not valid." % (volname,)) - - for i in range(0, len(volname)): - rc = string.find(string.letters + string.digits + '.' + '_', volname[i]) - if rc == -1: - return _("Error - the volume group name contains illegal " - "characters or spaces. Acceptable characters " - "are letters, digits, '.' or '_'.") - return None - -def sanityCheckLogicalVolumeName(logvolname): - """Make sure that the logical volume name doesn't contain invalid chars.""" - badNames = ['group', '.', '..' ] - - if not logvolname: - return _("Please enter a logical volume name.") - - # ripped the value for this out of linux/include/lvm.h - if len(logvolname) > 128: - return _("Logical Volume Names must be less than 128 characters") - - - if logvolname in badNames: - return _("Error - the logical volume name %s is not " - "valid." % (logvolname,)) - - for i in range(0, len(logvolname)): - rc = string.find(string.letters + string.digits + '.' + '_', logvolname[i]) - if rc == -1: - return _("Error - the logical volume name contains illegal " - "characters or spaces. Acceptable characters " - "are letters, digits, '.' or '_'.") - return None - -def sanityCheckMountPoint(mntpt, fstype, preexisting, format): - """Sanity check that the mountpoint is valid. - - mntpt is the mountpoint being used. - fstype is the file system being used on the request. - preexisting is whether the request was preexisting (request.preexist) - format is whether the request is being formatted or not - """ - if mntpt: - passed = 1 - if not mntpt: - passed = 0 - else: - if mntpt[0] != '/' or (len(mntpt) > 1 and mntpt[-1:] == '/'): - passed = 0 - elif mntpt.find(' ') > -1: - passed = 0 - - if not passed: - return _("The mount point %s is invalid. Mount points must start " - "with '/' and cannot end with '/', and must contain " - "printable characters and no spaces." % mntpt) - else: - return None - else: - if (fstype and fstype.isMountable() and (not preexisting or format)): - return _("Please specify a mount point for this partition.") - else: - # its an existing partition so don't force a mount point - return None - -def isNotChangable(request, requestlist): - if request: - if requestlist.isRaidMember(request): - parentreq = requestlist.getRaidMemberParent(request) - if parentreq.raidminor is not None: - return _("This partition is part of " - "the RAID device /dev/md%s.") % (parentreq.raidminor,) - else: - return _("This partition is part of a RAID device.") - - if requestlist.isLVMVolumeGroupMember(request): - parentreq = requestlist.getLVMVolumeGroupMemberParent(request) - if parentreq.volumeGroupName is not None: - return _("This partition is part of the " - "LVM volume group '%s'.") % (parentreq.volumeGroupName,) - else: - return _("This partition is part of a LVM volume group.") - - return None - - -def doDeletePartitionByRequest(intf, requestlist, partition, - confirm=1, quiet=0): - """Delete a partition from the request list. - - intf is the interface - requestlist is the list of requests - partition is either the part object or the uniqueID if not a part - """ - - if partition == None: - intf.messageWindow(_("Unable To Delete"), - _("You must first select a partition to delete."), - custom_icon="error") - return 0 - - if type(partition) == type("RAID"): - device = partition - elif partition.type & parted.PARTITION_FREESPACE: - intf.messageWindow(_("Unable To Delete"), - _("You cannot delete free space."), - custom_icon="error") - return 0 - elif partition.type & parted.PARTITION_PROTECTED: - # LDL formatted DASDs always have one partition, you'd have to reformat the - # DASD in CDL mode to get rid of it - intf.messageWindow(_("Unable To Delete"), - _("You cannot delete a partition of a LDL formatted DASD."), - custom_icon="error") - return 0 - else: - device = partedUtils.get_partition_name(partition) - - ret = requestlist.containsImmutablePart(partition) - if ret: - if not quiet: - intf.messageWindow(_("Unable To Delete"), - _("You cannot delete this " - "partition, as it is an extended partition " - "which contains %s") %(ret), - custom_icon="error") - return 0 - - # see if device is in our partition requests, remove - if type(partition) == type("RAID"): - request = requestlist.getRequestByID(device) - else: - request = requestlist.getRequestByDeviceName(device) - - if request: - state = isNotChangable(request, requestlist) - - # If the partition is protected, we also can't delete it so specify a - # reason why. - if state is None and request.getProtected(): - state = _("This partition is holding the data for the hard " - "drive install.") - - if state: - if not quiet: - intf.messageWindow(_("Unable To Delete"), - _("You cannot delete this partition:\n\n") + state, - custom_icon="error") - return 0 - - if confirm and not confirmDeleteRequest(intf, request): - return 0 - - if request.getPreExisting(): - if isinstance(request, partRequests.PartitionSpec): - # get the drive - drive = partedUtils.get_partition_drive(partition) - - if partition.type & parted.PARTITION_EXTENDED: - requestlist.deleteAllLogicalPartitions(partition) - - delete = partRequests.DeleteSpec(drive, partition.geom.start, - partition.geom.end) - requestlist.addDelete(delete) - elif isinstance(request, partRequests.LogicalVolumeRequestSpec): - vgreq = requestlist.getRequestByID(request.volumeGroup) - delete = partRequests.DeleteLogicalVolumeSpec(request.logicalVolumeName, - vgreq.volumeGroupName) - requestlist.addDelete(delete) - elif isinstance(request, partRequests.VolumeGroupRequestSpec): - delete = partRequests.DeleteVolumeGroupSpec(request.volumeGroupName) - requestlist.addDelete(delete) - # FIXME: do we need to do anything with preexisting raids? - - # now remove the request - requestlist.deleteDependentRequests(request) - requestlist.removeRequest(request) - else: # is this a extended partition we made? - if partition.type & parted.PARTITION_EXTENDED: - requestlist.deleteAllLogicalPartitions(partition) - else: - #raise ValueError, "Deleting a non-existent partition" - return 0 - - del partition - return 1 - -def doDeletePartitionsByDevice(intf, requestlist, diskset, device, - confirm=1, quiet=0): - """ Remove all partitions currently on device """ - if confirm: - rc = intf.messageWindow(_("Confirm Delete"), - _("You are about to delete all partitions on " - "the device '/dev/%s'.") % (device,), - type="custom", custom_icon="warning", - custom_buttons=[_("Cancel"), _("_Delete")]) - - if not rc: - return - - requests = requestlist.getRequestsByDevice(diskset, device) - if not requests: - return - - # get list of unique IDs of these requests - reqIDs = [] - for req in requests: - part = partedUtils.get_partition_by_name(diskset.disks, req.device) - if part.type & parted.PARTITION_FREESPACE or part.type & parted.PARTITION_METADATA or part.type & parted.PARTITION_PROTECTED: - continue - reqIDs.append(req.uniqueID) - - # now go thru and try to delete the unique IDs - for id in reqIDs: - try: - req = requestlist.getRequestByID(id) - if req is None: - continue - part = partedUtils.get_partition_by_name(diskset.disks, req.device) - rc = doDeletePartitionByRequest(intf, requestlist, part, - confirm=0, quiet=1) - if not rc: - pass - except: - pass - - # see which partitions are left - notdeleted = [] - left_requests = requestlist.getRequestsByDevice(diskset, device) - if left_requests: - # get list of unique IDs of these requests - leftIDs = [] - for req in left_requests: - part = partedUtils.get_partition_by_name(diskset.disks, req.device) - if part.type & parted.PARTITION_FREESPACE or part.type & parted.PARTITION_METADATA or part.type & parted.PARTITION_PROTECTED: - continue - leftIDs.append(req.uniqueID) - - for id in leftIDs: - req = requestlist.getRequestByID(id) - notdeleted.append(req) - - - # see if we need to report any failures - some were because we removed - # an extended partition which contained other members of our delete list - outlist = "" - for req in notdeleted: - newreq = requestlist.getRequestByID(req.uniqueID) - if newreq: - outlist = outlist + "\t/dev/%s\n" % (newreq.device,) - - if outlist != "" and not quiet: - intf.messageWindow(_("Notice"), - _("The following partitions were not deleted " - "because they are in use:\n\n%s") % outlist, - custom_icon="warning") - - return 1 - - -def doEditPartitionByRequest(intf, requestlist, part): - """Edit a partition from the request list. - - intf is the interface - requestlist is the list of requests - partition is either the part object or the uniqueID if not a part - """ - - if part == None: - intf.messageWindow(_("Unable To Edit"), - _("You must select a partition to edit"), custom_icon="error") - - return (None, None) - - if type(part) == type("RAID"): - - # see if device is in our partition requests, remove - request = requestlist.getRequestByID(int(part)) - - if request: - state = isNotChangable(request, requestlist) - if state is not None: - intf.messageWindow(_("Unable To Edit"), _("You cannot edit this partition:\n\n") + state, - custom_icon="error") - return (None, None) - - if request.type == REQUEST_RAID: - return ("RAID", request) - elif request.type == REQUEST_VG: - return ("LVMVG", request) - elif request.type == REQUEST_LV: - return ("LVMLV", request) - else: - return (None, None) - elif part.type & parted.PARTITION_FREESPACE: - request = partRequests.PartitionSpec(fsset.fileSystemTypeGetDefault(), - start = partedUtils.start_sector_to_cyl(part.geom.dev, - part.geom.start), - end = partedUtils.end_sector_to_cyl(part.geom.dev, - part.geom.end), - drive = [ partedUtils.get_partition_drive(part) ]) - - return ("NEW", request) - elif part.type & parted.PARTITION_EXTENDED: - return (None, None) - - ret = requestlist.containsImmutablePart(part) - if ret: - intf.messageWindow(_("Unable To Edit"), - _("You cannot edit this " - "partition, as it is an extended partition " - "which contains %s") %(ret), custom_icon="error") - return (None, None) - - name = partedUtils.get_partition_name(part) - request = requestlist.getRequestByDeviceName(name) - if request: - state = isNotChangable(request, requestlist) - if state is not None: - intf.messageWindow(_("Unable To Edit"), - _("You cannot edit this partition:\n\n") + state, custom_icon="error") - return (None, None) - - return ("PARTITION", request) - else: # shouldn't ever happen - raise ValueError, ("Trying to edit non-existent partition %s" - % (partedUtils.get_partition_name(part))) - - -def checkForSwapNoMatch(anaconda): - """Check for any partitions of type 0x82 which don't have a swap fs.""" - for request in anaconda.id.partitions.requests: - if not request.device or not request.fstype: - continue - - part = partedUtils.get_partition_by_name(anaconda.id.diskset.disks, - request.device) - if (part and (not part.type & parted.PARTITION_FREESPACE) - and (part.native_type == 0x82) - and (request.fstype and request.fstype.getName() != "swap") - and (not request.format)): - rc = anaconda.intf.messageWindow(_("Format as Swap?"), - _("/dev/%s has a partition type of 0x82 " - "(Linux swap) but does not appear to " - "be formatted as a Linux swap " - "partition.\n\n" - "Would you like to format this " - "partition as a swap partition?") - % (request.device), type = "yesno", - custom_icon="question") - if rc == 1: - request.format = 1 - request.fstype = fsset.fileSystemTypeGet("swap") - if request.fstype.getName() == "software RAID": - part.set_flag(parted.PARTITION_RAID, 1) - else: - part.set_flag(parted.PARTITION_RAID, 0) - - partedUtils.set_partition_file_system_type(part, - request.fstype) - -def mustHaveSelectedDrive(intf): - txt =_("You need to select at least one hard drive to install %s.") % (name,) - intf.messageWindow(_("Error"), txt, custom_icon="error") - -def queryNoFormatPreExisting(intf): - """Ensure the user wants to use a partition without formatting.""" - txt = _("You have chosen to use a pre-existing " - "partition for this installation without formatting it. " - "We recommend that you format this partition " - "to make sure files from a previous operating system installation " - "do not cause problems with this installation of Linux. " - "However, if this partition contains files that you need " - "to keep, such as home directories, then " - "continue without formatting this partition.") - rc = intf.messageWindow(_("Format?"), txt, type = "custom", custom_buttons=[_("_Modify Partition"), _("Do _Not Format")], custom_icon="warning") - return rc - -def partitionSanityErrors(intf, errors): - """Errors were found sanity checking. Tell the user they must fix.""" - rc = 1 - if errors: - errorstr = string.join(errors, "\n\n") - rc = intf.messageWindow(_("Error with Partitioning"), - _("The following critical errors exist " - "with your requested partitioning " - "scheme. " - "These errors must be corrected prior " - "to continuing with your install of " - "%s.\n\n%s") %(name, errorstr), - custom_icon="error") - return rc - -def partitionSanityWarnings(intf, warnings): - """Sanity check found warnings. Make sure the user wants to continue.""" - rc = 1 - if warnings: - warningstr = string.join(warnings, "\n\n") - rc = intf.messageWindow(_("Partitioning Warning"), - _("The following warnings exist with " - "your requested partition scheme.\n\n%s" - "\n\nWould you like to continue with " - "your requested partitioning " - "scheme?") % (warningstr), - type="yesno", custom_icon="warning") - return rc - - -def partitionPreExistFormatWarnings(intf, warnings): - """Double check that preexistings being formatted are fine.""" - rc = 1 - if warnings: - - labelstr1 = _("The following pre-existing partitions have been " - "selected to be formatted, destroying all data.") - - labelstr2 = _("Select 'Yes' to continue and format these " - "partitions, or 'No' to go back and change these " - "settings.") - commentstr = "" - for (dev, type, mntpt) in warnings: - commentstr = commentstr + "/dev/%s %s %s\n" % (dev,type,mntpt) - rc = intf.messageWindow(_("Format Warning"), "%s\n\n%s\n\n%s" % - (labelstr1, labelstr2, commentstr), - type="yesno", custom_icon="warning") - return rc - -def getPreExistFormatWarnings(partitions, diskset): - """Return a list of preexisting partitions being formatted.""" - - devs = [] - for request in partitions.requests: - if request.getPreExisting() == 1: - devs.append(request.uniqueID) - - devs.sort() - - rc = [] - for dev in devs: - request = partitions.getRequestByID(dev) - if request.format: - if request.fstype.isMountable(): - mntpt = request.mountpoint - else: - mntpt = "" - - if isinstance(request, partRequests.PartitionSpec): - dev = request.device - elif isinstance(request, partRequests.RaidRequestSpec): - dev = "md%s" %(request.raidminor,) - elif isinstance(request, partRequests.VolumeGroupRequestSpec): - dev = request.volumeGroupName - elif isinstance(request, partRequests.LogicalVolumeRequestSpec): - vgreq = partitions.getRequestByID(request.volumeGroup) - dev = "%s/%s" %(vgreq.volumeGroupName, - request.logicalVolumeName) - - rc.append((dev, request.fstype.getName(), mntpt)) - - if len(rc) == 0: - return None - else: - return rc - -def confirmDeleteRequest(intf, request): - """Confirm the deletion of a request.""" - if not request: - return - - if request.type == REQUEST_VG: - errmsg = (_("You are about to delete the volume group "%s"." - "\n\nALL logical volumes in this volume group " - "will be lost!") % (request.volumeGroupName,)) - elif request.type == REQUEST_LV: - errmsg = (_("You are about to delete the logical volume "%s".") - % (request.logicalVolumeName,)) - elif request.type == REQUEST_RAID: - errmsg = _("You are about to delete a RAID device.") - else: - if request.device: - errmsg = _("You are about to delete the /dev/%s partition.") % (request.device,) - else: - # XXX can this ever happen? - errmsg = _("The partition you selected will be deleted.") - - rc = intf.messageWindow(_("Confirm Delete"), errmsg, type="custom", - custom_buttons=[_("Cancel"), _("_Delete")], - custom_icon="question") - - return rc - -def confirmResetPartitionState(intf): - """Confirm reset of partitioning to that present on the system.""" - rc = intf.messageWindow(_("Confirm Reset"), - _("Are you sure you want to reset the " - "partition table to its original state?"), - type="yesno", custom_icon="question") - return rc diff --git a/pkgs/core/pomona/src/partRequests.py b/pkgs/core/pomona/src/partRequests.py deleted file mode 100644 index 25f70b7..0000000 --- a/pkgs/core/pomona/src/partRequests.py +++ /dev/null @@ -1,1038 +0,0 @@ -# -# partRequests.py: partition request objects and management thereof -# -# 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): Matt Wilson msw@redhat.com -# Jeremy Katz katzj@redhat.com -# Mike Fulbright msf@redhat.com -# Harald Hoyer harald@redhat.de -# - -"""Partition request objects and management thereof.""" - -import parted -import iutil -import string -import os, sys, math - -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -import fsset -import raid -import lvm -import partedUtils -import partIntfHelpers - -import logging -log = logging.getLogger("pomona") - -class DeleteSpec: - """Defines a preexisting partition which is intended to be removed.""" - - def __init__(self, drive, start, end): - """Initializes a DeleteSpec. - - drive is the text form of the drive - start is the start sector of the deleted partition - end is the end sector of the deleted partition - """ - - self.drive = drive - self.start = start - self.end = end - - def __str__(self): - return "drive: %s start: %s end: %s" %(self.drive, self.start, - self.end) - -class DeleteLogicalVolumeSpec: - """Defines a preexisting logical volume which is intended to be removed.""" - - def __init__(self, name, vg): - """Initializes a DeleteLogicalVolumeSpec. - - name is the name of the lv - vg is the name of the volume group - """ - - self.name = name - self.vg = vg - self.deleted = 0 - - def __str__(self): - return "lvname: %s vgname: %s" %(self.name, self.vg) - - def beenDeleted(self): - return self.deleted - - def setDeleted(self, val): - self.deleted = val - -class DeleteVolumeGroupSpec: - """Defines a preexisting volume group which is intended to be removed.""" - - def __init__(self, name): - """Initializes a DeleteVolumeGroupSpec - - name is the name of the volume group - """ - - self.name = name - self.deleted = 0 - - def __str__(self): - return "vgname: %s" %(self.name,) - - def beenDeleted(self): - return self.deleted - - def setDeleted(self, val): - self.deleted = val - -class DeleteRAIDSpec: - """Defines a preexisting RAID device which is intended to be removed.""" - - def __init__(self, minor): - """Initializes a DeleteRAIDSpec. - - minor is the minor of the RAID device being removed - """ - - self.minor = minor - - def __str__(self): - return "minor: %s" %(self.minor,) - -class RequestSpec: - """Generic Request specification.""" - def __init__(self, fstype, size = None, mountpoint = None, format = None, - preexist = 0, fslabel = None, - migrate = None, origfstype = None, - fsprofile = None): - """Create a generic RequestSpec. - - This should probably never be externally used. - """ - - self.fstype = fstype - self.mountpoint = mountpoint - self.size = size - self.format = format - - self.migrate = migrate - self.origfstype = origfstype - self.fslabel = fslabel - self.fsopts = None - self.fsprofile = fsprofile - - self.device = None - """what we currently think the device is""" - - self.uniqueID = None - """uniqueID is an integer and *MUST* be unique.""" - - self.ignoreBootConstraints = 0 - """Booting constraints should be ignored for this request.""" - - self.preexist = preexist - """Did this partition exist before we started playing with things?""" - - self.protected = 0 - """Is this partitiion 'protected', ie does it contain install media.""" - - self.dev = None - """A Device() as defined in fsset.py to correspond to this request.""" - - self.encryption = None - """An optional LUKSDevice() describing block device encryption.""" - - self.targetSize = None - """Size to resize to""" - - self.resizable = False - """Is this a request that can be resized?""" - - def __str__(self): - if self.fstype: - fsname = self.fstype.getName() - else: - fsname = "None" - - str = ("Generic Request -- mountpoint: %(mount)s uniqueID: %(id)s\n" - " type: %(fstype)s format: %(format)s\n" - " device: %(dev)s migrate: %(migrate)s fslabel: %(fslabel)s\n" - " options: '%(fsopts)s'" - " fsprofile: %(fsprofile)s" % - {"mount": self.mountpoint, "id": self.uniqueID, - "fstype": fsname, "format": self.format, - "dev": self.device, "migrate": self.migrate, - "fslabel": self.fslabel, - "fsopts": self.fsopts, "fsprofile": self.fsprofile}) - return str - - def getActualSize(self, partitions, diskset): - """Return the actual size allocated for the request in megabytes.""" - - sys.stderr.write("WARNING: Abstract RequestSpec.getActualSize() called\n") - import traceback - traceback.print_stack() - - def getDevice(self, partitions): - """Return a device to solidify.""" - - sys.stderr.write("WARNING: Abstract RequestSpec.getDevice() called\n") - import traceback - traceback.print_stack() - - def isResizable(self, partitions): - if self.isEncrypted(partitions): # FIXME: can't resize crypted devs yet - return False - return self.resizable and self.fstype is not None and self.fstype.isResizable() - - def isEncrypted(self, partitions, parentOnly = False): - if self.encryption: - return True - return False - - def toEntry(self, partitions): - """Turn a request into a fsset entry and return the entry.""" - device = self.getDevice(partitions) - - # pin down our partitions so that we can reread the table - device.solidify() - - if self.fstype.getName() == "swap": - mountpoint = "swap" - else: - mountpoint = self.mountpoint - - entry = fsset.FileSystemSetEntry(device, mountpoint, self.fstype, - origfsystem=self.origfstype, - options=self.fsopts, - fsprofile=self.fsprofile) - if self.format: - entry.setFormat(self.format) - - if self.migrate: - entry.setMigrate(self.migrate) - - if self.fslabel: - entry.setLabel(self.fslabel) - - if self.targetSize and self.fstype.isResizable(): - entry.setResizeTarget(self.targetSize, self.size) - - return entry - - def setProtected(self, val): - """Set the protected value for this partition.""" - self.protected = val - - def getProtected(self): - """Return the protected value for this partition.""" - return self.protected - - def getPreExisting(self): - """Return whether the partition existed before we started playing.""" - return self.preexist - - def doMountPointLinuxFSChecks(self): - """Return an error string if the mountpoint is not valid for Linux FS.""" - mustbeonroot = ('/bin','/dev','/sbin','/etc','/lib','/root', - '/mnt', 'lost+found', '/proc') - mustbeonlinuxfs = ('/', '/boot', '/var', '/tmp', '/usr', '/home', - '/usr/share', '/usr/lib' ) - - # these are symlinks so you cant make them mount points - otherexcept = ('/var/mail', '/usr/bin/X11', '/usr/lib/X11', '/usr/tmp') - - if not self.mountpoint: - return None - - if self.fstype is None: - return None - - if self.fstype.isMountable(): - if self.mountpoint in mustbeonroot: - return _("This mount point is invalid. The %s directory must " - "be on the / file system.") % (self.mountpoint,) - elif self.mountpoint in otherexcept: - return _("The mount point %s cannot be used. It must " - "be a symbolic link for proper system " - "operation. Please select a different " - "mount point.") % (self.mountpoint,) - - return None - - if not self.fstype.isLinuxNativeFS(): - if self.mountpoint in mustbeonlinuxfs: - return _("This mount point must be on a linux file system.") - - return None - - # requestSkipList is a list of uids for requests to ignore when - # looking for a conflict on the mount point name. Used in lvm - # editting code in disk druid, for example. - def isMountPointInUse(self, partitions, requestSkipList=None): - """Return whether my mountpoint is in use by another request.""" - mntpt = self.mountpoint - if not mntpt: - return None - - if partitions and partitions.requests: - for request in partitions.requests: - if requestSkipList is not None and request.uniqueID in requestSkipList: - continue - - if request.mountpoint == mntpt: - if (not self.uniqueID or - request.uniqueID != self.uniqueID): - return _("The mount point "%s" is already in use, " - "please choose a different mount point." - %(mntpt)) - return None - - def doSizeSanityCheck(self): - """Sanity check that the size of the request is sane.""" - if not self.fstype: - return None - - if not self.format: - return None - - if self.size and self.size > self.fstype.getMaxSizeMB(): - return (_("The size of the %s partition (%10.2f MB) " - "exceeds the maximum size of %10.2f MB.") - % (self.fstype.getName(), self.size, - self.fstype.getMaxSizeMB())) - - return None - - # set skipMntPtExistCheck to non-zero if you want to handle this - # check yourself. Used in lvm volume group editting code, for example. - def sanityCheckRequest(self, partitions, skipMntPtExistCheck=0): - """Run the basic sanity checks on the request.""" - # see if mount point is valid if its a new partition request - mntpt = self.mountpoint - fstype = self.fstype - preexist = self.preexist - format = self.format - - rc = self.doSizeSanityCheck() - if rc: - return rc - - rc = partIntfHelpers.sanityCheckMountPoint(mntpt, fstype, preexist, format) - if rc: - return rc - - if not skipMntPtExistCheck: - rc = self.isMountPointInUse(partitions) - if rc: - return rc - - rc = self.doMountPointLinuxFSChecks() - if rc: - return rc - - return None - - - def formatByDefault(self): - """Return whether or not the request should be formatted by default.""" - def inExceptionList(mntpt): - exceptlist = ['/home', '/usr/local', '/opt', '/var/www'] - for q in exceptlist: - if os.path.commonprefix([mntpt, q]) == q: - return 1 - return 0 - - # check first to see if its a Linux filesystem or not - formatlist = ['/boot', '/var', '/tmp', '/usr'] - - if not self.fstype: - return 0 - - if not self.fstype.isLinuxNativeFS(): - return 0 - - if self.fstype.isMountable(): - mntpt = self.mountpoint - if mntpt == "/": - return 1 - - if mntpt in formatlist: - return 1 - - for p in formatlist: - if os.path.commonprefix([mntpt, p]) == p: - if inExceptionList(mntpt): - return 0 - else: - return 1 - - return 0 - else: - if self.fstype.getName() == "swap": - return 1 - - # be safe for anything else and default to off - return 0 - - -# XXX preexistings store start/end as sectors, new store as cylinders. ICK -class PartitionSpec(RequestSpec): - """Object to define a requested partition.""" - - # XXX eep, still a few too many options but a lot better - def __init__(self, fstype, size = None, mountpoint = None, - preexist = 0, migrate = None, grow = 0, maxSizeMB = None, - start = None, end = None, drive = None, primary = None, - format = None, multidrive = None, - fslabel = None, fsprofile=None): - """Create a new PartitionSpec object. - - fstype is the fsset filesystem type. - size is the requested size (in megabytes). - mountpoint is the mountpoint. - grow is whether or not the partition is growable. - maxSizeMB is the maximum size of the partition in megabytes. - start is the starting cylinder/sector (new/preexist). - end is the ending cylinder/sector (new/preexist). - drive is the drive the partition goes on. - primary is whether or not the partition should be forced as primary. - format is whether or not the partition should be formatted. - preexist is whether this partition is preexisting. - migrate is whether or not the partition should be migrated. - multidrive specifies if this is a request that should be replicated - across _all_ of the drives in drive - fslabel is the label to give to the filesystem. - fsprofile is the usage profile for the filesystem. - """ - - # if it's preexisting, the original fstype should be set - if preexist == 1: - origfs = fstype - else: - origfs = None - - RequestSpec.__init__(self, fstype = fstype, size = size, - mountpoint = mountpoint, format = format, - preexist = preexist, migrate = None, - origfstype = origfs, - fslabel = fslabel, fsprofile = fsprofile) - self.type = REQUEST_NEW - - self.grow = grow - self.maxSizeMB = maxSizeMB - self.requestSize = size - self.start = start - self.end = end - - self.drive = drive - self.primary = primary - self.multidrive = multidrive - - # should be able to map this from the device =\ - self.currentDrive = None - """Drive that this request will currently end up on.""" - - - def __str__(self): - if self.fstype: - fsname = self.fstype.getName() - else: - fsname = "None" - - if self.origfstype: - oldfs = self.origfstype.getName() - else: - oldfs = "None" - - if self.preexist == 0: - pre = "New" - else: - pre = "Existing" - - if self.encryption is None: - crypto = "None" - else: - crypto = self.encryption.getScheme() - - str = ("%(n)s Part Request -- mountpoint: %(mount)s uniqueID: %(id)s\n" - " type: %(fstype)s format: %(format)s \n" - " device: %(dev)s drive: %(drive)s primary: %(primary)s\n" - " size: %(size)s grow: %(grow)s maxsize: %(max)s\n" - " start: %(start)s end: %(end)s migrate: %(migrate)s " - " fslabel: %(fslabel)s origfstype: %(origfs)s\n" - " options: '%(fsopts)s'\n" - " fsprofile: %(fsprofile)s encryption: %(encryption)s" % - {"n": pre, "mount": self.mountpoint, "id": self.uniqueID, - "fstype": fsname, "format": self.format, "dev": self.device, - "drive": self.drive, "primary": self.primary, - "size": self.size, "grow": self.grow, "max": self.maxSizeMB, - "start": self.start, "end": self.end, - "migrate": self.migrate, "fslabel": self.fslabel, - "origfs": oldfs, - "fsopts": self.fsopts, "fsprofile": self.fsprofile, - "encryption": crypto}) - return str - - - def getDevice(self, partitions): - """Return a device to solidify.""" - if self.dev: - return self.dev - - self.dev = fsset.PartitionDevice(self.device, - encryption = self.encryption) - - return self.dev - - def getActualSize(self, partitions, diskset): - """Return the actual size allocated for the request in megabytes.""" - part = partedUtils.get_partition_by_name(diskset.disks, self.device) - if not part: - # XXX kickstart might still call this before allocating the partitions - raise RuntimeError, "Checking the size of a partition which hasn't been allocated yet" - return partedUtils.getPartSizeMB(part) - - def doSizeSanityCheck(self): - """Sanity check that the size of the partition is sane.""" - if not self.fstype: - return None - if not self.format: - return None - ret = RequestSpec.doSizeSanityCheck(self) - if ret is not None: - return ret - - if (self.size and self.maxSizeMB - and (self.size > self.maxSizeMB)): - return (_("The size of the requested partition (size = %s MB) " - "exceeds the maximum size of %s MB.") - % (self.size, self.maxSizeMB)) - - if self.size and self.size < 0: - return _("The size of the requested partition is " - "negative! (size = %s MB)") % (self.size) - - if self.start and self.start < 1: - return _("Partitions can't start below the first cylinder.") - - if self.end and self.end < 1: - return _("Partitions can't end on a negative cylinder.") - - return None - -class NewPartitionSpec(PartitionSpec): - """Object to define a NEW requested partition.""" - - # XXX eep, still a few too many options but a lot better - def __init__(self, fstype, size = None, mountpoint = None, - grow = 0, maxSizeMB = None, - start = None, end = None, - drive = None, primary = None, format = None): - """Create a new NewPartitionSpec object. - - fstype is the fsset filesystem type. - size is the requested size (in megabytes). - mountpoint is the mountpoint. - grow is whether or not the partition is growable. - maxSizeMB is the maximum size of the partition in megabytes. - start is the starting cylinder. - end is the ending cylinder. - drive is the drive the partition goes on. - primary is whether or not the partition should be forced as primary. - format is whether or not the partition should be formatted. - """ - - PartitionSpec.__init__(self, fstype = fstype, size = size, - mountpoint = mountpoint, grow = grow, - maxSizeMB = maxSizeMB, start = start, - end = end, drive = drive, primary = primary, - format = format, preexist = 0) - self.type = REQUEST_NEW - -class PreexistingPartitionSpec(PartitionSpec): - """Request to represent partitions which already existed.""" - - def __init__(self, fstype, size = None, start = None, end = None, - drive = None, format = None, migrate = None, - mountpoint = None): - """Create a new PreexistingPartitionSpec object. - - fstype is the fsset filesystem type. - size is the size (in megabytes). - start is the starting sector. - end is the ending sector. - drive is the drive which the partition is on. - format is whether or not the partition should be formatted. - migrate is whether or not the partition fs should be migrated. - mountpoint is the mountpoint. - """ - - PartitionSpec.__init__(self, fstype = fstype, size = size, - start = start, end = end, drive = drive, - format = format, migrate = migrate, - mountpoint = mountpoint, preexist = 1) - self.type = REQUEST_PREEXIST - self.resizable = True - - self.maxResizeSize = None - """Maximum size of this partition request""" - - def getMaximumResizeMB(self, partitions): - if self.maxResizeSize is not None: - return self.maxResizeSize - log.warning("%s doesn't have a max size set" %(self.device,)) - return MAX_PART_SIZE - - def getMinimumResizeMB(self, partitions): - return self.fstype.getMinimumSize(self.device) - -class RaidRequestSpec(RequestSpec): - """Request to represent RAID devices.""" - - def __init__(self, fstype, format = None, mountpoint = None, - raidlevel = None, raidmembers = None, - raidspares = None, raidminor = None, fslabel = None, - preexist = 0, chunksize = None, - fsprofile = None): - """Create a new RaidRequestSpec object. - - fstype is the fsset filesystem type. - format is whether or not the partition should be formatted. - mountpoint is the mountpoint. - raidlevel is the raidlevel (as 'RAID0', 'RAID1', 'RAID5'). - chunksize is the chunksize which should be used. - raidmembers is list of ids corresponding to the members of the RAID. - raidspares is the number of spares to setup. - raidminor is the minor of the device which should be used. - fslabel is the label of the filesystem. - fsprofile is the usage profile for the filesystem. - """ - - # if it's preexisting, the original fstype should be set - if preexist == 1: - origfs = fstype - else: - origfs = None - - RequestSpec.__init__(self, fstype = fstype, format = format, - mountpoint = mountpoint, preexist = preexist, - origfstype = origfs, - fslabel=fslabel, fsprofile=fsprofile) - self.type = REQUEST_RAID - - - self.raidlevel = raidlevel - self.raidmembers = raidmembers - self.raidspares = raidspares - self.raidminor = raidminor - self.chunksize = chunksize - - def __str__(self): - if self.fstype: - fsname = self.fstype.getName() - else: - fsname = "None" - raidmem = [] - if self.raidmembers: - for i in self.raidmembers: - raidmem.append(i) - - if self.encryption is None: - crypto = "None" - else: - crypto = self.encryption.getScheme() - - str = ("RAID Request -- mountpoint: %(mount)s uniqueID: %(id)s\n" - " type: %(fstype)s format: %(format)s\n" - " raidlevel: %(level)s raidspares: %(spares)s\n" - " raidmembers: %(members)s fsprofile: %(fsprofile)s\n" - " encryption: %(encryption)s" % - {"mount": self.mountpoint, "id": self.uniqueID, - "fstype": fsname, "format": self.format, - "level": self.raidlevel, "spares": self.raidspares, - "members": self.raidmembers, "fsprofile": self.fsprofile, - "encryption": crypto - }) - return str - - def getDevice(self, partitions): - """Return a device which can be solidified.""" - # Alway return a new device for minor changing - raidmems = [] - for member in self.raidmembers: - request = partitions.getRequestByID(member) - raidmems.append(request.getDevice(partitions)) - self.dev = fsset.RAIDDevice(int(self.raidlevel[4:]), - raidmems, minor = self.raidminor, - spares = self.raidspares, - existing = self.preexist, - chunksize = self.chunksize, - encryption = self.encryption) - return self.dev - - def isEncrypted(self, partitions, parentOnly = False): - if RequestSpec.isEncrypted(self, partitions) is True: - return True - if parentOnly: - return False - for member in self.raidmembers: - if partitions.getRequestByID(member).isEncrypted(partitions): - return True - return False - - def getActualSize(self, partitions, diskset): - """Return the actual size allocated for the request in megabytes.""" - - # this seems like a check which should never fail... - if not self.raidmembers or not self.raidlevel: - return 0 - nummembers = len(self.raidmembers) - self.raidspares - smallest = None - sum = 0 - for member in self.raidmembers: - req = partitions.getRequestByID(member) - partsize = req.getActualSize(partitions, diskset) - - if raid.isRaid0(self.raidlevel): - sum = sum + partsize - else: - if not smallest: - smallest = partsize - elif partsize < smallest: - smallest = partsize - - if raid.isRaid0(self.raidlevel): - return sum - elif raid.isRaid1(self.raidlevel): - return smallest - elif raid.isRaid5(self.raidlevel): - return (nummembers-1) * smallest - elif raid.isRaid6(self.raidlevel): - return (nummembers-2) * smallest - elif raid.isRaid10(self.raidlevel): - return (nummembers/2) * smallest - else: - raise ValueError, "Invalid raidlevel in RaidRequest.getActualSize" - - - # do RAID specific sanity checks; this is an internal function - def sanityCheckRaid(self, partitions): - if not self.raidmembers or not self.raidlevel: - return _("No members in RAID request, or not RAID " - "level specified.") - - minmembers = raid.get_raid_min_members(self.raidlevel) - if len(self.raidmembers) < minmembers: - return _("A RAID device of type %s " - "requires at least %s members.") % (self.raidlevel, - minmembers) - - if len(self.raidmembers) > 27: - return "RAID devices are limited to 27 members." - - if self.raidspares: - if (len(self.raidmembers) - self.raidspares) < minmembers: - return _("This RAID device can have a maximum of %s spares. " - "To have more spares you will need to add members to " - "the RAID device.") % (len(self.raidmembers) - - minmembers ) - return None - - def sanityCheckRequest(self, partitions): - """Run the basic sanity checks on the request.""" - rc = self.sanityCheckRaid(partitions) - if rc: - return rc - - return RequestSpec.sanityCheckRequest(self, partitions) - -class VolumeGroupRequestSpec(RequestSpec): - """Request to represent volume group devices.""" - - def __init__(self, fstype =None, format = None, - vgname = None, physvols = None, - pesize = 32768, preexist = 0, - preexist_size = 0): - """Create a new VolumeGroupRequestSpec object. - - fstype is the fsset filesystem type. - format is whether or not the volume group should be created. - vgname is the name of the volume group. - physvols is a list of the ids for the physical volumes in the vg. - pesize is the size of a physical extent in kilobytes. - preexist is whether the volume group is preexisting. - preexist_size is the size of a preexisting VG read from /proc - (note that this is unclamped) - """ - - if not fstype: - fstype = fsset.fileSystemTypeGet("volume group (LVM)") - RequestSpec.__init__(self, fstype = fstype, format = format) - self.type = REQUEST_VG - - self.volumeGroupName = vgname - self.physicalVolumes = physvols - self.pesize = pesize - self.preexist = preexist - self.free = 0 - - # FIXME: this is a hack so that we can set the vg name automagically - # with autopartitioning to not conflict with existing vgs - self.autoname = 0 - - if preexist and preexist_size: - self.preexist_size = preexist_size - else: - self.preexist_size = None - - def __str__(self): - physvols = [] - if self.physicalVolumes: - for i in self.physicalVolumes: - physvols.append(i) - - str = ("VG Request -- name: %(vgname)s uniqueID: %(id)s\n" - " format: %(format)s pesize: %(pesize)s \n" - " physvols: %(physvol)s" % - {"vgname": self.volumeGroupName, "id": self.uniqueID, - "format": self.format, "physvol": physvols, - "pesize": self.pesize}) - return str - - def getDevice(self, partitions): - """Return a device which can be solidified.""" - if self.dev: - # FIXME: this warning can probably be removed post-beta - log.warning("getting self.dev more than once for %s" %(self,)) - return self.dev - - pvs = [] - for pv in self.physicalVolumes: - r = partitions.getRequestByID(pv) - # a size of zero implies we did autopartitioning of - # pvs everywhere we could - if (r.size > 0) or (r.device is not None): - pvs.append(r.getDevice(partitions)) - self.dev = fsset.VolumeGroupDevice(self.volumeGroupName, pvs, - self.pesize, - existing = self.preexist) - return self.dev - - def isEncrypted(self, partitions, parentOnly = False): - if RequestSpec.isEncrypted(self, partitions) is True: - return True - if parentOnly: - return False - for pvid in self.physicalVolumes: - pv = partitions.getRequestByID(pvid) - if pv.isEncrypted(partitions): - return True - return False - - def getActualSize(self, partitions, diskset): - """Return the actual size allocated for the request in megabytes.""" - - # if we have a preexisting size, use it - if self.preexist and self.preexist_size: - totalspace = lvm.clampPVSize(self.preexist_size, self.pesize) - else: - totalspace = 0 - for pvid in self.physicalVolumes: - pvreq = partitions.getRequestByID(pvid) - size = pvreq.getActualSize(partitions, diskset) - #log.info("size for pv %s is %s" % (pvid, size)) - size = lvm.clampPVSize(size, self.pesize) - (self.pesize/1024) - #log.info(" clamped size is %s" % (size,)) - totalspace = totalspace + size - - return totalspace - -class PartialVolumeGroupSpec: - """Request to represent partial volume group devices.""" - # note, these are just used as placeholders so we don't collide on names - - def __init__(self, vgname = None): - """Create a new PartialVolumeGroupSpec object. - - vgname is the name of the volume group. - """ - - self.volumeGroupName = vgname - - def __str__(self): - str = ("Partial VG Request -- name: %(vgname)s" % - {"vgname": self.volumeGroupName}) - return str - -class LogicalVolumeRequestSpec(RequestSpec): - """Request to represent logical volume devices.""" - - def __init__(self, fstype, format = None, mountpoint = None, - size = None, volgroup = None, lvname = None, - preexist = 0, percent = None, grow=0, maxSizeMB=0, - fslabel = None, fsprofile = None): - """Create a new VolumeGroupRequestSpec object. - - fstype is the fsset filesystem type. - format is whether or not the volume group should be created. - mountpoint is the mountpoint for the request. - size is the size of the request in MB. - volgroup is the request ID of the volume group. - lvname is the name of the logical volume. - preexist is whether the logical volume previously existed or not. - percent is the percentage of the volume group's space this should use. - grow is whether or not to use free space remaining. - maxSizeMB is max size to grow to. - fslabel is the label of the filesystem on the logical volume. - fsprofile is the usage profile for the filesystem. - """ - - # if it's preexisting, the original fstype should be set - if preexist == 1: - origfs = fstype - else: - origfs = None - - RequestSpec.__init__(self, fstype = fstype, format = format, - mountpoint = mountpoint, size = size, - preexist = preexist, origfstype = origfs, - fslabel = fslabel, fsprofile = fsprofile) - - self.type = REQUEST_LV - - self.logicalVolumeName = lvname - self.volumeGroup = volgroup - self.percent = percent - self.grow = grow - self.maxSizeMB = maxSizeMB - self.startSize = size - - self.minResizeSize = None - self.resizable = True - - if not percent and not size and not preexist: - raise RuntimeError, "Error with Volume Group:Logical Volume %s:%s - Logical Volume must specify either percentage of vgsize or size" % (volgroup, lvname) - - if percent and grow: - raise RuntimeError, "Error with Volume Group:Logical Volume %s:%s - Logical Volume cannot grow if percentage given" % (volgroup, lvname) - - def __str__(self): - if self.fstype: - fsname = self.fstype.getName() - else: - fsname = "None" - - if self.size is not None: - size = self.size - else: - size = "%s percent" %(self.percent,) - - if self.encryption is None: - crypto = "None" - else: - crypto = self.encryption.getScheme() - - str = ("LV Request -- mountpoint: %(mount)s uniqueID: %(id)s\n" - " type: %(fstype)s format: %(format)s\n" - " size: %(size)s lvname: %(lvname)s volgroup: %(vgid)s\n" - " options: '%(fsopts)s' fsprofile: %(fsprofile)s" - " encryption: '%(crypto)s'" % - {"mount": self.mountpoint, "id": self.uniqueID, - "fstype": fsname, "format": self.format, - "lvname": self.logicalVolumeName, "vgid": self.volumeGroup, - "size": size, "crypto": crypto, - "fsopts": self.fsopts, "fsprofile": self.fsprofile}) - return str - - def getDevice(self, partitions): - """Return a device which can be solidified.""" - vg = partitions.getRequestByID(self.volumeGroup) - vgname = vg.volumeGroupName - self.dev = fsset.LogicalVolumeDevice(vgname, self.size, - self.logicalVolumeName, - vg = vg, - existing = self.preexist, - encryption = self.encryption) - return self.dev - - def isEncrypted(self, partitions, parentOnly = False): - if RequestSpec.isEncrypted(self, partitions) is True: - return True - if parentOnly: - return False - vg = partitions.getRequestByID(self.volumeGroup) - if vg.isEncrypted(partitions): - return True - return False - - def getActualSize(self, partitions = None, diskset = None, target = False): - """Return the actual size allocated for the request in megabytes.""" - if self.percent: - if partitions is None or diskset is None: - raise RuntimeError, "trying to get a percentage lv size on resize path" - vgreq = partitions.getRequestByID(self.volumeGroup) - vgsize = vgreq.getActualSize(partitions, diskset) - lvsize = int(self.percent * 0.01 * vgsize) - #lvsize = lvm.clampLVSizeRequest(lvsize, vgreq.pesize) - return lvsize - # FIXME: the target bit here is a bit of a hack... - elif self.targetSize is not None and target: - return self.targetSize - else: - return self.size - - def getStartSize(self): - """Return the starting size allocated for the request in megabytes.""" - return self.startSize - - def setSize(self, size): - """Set the size (in MB) of request (does not clamp to PE however) - - size - size in MB - """ - if self.percent: - self.percent = None - - self.size = size - - def sanityCheckRequest(self, partitions, skipMntPtExistCheck=0, pesize=32768): - """Run the basic sanity checks on the request.""" - if not self.grow and not self.percent and self.size*1024 < pesize: - return _("Logical volume size must be larger than the volume " - "group's physical extent size.") - - return RequestSpec.sanityCheckRequest(self, partitions, skipMntPtExistCheck) - - def getMaximumResizeMB(self, partitions): - vg = partitions.getRequestByID(self.volumeGroup) - print("max is", self.getActualSize(), vg.free, self.getActualSize() + vg.free) - return self.getActualSize() + vg.free - - def getMinimumResizeMB(self, partitions): - if self.minResizeSize is None: - log.warning("don't know the minimum size of %s" %(self.logicalVolumeName,)) - return 1 - return self.minResizeSize diff --git a/pkgs/core/pomona/src/partedUtils.py b/pkgs/core/pomona/src/partedUtils.py deleted file mode 100644 index 62e542e..0000000 --- a/pkgs/core/pomona/src/partedUtils.py +++ /dev/null @@ -1,1189 +0,0 @@ -# -# partedUtils.py: helper functions for use with parted objects -# -# 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): Matt Wilson msw@redhat.com -# Jeremy Katz katzj@redhat.com -# Mike Fulbright msf@redhat.com -# Karsten Hopp karsten@redhat.com -# - -"""Helper functions for use when dealing with parted objects.""" - -import parted -import math -import os, sys, string, struct, resource - -import exception -import fsset -import iutil, isys -import raid -import dmraid -import block -import lvm -import inspect -from flags import flags -from errors import * -from constants import * - -import logging -log = logging.getLogger("pomona") - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -fsTypes = {} - -fs_type = parted.file_system_type_get_next () -while fs_type: - fsTypes[fs_type.name] = fs_type - fs_type = parted.file_system_type_get_next (fs_type) - - - -def get_flags (part): - """Retrieve a list of strings representing the flags on the partition.""" - string="" - if not part.is_active (): - return string - first=1 - flag = parted.partition_flag_next (0) - while flag: - if part.get_flag (flag): - string = string + parted.partition_flag_get_name (flag) - if first: - first = 0 - else: - string = string + ", " - flag = parted.partition_flag_next (flag) - return string - -def start_sector_to_cyl(device, sector): - """Return the closest cylinder (round down) to sector on device.""" - return int(math.floor((float(sector) - / (device.heads * device.sectors)) + 1)) - -def end_sector_to_cyl(device, sector): - """Return the closest cylinder (round up) to sector on device.""" - return int(math.ceil(float((sector + 1)) - / (device.heads * device.sectors))) - -def start_cyl_to_sector(device, cyl): - "Return the sector corresponding to cylinder as a starting cylinder." - return long((cyl - 1) * (device.heads * device.sectors)) - -def end_cyl_to_sector(device, cyl): - "Return the sector corresponding to cylinder as a ending cylinder." - return long(((cyl) * (device.heads * device.sectors)) - 1) - -def getPartSize(partition): - """Return the size of partition in sectors.""" - return partition.geom.length - -def getPartSizeMB(partition): - """Return the size of partition in megabytes.""" - return (partition.geom.length * partition.geom.dev.sector_size - / 1024.0 / 1024.0) - -def getDeviceSizeMB(dev): - """Return the size of dev in megabytes.""" - return (float(dev.heads * dev.cylinders * dev.sectors) / (1024 * 1024) - * dev.sector_size) - -def getMaxAvailPartSizeMB(part): - """Return the maximum size this partition can grow to by looking - at contiguous freespace partitions.""" - - disk = part.disk - maxlen = part.geom.length - - # let's look at the next partition(s) and if they're freespace, - # they can add to our maximum size. - np = disk.next_partition(part) - while np: - if np.type & parted.PARTITION_FREESPACE: - maxlen += np.geom.length - else: - break - np = disk.next_partition(np) - return math.floor(maxlen * part.geom.dev.sector_size / 1024.0 / 1024.0) - -def get_partition_by_name(disks, partname): - """Return the parted part object associated with partname. - - Arguments: - disks -- Dictionary of diskname->PedDisk objects - partname -- Name of partition to find - - Return: - PedPartition object with name partname. None if no such partition. - """ - for diskname in disks.keys(): - disk = disks[diskname] - part = disk.next_partition() - while part: - if get_partition_name(part) == partname: - return part - - part = disk.next_partition(part) - - return None - -def get_partition_name(partition): - """Return the device name for the PedPartition partition.""" - if (partition.geom.dev.type == parted.DEVICE_DAC960 - or partition.geom.dev.type == parted.DEVICE_CPQARRAY): - return "%sp%d" % (partition.geom.dev.path[5:], - partition.num) - if (parted.__dict__.has_key("DEVICE_SX8") and - partition.geom.dev.type == parted.DEVICE_SX8): - return "%sp%d" % (partition.geom.dev.path[5:], - partition.num) - - drive = partition.geom.dev.path[5:] - if (drive.startswith("cciss") or drive.startswith("ida") or - drive.startswith("rd") or drive.startswith("sx8") or - drive.startswith("mapper") or drive.startswith("mmcblk")): - sep = "p" - else: - sep = "" - return "%s%s%d" % (partition.geom.dev.path[5:], sep, partition.num) - - -def get_partition_file_system_type(part): - """Return the file system type of the PedPartition part. - - Arguments: - part -- PedPartition object - - Return: - Filesystem object (as defined in fsset.py) - """ - if part.fs_type is None and part.native_type == 0x41: - ptype = fsset.fileSystemTypeGet("PPC PReP Boot") - elif part.fs_type == None: - return None - elif (part.get_flag(parted.PARTITION_BOOT) == 1 and - getPartSizeMB(part) <= 1 and part.fs_type.name == "hfs"): - ptype = fsset.fileSystemTypeGet("Apple Bootstrap") - elif part.fs_type.name == "linux-swap": - ptype = fsset.fileSystemTypeGet("swap") - elif isEfiSystemPartition(part): - ptype = fsset.fileSystemTypeGet("efi") - elif isEfiSystemPartition(part): - ptype = fsset.fileSystemTypeGet("efi") - elif part.fs_type.name in ("fat16", "fat32"): - ptype = fsset.fileSystemTypeGet("vfat") - else: - try: - ptype = fsset.fileSystemTypeGet(part.fs_type.name) - except: - ptype = fsset.fileSystemTypeGet("foreign") - - return ptype - - -def set_partition_file_system_type(part, fstype): - """Set partition type of part to PedFileSystemType implied by fstype.""" - if fstype == None: - return - try: - for flag in fstype.getPartedPartitionFlags(): - if not part.is_flag_available(flag): - raise PartitioningError, ("requested FileSystemType needs " - "a flag that is not available.") - part.set_flag(flag, 1) - if isEfiSystemPartition(part): - part.set_system(parted.file_system_type_get("fat32")) - else: - part.set_system(fstype.getPartedFileSystemType()) - except: - print("Failed to set partition type to ",fstype.getName()) - pass - -def get_partition_drive(partition): - """Return the device name for disk that PedPartition partition is on.""" - return "%s" %(partition.geom.dev.path[5:]) - -def get_max_logical_partitions(disk): - if not disk.type.check_feature(parted.DISK_TYPE_EXTENDED): - return 0 - dev = disk.dev.path[5:] - for key in max_logical_partition_count.keys(): - if dev.startswith(key): - return max_logical_partition_count[key] - # FIXME: if we don't know about it, should we pretend it can't have - # logicals? probably safer to just use something reasonable - return 11 - -def map_foreign_to_fsname(type): - """Return the partition type associated with the numeric type.""" - if type in allPartitionTypesDict.keys(): - return allPartitionTypesDict[type] - else: - return _("Foreign") - -def filter_partitions(disk, func): - rc = [] - part = disk.next_partition () - while part: - if func(part): - rc.append(part) - part = disk.next_partition (part) - - return rc - -def get_all_partitions(disk): - """Return a list of all PedPartition objects on disk.""" - func = lambda part: part.is_active() - return filter_partitions(disk, func) - -def get_logical_partitions(disk): - """Return a list of logical PedPartition objects on disk.""" - func = lambda part: (part.is_active() - and part.type & parted.PARTITION_LOGICAL) - return filter_partitions(disk, func) - -def get_primary_partitions(disk): - """Return a list of primary PedPartition objects on disk.""" - func = lambda part: part.type == parted.PARTITION_PRIMARY - return filter_partitions(disk, func) - -def get_raid_partitions(disk): - """Return a list of RAID-type PedPartition objects on disk.""" - func = lambda part: (part.is_active() - and part.get_flag(parted.PARTITION_RAID) == 1) - return filter_partitions(disk, func) - -def get_lvm_partitions(disk): - """Return a list of physical volume-type PedPartition objects on disk.""" - func = lambda part: (part.is_active() - and part.get_flag(parted.PARTITION_LVM) == 1) - return filter_partitions(disk, func) - - -def getDefaultDiskType(): - """Get the default partition table type for this architecture.""" - return parted.disk_type_get("msdos") - -def hasGptLabel(diskset, device): - disk = diskset.disks[device] - return disk.type.name == "gpt" - -def isEfiSystemPartition(part): - if not part.is_active(): - return False - return (part.disk.type.name == "gpt" and - part.get_name() == "EFI System Partition" and - part.get_flag(parted.PARTITION_BOOT) == 1 and - part.fs_type.name in ("fat16", "fat32") and - isys.readFSLabel(get_partition_name(part)) != "pomona") - -archLabels = {'i386': ['msdos', 'gpt'], - 's390': ['dasd', 'msdos'], - 'alpha': ['bsd', 'msdos'], - 'sparc': ['sun'], - 'ia64': ['msdos', 'gpt'], - 'ppc': ['msdos', 'mac', 'amiga', 'gpt'], - 'x86_64': ['msdos', 'gpt']} - -def labelDisk(deviceFile, forceLabelType=None): - dev = parted.PedDevice.get(deviceFile) - label = getDefaultDiskType() - - if not forceLabelType is None: - label = forceLabelType - else: - if label.name == 'msdos' and \ - dev.length > (2L**41) / dev.sector_size and \ - 'gpt' in archLabels[iutil.getArch()]: - label = parted.disk_type_get('gpt') - - disk = dev.disk_new_fresh(label) - disk.commit() - return disk - -def checkDiskLabel(disk, intf): - """Check that the disk label on disk is valid for this machine type.""" - arch = iutil.getArch() - if arch in archLabels.keys(): - pass - else: - if disk.type.name == "msdos": - return 0 - - if intf: - rc = intf.messageWindow(_("Warning"), - _("/dev/%s currently has a %s partition " - "layout. To use this drive for " - "the installation of %s, it must be " - "re-initialized, causing the loss of " - "ALL DATA on this drive.\n\n" - "Would you like to re-initialize this " - "drive?") - %(disk.dev.path[5:], disk.type.name, - name), type="custom", - custom_buttons = [ _("_Ignore drive"), - _("_Re-initialize drive") ], - custom_icon="question") - - if rc == 0: - return 1 - else: - return -1 - else: - return 1 - -def hasProtectedPartitions(drive, pomona): - rc = False - if pomona is None: - return rc - - try: - for protected in pomona.id.partitions.protectedPartitions(): - if protected.startswith(drive): - part = protected[len(drive):] - if part[0] == "p": - part = part[1:] - if part.isdigit(): - rc = True - break - except: - pass - - return rc - -# attempt to associate a parted filesystem type on a partition that -# didn't probe as one type or another. -def validateFsType(part): - # we only care about primary and logical partitions - if not part.type in (parted.PARTITION_PRIMARY, - parted.PARTITION_LOGICAL): - return - # if the partition already has a type, no need to search - if part.fs_type: - return - - # first fsystem to probe wins, so sort the types into a preferred - # order. - fsnames = fsTypes.keys() - goodTypes = ['ext3', 'ext2'] - badTypes = ['linux-swap',] - for fstype in goodTypes: - fsnames.remove(fstype) - fsnames = goodTypes + fsnames - for fstype in badTypes: - fsnames.remove(fstype) - fsnames.extend(badTypes) - - # now check each type, and set the partition system accordingly. - for fsname in fsnames: - fstype = fsTypes[fsname] - if fstype.probe_specific(part.geom) != None: - # XXX verify that this will not modify system type - # in the case where a user does not modify partitions - part.set_system(fstype) - return - -def isLinuxNativeByNumtype(numtype): - """Check if the type is a 'Linux native' filesystem.""" - linuxtypes = [0x82, 0x83, 0x8e, 0xfd] - - for t in linuxtypes: - if int(numtype) == t: - return 1 - - return 0 - -def sniffFilesystemType(device): - """Sniff to determine the type of fs on device. - - device - name of device to sniff. - """ - return isys.readFSType(device) - -def getReleaseString(mountpoint): - if os.access(mountpoint + "/etc/redhat-release", os.R_OK): - f = open(mountpoint + "/etc/redhat-release", "r") - try: - lines = f.readlines() - except IOError: - try: - f.close() - except: - pass - return "" - f.close() - # return the first line with the newline at the end stripped - if len(lines) == 0: - return "" - relstr = string.strip(lines[0][:-1]) - - # get the release name and version - # assumes that form is something - # like "Red Hat Linux release 6.2 (Zoot)" - if relstr.find("release") != -1: - try: - idx = relstr.find("release") - prod = relstr[:idx - 1] - - ver = "" - for a in relstr[idx + 8:]: - if a in string.digits + ".": - ver = ver + a - else: - break - - relstr = prod + " " + ver - except: - pass # don't worry, just use the relstr as we have it - return relstr - return "" - -class DiskSet: - """The disks in the system.""" - - skippedDisks = [] - mdList = [] - exclusiveDisks = [] - - dmList = None - mpList = None - - def __init__ (self, pomona): - self.disks = {} - self.initializedDisks = {} - self.onlyPrimary = None - self.pomona = pomona - self.devicesOpen = False - - def onlyPrimaryParts(self): - for disk in self.disks.values(): - if disk.type.check_feature(parted.DISK_TYPE_EXTENDED): - return 0 - - return 1 - - def startMPath(self): - """Start all of the dm multipath devices associated with the DiskSet.""" - - if not DiskSet.mpList is None and DiskSet.mpList.__len__() > 0: - return - - log.debug("starting mpaths") - log.debug("self.driveList(): %s" % (self.driveList(),)) - log.debug("DiskSet.skippedDisks: %s" % (DiskSet.skippedDisks,)) - driveList = filter(lambda x: x not in DiskSet.skippedDisks, - self.driveList()) - log.debug("DiskSet.skippedDisks: %s" % (DiskSet.skippedDisks,)) - - mpList = dmraid.startAllMPath(driveList) - DiskSet.mpList = mpList - log.debug("done starting mpaths. Drivelist: %s" % \ - (self.driveList(),)) - - def renameMPath(self, mp, name): - dmraid.renameMPath(mp, name) - - def stopMPath(self): - """Stop all of the mpath devices associated with the DiskSet.""" - - if DiskSet.mpList: - dmraid.stopAllMPath(DiskSet.mpList) - DiskSet.mpList = None - - def startDmRaid(self): - """Start all of the dmraid devices associated with the DiskSet.""" - - if not DiskSet.dmList is None: - return - - log.debug("starting dmraids") - log.debug("self.driveList(): %s" % (self.driveList(),)) - log.debug("DiskSet.skippedDisks: %s" % (DiskSet.skippedDisks,)) - driveList = filter(lambda x: x not in DiskSet.skippedDisks, - self.driveList()) - log.debug("DiskSet.skippedDisks: %s" % (DiskSet.skippedDisks,)) - - dmList = dmraid.startAllRaid(driveList) - DiskSet.dmList = dmList - log.debug("done starting dmraids. Drivelist: %s" % \ - (self.driveList(),)) - - def renameDmRaid(self, rs, name): - dmraid.renameRaidSet(rs, name) - - def stopDmRaid(self): - """Stop all of the dmraid devices associated with the DiskSet.""" - - if DiskSet.dmList: - dmraid.stopAllRaid(DiskSet.dmList) - DiskSet.dmList = None - - def startMdRaid(self): - """Start all of the md raid devices associated with the DiskSet.""" - - testList = [] - testList.extend(DiskSet.skippedDisks) - - for mp in DiskSet.mpList or []: - for m in mp.members: - disk = m.split('/')[-1] - testList.append(disk) - - for rs in DiskSet.dmList or []: - for m in rs.members: - if isinstance(m, block.RaidDev): - disk = m.rd.device.path.split('/')[-1] - testList.append(disk) - - driveList = filter(lambda x: x not in testList, self.driveList()) - DiskSet.mdList.extend(raid.startAllRaid(driveList)) - - def stopMdRaid(self): - """Stop all of the md raid devices associated with the DiskSet.""" - - raid.stopAllRaid(DiskSet.mdList) - - while DiskSet.mdList: - DiskSet.mdList.pop() - - def getInfo(self, readFn=lambda d: isys.readFSLabel(d)): - """Return a dict keyed on device name, storing some sort of data - about each device. This is typially going to be labels or UUIDs, - as required by readFstab. - """ - ret = {} - - encryptedDevices = self.pomona.id.partitions.encryptedDevices - - for drive in self.driveList(): - # Don't read labels from drives we cleared using clearpart, as - # we don't actually remove the existing filesystems so those - # labels will still be present (#209291). - if drive in DiskSet.skippedDisks: - continue - - # ignoredisk takes precedence over clearpart (#186438). - if DiskSet.exclusiveDisks != [] and \ - drive not in DiskSet.exclusiveDisks: - continue - - disk = self.disks[drive] - func = lambda part: (part.is_active() and - not (part.get_flag(parted.PARTITION_RAID) - or part.get_flag(parted.PARTITION_LVM))) - parts = filter_partitions(disk, func) - for part in parts: - node = get_partition_name(part) - crypto = encryptedDevices.get(node) - if crypto and not crypto.openDevice(): - node = crypto.getDevice() - - val = readFn(node) - if val: - ret[node] = val - - if crypto: - crypto.closeDevice() - - # not doing this right now, because we should _always_ have a - # partition table of some kind on dmraid. - #if False: - # for rs in DiskSet.dmList or [] + DiskSet.mpList or []: - # label = isys.readFSLabel(rs.name) - # if label: - # labels[rs.name] = label - - for dev, devices, level, numActive in DiskSet.mdList: - crypto = encryptedDevices.get(dev) - if crypto and not crypto.openDevice(): - dev = crypto.getDevice() - - val = readFn(dev) - if val: - ret[dev] = val - - if crypto: - crypto.closeDevice() - - active = lvm.vgcheckactive() - if not active: - lvm.vgscan() - lvm.vgactivate() - - for (vg, lv, size, lvorigin) in lvm.lvlist(): - if lvorigin: - continue - node = "%s/%s" % (vg, lv) - crypto = encryptedDevices.get(node) - if crypto and not crypto.openDevice(): - node = crypto.getDevice() - - val = readFn("/dev/" + node) - if val: - ret[node] = val - - if crypto: - crypto.closeDevice() - - if not active: - lvm.vgdeactivate() - - return ret - - def findExistingRootPartitions(self, upgradeany = 0): - """Return a list of all of the partitions which look like a root fs.""" - rootparts = [] - - self.startMPath() - self.startDmRaid() - self.startMdRaid() - - for dev, crypto in self.pomona.id.partitions.encryptedDevices.items(): - # FIXME: order these so LVM and RAID always work on the first try - if crypto.openDevice(): - log.error("failed to open encrypted device %s" % (dev,)) - - if flags.cmdline.has_key("upgradeany"): - upgradeany = 1 - - for dev, devices, level, numActive in self.mdList: - (errno, msg) = (None, None) - found = 0 - theDev = dev - crypto = self.pomona.id.partitions.encryptedDevices.get(dev) - if crypto and not crypto.openDevice(): - theDev = "/dev/%s" % (crypto.getDevice(),) - elif crypto: - log.error("failed to open encrypted device %s" % dev) - - fs = isys.readFSType(theDev) - if fs is not None: - try: - isys.mount(theDev, self.pomona.rootPath, fs, readOnly = 1) - found = 1 - except SystemError: - pass - - isys.umount(self.pomona.rootPath) - - # now, look for candidate lvm roots - lvm.vgscan() - lvm.vgactivate() - - for dev, crypto in self.pomona.id.partitions.encryptedDevices.items(): - # FIXME: order these so LVM and RAID always work on the first try - if crypto.openDevice(): - log.error("failed to open encrypted device %s" % (dev,)) - - for (vg, lv, size, lvorigin) in lvm.lvlist(): - if lvorigin: - continue - dev = "/dev/%s/%s" %(vg, lv) - found = 0 - theDev = dev - node = "%s/%s" % (vg, lv) - dmnode = "mapper/%s-%s" % (vg, lv) - crypto = self.pomona.id.partitions.encryptedDevices.get(dmnode) - if crypto and not crypto.openDevice(): - theDev = "/dev/%s" % (crypto.getDevice(),) - elif crypto: - log.error("failed to open encrypted device %s" % dev) - - fs = isys.readFSType(theDev) - if fs is not None: - try: - isys.mount(theDev, self.pomona.rootPath, fs, readOnly = 1) - found = 1 - except SystemError: - pass - - lvm.vgdeactivate() - - # don't stop raid until after we've looked for lvm on top of it - self.stopMdRaid() - - drives = self.disks.keys() - drives.sort() - - protected = self.pomona.id.partitions.protectedPartitions() - - for drive in drives: - disk = self.disks[drive] - part = disk.next_partition () - while part: - node = get_partition_name(part) - crypto = self.pomona.id.partitions.encryptedDevices.get(node) - if (part.is_active() - and (part.get_flag(parted.PARTITION_RAID) - or part.get_flag(parted.PARTITION_LVM))): - part = disk.next_partition(part) - continue - elif part.fs_type or crypto: - theDev = node - if part.fs_type: - fstype = part.fs_type.name - else: - fstype = None - - # parted doesn't tell ext4 from ext3 - if fstype == "ext3": - fstype = isys.readFSType(theDev) - - if crypto and not crypto.openDevice(): - theDev = crypto.getDevice() - fstype = isys.readFSType("/dev/%s" % theDev) - elif crypto: - log.error("failed to open encrypted device %s" % node) - - if not fstype or fstype not in fsset.getUsableLinuxFs(): - part = disk.next_partition(part) - continue - - try: - isys.mount("/dev/%s" % (theDev,), - self.pomona.rootPath, fstype) - checkRoot = self.pomona.rootPath - except SystemError: - part = disk.next_partition(part) - continue - - part = disk.next_partition(part) - return rootparts - - def driveList (self): - """Return the list of drives on the system.""" - drives = isys.hardDriveDict().keys() - drives.sort (isys.compareDrives) - return drives - - def drivesByName (self): - """Return a dictionary of the drives on the system.""" - return isys.hardDriveDict() - - def savePartitions (self): - """Write the partition tables out to the disks.""" - for disk in self.disks.values(): - if disk.dev.path[5:].startswith("sd") and disk.get_last_partition_num() > 15: - log.debug("not saving partition table of disk with > 15 partitions") - del disk - continue - - log.info("disk.commit() for %s" % (disk.dev.path,)) - try: - disk.commit() - except: - # if this fails, remove the disk so we don't use it later - # Basically if we get here, badness has happened and we want - # to prevent tracebacks from ruining the day any more. - del disk - continue - - del disk - self.refreshDevices() - - def _addDisk(self, drive, disk): - log.debug("adding drive %s to disk list" % (drive,)) - self.initializedDisks[drive] = True - self.disks[drive] = disk - - def _removeDisk(self, drive, addSkip=True): - msg = "removing drive %s from disk lists" % (drive,) - if addSkip: - msg += "; adding to skip list" - log.debug(msg) - - if self.disks.has_key(drive): - del self.disks[drive] - if addSkip: - if self.initializedDisks.has_key(drive): - del self.initializedDisks[drive] - DiskSet.skippedDisks.append(drive) - - def refreshDevices (self): - """Reread the state of the disks as they are on disk.""" - self.closeDevices() - self.disks = {} - self.openDevices() - - def closeDevices (self): - """Close all of the disks which are open.""" - self.stopDmRaid() - self.stopMPath() - for disk in self.disks.keys(): - #self.disks[disk].close() - del self.disks[disk] - self.devicesOpen = False - - def isDisciplineFBA (self, drive): - drive = drive.replace('/dev/', '') - - if drive.startswith("dasd"): - discipline = "/sys/block/%s/device/discipline" % (drive,) - if os.path.isfile(discipline): - try: - fp = open(discipline, "r") - lines = fp.readlines() - fp.close() - - if len(lines) == 1: - if lines[0].strip() == "FBA": - return True - except: - log.error("failed to check discipline of %s" % (drive,)) - pass - - return False - - def _askForLabelPermission(self, intf, drive, clearDevs, initAll, ks): - rc = 0 - if (ks and (drive in clearDevs) and initAll) or \ - self.isDisciplineFBA(drive): - rc = 1 - elif intf: - deviceFile = "/dev/" + drive - dev = parted.PedDevice.get(deviceFile) - - msg = _("The partition table on device %s (%s %-0.f MB) was unreadable.\n\n" - "To create new partitions it must be initialized, " - "causing the loss of ALL DATA on this drive.\n\n" - "This operation will override any previous " - "installation choices about which drives to " - "ignore.\n\n" - "Would you like to initialize this drive, " - "erasing ALL DATA?") % (drive, dev.model, getDeviceSizeMB (dev),) - - rc = intf.messageWindow(_("Warning"), msg, type="yesno") - - if rc != 0: - return True - - self._removeDisk(drive) - return False - - def _labelDevice(self, drive): - log.info("Reinitializing label for drive %s" % (drive,)) - - deviceFile = "/dev/" + drive - - try: - try: - disk = labelDisk(deviceFile) - except parted.error, msg: - log.error("parted error: %s" % (msg,)) - raise - except: - (type, value, tb) = sys.exc_info() - lines = exception.formatException(type, value, tb) - for line in lines: - log.error(line) - self._removeDisk(drive) - raise LabelError, drive - - self._addDisk(drive, disk) - return disk, deviceFile - - def openDevices (self): - """Open the disks on the system and skip unopenable devices.""" - - if self.disks: - return - self.startMPath() - self.startDmRaid() - - intf = self.pomona.intf - zeroMbr = self.pomona.id.partitions.zeroMbr - - for drive in self.driveList(): - # ignoredisk takes precedence over clearpart (#186438). - if drive in DiskSet.skippedDisks: - continue - - if DiskSet.exclusiveDisks != [] and \ - drive not in DiskSet.exclusiveDisks: - continue - - if not isys.mediaPresent(drive): - DiskSet.skippedDisks.append(drive) - continue - - disk = None - dev = None - - if self.initializedDisks.has_key(drive): - if not self.disks.has_key(drive): - try: - dev = parted.PedDevice.get("/dev/%s" % (drive,)) - disk = parted.PedDisk.new(dev) - self._addDisk(drive, disk) - except parted.error, msg: - self._removeDisk(drive) - continue - - ks = False - clearDevs = [] - initAll = False - - if initAll and ((clearDevs is None) or (len(clearDevs) == 0) \ - or (drive in clearDevs)) and \ - not hasProtectedPartitions(drive, self.pomona): - try: - disk, dev = self._labelDevice(drive) - except: - continue - - try: - if not dev: - dev = parted.PedDevice.get("/dev/%s" % (drive,)) - disk = None - except parted.error, msg: - log.debug("parted error: %s" % (msg,)) - self._removeDisk(drive, disk) - continue - - try: - if not disk: - disk = parted.PedDisk.new(dev) - self._addDisk(drive, disk) - except parted.error, msg: - recreate = 0 - if zeroMbr: - log.error("zeroMBR was set and invalid partition table " - "found on %s" % (dev.path[5:])) - recreate = 1 - else: - if not self._askForLabelPermission(intf, drive, clearDevs, - initAll, ks): - continue - - recreate = 1 - - if recreate == 1: - try: - disk, dev = self._labelDevice(drive) - except: - continue - - filter_partitions(disk, validateFsType) - - # check for more than 15 partitions (libata limit) - if drive.startswith('sd') and disk.get_last_partition_num() > 15: - str = _("The drive /dev/%s has more than 15 partitions on it. " - "The SCSI subsystem in the Linux kernel does not " - "allow for more than 15 partitons at this time. You " - "will not be able to make changes to the partitioning " - "of this disk or use any partitions beyond /dev/%s15 " - "in %s") % (drive, drive, name) - - rc = intf.messageWindow(_("Warning"), str, - type="custom", - custom_buttons = [_("_Reboot"), - _("_Continue")], - custom_icon="warning") - if rc == 0: - sys.exit(0) - - # check that their partition table is valid for their architecture - ret = checkDiskLabel(disk, intf) - if ret == 1: - self._removeDisk(drive) - elif ret == -1: - try: - disk, dev = self._labelDevice(drive) - except: - pass - self.devicesOpen = True - - def partitionTypes (self): - """Return list of (partition, partition type) tuples for all parts.""" - rc = [] - drives = self.disks.keys() - drives.sort() - - for drive in drives: - disk = self.disks[drive] - part = disk.next_partition () - while part: - if part.type in (parted.PARTITION_PRIMARY, - parted.PARTITION_LOGICAL): - device = get_partition_name(part) - if part.fs_type: - ptype = part.fs_type.name - else: - ptype = None - rc.append((device, ptype)) - part = disk.next_partition (part) - - return rc - - def diskState (self): - """Print out current disk state. DEBUG.""" - rc = "" - for disk in self.disks.values(): - rc = rc + ("%s: %s length %ld, maximum " - "primary partitions: %d\n" % - (disk.dev.path, - disk.dev.model, - disk.dev.length, - disk.max_primary_partition_count)) - - part = disk.next_partition() - if part: - rc = rc + ("Device Type Filesystem Start " - "End Length Flags\n") - rc = rc + ("------ ---- ---------- ----- " - "--- ------ -----\n") - while part: - if not part.type & parted.PARTITION_METADATA: - device = "" - fs_type_name = "" - if part.num > 0: - device = get_partition_name(part) - if part.fs_type: - fs_type_name = part.fs_type.name - partFlags = get_flags (part) - rc = rc + ("%-9s %-12s %-12s %-10ld %-10ld %-10ld %7s\n" - % (device, part.type_name, fs_type_name, - part.geom.start, part.geom.end, part.geom.length, - partFlags)) - part = disk.next_partition(part) - return rc - - def checkNoDisks(self): - """Check that there are valid disk devices.""" - if len(self.disks.keys()) == 0: - self.pomona.intf.messageWindow(_("No Drives Found"), - _("An error has occurred - no valid devices were " - "found on which to create new file systems. " - "Please check your hardware for the cause " - "of this problem.")) - return True - return False - - - def exceptionDisks(self, pomona, probe=True): - if probe: - isys.flushDriveDict() - self.refreshDevices() - - drives = [] - for d in isys.removableDriveDict().items(): - func = lambda p: p.is_active() and not p.get_flag(parted.PARTITION_RAID) and not p.get_flag(parted.PARTITION_LVM) and p.fs_type.name in ["ext3", "ext2", "fat16", "fat32"] - - disk = self.disks[d[0]] - parts = filter_partitions(disk, func) - - if len(parts) == 0: - drives.append(d) - else: - for part in parts: - name = "%s%s" % (part.disk.dev.path, part.num) - drives.append((os.path.basename(name), d[1])) - - return drives - -# XXX is this all of the possibilities? -dosPartitionTypes = [ 1, 6, 7, 11, 12, 14, 15 ] - -# master list of partition types -allPartitionTypesDict = { - 0 : "Empty", - 1: "DOS 12-bit FAT", - 2: "XENIX root", - 3: "XENIX usr", - 4: "DOS 16-bit <32M", - 5: "Extended", - 6: "DOS 16-bit >=32M", - 7: "NTFS/HPFS", - 8: "AIX", - 9: "AIX bootable", - 10: "OS/2 Boot Manager", - 0xb: "Win95 FAT32", - 0xc: "Win95 FAT32", - 0xe: "Win95 FAT16", - 0xf: "Win95 Ext'd", - 0x10: "OPUS", - 0x11: "Hidden FAT12", - 0x12: "Compaq Setup", - 0x14: "Hidden FAT16 <32M", - 0x16: "Hidden FAT16", - 0x17: "Hidden HPFS/NTFS", - 0x18: "AST SmartSleep", - 0x1b: "Hidden Win95 FAT32", - 0x1c: "Hidden Win95 FAT32 (LBA)", - 0x1e: "Hidden Win95 FAT16 (LBA)", - 0x24: "NEC_DOS", - 0x39: "Plan 9", - 0x40: "Venix 80286", - 0x41: "PPC_PReP Boot", - 0x42: "SFS", - 0x4d: "QNX4.x", - 0x4e: "QNX4.x 2nd part", - 0x4f: "QNX4.x 2nd part", - 0x51: "Novell?", - 0x52: "Microport", - 0x63: "GNU HURD", - 0x64: "Novell Netware 286", - 0x65: "Novell Netware 386", - 0x75: "PC/IX", - 0x80: "Old MINIX", - 0x81: "Linux/MINIX", - 0x82: "Linux swap", - 0x83: "Linux native", - 0x84: "OS/2 hidden C:", - 0x85: "Linux Extended", - 0x86: "NTFS volume set", - 0x87: "NTFS volume set", - 0x8e: "Linux LVM", - 0x93: "Amoeba", - 0x94: "Amoeba BBT", - 0x9f: "BSD/OS", - 0xa0: "IBM Thinkpad hibernation", - 0xa5: "BSD/386", - 0xa6: "OpenBSD", - 0xb7: "BSDI fs", - 0xb8: "BSDI swap", - 0xbf: "Solaris", - 0xc7: "Syrinx", - 0xdb: "CP/M", - 0xde: "Dell Utility", - 0xe1: "DOS access", - 0xe3: "DOS R/O", - 0xeb: "BEOS", - 0xee: "EFI GPT", - 0xef: "EFI (FAT-12/16/32)", - 0xf2: "DOS secondary", - 0xfd: "Linux RAID", - 0xff: "BBT" - } - -max_logical_partition_count = { - "hd": 59, - "sd": 11, - "ataraid/": 11, - "rd/": 3, - "cciss/": 11, - "i2o/": 11, - "iseries/vd": 3, - "ida/": 11, - "sx8/": 11, - "xvd": 11, - "vd": 11, - "mmcblk": 5 -} diff --git a/pkgs/core/pomona/src/partition.py b/pkgs/core/pomona/src/partition.py new file mode 100644 index 0000000..3acd670 --- /dev/null +++ b/pkgs/core/pomona/src/partition.py @@ -0,0 +1,394 @@ +#!/usr/bin/python + +from snack import * + +from storage.deviceaction import * +import storage +import storage.formats as formats +from storage.devicelibs.lvm import safeLvmName + +from constants import * + +import gettext +_ = lambda x: gettext.ldgettext("pomona", x) + +def logicalVolumeGroupList(installer): + storage = installer.ds.storage + + vgs = [] + for vg in storage.vgs: + vgs.append(vg.name) + (button, choice) = ListboxChoiceWindow(installer.intf.screen, + _("Volume Group Selection"), + _("What language would you like to use during the " + "installation process?"), vgs, + buttons = [TEXT_OK_BUTTON, TEXT_BACK_BUTTON], + width = 30, scroll = 1, + height = min((8, len(vgs)))) + if button == TEXT_BACK_CHECK: + return + + for vg in storage.vgs: + if choice == vg.name: + return vg + return + +class PartitionWindow(object): + def populate(self): + self.lb.clear() + + for vg in self.storage.vgs: + self.lb.append([vg.name, "", "", "",], vg) + + freespace = vg.freeSpace + if freespace: + self.lb.append([" %s" % _("Free Space"), "", "", "%dM" % freespace,], + None, [LEFT, LEFT, LEFT, RIGHT]) + + for disk in self.storage.disks: + self.lb.append([disk.path, "", "", "",], None) + for part in self.storage.partitions: + if disk == part.disk: + mountpoint = type = "" + if part.format: + type = part.format.name + try: + if part.format.mountpoint: + mountpoint = part.format.mountpoint + except AttributeError: + pass + self.lb.append([" %s" % part.name, + mountpoint, + type, + "%dM" % part.size,], + part, + [LEFT, LEFT, LEFT, RIGHT]) + + def makeFileSystemList(self, device): + grid = Grid(1, 2) + + label = Label(_("File System type:")) + grid.setField(label, 0, 0) + + fstype = Listbox(height=4, scroll=1) + for fs in sorted(formats.device_formats.values()): + if not fs.supported: + continue + if fs.formattable: + fstype.append(fs._type, fs) + # XXX select default + #current = formats.device_formats[formats.get_default_filesystem_type()] + #print current + #fstype.setCurrent(current) + ### XXX Callback + grid.setField(fstype, 0, 1) + return (grid, fstype) + + def makeDriveList(self, device): + grid = Grid(1, 2) + + label = Label(_("Allowable Drives:")) + grid.setField(label, 0, 0) + + drivelist = CheckboxTree(height=4, scroll=1) + for disk in self.storage.disks: + drivelist.append(disk.name) + grid.setField(drivelist, 0, 1) + return (grid, drivelist) + + def makeMountPoint(self, device): + grid = Grid(2, 1) + label = Label(_("Mount Point:")) + grid.setField(label, 0, 0, (0,0,0,0), anchorLeft = 1) + + try: + mountpoint = device.format.mountpoint + except AttributeError: + mountpoint = "" + mount = Entry(20, mountpoint) + + grid.setField(mount, 1, 0, anchorRight = 1, growx = 1) + + return (grid, mount) + + def makeVGName(self, device): + grid = Grid(2, 1) + label = Label(_("VG Name:")) + grid.setField(label, 0, 0, (0,0,0,0), anchorLeft = 1) + name = Entry(20, device.name) + grid.setField(name, 1, 0, anchorRight = 1, growx = 1) + return (grid, name) + + def newCb(self): + choices = [_("Partition"), _("RAID"), _("Logical Volume Group")] + + if self.storage.vgs: + choices.append(_("Logical Volume Device")) + + (button, choice) = ListboxChoiceWindow(self.installer.intf.screen, + _("New device"), + _("Which type of device do you want to create?\n\n"), + choices, buttons = [TEXT_OK_BUTTON, TEXT_BACK_BUTTON], + width = 35, height = len(choices)) + + if button == TEXT_BACK_CHECK: + return + + choice = choices[choice] + if choice == _("Partition"): + self.newPart() + elif choice == _("RAID"): + pass # XXX self.newRaid() + elif choice == _("Logical Volume Group"): + self.newVG() + elif choice == _("Logical Volume Device"): + self.newLV() + + def newPart(self): + disks = [] + for disk in self.storage.disks: + disks.append(("%s - %s" % (disk.name, disk.model,), disk,)) + + (button, disk) = ListboxChoiceWindow(self.installer.intf.screen, + _("Disk Selection"), + _("Choose the disk you want create the new " + "partition on."), + disks, buttons = [TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON], + height=len(disks)) + if button == TEXT_CANCEL_CHECK: + return + + device = self.storage.newPartition(parents=disk) + self.editPart(device=device) + + def newVG(self): + device = self.storage.newVG() + self.storage.createDevice(device) + self.editVG(device=device) + + def newLV(self): + vg = logicalVolumeGroupList(self.installer) + if vg: + device = self.storage.newLV(vg=vg) + self.editLV(device=device) + + def editPart(self, device): + if not device: + return + + row = 0 + actions = [] + + if not device.exists: + tstr = _("Add Partition") + else: + tstr = _("Edit Partition") + grid = GridForm(self.screen, tstr, 1, 6) + + if device.exists: + if device.format.exists and getattr(device.format, "label", None): + lbl = Label("%s %s" % (_("Original File System Label:"), device.format.label)) + grid.add(lbl, 0, row) + row += 1 + + (mountgrid, mountpoint) = self.makeMountPoint(device) + grid.add(mountgrid, 0, row) + row += 1 + + if not device.exists: + subgrid1 = Grid(2, 1) + + (fsgrid, fstype) = self.makeFileSystemList(device) + subgrid1.setField(fsgrid, 0, 0) + + #(devgrid, drivelist) = self.makeDriveList(device) + #subgrid1.setField(devgrid, 0, 0) + + #(fsgrid, fstype) = self.makeFileSystemList(device) + #subgrid1.setField(fsgrid, 1, 0, (1,0,0,0), growx=1) + + grid.add(subgrid1, 0, row, (0,1,0,0), growx=1) + row += 1 + else: + pass + + bb = ButtonBar(self.screen, (TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON)) + grid.add(bb, 0, row, (0,1,0,0), growx = 1) + row += 1 + + while 1: + rc = grid.run() + button = bb.buttonPressed(rc) + + if button == TEXT_CANCEL_CHECK: + break + + if mountpoint.value() and not mountpoint.value().startswith("/"): + self.installer.intf.messageWindow(_("Error"), + _("Mountpoint must be an absolute path.")) + continue + + if device.format: + device.format.mountpoint = mountpoint.value() + + if not device.exists: + actions.append(ActionCreateDevice(self.installer, device)) + + break + + self.screen.popWindow() + return actions + + def editVG(self, device): + if not device.exists: + tstr = _("Add Logical Volume Group") + else: + tstr = _("Edit Logical Volume Group") + grid = GridForm(self.screen, tstr, 1, 6) + row = 0 + + (namegrid, name) = self.makeVGName(device) + grid.add(namegrid, 0, row) + row += 1 + + # XXX size? + + bb = ButtonBar(self.screen, (TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON)) + grid.add(bb, 0, row, (0,1,0,0), growx = 1) + row += 1 + + while 1: + rc = grid.run() + button = bb.buttonPressed(rc) + + if button == TEXT_CANCEL_CHECK: + break + + if not name.value(): + self.installer.intf.messageWindow(_("Error"), + _("You must enter a name for the " + "Logical Volume Group.")) + continue + device.name = safeLvmName(name.value()) + + break + + self.screen.popWindow() + + editLV = editPart + + def editCb(self): + device = self.lb.current() + if not device: + self.installer.intf.messageWindow(_("Unable To Edit"), + _("You must first select a partition to edit.")) + return + + reason = self.storage.deviceImmutable(device) + if reason: + self.installer.intf.messageWindow(_("Unable To Edit"), + _("You cannot edit this device:\n\n%s") + % reason,) + return + + actions = None + if device.type == "mdarray": + pass #self.editRaidArray(device) + elif device.type == "lvmvg": + actions = self.editVG(device) + elif device.type == "lvmlv": + actions = self.editLV(device) + elif isinstance(device, storage.devices.PartitionDevice): + actions = self.editPart(device) + + for action in actions: + self.storage.devicetree.registerAction(action) + + def deleteCb(self): + device = self.lb.current() + + if not device: + self.installer.intf.messageWindow(_("Unable To Delete"), + _("You must first select a partition to delete.")) + return + + if device.type == "lvmvg": + text = _("Do you really want to delete the selected Logical Volume Group and " + "all its Logical Volumes?") + else: + text = _("Do you really want to delete the selected partition?") + + if not self.installer.intf.messageWindow(_("Confirm Delete"), text, type="yesno"): + return + + self.storage.destroyDevice(device) + + def __call__(self, installer): + self.installer = installer + self.screen = self.installer.intf.screen + self.storage = self.installer.ds.storage + + self.installer.intf.setHelpline(_("F2-New F3-Edit F4-Delete F5-Reset F12-OK")) + + self.g = GridForm(self.screen, _("Partitioning"), 1, 5) + self.lb = CListbox(height=10, cols=4, + col_widths=[22,14,14,10], + scroll=1, returnExit = 1, + width=70, col_pad=2, + col_labels=[_('Device'), _('Mount Point'), _("Filesystem"), _('Size') ], + col_label_align=[LEFT, LEFT, LEFT, CENTER]) + self.g.add(self.lb, 0, 1) + + self.bb = ButtonBar(self.screen, ((_("New"), "new", "F2"), + (_("Edit"), "edit", "F3"), + (_("Delete"), "delete", "F4"), + TEXT_OK_BUTTON, TEXT_BACK_BUTTON)) + + self.g.add(self.bb, 0, 2, (0, 1, 0, 0)) + self.g.addHotKey("F5") + + while 1: + self.populate() + rc = self.g.run() + button = self.bb.buttonPressed(rc) + + if button == "new": + self.newCb() + elif button == "edit" or rc == self.lb.listbox: # XXX better way? + self.editCb() + elif button == "delete": + self.deleteCb() + elif button == "reset" or rc == "F5": + self.storage.reset() + elif button == TEXT_BACK_CHECK: + self.storage.reset() + + self.screen.popHelpLine() + self.screen.popWindow() + return INSTALL_BACK + else: + #if not self.partitions.getRequestByMountPoint("/"): + # self.intf.messageWindow(_("No Root Partition"), + # _("Installation requires a / partition.")) + # continue + + #(errors, warnings) = self.partitions.sanityCheckAllRequests(self.diskset) + #rc = partitionSanityErrors(self.intf, errors) + #if rc != 1: + # continue + + #rc = partitionSanityWarnings(self.intf, warnings) + #if rc != 1: + # continue + + #warnings = getPreExistFormatWarnings(self.partitions, + # self.diskset) + #rc = partitionPreExistFormatWarnings(self.intf, warnings) + #if rc != 1: + # continue + + self.screen.popHelpLine() + self.screen.popWindow() + return INSTALL_OK + + return INSTALL_OK diff --git a/pkgs/core/pomona/src/partitioning.py b/pkgs/core/pomona/src/partitioning.py deleted file mode 100644 index dc4fa50..0000000 --- a/pkgs/core/pomona/src/partitioning.py +++ /dev/null @@ -1,79 +0,0 @@ -# -# partitioning.py: partitioning and other disk management -# -# Matt Wilson msw@redhat.com -# Jeremy Katz katzj@redhat.com -# Mike Fulbright msf@redhat.com -# Harald Hoyer harald@redhat.de -# -# Copyright 2001-2003 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -import isys -import sys -import iutil -from constants import * -from flags import flags -from partErrors import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -def partitionObjectsInitialize(pomona): - # read in drive info - pomona.id.diskset.refreshDevices() - pomona.id.partitions.setFromDisk(pomona.id.diskset) - -def partitioningComplete(pomona): - if pomona.dir == DISPATCH_BACK and pomona.id.fsset.isActive(): - rc = pomona.intf.messageWindow(_("Installation cannot continue."), - _("The partitioning options you have chosen " - "have already been activated. You can " - "no longer return to the disk editing " - "screen. Would you like to continue " - "with the installation process?"), - type = "yesno") - if rc == 0: - sys.exit(0) - return DISPATCH_FORWARD - - pomona.id.partitions.sortRequests() - pomona.id.fsset.reset() - for request in pomona.id.partitions.requests: - # XXX improve sanity checking - if (not request.fstype or (request.fstype.isMountable() - and not request.mountpoint)): - continue - - entry = request.toEntry(pomona.id.partitions) - if entry: - pomona.id.fsset.add(entry) - else: - raise RuntimeError, ("Managed to not get an entry back from " - "request.toEntry") - - if iutil.memAvailable() > isys.EARLY_SWAP_RAM: - return - - rc = pomona.intf.messageWindow(_("Low Memory"), - _("As you don't have much memory in this " - "machine, we need to turn on swap space " - "immediately. To do this we'll have to " - "write your new partition table to the disk " - "immediately. Is that OK?"), "yesno") - - if rc: - pomona.id.diskset.clearDevices() - pomona.id.fsset.setActive(pomona.id.diskset) - pomona.id.diskset.savePartitions() - pomona.id.fsset.formatSwap(pomona.rootPath) - pomona.id.fsset.turnOnSwap(pomona.rootPath) - - return diff --git a/pkgs/core/pomona/src/partitions.py b/pkgs/core/pomona/src/partitions.py deleted file mode 100644 index 6eae948..0000000 --- a/pkgs/core/pomona/src/partitions.py +++ /dev/null @@ -1,1672 +0,0 @@ -# -# partitions.py: partition object containing partitioning info -# -# Copyright (C) 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): Matt Wilson msw@redhat.com -# Jeremy Katz katzj@redhat.com -# Mike Fulbright msf@redhat.com -# Harald Hoyer harald@redhat.de -# - -"""Overarching partition object.""" - -import parted -import iutil -import isys -import string -import os -import sys - -from constants import * -from flags import flags -from errors import * - -import fsset -import raid -import lvm -import partedUtils -import partRequests -import cryptodev - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -import logging -log = logging.getLogger("pomona") - -# dispatch.py helper function -def partitionObjectsInitialize(pomona): - # shut down all dm devices - pomona.id.diskset.closeDevices() - pomona.id.diskset.stopMdRaid() - - # clean slate about drives - isys.flushDriveDict() - - if pomona.dir == DISPATCH_BACK: - return - - # pull in the new iscsi drive - isys.flushDriveDict() - - # read in drive info - pomona.id.diskset.refreshDevices() - - pomona.id.partitions.setFromDisk(pomona.id.diskset) - pomona.id.partitions.setProtected(pomona.dispatch) - -# dispatch.py helper function -def partitioningComplete(pomona): - if pomona.dir == DISPATCH_BACK and pomona.id.fsset.isActive(): - rc = pomona.intf.messageWindow(_("Installation cannot continue."), - _("The partitioning options you have chosen " - "have already been activated. You can " - "no longer return to the disk editing " - "screen. Would you like to continue " - "with the installation process?"), - type = "yesno") - if rc == 0: - sys.exit(0) - return DISPATCH_FORWARD - - pomona.id.partitions.sortRequests() - pomona.id.fsset.reset() - undoEncryption = False - partitions = pomona.id.partitions - preexist = partitions.hasPreexistingCryptoDev() - for request in pomona.id.partitions.requests: - # XXX improve sanity checking - if (not request.fstype or (request.fstype.isMountable() - and not request.mountpoint)): - continue - - if request.encryption and request.encryption.format: - if pomona.isKickstart and request.passphrase: - # they set a passphrase for this device explicitly - pass - elif partitions.encryptionPassphrase: - request.encryption.setPassphrase(partitions.encryptionPassphrase) - elif undoEncryption: - request.encryption = None - if request.dev: - request.dev.crypto = None - else: - while True: - (passphrase, retrofit) = pomona.intf.getLuksPassphrase(preexist=preexist) - if passphrase: - request.encryption.setPassphrase(passphrase) - partitions.encryptionPassphrase = passphrase - partitions.retrofitPassphrase = retrofit - break - else: - rc = pomona.intf.messageWindow(_("Encrypt device?"), - _("You specified block device encryption " - "should be enabled, but you have not " - "supplied a passphrase. If you do not " - "go back and provide a passphrase, " - "block device encryption will be " - "disabled."), - type="custom", - custom_buttons=[_("Back"), _("Continue")], - default=0) - if rc == 1: - log.info("user elected to not encrypt any devices.") - request.encryption = None - if request.dev: - request.dev.encryption = None - undoEncryption = True - partitions.autoEncrypt = False - break - - entry = request.toEntry(pomona.id.partitions) - if entry: - pomona.id.fsset.add (entry) - else: - raise RuntimeError, ("Managed to not get an entry back from " - "request.toEntry") - - if pomona.isKickstart: - return - - rc = pomona.intf.messageWindow(_("Writing partitioning to disk"), - _("The partitioning options you have selected " - "will now be written to disk. Any " - "data on deleted or reformatted partitions " - "will be lost."), - type = "custom", custom_icon="warning", - custom_buttons=[_("Go _back"), - _("_Write changes to disk")], - default = 0) - if rc == 0: - return DISPATCH_BACK - -def lookup_cryptodev(device): - for encryptedDev, cdev in Partitions.encryptedDevices.items(): - mappedDev = cdev.getDevice() - if device == encryptedDev or device == mappedDev: - return cdev - -class Partitions: - """Defines all of the partition requests and delete requests.""" - encryptedDevices = {} - - def __init__ (self, pomona, readDisks=False): - """Initializes a Partitions object. - - Can pass in the diskset if it already exists. - """ - self.pomona = pomona - - self.requests = [] - """A list of RequestSpec objects for all partitions.""" - - self.deletes = [] - """A list of DeleteSpec objects for partitions to be deleted.""" - - self.autoPartitionRequests = [] - """A list of RequestSpec objects for autopartitioning. - These are setup by the installclass and folded into self.requests - by auto partitioning.""" - - self.autoClearPartType = CLEARPART_TYPE_NONE - """What type of partitions should be cleared?""" - - self.autoClearPartDrives = None - """Drives to clear partitions on (note that None is equiv to all).""" - - self.nextUniqueID = 1 - """Internal counter. Don't touch unless you're smarter than me.""" - - self.reinitializeDisks = 0 - """Should the disk label be reset on all disks?""" - - self.zeroMbr = 0 - """Should the mbr be zero'd?""" - - self.protected = [] - """A list of partitions that are the installation source for hard - drive or livecd installs. Partitions on this list may not be - formatted.""" - - self.autoEncrypt = False - - self.encryptionPassphrase = "" - self.retrofitPassphrase = False - - # partition method to be used. not to be touched externally - self.useAutopartitioning = 1 - self.useFdisk = 0 - - if readDisks: - self.pomona.id.diskset.refreshDevices() - self.setFromDisk(self.pomona.id.diskset) - - def protectedPartitions(self): - return self.protected - - def hasPreexistingCryptoDev(self): - rc = False - for request in self.requests: - if request.encryption and request.encryption.format == 0: - rc = True - break - - return rc - - def getCryptoDev(self, device): - log.info("going to get passphrase for encrypted device %s" % device) - luksDev = self.encryptedDevices.get(device) - if luksDev: - log.debug("passphrase for device %s already known" % device) - return luksDev - - intf = self.pomona.intf - luksDev = cryptodev.LUKSDevice(device) - if self.encryptionPassphrase: - luksDev.setPassphrase(self.encryptionPassphrase) - if not luksDev.openDevice(): - self.encryptedDevices[device] = luksDev - return luksDev - else: - luksDev.setPassphrase("") - - if intf is None: - return - - buttons = [_("Back"), _("Continue")] - devname = os.path.basename(device) - while True: - (passphrase, isglobal) = intf.passphraseEntryWindow(devname) - if not passphrase: - rc = intf.messageWindow(_("Confirm"), - _("Are you sure you want to skip " - "entering a passphrase for device " - "%s?\n\n" - "If you skip this step the " - "device's contents will not " - "be available during " - "installation.") % devname, - type = "custom", - default = 0, - custom_buttons = buttons) - if rc == 0: - continue - else: - log.info("skipping passphrase for %s" % (device,)) - break - - luksDev.setPassphrase(passphrase) - rc = luksDev.openDevice() - if rc: - luksDev.setPassphrase("") - continue - else: - self.encryptedDevices[device] = luksDev - if isglobal: - self.encryptionPassphrase = passphrase - break - - return self.encryptedDevices.get(device) - - def getEncryptedDevices(self, diskset): - """ find and obtain passphrase for any encrypted devices """ - drives = diskset.disks.keys() - drives.sort() - for drive in drives: - if diskset.pomona.isKickstart and \ - ((self.autoClearPartType != CLEARPART_TYPE_NONE and \ - (not self.autoClearPartDrives or \ - drive in self.autoClearPartDrives)) or \ - drive in diskset.skippedDisks): - continue - - disk = diskset.disks[drive] - part = disk.next_partition() - while part: - if part.type & parted.PARTITION_METADATA: - part = disk.next_partition(part) - continue - - device = partedUtils.get_partition_name(part) - fs = partedUtils.sniffFilesystemType("/dev/%s" % (device,)) - if fs and fs.endswith("raid"): - part = disk.next_partition(part) - continue - - if cryptodev.isLuks("/dev/%s" % device): - self.getCryptoDev(device) - - part = disk.next_partition(part) - - diskset.startMPath() - diskset.startDmRaid() - diskset.startMdRaid() - mdList = diskset.mdList - for raidDev in mdList: - (theDev, devices, level, numActive) = raidDev - if cryptodev.isLuks("/dev/%s" % theDev): - self.getCryptoDev(theDev) - - lvm.writeForceConf() - # now to read in pre-existing LVM stuff - lvm.vgscan() - lvm.vgactivate() - - for (vg, size, pesize, vgfree) in lvm.vglist(): - for (lvvg, lv, size, lvorigin) in lvm.lvlist(): - if lvorigin: - continue - if lvvg != vg: - continue - - theDev = "/dev/mapper/%s-%s" %(vg, lv) - if cryptodev.isLuks(theDev): - self.getCryptoDev("mapper/%s-%s" % (vg, lv)) - - lvm.vgdeactivate() - diskset.stopMdRaid() - for luksDev in self.encryptedDevices.values(): - luksDev.closeDevice() - # try again now that encryption mappings are closed - lvm.vgdeactivate() - diskset.stopMdRaid() - for luksDev in self.encryptedDevices.values(): - luksDev.closeDevice() - - # We shouldn't have any further need for the global passphrase - # except for new device creation, in which case we want to give - # the user a chance to establish a new global passphrase. - self.encryptionPassphrase = "" - - def setFromDisk(self, diskset): - """Clear the delete list and set self.requests to reflect disk.""" - self.deletes = [] - self.requests = [] - labels = diskset.getInfo() - drives = diskset.disks.keys() - drives.sort() - for drive in drives: - disk = diskset.disks[drive] - part = disk.next_partition() - while part: - if part.type & parted.PARTITION_METADATA: - part = disk.next_partition(part) - continue - - format = None - if part.type & parted.PARTITION_FREESPACE: - ptype = None - elif part.type & parted.PARTITION_EXTENDED: - ptype = None - elif part.get_flag(parted.PARTITION_RAID) == 1: - ptype = fsset.fileSystemTypeGet("software RAID") - elif part.get_flag(parted.PARTITION_LVM) == 1: - ptype = fsset.fileSystemTypeGet("physical volume (LVM)") - else: - ptype = partedUtils.get_partition_file_system_type(part) - - # FIXME: we don't handle ptype being None very well, so - # just say it's foreign. Should probably fix None - # handling instead some day. - if ptype is None: - ptype = fsset.fileSystemTypeGet("foreign") - - device = partedUtils.get_partition_name(part) - luksDev = self.encryptedDevices.get(device) - if luksDev and not luksDev.openDevice(): - mappedDev = luksDev.getDevice() - fsname = partedUtils.sniffFilesystemType("/dev/%s" % mappedDev) - try: - ptype = fsset.fileSystemTypeGet(fsname) - except: - ptype = fsset.fileSystemTypeGet("foreign") - - start = part.geom.start - end = part.geom.end - size = partedUtils.getPartSizeMB(part) - drive = partedUtils.get_partition_drive(part) - - spec = partRequests.PreexistingPartitionSpec(ptype, - size = size, - start = start, - end = end, - drive = drive, - format = format) - spec.device = fsset.PartedPartitionDevice(part).getDevice() - spec.encryption = luksDev - spec.maxResizeSize = partedUtils.getMaxAvailPartSizeMB(part) - - # set label if makes sense - if ptype and ptype.isMountable(): - if spec.device in labels.keys(): - if labels[spec.device] and len(labels[spec.device])>0: - spec.fslabel = labels[spec.device] - elif luksDev and not luksDev.getStatus() and mappedDev in labels.keys(): - if labels[mappedDev] and len(labels[mappedDev])>0: - spec.fslabel = labels[mappedDev] - self.addRequest(spec) - part = disk.next_partition(part) - - # now we need to read in all pre-existing RAID stuff - diskset.startMPath() - diskset.startDmRaid() - diskset.startMdRaid() - mdList = diskset.mdList - for raidDev in mdList: - (theDev, devices, level, numActive) = raidDev - level = "RAID%s" %(level,) - - if level not in raid.availRaidLevels: - log.warning("raid level %s not supported, skipping %s" %(level, - theDev)) - continue - - try: - chunk = isys.getRaidChunkFromDevice("/dev/%s" %(devices[0],)) - except Exception, e: - log.error("couldn't get chunksize of %s: %s" %(theDev, e)) - chunk = None - - # is minor always mdN ? - minor = int(theDev[2:]) - raidvols = [] - for dev in devices: - req = self.getRequestByDeviceName(dev) - if not req: - log.error("RAID device %s using non-existent partition %s" - %(theDev, dev)) - continue - raidvols.append(req.uniqueID) - - - luksDev = self.encryptedDevices.get(theDev) - if luksDev and not luksDev.openDevice(): - device = luksDev.getDevice() - else: - device = theDev - - fs = partedUtils.sniffFilesystemType("/dev/%s" %(device,)) - try: - fsystem = fsset.fileSystemTypeGet(fs) - except: - fsystem = fsset.fileSystemTypeGet("foreign") - - try: - fslabel = isys.readFSLabel(device) - except: - fslabel = None - - mnt = None - format = 0 - - spares = len(devices) - numActive - spec = partRequests.RaidRequestSpec(fsystem, format = format, - raidlevel = level, - raidmembers = raidvols, - raidminor = minor, - raidspares = spares, - mountpoint = mnt, - preexist = 1, - chunksize = chunk, - fslabel = fslabel) - spec.size = spec.getActualSize(self, diskset) - spec.encryption = luksDev - self.addRequest(spec) - - lvm.writeForceConf() - # now to read in pre-existing LVM stuff - lvm.vgscan() - lvm.vgactivate() - - pvs = lvm.pvlist() - for (vg, size, pesize, vgfree) in lvm.vglist(): - try: - preexist_size = float(size) - except: - log.error("preexisting size for %s not a valid integer, ignoring" %(vg,)) - preexist_size = None - - pvids = [] - for (dev, pvvg, size) in pvs: - if vg != pvvg: - continue - req = self.getRequestByDeviceName(dev[5:]) - if not req: - log.error("Volume group %s using non-existent partition %s" - %(vg, dev)) - continue - pvids.append(req.uniqueID) - spec = partRequests.VolumeGroupRequestSpec(format = 0, - vgname = vg, - physvols = pvids, - pesize = pesize, - preexist = 1, - preexist_size = preexist_size) - spec.free = vgfree - vgid = self.addRequest(spec) - - for (lvvg, lv, size, lvorigin) in lvm.lvlist(): - if lvorigin: - continue - if lvvg != vg: - continue - - # size is number of bytes, we want size in megs - lvsize = float(size) - - theDev = "/dev/%s/%s" %(vg, lv) - - luksDev = self.encryptedDevices.get("mapper/%s-%s" % (vg, lv)) - if luksDev and not luksDev.openDevice(): - device = luksDev.getDevice() - else: - device = theDev - - fs = partedUtils.sniffFilesystemType(device) - fslabel = None - - try: - fsystem = fsset.fileSystemTypeGet(fs) - except: - fsystem = fsset.fileSystemTypeGet("foreign") - - try: - fslabel = isys.readFSLabel(device) - except: - fslabel = None - - mnt = None - format = 0 - - spec = partRequests.LogicalVolumeRequestSpec(fsystem, - format = format, size = lvsize, volgroup = vgid, - lvname = lv, mountpoint = mnt, fslabel = fslabel, - preexist = 1) - if fsystem.isResizable(): - spec.minResizeSize = fsystem.getMinimumSize("%s/%s" %(vg, lv)) - spec.encryption = luksDev - self.addRequest(spec) - - for vg in lvm.partialvgs(): - spec = partRequests.PartialVolumeGroupSpec(vgname = vg) - self.addDelete(spec) - - lvm.vgdeactivate() - diskset.stopMdRaid() - for luksDev in self.encryptedDevices.values(): - luksDev.closeDevice() - - # try again now that encryption mappings are closed - lvm.vgdeactivate() - diskset.stopMdRaid() - for luksDev in self.encryptedDevices.values(): - luksDev.closeDevice() - - def addRequest (self, request): - """Add a new request to the list.""" - if not request.uniqueID: - request.uniqueID = self.nextUniqueID - self.nextUniqueID = self.nextUniqueID + 1 - self.requests.append(request) - self.requests.sort() - - return request.uniqueID - - def addDelete (self, delete): - """Add a new DeleteSpec to the list.""" - self.deletes.append(delete) - self.deletes.sort() - - def removeRequest (self, request): - """Remove a request from the list.""" - self.requests.remove(request) - - def getRequestByMountPoint(self, mount): - """Find and return the request with the given mountpoint.""" - for request in self.requests: - if request.mountpoint == mount: - return request - - for request in self.requests: - if request.type == REQUEST_LV and request.mountpoint == mount: - return request - return None - - def getRequestByDeviceName(self, device): - """Find and return the request with the given device name.""" - if device is None: - return None - - for request in self.requests: - if request.type == REQUEST_RAID and request.raidminor is not None: - tmp = "md%d" % (request.raidminor,) - if tmp == device: - return request - elif request.device == device: - return request - elif request.encryption: - deviceUUID = cryptodev.luksUUID("/dev/" + device) - cryptoDev = request.encryption.getDevice() - cryptoUUID = request.encryption.getUUID() - if cryptoDev == device or \ - (cryptoUUID and cryptoUUID == deviceUUID): - return request - return None - - - def getRequestsByDevice(self, diskset, device): - """Find and return the requests on a given device (like 'hda').""" - if device is None: - return None - - drives = diskset.disks.keys() - if device not in drives: - return None - - rc = [] - disk = diskset.disks[device] - part = disk.next_partition() - while part: - dev = partedUtils.get_partition_name(part) - request = self.getRequestByDeviceName(dev) - - if request: - rc.append(request) - part = disk.next_partition(part) - - if len(rc) > 0: - return rc - else: - return None - - def getRequestByVolumeGroupName(self, volname): - """Find and return the request with the given volume group name.""" - if volname is None: - return None - - for request in self.requests: - if (request.type == REQUEST_VG and - request.volumeGroupName == volname): - return request - return None - - def getRequestByLogicalVolumeName(self, lvname): - """Find and return the request with the given logical volume name.""" - if lvname is None: - return None - for request in self.requests: - if (request.type == REQUEST_LV and - request.logicalVolumeName == lvname): - return request - return None - - def getRequestByID(self, id): - """Find and return the request with the given unique ID. - - Note that if id is a string, it will be converted to an int for you. - """ - if type(id) == type("a string"): - id = int(id) - for request in self.requests: - if request.uniqueID == id: - return request - return None - - def getRaidRequests(self): - """Find and return a list of all of the RAID requests.""" - retval = [] - for request in self.requests: - if request.type == REQUEST_RAID: - retval.append(request) - - return retval - - def getRaidDevices(self): - """Find and return a list of all of the requests for use in RAID.""" - raidRequests = [] - for request in self.requests: - if isinstance(request, partRequests.RaidRequestSpec): - raidRequests.append(request) - - return raidRequests - - def getAvailableRaidMinors(self): - """Find and return a list of all of the unused minors for use in RAID.""" - raidMinors = range(0,32) - for request in self.requests: - if isinstance(request, partRequests.RaidRequestSpec) and request.raidminor in raidMinors: - raidMinors.remove(request.raidminor) - - return raidMinors - - - def getAvailRaidPartitions(self, request, diskset): - """Return a list of tuples of RAID partitions which can be used. - - Return value is (part, size, used) where used is 0 if not, - 1 if so, 2 if used for *this* request. - """ - rc = [] - drives = diskset.disks.keys() - raiddevs = self.getRaidDevices() - drives.sort() - for drive in drives: - disk = diskset.disks[drive] - for part in partedUtils.get_raid_partitions(disk): - partname = partedUtils.get_partition_name(part) - used = 0 - for raid in raiddevs: - if raid.raidmembers: - for raidmem in raid.raidmembers: - tmpreq = self.getRequestByID(raidmem) - if (partname == tmpreq.device): - if raid.uniqueID == request.uniqueID: - used = 2 - else: - used = 1 - break - if used: - break - size = partedUtils.getPartSizeMB(part) - - if not used: - rc.append((partname, size, 0)) - elif used == 2: - rc.append((partname, size, 1)) - - return rc - - def getRaidMemberParent(self, request): - """Return RAID device request containing this request.""" - raiddev = self.getRaidRequests() - if not raiddev or not request.device: - return None - for dev in raiddev: - if not dev.raidmembers: - continue - for member in dev.raidmembers: - if request.device == self.getRequestByID(member).device: - return dev - return None - - def isRaidMember(self, request): - """Return whether or not the request is being used in a RAID device.""" - if self.getRaidMemberParent(request) is not None: - return 1 - else: - return 0 - - def getLVMLVForVGID(self, vgid): - """Find and return a list of all the LVs associated with a VG id.""" - retval = [] - for request in self.requests: - if request.type == REQUEST_LV: - if request.volumeGroup == vgid: - retval.append(request) - return retval - - def getLVMLVForVG(self, vgrequest): - """Find and return a list of all of the LVs in the VG.""" - vgid = vgrequest.uniqueID - return self.getLVMLVForVGID(vgid) - - def getLVMRequests(self): - """Return a dictionary of all of the LVM bits. - - The dictionary returned is of the form vgname: [ lvrequests ] - """ - retval = {} - for request in self.requests: - if request.type == REQUEST_VG: - retval[request.volumeGroupName] = self.getLVMLVForVG(request) - - return retval - - def getPartialLVMRequests(self): - """Return a list of all of the partial volume groups names.""" - retval = [] - for request in self.deletes: - if isinstance(request, partRequests.PartialVolumeGroupSpec): - retval.append(request.volumeGroupName) - - return retval - - def getLVMVGRequests(self): - """Find and return a list of all of the volume groups.""" - retval = [] - for request in self.requests: - if request.type == REQUEST_VG: - retval.append(request) - - return retval - - def getLVMLVRequests(self): - """Find and return a list of all of the logical volumes.""" - retval = [] - for request in self.requests: - if request.type == REQUEST_LV: - retval.append(request) - - return retval - - def getAvailLVMPartitions(self, request, diskset): - """Return a list of tuples of PV partitions which can be used. - - Return value is (part, size, used) where used is 0 if not, - 1 if so, 2 if used for *this* request. - """ - rc = [] - drives = diskset.disks.keys() - drives.sort() - volgroups = self.getLVMVGRequests() - pvlist = lvm.pvlist() - for drive in drives: - disk = diskset.disks[drive] - for part in partedUtils.get_lvm_partitions(disk): - partname = partedUtils.get_partition_name(part) - partrequest = self.getRequestByDeviceName(partname) - used = 0 - for volgroup in volgroups: - if volgroup.physicalVolumes: - if partrequest.uniqueID in volgroup.physicalVolumes: - if (request and request.uniqueID and - volgroup.uniqueID == request.uniqueID): - used = 2 - else: - used = 1 - - if used: - break - size = None - for pvpart, pvvg, pvsize in pvlist: - if pvpart == "/dev/%s" % (partname,): - size = pvsize - if size is None: - # if we get here, there's no PV data in the partition, - # so clamp the partition's size to 64M - size = partedUtils.getPartSizeMB(part) - size = lvm.clampPVSize(size, 65536) - - if used == 0: - rc.append((partrequest.uniqueID, size, 0)) - elif used == 2: - rc.append((partrequest.uniqueID, size, 1)) - - # now find available RAID devices - raiddev = self.getRaidRequests() - if raiddev: - raidcounter = 0 - for dev in raiddev: - used = 0 - - if dev.fstype is None: - continue - if dev.fstype.getName() != "physical volume (LVM)": - continue - - for volgroup in volgroups: - if volgroup.physicalVolumes: - if dev.uniqueID in volgroup.physicalVolumes: - if (request and request.uniqueID and - volgroup.uniqueID == request.uniqueID): - used = 2 - else: - used = 1 - - if used: - break - - size = dev.getActualSize(self, diskset) - - if used == 0: - rc.append((dev.uniqueID, size, 0)) - elif used == 2: - rc.append((dev.uniqueID, size, 1)) - - raidcounter = raidcounter + 1 - return rc - - def getLVMVolumeGroupMemberParent(self, request): - """Return parent volume group of a physical volume""" - volgroups = self.getLVMVGRequests() - if not volgroups: - return None - - for volgroup in volgroups: - if volgroup.physicalVolumes: - if request.uniqueID in volgroup.physicalVolumes: - return volgroup - - return None - - def isLVMVolumeGroupMember(self, request): - """Return whether or not the request is being used in an LVM device.""" - if self.getLVMVolumeGroupMemberParent(request) is None: - return 0 - else: - return 1 - - def isVolumeGroupNameInUse(self, vgname): - """Return whether or not the requested volume group name is in use.""" - if not vgname: - return None - - lvmrequests = self.getLVMRequests() - if lvmrequests: - if vgname in lvmrequests.keys(): - return 1 - - lvmrequests = self.getPartialLVMRequests() - if lvmrequests: - if vgname in lvmrequests: - return 1 - - return 0 - - def getBootableRequest(self): - """Return the name of the current 'boot' mount point.""" - bootreq = self.getRequestByMountPoint("/boot") - if not bootreq: - bootreq = self.getRequestByMountPoint("/") - - if bootreq: - return [ bootreq ] - return None - - def getBootableMountpoints(self): - """Return a list of bootable valid mountpoints for this arch.""" - # FIXME: should be somewhere else, preferably some sort of arch object - return [ "/boot", "/" ] - - def isBootable(self, request): - """Returns if the request should be considered a 'bootable' request. - - This basically means that it should be sorted to the beginning of - the drive to avoid cylinder problems in most cases. - """ - bootreqs = self.getBootableRequest() - if not bootreqs: - return 0 - - for bootreq in bootreqs: - if bootreq == request: - return 1 - - if bootreq.type == REQUEST_RAID and \ - request.uniqueID in bootreq.raidmembers: - return 1 - - return 0 - - def sortRequests(self): - """Resort the requests into allocation order.""" - n = 0 - while n < len(self.requests): - # Ignore LVM Volume Group and Logical Volume requests, - # since these are not related to allocating disk partitions - if (self.requests[n].type == REQUEST_VG or self.requests[n].type == REQUEST_LV): - n = n + 1 - continue - - for request in self.requests: - # Ignore LVM Volume Group and Logical Volume requests, - # since these are not related to allocating disk partitions - if (request.type == REQUEST_VG or request.type == REQUEST_LV): - continue - # for raid requests, the only thing that matters for sorting - # is the raid device since ordering by size is mostly - # irrelevant. this also keeps things more consistent - elif (request.type == REQUEST_RAID or - self.requests[n].type == REQUEST_RAID): - if (request.type == self.requests[n].type and - (self.requests[n].raidminor != None) and - ((request.raidminor is None) or - request.raidminor > self.requests[n].raidminor)): - tmp = self.requests[n] - index = self.requests.index(request) - self.requests[n] = request - self.requests[index] = tmp - # for sized requests, we want the larger ones first - elif (request.size and self.requests[n].size and - (request.size < self.requests[n].size)): - tmp = self.requests[n] - index = self.requests.index(request) - self.requests[n] = request - self.requests[index] = tmp - # for cylinder-based, sort by order on the drive - elif (request.start and self.requests[n].start and - (request.drive == self.requests[n].drive) and - (request.type == self.requests[n].type) and - (request.start > self.requests[n].start)): - tmp = self.requests[n] - index = self.requests.index(request) - self.requests[n] = request - self.requests[index] = tmp - # finally just use when they defined the partition so - # there's no randomness thrown in - elif (request.size and self.requests[n].size and - (request.size == self.requests[n].size) and - (request.uniqueID < self.requests[n].uniqueID)): - tmp = self.requests[n] - index = self.requests.index(request) - self.requests[n] = request - self.requests[index] = tmp - n = n + 1 - - tmp = self.getBootableRequest() - - boot = [] - if tmp: - for req in tmp: - # if raid, we want all of the contents of the bootable raid - if req.type == REQUEST_RAID: - for member in req.raidmembers: - boot.append(self.getRequestByID(member)) - else: - boot.append(req) - - # remove the bootables from the request - for bootable in boot: - self.requests.pop(self.requests.index(bootable)) - - # move to the front of the list - boot.extend(self.requests) - self.requests = boot - - def sanityCheckAllRequests(self, diskset, baseChecks = 0): - """Do a sanity check of all of the requests. - - This function is called at the end of partitioning so that we - can make sure you don't have anything silly (like no /, a really - small /, etc). Returns (errors, warnings) where each is a list - of strings or None if there are none. - If baseChecks is set, the basic sanity tests which the UI runs prior to - accepting a partition will be run on the requests as well. - """ - checkSizes = [('/usr', 250), ('/tmp', 50), ('/var', 384), - ('/home', 100), ('/boot', 75)] - warnings = [] - errors = [] - - slash = self.getRequestByMountPoint('/') - if not slash: - errors.append(_("You have not defined a root partition (/), " - "which is required for installation of %s " - "to continue.") % (name,)) - - if slash and slash.getActualSize(self, diskset) < 250: - warnings.append(_("Your root partition is less than 250 " - "megabytes which is usually too small to " - "install %s.") % (name,)) - - def getBaseReqs(reqs): - n = 0 - while not reduce(lambda x,y: x and (y.type not in [REQUEST_RAID, REQUEST_LV]), - reqs, True) \ - and len(reqs) > n: - req = reqs[n] - if req.type == REQUEST_RAID: - for id in req.raidmembers: - reqs.append(self.getRequestByID(id)) - del reqs[n] - continue - elif req.type == REQUEST_LV: - del reqs[n] - continue - n += 1 - return reqs - - for (mount, size) in checkSizes: - req = self.getRequestByMountPoint(mount) - if not req: - continue - if req.getActualSize(self, diskset) < size: - warnings.append(_("Your %s partition is less than %s " - "megabytes which is lower than recommended " - "for a normal %s install.") - %(mount, size, name)) - - foundSwap = 0 - swapSize = 0 - usesUSB = False - usesFireWire = False - - for request in self.requests: - if request.fstype and request.fstype.getName() == "swap": - foundSwap = foundSwap + 1 - swapSize = swapSize + request.getActualSize(self, diskset) - if baseChecks: - rc = request.doSizeSanityCheck() - if rc: - warnings.append(rc) - rc = request.doMountPointLinuxFSChecks() - if rc: - errors.append(rc) - if isinstance(request, partRequests.RaidRequestSpec): - rc = request.sanityCheckRaid(self) - if rc: - errors.append(rc) - if not hasattr(request,'drive'): - continue - for x in request.drive or []: - if isys.driveUsesModule(x, ["usb-storage", "ub"]): - usesUSB = True - elif isys.driveUsesModule(x, ["sbp2", "firewire-sbp2"]): - usesFireWire = True - - if usesUSB: - warnings.append(_("Installing on a USB device. This may " - "or may not produce a working system.")) - if usesFireWire: - warnings.append(_("Installing on a FireWire device. This may " - "or may not produce a working system.")) - - bootreqs = self.getBootableRequest() - if bootreqs: - for bootreq in bootreqs: - if not bootreq: - continue - if (isinstance(bootreq, partRequests.RaidRequestSpec) and - not raid.isRaid1(bootreq.raidlevel)): - errors.append(_("Bootable partitions can only be on RAID1 " - "devices.")) - - # can't have bootable partition on LV - if (isinstance(bootreq, partRequests.LogicalVolumeRequestSpec)): - errors.append(_("Bootable partitions cannot be on a " - "logical volume.")) - - # most arches can't have boot on RAID - if (isinstance(bootreq, partRequests.RaidRequestSpec) and - iutil.getArch() not in raid.raidBootArches): - errors.append(_("Bootable partitions cannot be on a RAID " - "device.")) - - # Lots of filesystems types don't support /boot. - if (bootreq.fstype and not bootreq.fstype.isBootable()): - errors.append(_("Bootable partitions cannot be on an %s " - "filesystem.")%(bootreq.fstype.getName(),)) - - # vfat /boot is insane. - if (bootreq.mountpoint and bootreq.mountpoint == "/" and - bootreq.fstype and bootreq.fstype.getName() == "vfat"): - errors.append(_("Bootable partitions cannot be on an %s " - "filesystem.")%(bootreq.fstype.getName(),)) - - if (bootreq.isEncrypted(self)): - errors.append(_("Bootable partitions cannot be on an " - "encrypted block device")) - - if foundSwap == 0: - warnings.append(_("You have not specified a swap partition. " - "Although not strictly required in all cases, " - "it will significantly improve performance for " - "most installations.")) - - # XXX number of swaps not exported from kernel and could change - if foundSwap >= 32: - warnings.append(_("You have specified more than 32 swap devices. " - "The kernel for %s only supports 32 " - "swap devices.") % (name,)) - - mem = iutil.memInstalled() - rem = mem % 16384 - if rem: - mem = mem + (16384 - rem) - mem = mem / 1024 - - if foundSwap and (swapSize < (mem - 8)) and (mem < 1024): - warnings.append(_("You have allocated less swap space (%dM) than " - "available RAM (%dM) on your system. This " - "could negatively impact performance.") - %(swapSize, mem)) - - if warnings == []: - warnings = None - if errors == []: - errors = None - - return (errors, warnings) - - def setProtected(self, dispatch): - """Set any partitions which should be protected to be so.""" - for device in self.protectedPartitions(): - log.info("%s is a protected partition" % (device)) - request = self.getRequestByDeviceName(device) - if request is not None: - request.setProtected(1) - else: - log.info("no request, probably a removable drive") - - def copy (self): - """Deep copy the object.""" - new = Partitions(self.pomona) - for request in self.requests: - new.addRequest(request) - for delete in self.deletes: - new.addDelete(delete) - new.autoPartitionRequests = self.autoPartitionRequests - new.autoClearPartType = self.autoClearPartType - new.autoClearPartDrives = self.autoClearPartDrives - new.nextUniqueID = self.nextUniqueID - new.useAutopartitioning = self.useAutopartitioning - new.useFdisk = self.useFdisk - new.reinitializeDisks = self.reinitializeDisks - new.protected = self.protected - return new - - def getClearPart(self): - """Get the kickstart directive related to the clearpart being used.""" - clearpartargs = [] - if self.autoClearPartType == CLEARPART_TYPE_ALL: - clearpartargs.append('--all') - else: - return None - - if self.reinitializeDisks: - clearpartargs.append('--initlabel') - - if self.autoClearPartDrives: - drives = string.join(self.autoClearPartDrives, ',') - clearpartargs.append('--drives=%s' % (drives)) - - return "#clearpart %s\n" %(string.join(clearpartargs)) - - def writeKS(self, f): - """Write out the partitioning information in kickstart format.""" - f.write("# The following is the partition information you requested\n") - f.write("# Note that any partitions you deleted are not expressed\n") - f.write("# here so unless you clear all partitions first, this is\n") - f.write("# not guaranteed to work\n") - clearpart = self.getClearPart() - if clearpart: - f.write(clearpart) - - # lots of passes here -- parts, raid, volgroup, logvol - # XXX what do we do with deleted partitions? - for request in self.requests: - args = [] - if request.type == REQUEST_RAID: - continue - - # no fstype, no deal (same with foreigns) - if not request.fstype or request.fstype.getName() == "foreign": - continue - - # first argument is mountpoint, which can also be swap or - # the unique RAID identifier. I hate kickstart partitioning - # syntax. a lot. too many special cases - if request.fstype.getName() == "swap": - args.append("swap") - elif request.fstype.getName() == "software RAID": - # since we guarantee that uniqueIDs are ints now... - args.append("raid.%s" % (request.uniqueID)) - elif request.fstype.getName() == "physical volume (LVM)": - # see above about uniqueIDs being ints - args.append("pv.%s" % (request.uniqueID)) - elif request.fstype.getName() == "PPC PReP Boot": - args.extend(["prepboot", "--fstype", ""PPC PReP Boot""]) - elif request.fstype.getName() == "Apple Bootstrap": - args.extend(["appleboot", "--fstype", ""Apple Bootstrap""]) - elif request.mountpoint: - args.extend([request.mountpoint, "--fstype", - request.fstype.getName(quoted = 1)]) - else: - continue - - # generic options - if not request.format: - args.append("--noformat") - - # device encryption - if request.encryption: - args.append("--encrypted") - - # preexisting only - if request.type == REQUEST_PREEXIST and request.device: - args.append("--onpart") - args.append(request.device) - # we have a billion ways to specify new partitions - elif request.type == REQUEST_NEW: - if request.size: - args.append("--size=%s" % (int(request.size),)) - if request.size == 0: - args.append("--size=0") - if request.grow: - args.append("--grow") - if request.start: - args.append("--start=%s" % (request.start)) - if request.end: - args.append("--end=%s" % (request.end)) - if request.maxSizeMB: - args.append("--maxsize=%s" % (request.maxSizeMB)) - if request.drive: - args.append("--ondisk=%s" % (request.drive[0])) - if request.primary: - args.append("--asprimary") - else: # how the hell did we get this? - continue - - f.write("#part %s\n" % (string.join(args))) - - - for request in self.requests: - args = [] - if request.type != REQUEST_RAID: - continue - - # no fstype, no deal (same with foreigns) - if not request.fstype or request.fstype.getName() == "foreign": - continue - - # also require a raidlevel and raidmembers for raid - if (request.raidlevel == None) or not request.raidmembers: - continue - - # first argument is mountpoint, which can also be swap - if request.fstype.getName() == "swap": - args.append("swap") - elif request.fstype.getName() == "physical volume (LVM)": - # see above about uniqueIDs being ints - args.append("pv.%s" % (request.uniqueID)) - elif request.mountpoint: - args.append(request.mountpoint) - else: - continue - - # generic options - if not request.format: - args.append("--noformat") - if request.preexist: - args.append("--useexisting") - if request.fstype: - args.extend(["--fstype", request.fstype.getName(quoted = 1)]) - - # device encryption - if request.encryption: - args.append("--encrypted") - - args.append("--level=%s" % (request.raidlevel)) - args.append("--device=md%s" % (request.raidminor)) - - if request.raidspares: - args.append("--spares=%s" % (request.raidspares)) - - # silly raid member syntax - raidmems = [] - for member in request.raidmembers: - if (type(member) != type("")) or (member[0:5] != "raid."): - raidmems.append("raid.%s" % (member)) - else: - raidmems.append(member) - args.append("%s" % (string.join(raidmems))) - - f.write("#raid %s\n" % (string.join(args))) - - for request in self.requests: - args = [] - if request.type != REQUEST_VG: - continue - - args.append(request.volumeGroupName) - - # generic options - if not request.format: - args.append("--noformat") - if request.preexist: - args.append("--useexisting") - - args.append("--pesize=%s" %(request.pesize,)) - - # silly pv syntax - pvs = [] - for member in request.physicalVolumes: - if (type(member) != type("")) or not member.startswith("pv."): - pvs.append("pv.%s" % (member)) - else: - pvs.append(member) - args.append("%s" % (string.join(pvs))) - - f.write("#volgroup %s\n" % (string.join(args))) - - for request in self.requests: - args = [] - if request.type != REQUEST_LV: - continue - - # no fstype, no deal (same with foreigns) - if not request.fstype or request.fstype.getName() == "foreign": - continue - - # require a vg name and an lv name - if (request.logicalVolumeName is None or - request.volumeGroup is None): - continue - - # first argument is mountpoint, which can also be swap - if request.fstype.getName() == "swap": - args.append("swap") - elif request.mountpoint: - args.append(request.mountpoint) - else: - continue - - # generic options - if not request.format: - args.append("--noformat") - if request.preexist: - args.append("--useexisting") - if request.fstype: - args.extend(["--fstype", request.fstype.getName(quoted = 1)]) - - # device encryption - if request.encryption: - args.append("--encrypted") - - vg = self.getRequestByID(request.volumeGroup) - if vg is None: - continue - - args.extend(["--name=%s" %(request.logicalVolumeName,), - "--vgname=%s" %(vg.volumeGroupName,)]) - - if request.grow: - if request.startSize: - args.append("--size=%s" % (int(request.startSize),)) - else: - # shouldnt happen - continue - - args.append("--grow") - if request.maxSizeMB and int(request.maxSizeMB) > 0: - args.append("--maxsize=%s" % (request.maxSizeMB,)) - else: - if request.percent: - args.append("--percent=%s" %(request.percent,)) - elif request.size: - args.append("--size=%s" %(int(request.size),)) - else: - continue - - f.write("#logvol %s\n" % (string.join(args))) - - def deleteAllLogicalPartitions(self, part): - """Add delete specs for all logical partitions in part.""" - for partition in partedUtils.get_logical_partitions(part.disk): - partName = partedUtils.get_partition_name(partition) - request = self.getRequestByDeviceName(partName) - self.removeRequest(request) - if request.preexist: - drive = partedUtils.get_partition_drive(partition) - delete = partRequests.DeleteSpec(drive, partition.geom.start, - partition.geom.end) - self.addDelete(delete) - - def containsImmutablePart(self, part): - """Returns whether the partition contains parts we can't delete.""" - if not part or (type(part) == type("RAID")) or (type(part) == type(1)): - return None - - if not part.type & parted.PARTITION_EXTENDED: - return None - - disk = part.disk - while part: - if not part.is_active(): - part = disk.next_partition(part) - continue - - device = partedUtils.get_partition_name(part) - request = self.getRequestByDeviceName(device) - - if request: - if request.getProtected(): - return _("the partition in use by the installer.") - - if self.isRaidMember(request): - return _("a partition which is a member of a RAID array.") - - if self.isLVMVolumeGroupMember(request): - return _("a partition which is a member of a LVM Volume Group.") - - part = disk.next_partition(part) - return None - - - def doMetaDeletes(self, diskset): - """Does the removal of all of the non-physical volumes in the delete list.""" - - # have to have lvm on, which requires raid to be started - diskset.startMPath() - diskset.startDmRaid() - diskset.startMdRaid() - for luksDev in self.encryptedDevices.values(): - luksDev.openDevice() - lvm.vgactivate() - - snapshots = {} - for (lvvg, lv, size, lvorigin) in lvm.lvlist(): - snapshots.setdefault(lv, []) - if lvorigin: - snapshots.setdefault(lvorigin, []) - snapshots[lvorigin].append((lv, lvvg)) - - lvm_parent_deletes = [] - tmp = {} - def addSnap(name, vg): - snaps = snapshots[name] - for snap, snapvg in snaps: - addSnap(snap, snapvg) - if not tmp.has_key((name, vg)): - tmp[(name, vg)] = 1 - lvm_parent_deletes.append((name,vg)) - - # now, go through and delete logical volumes - for delete in self.deletes: - if isinstance(delete, partRequests.DeleteLogicalVolumeSpec): - if not delete.beenDeleted(): - addSnap(delete.name, delete.vg) - delete.setDeleted(1) - - for name,vg in lvm_parent_deletes: - log.info("removing lv %s" % (name,)) - key = "mapper/%s-%s" % (vg, name) - if key in self.encryptedDevices.keys(): - self.encryptedDevices[key].closeDevice() - del self.encryptedDevices[key] - lvm.lvremove(name, vg) - - # now, go through and delete volume groups - for delete in self.deletes: - if isinstance(delete, partRequests.DeleteVolumeGroupSpec): - if not delete.beenDeleted(): - lvm.vgremove(delete.name) - delete.setDeleted(1) - - lvm.vgdeactivate() - - # now, remove obsolete cryptodev instances - for (device, luksDev) in self.encryptedDevices.items(): - luksDev.closeDevice() - found = 0 - for req in self.requests: - if req.encryption == luksDev: - found = 1 - - if not found: - del self.encryptedDevices[device] - - diskset.stopMdRaid() - - def doMetaResizes(self, diskset): - """Does resizing of non-physical volumes.""" - - # have to have lvm on, which requires raid to be started - devicesActive = diskset.devicesOpen - if not devicesActive: - # should this not be diskset.openDevices() ? - diskset.startMPath() - diskset.startDmRaid() - diskset.startMdRaid() - - for luksDev in self.encryptedDevices.values(): - luksDev.openDevice() - lvm.vgactivate() - - # we only support resizing LVM of these types of things currently - for lv in self.getLVMLVRequests(): - if not lv.preexist: - continue - if lv.targetSize is None: - continue - - vg = self.getRequestByID(lv.volumeGroup) - if vg is None: - continue - - lvm.lvresize(lv.logicalVolumeName, vg.volumeGroupName, - lv.targetSize) - - lvm.vgdeactivate() - for luksDev in self.encryptedDevices.values(): - luksDev.closeDevice() - - if not devicesActive: - # should this not be diskset.closeDevices() ? - diskset.stopMdRaid() - diskset.stopDmRaid() - diskset.stopMPath() - - def doEncryptionRetrofits(self): - if not self.retrofitPassphrase or not self.encryptionPassphrase: - return - - for request in self.requests: - if not request.encryption: - continue - - # XXX this will only work before the new LUKS devices are created - # since the format flag gets unset when they are formatted - if request.encryption.format: - continue - - if request.encryption.addPassphrase(self.encryptionPassphrase): - log.error("failed to add new passphrase to existing device %s" % (request.encryption.getDevice(encrypted=1),)) - - def deleteDependentRequests(self, request): - """Handle deletion of this request and all requests which depend on it. - - eg, delete all logical volumes from a volume group, all volume groups - which depend on the raid device. - - Side effects: removes all dependent requests from self.requests - adds needed dependent deletes to self.deletes - """ - - toRemove = [] - id = request.uniqueID - for req in self.requests: - if isinstance(req, partRequests.RaidRequestSpec): - if id in req.raidmembers: - toRemove.append(req) - # XXX do we need to do anything special with preexisting raids? - elif isinstance(req, partRequests.VolumeGroupRequestSpec): - if id in req.physicalVolumes: - toRemove.append(req) - if req.getPreExisting(): - delete = partRequests.DeleteVolumeGroupSpec(req.volumeGroupName) - self.addDelete(delete) - elif isinstance(req, partRequests.LogicalVolumeRequestSpec): - if id == req.volumeGroup: - toRemove.append(req) - tmp = self.getRequestByID(req.volumeGroup) - if not tmp: - log.error("Unable to find the vg for %s" - % (req.logicalVolumeName,)) - vgname = req.volumeGroup - else: - vgname = tmp.volumeGroupName - - if req.getPreExisting(): - delete = partRequests.DeleteLogicalVolumeSpec(req.logicalVolumeName, - vgname) - self.addDelete(delete) - - for req in toRemove: - self.deleteDependentRequests(req) - self.removeRequest(req) diff --git a/pkgs/core/pomona/src/po/Makefile b/pkgs/core/pomona/src/po/Makefile index a1ee8b0..f33dfe6 100644 --- a/pkgs/core/pomona/src/po/Makefile +++ b/pkgs/core/pomona/src/po/Makefile @@ -12,19 +12,19 @@ MSGMERGE = msgmerge -v all: $(FMTCATALOGS) report
$(PSNAME).pot: $(POTFILES) $(NONPOTFILES) - xgettext --from-code=UTF-8 --default-domain=$(PSNAME) \ + xgettext --from-code=UTF-8 --default-domain=pomona \ --keyword=_ --keyword=N_ $(POTFILES) - cat ../lang-table | cut -f1 | while read line; do echo -e "\n#. generated from lang-table\nmsgid "$$line"\nmsgstr """; done >> $(PSNAME).po - if cmp -s $(PSNAME).po $(PSNAME).pot; then \ - rm -f $(PSNAME).po; \ + cat ../lang-table | cut -f1 | while read line; do echo -e "\n#. generated from lang-table\nmsgid "$$line"\nmsgstr """; done >> pomona.po + if cmp -s pomona.po pomona.pot; then \ + rm -f pomona.po; \ else \ - mv $(PSNAME).po $(PSNAME).pot; \ + mv pomona.po pomona.pot; \ fi
refresh-po: for cat in $(POS); do \ lang=`basename $$cat .po`; \ - if $(MSGMERGE) $$lang.po $(PSNAME).pot > $$lang.pot ; then \ + if $(MSGMERGE) $$lang.po pomona.pot > $$lang.pot ; then \ mv -f $$lang.pot $$lang.po ; \ echo "$(MSGMERGE) of $$lang succeeded" ; \ else \ @@ -42,7 +42,7 @@ install: all $(INSTALL) -m 755 -d $(INSTALLNLSDIR)/$$l; \ $(INSTALL) -m 755 -d $(INSTALLNLSDIR)/$$l/LC_MESSAGES; \ $(INSTALL) -m 644 $$n \ - $(INSTALLNLSDIR)/$$l/LC_MESSAGES/$(PSNAME).mo; \ + $(INSTALLNLSDIR)/$$l/LC_MESSAGES/pomona.mo; \ done
%.mo: %.po diff --git a/pkgs/core/pomona/src/pomona b/pkgs/core/pomona/src/pomona index ab448da..75c9ce5 100644 --- a/pkgs/core/pomona/src/pomona +++ b/pkgs/core/pomona/src/pomona @@ -25,15 +25,10 @@ # # ###############################################################################
-echo "Running the Pomona Text Installer..." -echo -n "Loading modules:" -for i in md_mod dm_mod ext3 xfs reiserfs reiser4 btrfs; do - echo -n " $i" - modprobe $i -done -echo # Newline +echo "Running the Pomona Installer..."
-python /usr/lib/pomona/installer.py $@ +python /usr/lib/pomona/pomona.py $@ +ret=$?
for i in $@; do if [ "$i" == "--debug" ]; then @@ -47,4 +42,13 @@ for i in $@; do fi done
-reboot +#reboot + +cat <<EOF + + The installer program has finished with exit code ${ret}. + + Please reboot your system or do some debugging work :P + +EOF +sleep 1h diff --git a/pkgs/core/pomona/src/pomona.py b/pkgs/core/pomona/src/pomona.py new file mode 100644 index 0000000..9348d25 --- /dev/null +++ b/pkgs/core/pomona/src/pomona.py @@ -0,0 +1,113 @@ +#!/usr/bin/python + +import imputil +import os +import sys + +from datastore import DataStore +from dispatch import Dispatcher +from exception import handleException +from text import TextInterface +from log import Logger + +from constants import * + +import gettext +_ = lambda x: gettext.ldgettext("pomona", x) + +class Installer: + def __init__(self): + self.log = Logger() + + self.dispatch = None + self.ds = None + self.intf = TextInterface(self.log) + self.window = None + + def __call__(self): + if self.window: + self.window.pop() + + step = self.dispatch.nextStep() + while step: + self.log.info("") + self.log.info("---------- Running step "%s" ----------" % step[0]) + + if type(step[1]) == type(_): + (name, function) = step + self.log.debug(""%s" is called directly (%s)" % (name, function,)) + rc = function(self) + if rc in [DISPATCH_BACK, DISPATCH_FORWARD]: + self.dispatch.dir = rc + else: + (file, classes) = step + substep = 0 + while substep < len(classes): + while 1: + try: + found = imputil.imp.find_module(file) + loaded = imputil.imp.load_module(classes[substep], + found[0], found[1], + found[2]) + nextWindow = loaded.__dict__[classes[substep]] + break + except ImportError, e: + rc = self.intf.messageWindow(_("Error!"), + _("An error occurred when attempting " + "to load an pomona interface " + "component.\n\nclassName = %s\n\n" + "Error: %s") % (classes[substep],e), + type="custom", custom_buttons=[_("Exit"), _("Retry")]) + if rc == 0: + sys.exit(0) + + self.window = nextWindow() + rc = self.window(self) + + #if rc == INSTALL_NOOP: + # rc = lastrc + + if rc == INSTALL_BACK: + #step = step - 1 + self.dispatch.dir = DISPATCH_BACK + elif rc == INSTALL_OK: + #step = step + 1 + self.dispatch.dir = DISPATCH_FORWARD + + substep += 1 + + step = self.dispatch.nextStep() + + + +if __name__ == "__main__": + # Set up environment + if not os.environ.has_key("LANG"): + os.environ["LANG"] = "en_US.UTF-8" + os.environ['HOME'] = '/tmp' + os.environ['LC_NUMERIC'] = 'C' + + installer = Installer() + + sys.excepthook = lambda type, value, tb, installer=installer: \ + handleException(installer, (type, value, tb)) + + # Display some information + installer.window = \ + installer.intf.waitWindow(_("Installer"), _("Setting up installer..."),) + installer.log.info("Going on to install %s-v%s (%s)..." % \ + (PRODUCT_NAME, PRODUCT_VERSION, PRODUCT_SLOGAN,)) + + # Applying classes to installer + installer.dispatch = Dispatcher(installer) + installer.ds = DataStore(installer) + + try: + installer() + except SystemExit, code: + pass + except: + handleException(installer, sys.exc_info()) + + del installer.intf + del installer diff --git a/pkgs/core/pomona/src/pomona_log.py b/pkgs/core/pomona/src/pomona_log.py deleted file mode 100644 index 0bf79a7..0000000 --- a/pkgs/core/pomona/src/pomona_log.py +++ /dev/null @@ -1,103 +0,0 @@ -############################################################################### -# # -# IPFire.org - A linux based firewall # -# Copyright (C) 2007 Michael Tremer & Christian Schmidt # -# # -# 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 3 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/. # -# # -############################################################################### -# Chris Lumens clumens@redhat.com # -# Matt Wilson msw@redhat.com # -# Michael Fulbright msf@redhat.com # -############################################################################### - -import sys -import logging -from logging.handlers import SysLogHandler, SYSLOG_UDP_PORT - -DEFAULT_LEVEL = logging.INFO - -logFile = "/root/pomona.log" - -logLevelMap = {"debug": logging.DEBUG, "info": logging.INFO, - "warning": logging.WARNING, "error": logging.ERROR, - "critical": logging.CRITICAL} - -# Base class for logger instances. This is what will be created any time -# someone calls logging.getLogger("whatever"). We need this class to -# provide the setHandlersLevel function. -class LoggerClass(logging.Logger): - # Set the level of all handlers attached to a logger, except those - # with the autoSetLevel=False attribute. - def setHandlersLevel(self, level): - map(lambda hdlr: hdlr.setLevel(level), - filter (lambda hdlr: hasattr(hdlr, "autoSetLevel") and hdlr.autoSetLevel, self.handlers)) - - # Specialized addHandler that also adds the autoSetLevel attribute. - def addHandler(self, hdlr, autoSetLevel=True): - setattr(hdlr, "autoSetLevel", autoSetLevel) - logging.Logger.addHandler(self, hdlr) - -class InstallerLog: - def __init__(self, minLevel=DEFAULT_LEVEL): - # Create the base of the logger hierarcy. - self.logger = logging.getLogger("pomona") - self.logger.setLevel(logging.DEBUG) - - # Add a handler for the log file. - self.addFileHandler(logFile, logging.getLogger("pomona"), - autoSetLevel=False, minLevel=logging.DEBUG) - - # 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. - self.stdoutLogger = logging.getLogger("pomona.stdout") - self.stdoutLogger.setLevel(logging.INFO) - - # Add a handler for the duped stuff. No fancy formatting, thanks. - self.addFileHandler (sys.stdout, self.stdoutLogger, - fmtStr="%(message)s", minLevel=logging.INFO) - - # Add a simple handler - file or stream, depending on what we're given. - def addFileHandler(self, file, addToLogger, minLevel=DEFAULT_LEVEL, - fmtStr="%(asctime)s %(levelname)-8s: %(message)s", - autoSetLevel=True): - if type (file) == type ("string"): - logfileHandler = logging.FileHandler(file) - else: - logfileHandler = logging.StreamHandler(file) - - logfileHandler.setLevel(minLevel) - logfileHandler.setFormatter (logging.Formatter (fmtStr, "%H:%M:%S")) - addToLogger.addHandler(logfileHandler) - - # Add another logger to the hierarchy. For best results, make sure - # name falls under infire in the tree. - def addLogger(self, name, minLevel=DEFAULT_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_LEVEL): - fmt = logging.Formatter("%(levelname)-8s %(message)s") - syslogHandler = SysLogHandler((host, port)) - syslogHandler.setLevel(minLevel) - syslogHandler.setFormatter(fmt) - logger.addHandler(syslogHandler) - -# Set base class for logger instances. -logging.setLoggerClass(LoggerClass) -logger = InstallerLog() diff --git a/pkgs/core/pomona/src/pychecker-false-positives b/pkgs/core/pomona/src/pychecker-false-positives index 1e06e51..a800d13 100644 --- a/pkgs/core/pomona/src/pychecker-false-positives +++ b/pkgs/core/pomona/src/pychecker-false-positives @@ -3,12 +3,5 @@ filter setattr ^$ ^Warnings...$ -^installer.py:[0-9]*: No global .* found$ -^fsset.py:[0-9]*: Object (bestprep) has no attribute (format)$ -^partitions.py:[0-9]*: Object (bestprep) has no attribute (getPreExisting)$ -^partitions.py:[0-9]*: Object (bestreq) has no attribute (format)$ -^.*isys/isys.py:[0-9]*: Object (.*_iface) has no attribute (Get.*)$ -^partedUtils.py:[0-9]*: No module attribute (__dict__) found$ -^partedUtils.py:[0-9]*: No module attribute (DEVICE_SX8) found$ -^partRequests.py:[0-9]*: Format string argument count (0) doesn't match arguments (1)$ +^pomona.py:[0-9]*: Catching a non-Exception object (SystemExit)$ Note this last line must never end with a newline \ No newline at end of file diff --git a/pkgs/core/pomona/src/raid.py b/pkgs/core/pomona/src/raid.py deleted file mode 100644 index 312f71b..0000000 --- a/pkgs/core/pomona/src/raid.py +++ /dev/null @@ -1,226 +0,0 @@ -# -# raid.py - raid probing control -# -# 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): Erik Troan ewt@redhat.com -# - -"""Raid probing control.""" - -def getRaidLevels(): - avail = [] - try: - f = open("/proc/mdstat", "r") - except: - pass - else: - for l in f.readlines(): - if not l.startswith("Personalities"): - continue - - lst = l.split() - - for lev in ["RAID0", "RAID1", "RAID5", "RAID6", "RAID10"]: - if "[" + lev + "]" in lst or "[" + lev.lower() + "]" in lst: - avail.append(lev) - - f.close() - - avail.sort() - return avail - -# XXX define availraidlevels and defaultmntpts as arch characteristics -availRaidLevels = getRaidLevels() - -import parted -import isys -import os -import partitions -import partedUtils - -import logging -log = logging.getLogger("pomona") - -# these arches can have their /boot on RAID and not have their -# boot loader blow up -raidBootArches = [ "i386", "x86_64", "ppc" ] - -def scanForRaid(drives): - """Scans for raid devices on drives. - - drives is a list of device names. - Returns a list of (mdMinor, devices, level, totalDisks) tuples. - """ - - raidSets = {} - raidDevices = {} - - for d in drives: - parts = [] - try: - dev = parted.PedDevice.get("/dev/%s" % (d,)) - disk = parted.PedDisk.new(dev) - - raidParts = partedUtils.get_raid_partitions(disk) - for part in raidParts: - # if the part is encrypted, add the mapped dev instead - pname = partedUtils.get_partition_name(part) - cryptoDev = partitions.Partitions.encryptedDevices.get(pname) - if cryptoDev and not cryptoDev.openDevice(): - dev = cryptoDev.getDevice() - else: - dev = pname - parts.append(dev) - except: - pass - - for dev in parts: - try: - (major, minor, raidSet, level, nrDisks, totalDisks, mdMinor) =\ - isys.raidsb(dev) - except ValueError: - # bad magic, this can't be part of our raid set - log.error("reading raid sb failed for %s",dev) - continue - - if raidSets.has_key(raidSet): - (knownLevel, knownDisks, knownMinor, knownDevices) = \ - raidSets[raidSet] - if knownLevel != level or knownDisks != totalDisks or \ - knownMinor != mdMinor: - # Raise hell - log.error("raid set inconsistency for md%d: " - "all drives in this raid set do not " - "agree on raid parameters. Skipping raid device", - mdMinor) - continue - knownDevices.append(dev) - raidSets[raidSet] = (knownLevel, knownDisks, knownMinor, - knownDevices) - else: - raidSets[raidSet] = (level, totalDisks, mdMinor, [dev,]) - - if raidDevices.has_key(mdMinor): - if (raidDevices[mdMinor] != raidSet): - log.error("raid set inconsistency for md%d: " - "found members of multiple raid sets " - "that claim to be md%d. Using only the first " - "array found.", mdMinor, mdMinor) - continue - else: - raidDevices[mdMinor] = raidSet - - raidList = [] - for key in raidSets.keys(): - (level, totalDisks, mdMinor, devices) = raidSets[key] - if len(devices) < totalDisks: - log.warning("missing components of raid device md%d. The " - "raid device needs %d drive(s) and only %d (was/were) " - "found. This raid device will not be started.", mdMinor, - totalDisks, len(devices)) - continue - raidList.append((mdMinor, devices, level, totalDisks)) - - return raidList - -def startAllRaid(driveList): - """Do a raid start on raid devices and return a list like scanForRaid.""" - rc = [] - mdList = scanForRaid(driveList) - for mdDevice, deviceList, level, numActive in mdList: - devName = "md%d" % (mdDevice,) - isys.raidstart(devName, deviceList[0]) - rc.append((devName, deviceList, level, numActive)) - return rc - -def stopAllRaid(mdList): - """Do a raid stop on each of the raid device tuples given.""" - for dev, devices, level, numActive in mdList: - isys.raidstop(dev) - -def isRaid10(raidlevel): - """Return whether raidlevel is a valid descriptor of RAID10.""" - if raidlevel in ("RAID10", "10", 10): - return True - return False - -def isRaid6(raidlevel): - """Return whether raidlevel is a valid descriptor of RAID6.""" - if raidlevel in ("RAID6", "6", 6): - return True - return False - -def isRaid5(raidlevel): - """Return whether raidlevel is a valid descriptor of RAID5.""" - if raidlevel in ("RAID5", "5", 5): - return True - return False - -def isRaid1(raidlevel): - """Return whether raidlevel is a valid descriptor of RAID1.""" - if raidlevel in ("mirror", "RAID1", "1", 1): - return True - return False - -def isRaid0(raidlevel): - """Return whether raidlevel is a valid descriptor of RAID0.""" - if raidlevel in ("stripe", "RAID0", "0", 0): - return True - return False - -def get_raid_min_members(raidlevel): - """Return the minimum number of raid members required for raid level""" - if isRaid0(raidlevel): - return 2 - elif isRaid1(raidlevel): - return 2 - elif isRaid5(raidlevel): - return 3 - elif isRaid6(raidlevel): - return 4 - elif isRaid10(raidlevel): - return 4 - else: - raise ValueError, "invalid raidlevel in get_raid_min_members" - -def get_raid_max_spares(raidlevel, nummembers): - """Return the maximum number of raid spares for raidlevel.""" - if isRaid0(raidlevel): - return 0 - elif isRaid1(raidlevel) or isRaid5(raidlevel) or isRaid6(raidlevel) or isRaid10(raidlevel): - return max(0, nummembers - get_raid_min_members(raidlevel)) - else: - raise ValueError, "invalid raidlevel in get_raid_max_spares" - -def register_raid_device(mdname, newdevices, newlevel, newnumActive): - """Register a new RAID device in the mdlist.""" - for dev, devices, level, numActive in partedUtils.DiskSet.mdList: - if mdname == dev: - if (devices != newdevices or level != newlevel or numActive != newnumActive): - raise ValueError, "%s is already in the mdList!" % (mdname,) - else: - return - partedUtils.DiskSet.mdList.append((mdname, newdevices[:], newlevel, - newnumActive)) - -def lookup_raid_device(mdname): - """Return the requested RAID device information.""" - for dev, devices, level, numActive in partedUtils.DiskSet.mdList: - if mdname == dev: - return (dev, devices, level, numActive) - raise KeyError, "md device not found" diff --git a/pkgs/core/pomona/src/runpychecker.sh b/pkgs/core/pomona/src/runpychecker.sh index 30f8eb1..fa65ad5 100755 --- a/pkgs/core/pomona/src/runpychecker.sh +++ b/pkgs/core/pomona/src/runpychecker.sh @@ -39,8 +39,8 @@ fi
export PYTHONPATH="isys"
-FILES=installer.py -for file in *.py isys/*.py; do FILES="${FILES} ${file}"; done +#for file in *.py isys/*.py; do FILES="${FILES} ${file}"; done +FILES=$(find . -name "*.py")
pychecker --only --limit 1000 \ --maxlines 500 --maxargs 20 --maxbranches 80 --maxlocals 60 --maxreturns 20 \ diff --git a/pkgs/core/pomona/src/scripts/getlangnames.py b/pkgs/core/pomona/src/scripts/getlangnames.py deleted file mode 100755 index 865245e..0000000 --- a/pkgs/core/pomona/src/scripts/getlangnames.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/python - -import os -import sys - -sys.path.append("..") -import console - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -console = console.Console("/etc/sysconfig/console") -names = {} -for k in console.locales.keys(): - os.environ["LANG"] = console.locales[k][3] - names[console.locales[k][0]] = _(console.locales[k][0]) - -nameList = names.keys() -nameList.sort() - -for k in nameList: - print "%s\t%s" % (k, names[k]) diff --git a/pkgs/core/pomona/src/storage/__init__.py b/pkgs/core/pomona/src/storage/__init__.py new file mode 100644 index 0000000..2a0da0b --- /dev/null +++ b/pkgs/core/pomona/src/storage/__init__.py @@ -0,0 +1,1176 @@ +#!/usr/bin/python + +from devicetree import DeviceTree + +from deviceaction import * +from devicelibs import lvm +from devicelibs.lvm import safeLvmName +from devices import * +from formats import get_default_filesystem_type +from udev import * + +from constants import * + +import gettext +_ = lambda x: gettext.ldgettext("pomona", x) + +def storageInitialize(installer): + storage = installer.ds.storage + + storage.shutdown() + + if installer.dispatch.dir == DISPATCH_BACK: + return + + # XXX I don't understand why I have to do this + udev_trigger(subsystem="block") + + #XXX Determine our cdrom drive/usb key here and add it to protectedPartiotions + storage.reset() + +class Storage(object): + def __init__(self, installer): + self.installer = installer + + self.protectedDisks = [] + self.clearDisks = [] + self.ignoredDisks = [] + + self.defaultFSType = get_default_filesystem_type() + self.defaultBootFSType = get_default_filesystem_type(boot=True) + + self.doAutoPartition = False + self.encryptedAutoPart = False + #self.autoPartitionRequests = [] + self.autoPartitionRequests = [PartSpec(mountpoint="/", fstype=self.defaultFSType, size=1024, grow=True), + PartSpec(mountpoint="/boot", fstype=self.defaultFSType, size=75, grow=False),] + + #self.devicetree = DeviceTree(self.installer) + self.devicetree = None + + self._nextID = 0 + + def shutdown(self): + self.installer.log.debug("Shutting down storage...") + + def reset(self): + """ Reset storage configuration to reflect actual system state. + + This should rescan from scratch but not clobber user-obtained + information like passphrases + """ + #for device in self.devices: + # if device.format.type == "luks" and device.format.exists: + # self.__luksDevs[device.format.uuid] = device.format._LUKS__passphrase + + self.installer.window = self.installer.intf.waitWindow(_("Finding Devices"), + _("Finding storage devices...")) + self.devicetree = DeviceTree(self.installer) + self.devicetree.populate() + self.fsset = FSSet(self.installer) + self.installer.window.pop() + + def checkNoDisks(self): + """Check that there are valid disk devices.""" + if not self.disks: + self.installer.intf.messageWindow(_("No Drives Found"), + _("An error has occurred - no valid devices were " + "found on which to create new file systems. " + "Please check your hardware for the cause " + "of this problem.")) + return True + return False + + def sanityCheck(self): + """ Run a series of tests to verify the storage configuration. + + This function is called at the end of partitioning so that + we can make sure you don't have anything silly (like no /, + a really small /, etc). Returns (errors, warnings) where + each is a list of strings. + """ + checkSizes = [('/usr', 250), ('/tmp', 50), ('/var', 384), + ('/home', 100), ('/boot', 75)] + warnings = [] + errors = [] + + filesystems = self.fsset.mountpoints + root = self.fsset.rootDevice + swaps = self.fsset.swapDevices + #try: + # boot = self.anaconda.platform.bootDevice() + #except DeviceError: + # boot = None + boot = None + + if not root: + errors.append(_("You have not defined a root partition (/), " + "which is required for installation of %s " + "to continue.") % (PRODUCT_NAME,)) + + if root and root.size < 250: + warnings.append(_("Your root partition is less than 250 " + "megabytes which is usually too small to " + "install %s.") % (PRODUCT_NAME,)) + + recommended_size = 1024 + if (root and root.size < recommended_size): + errors.append(_("Your / partition is less than %s " + "megabytes which is lower than recommended " + "for a normal %s install.") + %(recommended_size, PRODUCT_NAME)) + + # livecds have to have the rootfs type match up + #if (root and + # self.installer.backend.rootFsType and + # root.format.type != self.installer.backend.rootFsType): + # errors.append(_("Your / partition does not match the " + # "the live image you are installing from. " + # "It must be formatted as %s.") + # % (self.anaconda.backend.rootFsType,)) + + for (mount, size) in checkSizes: + if mount in filesystems and filesystems[mount].size < size: + warnings.append(_("Your %s partition is less than %s " + "megabytes which is lower than recommended " + "for a normal %s install.") + %(mount, size, PRODUCT_NAME)) + + usb_disks = [] + firewire_disks = [] + #for disk in self.disks: + # if isys.driveUsesModule(disk.name, ["usb-storage", "ub"]): + # usb_disks.append(disk) + # elif isys.driveUsesModule(disk.name, ["sbp2", "firewire-sbp2"]): + # firewire_disks.append(disk) + + uses_usb = False + uses_firewire = False + for device in filesystems.values(): + for disk in usb_disks: + if device.dependsOn(disk): + uses_usb = True + break + + for disk in firewire_disks: + if device.dependsOn(disk): + uses_firewire = True + break + + if uses_usb: + warnings.append(_("Installing on a USB device. This may " + "or may not produce a working system.")) + if uses_firewire: + warnings.append(_("Installing on a FireWire device. This may " + "or may not produce a working system.")) + + if not boot: + errors.append(_("You have not created a boot partition.")) + + if (boot and boot.type == "mdarray" and + boot.level != 1): + errors.append(_("Bootable partitions can only be on RAID1 " + "devices.")) + + # can't have bootable partition on LV + if boot and boot.type == "lvmlv": + errors.append(_("Bootable partitions cannot be on a " + "logical volume.")) + + # most arches can't have boot on RAID + if boot and boot.type == "mdarray" and not self.anaconda.platform.supportsMdRaidBoot: + errors.append(_("Bootable partitions cannot be on a RAID " + "device.")) + + # Lots of filesystems types don't support /boot. + if boot and not boot.format.bootable: + errors.append(_("Bootable partitions cannot be on an %s " + "filesystem.") % boot.format.name) + + # vfat /boot is insane. + if (boot and boot == root and boot.format.type == "vfat"): + errors.append(_("Bootable partitions cannot be on an %s " + "filesystem.") % boot.format.type) + + if (boot and filter(lambda d: d.type == "luks/dm-crypt", + self.deviceDeps(boot))): + errors.append(_("Bootable partitions cannot be on an " + "encrypted block device")) + + if not swaps: + warnings.append(_("You have not specified a swap partition. " + "Although not strictly required in all cases, " + "it will significantly improve performance for " + "most installations.")) + + return (errors, warnings) + + def deviceDeps(self, device): + return self.devicetree.getDependentDevices(device) + + @property + def nextID(self): + id = self._nextID + self._nextID += 1 + return id + + @property + def disks(self): + """ A list of the disks in the device tree. + + Ignored disks are not included, as are disks with no media present. + + This is based on the current state of the device tree and + does not necessarily reflect the actual on-disk state of the + system's disks. + """ + disks = [] + devices = self.devicetree.devices + for d in devices: + if isinstance(devices[d], DiskDevice) and devices[d].mediaPresent: + disks.append(devices[d]) + disks.sort(key=lambda d: d.name) + return disks + + @property + def devices(self): + """ A list of all the devices in the device tree. """ + devices = self.devicetree.devices.values() + devices.sort(key=lambda d: d.path) + return devices + + @property + def partitions(self): + """ A list of the partitions in the device tree. + + This is based on the current state of the device tree and + does not necessarily reflect the actual on-disk state of the + system's disks. + """ + partitions = self.devicetree.getDevicesByInstance(PartitionDevice) + partitions.sort(key=lambda d: d.name) + return partitions + + @property + def vgs(self): + """ A list of the LVM Volume Groups in the device tree. + + This is based on the current state of the device tree and + does not necessarily reflect the actual on-disk state of the + system's disks. + """ + vgs = self.devicetree.getDevicesByType("lvmvg") + vgs.sort(key=lambda d: d.name) + return vgs + + def createDevice(self, device): + """ Schedule creation of a device. + + TODO: We could do some things here like assign the next + available raid minor if one isn't already set. + """ + self.devicetree.registerAction(ActionCreateDevice(self.installer, device)) + if device.format.type: + self.devicetree.registerAction(ActionCreateFormat(self.installer, device)) + + def destroyDevice(self, device): + """ Schedule destruction of a device. """ + if device.format.exists and device.format.type: + # schedule destruction of any formatting while we're at it + self.devicetree.registerAction(ActionDestroyFormat(self.installer, device)) + + action = ActionDestroyDevice(self.installer, device) + self.devicetree.registerAction(action) + + def newPartition(self, *args, **kwargs): + """ Return a new PartitionDevice instance for configuring. """ + if kwargs.has_key("fmt_type"): + kwargs["format"] = getFormat(kwargs.pop("fmt_type"), installer=self.installer, + mountpoint=kwargs.pop("mountpoint", None)) + + if kwargs.has_key("disks"): + parents = kwargs.pop("disks") + if isinstance(parents, Device): + kwargs["parents"] = [parents] + else: + kwargs["parents"] = parents + + if kwargs.has_key("name"): + name = kwargs.pop("name") + else: + name = "req%d" % self.nextID + + return PartitionDevice(self.installer, name, *args, **kwargs) + + def newVG(self, *args, **kwargs): + """ Return a new LVMVolumeGroupDevice instance. """ + pvs = kwargs.pop("pvs", []) + for pv in pvs: + if pv not in self.devices: + raise ValueError("pv is not in the device tree") + + if kwargs.has_key("name"): + name = kwargs.pop("name") + else: + # XXX name = self.createSuggestedVGName(self.anaconda.id.network) + name = self.createSuggestedVGName(None) + + if name in [d.name for d in self.devices]: + raise ValueError("name already in use") + + return LVMVolumeGroupDevice(self.installer, name, pvs, *args, **kwargs) + + def newLV(self, *args, **kwargs): + """ Return a new LVMLogicalVolumeDevice instance. """ + if kwargs.has_key("vg"): + vg = kwargs.pop("vg") + + mountpoint = kwargs.pop("mountpoint", None) + if kwargs.has_key("fmt_type"): + kwargs["format"] = getFormat(kwargs.pop("fmt_type"), + installer=self.installer, + mountpoint=mountpoint) + + if kwargs.has_key("name"): + name = kwargs.pop("name") + else: + if kwargs.get("format") and kwargs["format"].type == "swap": + swap = True + else: + swap = False + name = self.createSuggestedLVName(vg, + swap=swap, + mountpoint=mountpoint) + + if name in [d.name for d in self.devices]: + raise ValueError("Name already in use") + + return LVMLogicalVolumeDevice(self.installer, name, vg, *args, **kwargs) + + def createSuggestedVGName(self, network): + """ Return a reasonable, unused VG name. """ + # try to create a volume group name incorporating the hostname + #hn = network.hostname # XXX + hn = "%s.localdomain" % PROCUCT_SNAME + vgnames = [vg.name for vg in self.vgs] + if hn is not None and hn != '': + if hn == 'localhost' or hn == 'localhost.localdomain': + vgtemplate = "VolGroup" + elif hn.find('.') != -1: + hn = safeLvmName(hn) + vgtemplate = "vg_%s" % (hn.split('.')[0].lower(),) + else: + hn = safeLvmName(hn) + vgtemplate = "vg_%s" % (hn.lower(),) + else: + vgtemplate = "VolGroup" + + if vgtemplate not in vgnames and \ + vgtemplate not in lvm.lvm_vg_blacklist: + return vgtemplate + else: + i = 0 + while 1: + tmpname = "%s%02d" % (vgtemplate, i,) + if not tmpname in vgnames and \ + tmpname not in lvm.lvm_vg_blacklist: + break + + i += 1 + if i > 99: + tmpname = "" + + return tmpname + + def createSuggestedLVName(self, vg, swap=None, mountpoint=None): + """ Return a suitable, unused name for a new logical volume. """ + # FIXME: this is not at all guaranteed to work + if mountpoint: + # try to incorporate the mountpoint into the name + if mountpoint == '/': + lvtemplate = 'lv_root' + else: + tmp = safeLvmName(mountpoint) + lvtemplate = "lv_%s" % (tmp,) + else: + if swap: + if len([s for s in self.swaps if s in vg.lvs]): + idx = len([s for s in self.swaps if s in vg.lvs]) + while True: + lvtemplate = "lv_swap%02d" % idx + if lvtemplate in [lv.lvname for lv in vg.lvs]: + idx += 1 + else: + break + else: + lvtemplate = "lv_swap" + else: + idx = len(vg.lvs) + while True: + lvtemplate = "LogVol%02d" % idx + if lvtemplate in [l.lvname for l in vg.lvs]: + idx += 1 + else: + break + + return lvtemplate + + def deviceImmutable(self, device): + """ Return any reason the device cannot be modified/removed. + + Return False if the device can be removed. + + Devices that cannot be removed include: + + - protected partitions + - devices that are part of an md array or lvm vg + - extended partition containing logical partitions that + meet any of the above criteria + + """ + if not isinstance(device, Device): + raise ValueError("arg1 (%s) must be a Device instance" % device) + + if device.name in self.protectedDisks: + return _("This partition is holding the data for the hard " + "drive install.") + elif device.format.type == "mdmember": + for array in self.mdarrays: + if array.dependsOn(device): + if array.minor is not None: + return _("This device is part of the RAID " + "device %s.") % (array.path,) + else: + return _("This device is part of a RAID device.") + elif device.format.type == "lvmpv": + for vg in self.vgs: + if vg.dependsOn(device): + if vg.name is not None: + return _("This device is part of the LVM " + "volume group '%s'.") % (vg.name,) + else: + return _("This device is part of a LVM volume " + "group.") + elif device.format.type == "luks": + try: + luksdev = self.devicetree.getChildren(device)[0] + except IndexError: + pass + else: + return self.deviceImmutable(luksdev) + elif isinstance(device, PartitionDevice) and device.isExtended: + reasons = {} + for dep in self.deviceDeps(device): + reason = self.deviceImmutable(dep) + if reason: + reasons[dep.path] = reason + if reasons: + msg = _("This device is an extended partition which " + "contains logical partitions that cannot be " + "deleted:\n\n") + for dev in reasons: + msg += "%s: %s" % (dev, reasons[dev]) + return msg + + for i in self.devicetree.immutableDevices: + if i[0] == device.name: + return i[1] + + return False + + +class FSSet(object): + """ A class to represent a set of filesystems. """ + def __init__(self, installer): + self.installer = installer + self.devicetree = installer.ds.storage.devicetree + self.cryptTab = None + self.blkidTab = None + self.origFStab = None + self.active = False + self._dev = None + self._devpts = None + self._sysfs = None + self._proc = None + self._devshm = None + + @property + def sysfs(self): + if not self._sysfs: + self._sysfs = NoDevice(format=getFormat("sysfs", + device="sys", + mountpoint="/sys")) + return self._sysfs + + @property + def dev(self): + if not self._dev: + self._dev = DirectoryDevice("/dev", format=getFormat("bind", + device="/dev", + mountpoint="/dev", + exists=True), + exists=True) + + return self._dev + + @property + def devpts(self): + if not self._devpts: + self._devpts = NoDevice(format=getFormat("devpts", + device="devpts", + mountpoint="/dev/pts")) + return self._devpts + + @property + def proc(self): + if not self._proc: + self._proc = NoDevice(format=getFormat("proc", + device="proc", + mountpoint="/proc")) + return self._proc + + @property + def devshm(self): + if not self._devshm: + self._devshm = NoDevice(format=getFormat("tmpfs", + device="tmpfs", + mountpoint="/dev/shm")) + return self._devshm + + @property + def devices(self): + devices = self.devicetree.devices.values() + devices.sort(key=lambda d: d.path) + return devices + + @property + def mountpoints(self): + filesystems = {} + for device in self.devices: + if device.format.mountable and device.format.mountpoint: + filesystems[device.format.mountpoint] = device + return filesystems + + def _parseOneLine(self, (devspec, mountpoint, fstype, options, dump, passno)): + # find device in the tree + device = self.devicetree.resolveDevice(devspec, + cryptTab=self.cryptTab, + blkidTab=self.blkidTab) + if device: + # fall through to the bottom of this block + pass + elif devspec.startswith("/dev/loop"): + # FIXME: create devices.LoopDevice + self.installer.log.warning("completely ignoring your loop mount") + elif ":" in devspec: + # NFS -- preserve but otherwise ignore + device = NFSDevice(devspec, + format=getFormat(fstype, + device=devspec)) + elif devspec.startswith("/") and fstype == "swap": + # swap file + device = FileDevice(devspec, + parents=get_containing_device(devspec, self.devicetree), + format=getFormat(fstype, + device=devspec, + exists=True), + exists=True) + elif fstype == "bind" or "bind" in options: + # bind mount... set fstype so later comparison won't + # turn up false positives + fstype = "bind" + device = FileDevice(devspec, + parents=get_containing_device(devspec, self.devicetree), + exists=True) + device.format = getFormat("bind", + device=device.path, + exists=True) + elif mountpoint in ("/proc", "/sys", "/dev/shm", "/dev/pts"): + # drop these now -- we'll recreate later + return None + else: + # nodev filesystem -- preserve or drop completely? + format = getFormat(fstype) + if devspec == "none" or \ + isinstance(format, get_device_format_class("nodev")): + device = NoDevice(format) + else: + device = StorageDevice(devspec) + + if device is None: + self.installer.log.error("failed to resolve %s (%s) from fstab" % (devspec, + fstype)) + return None + + # make sure, if we're using a device from the tree, that + # the device's format we found matches what's in the fstab + fmt = getFormat(fstype, device=device.path) + if fmt.type != device.format.type: + self.installer.log.warning("scanned format (%s) differs from fstab " + "format (%s)" % (device.format.type, fstype)) + + if device.format.mountable: + device.format.mountpoint = mountpoint + device.format.mountopts = options + + # is this useful? + try: + device.format.options = options + except AttributeError: + pass + + return device + + def parseFSTab(self, chroot=""): + """ parse /etc/fstab + + preconditions: + all storage devices have been scanned, including filesystems + postconditions: + + FIXME: control which exceptions we raise + + XXX do we care about bind mounts? + how about nodev mounts? + loop mounts? + """ + if not chroot or not os.path.isdir(chroot): + chroot = "" + + path = "%s/etc/fstab" % chroot + if not os.access(path, os.R_OK): + # XXX should we raise an exception instead? + self.installer.log.info("cannot open %s for read" % path) + return + + blkidTab = BlkidTab(self.installer, chroot=chroot) + try: + blkidTab.parse() + self.installer.log.debug("blkid.tab devs: %s" % blkidTab.devices.keys()) + except Exception as e: + self.installer.log.info("error parsing blkid.tab: %s" % e) + blkidTab = None + + cryptTab = CryptTab(self.devicetree, blkidTab=blkidTab, chroot=chroot) + try: + cryptTab.parse(chroot=chroot) + self.installer.log.debug("crypttab maps: %s" % cryptTab.mappings.keys()) + except Exception as e: + self.installer.log.info("error parsing crypttab: %s" % e) + cryptTab = None + + self.blkidTab = blkidTab + self.cryptTab = cryptTab + + with open(path) as f: + self.installer.log.debug("parsing %s" % path) + + lines = f.readlines() + + # save the original file + self.origFStab = ''.join(lines) + + for line in lines: + # strip off comments + (line, pound, comment) = line.partition("#") + fields = line.split() + + if not 4 <= len(fields) <= 6: + continue + elif len(fields) == 4: + fields.extend([0, 0]) + elif len(fields) == 5: + fields.append(0) + + (devspec, mountpoint, fstype, options, dump, passno) = fields + + try: + device = self._parseOneLine((devspec, mountpoint, fstype, options, dump, passno)) + except Exception as e: + raise Exception("fstab entry %s is malformed: %s" % (devspec, e)) + + if not device: + continue + + if device not in self.devicetree.devices.values(): + self.devicetree._addDevice(device) + + def fsFreeSpace(self, chroot='/'): + space = [] + for device in self.devices: + if not device.format.mountable or \ + not device.format.status: + continue + + path = "%s/%s" % (chroot, device.format.mountpoint) + try: + space.append((device.format.mountpoint, + isys.pathSpaceAvailable(path))) + except SystemError: + self.installer.log.error("failed to calculate free space for %s" % (device.format.mountpoint,)) + + space.sort(key=lambda s: s[1]) + return space + + def mtab(self): + format = "%s %s %s %s 0 0\n" + mtab = "" + devices = self.mountpoints.values() + self.swapDevices + devices.extend([self.devshm, self.devpts, self.sysfs, self.proc]) + devices.sort(key=lambda d: getattr(d.format, "mountpoint", None)) + for device in devices: + if not device.format.status: + continue + if not device.format.mountable: + continue + if device.format.mountpoint: + options = device.format.mountopts + if options: + options = options.replace("defaults,", "") + options = options.replace("defaults", "") + + if options: + options = "rw," + options + else: + options = "rw" + mtab = mtab + format % (device.path, + device.format.mountpoint, + device.format.type, + options) + return mtab + + def turnOnSwap(self): + intf = self.installer.intf + for device in self.swapDevices: + try: + device.setup() + device.format.setup() + except SuspendError: + if intf: + msg = _("The swap device:\n\n %s\n\n" + "in your /etc/fstab file is currently in " + "use as a software suspend device, " + "which means your system is hibernating. " + "If you are performing a new install, " + "make sure the installer is set " + "to format all swap devices.") \ + % device.path + intf.messageWindow(_("Error"), msg) + sys.exit(0) + except DeviceError as msg: + if intf: + err = _("Error enabling swap device %s: %s\n\n" + "This most likely means this swap " + "device has not been initialized.\n\n" + "Press OK to exit the installer.") % \ + (device.path, msg) + intf.messageWindow(_("Error"), err) + sys.exit(0) + + def mountFilesystems(self, installer, raiseErrors=None, readOnly=None, + skipRoot=False): + intf = installer.intf + devices = self.mountpoints.values() + self.swapDevices + devices.extend([self.dev, self.devshm, self.devpts, self.sysfs, self.proc]) + devices.sort(key=lambda d: getattr(d.format, "mountpoint", None)) + + for device in devices: + if not device.format.mountable or not device.format.mountpoint: + continue + + if skipRoot and device.format.mountpoint == "/": + continue + + options = device.format.options + if "noauto" in options.split(","): + continue + + try: + device.setup() + except Exception as msg: + # FIXME: need an error popup + continue + + if readOnly: + options = "%s,%s" % (options, readOnly) + + try: + device.format.setup(options=options, + chroot=installer.rootPath) + except OSError as (num, msg): + if intf: + if num == errno.EEXIST: + intf.messageWindow(_("Invalid mount point"), + _("An error occurred when trying " + "to create %s. Some element of " + "this path is not a directory. " + "This is a fatal error and the " + "install cannot continue.\n\n" + "Press <Enter> to exit the " + "installer.") + % (device.format.mountpoint,)) + else: + intf.messageWindow(_("Invalid mount point"), + _("An error occurred when trying " + "to create %s: %s. This is " + "a fatal error and the install " + "cannot continue.\n\n" + "Press <Enter> to exit the " + "installer.") + % (device.format.mountpoint, msg)) + self.installer.log.error("OSError: (%d) %s" % (num, msg) ) + sys.exit(0) + except SystemError as (num, msg): + if raiseErrors: + raise + if intf and not device.format.linuxNative: + ret = intf.messageWindow(_("Unable to mount filesystem"), + _("An error occurred mounting " + "device %s as %s. You may " + "continue installation, but " + "there may be problems.") % + (device.path, + device.format.mountpoint), + type="custom", + custom_icon="warning", + custom_buttons=[_("_Exit installer"), + _("_Continue")]) + + if ret == 0: + sys.exit(0) + else: + continue + + self.installer.log.error("SystemError: (%d) %s" % (num, msg) ) + sys.exit(0) + except FSError as msg: + if intf: + intf.messageWindow(_("Unable to mount filesystem"), + _("An error occurred mounting " + "device %s as %s: %s. This is " + "a fatal error and the install " + "cannot continue.\n\n" + "Press <Enter> to exit the " + "installer.") + % (device.path, + device.format.mountpoint, + msg)) + self.installer.log.error("FSError: %s" % msg) + sys.exit(0) + + self.active = True + + def umountFilesystems(self, instPath, ignoreErrors=True, swapoff=True): + devices = self.mountpoints.values() + self.swapDevices + devices.extend([self.dev, self.devshm, self.devpts, self.sysfs, self.proc]) + devices.sort(key=lambda d: getattr(d.format, "mountpoint", None)) + devices.reverse() + for device in devices: + if not device.format.mountable and \ + (device.format.type != "swap" or swapoff): + continue + + device.format.teardown() + device.teardown() + + self.active = False + + def createSwapFile(self, rootPath, device, size): + """ Create and activate a swap file under rootPath. """ + filename = "/SWAP" + count = 0 + basedir = os.path.normpath("%s/%s" % (rootPath, + device.format.mountpoint)) + while os.path.exists("%s/%s" % (basedir, filename)) or \ + self.devicetree.getDeviceByName(filename): + file = os.path.normpath("%s/%s" % (basedir, filename)) + count += 1 + filename = "/SWAP-%d" % count + + dev = FileDevice(filename, + size=size, + parents=[device], + format=getFormat("swap", device=filename)) + dev.create() + dev.setup() + dev.format.create() + dev.format.setup() + # nasty, nasty + self.devicetree._addDevice(dev) + + def mkDevRoot(self, instPath): + root = self.rootDevice + dev = "%s/%s" % (instPath, root.path) + if not os.path.exists("%s/dev/root" %(instPath,)) and os.path.exists(dev): + rdev = os.stat(dev).st_rdev + os.mknod("%s/dev/root" % (instPath,), stat.S_IFBLK | 0600, rdev) + + @property + def swapDevices(self): + swaps = [] + for device in self.devices: + if device.format.type == "swap": + swaps.append(device) + return swaps + + @property + def rootDevice(self): + for device in self.devices: + try: + mountpoint = device.format.mountpoint + except AttributeError: + mountpoint = None + + if mountpoint == "/": + return device + + @property + def migratableDevices(self): + """ List of devices whose filesystems can be migrated. """ + migratable = [] + for device in self.devices: + if device.format.migratable and device.format.exists: + migratable.append(device) + + return migratable + + def write(self, instPath): + """ write out all config files based on the set of filesystems """ + # /etc/fstab + fstab_path = os.path.normpath("%s/etc/fstab" % instPath) + fstab = self.fstab() + open(fstab_path, "w").write(fstab) + + # /etc/crypttab + crypttab_path = os.path.normpath("%s/etc/crypttab" % instPath) + crypttab = self.crypttab() + open(crypttab_path, "w").write(crypttab) + + # /etc/mdadm.conf + mdadm_path = os.path.normpath("%s/etc/mdadm.conf" % instPath) + mdadm_conf = self.mdadmConf() + open(mdadm_path, "w").write(mdadm_conf) + + def crypttab(self): + # if we are upgrading, do we want to update crypttab? + # gut reaction says no, but plymouth needs the names to be very + # specific for passphrase prompting + if not self.cryptTab: + self.cryptTab = CryptTab(self.devicetree) + self.cryptTab.populate() + + devices = self.mountpoints.values() + self.swapDevices + + # prune crypttab -- only mappings required by one or more entries + for name in self.cryptTab.mappings.keys(): + keep = False + mapInfo = self.cryptTab[name] + cryptoDev = mapInfo['device'] + for device in devices: + if device == cryptoDev or device.dependsOn(cryptoDev): + keep = True + break + + if not keep: + del self.cryptTab.mappings[name] + + return self.cryptTab.crypttab() + + def mdadmConf(self): + """ Return the contents of mdadm.conf. """ + arrays = self.devicetree.getDevicesByType("mdarray") + conf = "" + devices = self.mountpoints.values() + self.swapDevices + for array in arrays: + writeConf = False + for device in devices: + if device == array or device.dependsOn(array): + writeConf = True + break + + if writeConf: + conf += array.mdadmConfEntry + + return conf + + def fstab (self): + format = "%-23s %-23s %-7s %-15s %d %d\n" + fstab = """ +# +# /etc/fstab +# Created by pomona on %s +# +# Accessible filesystems, by reference, are maintained under '/dev/disk' +# See man pages fstab(5), findfs(8), mount(8) and/or vol_id(8) for more info +# +""" % time.asctime() + + devices = self.mountpoints.values() + self.swapDevices + devices.extend([self.devshm, self.devpts, self.sysfs, self.proc]) + netdevs = self.devicetree.getDevicesByInstance(NetworkStorageDevice) + for device in devices: + # why the hell do we put swap in the fstab, anyway? + if not device.format.mountable and device.format.type != "swap": + continue + + fstype = device.format.type + if fstype == "swap": + mountpoint = "swap" + options = device.format.options + else: + mountpoint = device.format.mountpoint + options = device.format.mountopts + if not mountpoint: + self.installer.log.warning("%s filesystem on %s has no mountpoint" % \ + (fstype, device.path)) + continue + + options = options or "defaults" + for netdev in netdevs: + if device.dependsOn(netdev): + options = options + ",_netdev" + break + devspec = device.fstabSpec + dump = device.format.dump + if device.format.check and mountpoint == "/": + passno = 1 + elif device.format.check: + passno = 2 + else: + passno = 0 + fstab = fstab + device.fstabComment + fstab = fstab + format % (devspec, mountpoint, fstype, + options, dump, passno) + return fstab + +class PartSpec(object): + def __init__(self, mountpoint=None, fstype=None, size=None, maxSize=None, + grow=False, asVol=False, weight=0): + self.mountpoint = mountpoint + self.fstype = fstype + self.size = size + self.maxSize = maxSize + self.grow = grow + self.asVol = asVol + self.weight = weight + + +class BlkidTab(object): + """ Dictionary-like interface to blkid.tab with device path keys """ + def __init__(self, installer, chroot=""): + self.installer = installer + self.chroot = chroot + self.devices = {} + + def parse(self): + path = "%s/etc/blkid/blkid.tab" % self.chroot + self.installer.log.debug("parsing %s" % path) + with open(path) as f: + for line in f.readlines(): + # this is pretty ugly, but an XML parser is more work than + # is justifiable for this purpose + if not line.startswith("<device "): + continue + + line = line[len("<device "):-len("</device>\n")] + (data, sep, device) = line.partition(">") + if not device: + continue + + self.devices[device] = {} + for pair in data.split(): + try: + (key, value) = pair.split("=") + except ValueError: + continue + + self.devices[device][key] = value[1:-1] # strip off quotes + + def __getitem__(self, key): + return self.devices[key] + + def get(self, key, default=None): + return self.devices.get(key, default) + + +class CryptTab(object): + """ Dictionary-like interface to crypttab entries with map name keys """ + def __init__(self, devicetree, blkidTab=None, chroot=""): + self.devicetree = devicetree + self.blkidTab = blkidTab + self.chroot = chroot + self.mappings = {} + + def parse(self, chroot=""): + """ Parse /etc/crypttab from an existing installation. """ + if not chroot or not os.path.isdir(chroot): + chroot = "" + + path = "%s/etc/crypttab" % chroot + log.debug("parsing %s" % path) + with open(path) as f: + if not self.blkidTab: + try: + self.blkidTab = BlkidTab(chroot=chroot) + self.blkidTab.parse() + except Exception: + self.blkidTab = None + + for line in f.readlines(): + (line, pound, comment) = line.partition("#") + fields = line.split() + if not 2 <= len(fields) <= 4: + continue + elif len(fields) == 2: + fields.extend(['none', '']) + elif len(fields) == 3: + fields.append('') + + (name, devspec, keyfile, options) = fields + + # resolve devspec to a device in the tree + device = self.devicetree.resolveDevice(devspec, + blkidTab=self.blkidTab) + if device: + self.mappings[name] = {"device": device, + "keyfile": keyfile, + "options": options} + + def populate(self): + """ Populate the instance based on the device tree's contents. """ + for device in self.devicetree.devices.values(): + # XXX should we put them all in there or just the ones that + # are part of a device containing swap or a filesystem? + # + # Put them all in here -- we can filter from FSSet + if device.format.type != "luks": + continue + + key_file = device.format.keyFile + if not key_file: + key_file = "none" + + options = device.format.options + if not options: + options = "" + + self.mappings[device.format.mapName] = {"device": device, + "keyfile": key_file, + "options": options} + + def crypttab(self): + """ Write out /etc/crypttab """ + crypttab = "" + for name in self.mappings: + entry = self[name] + crypttab += "%s UUID=%s %s %s\n" % (name, + entry['device'].format.uuid, + entry['keyfile'], + entry['options']) + return crypttab + + def __getitem__(self, key): + return self.mappings[key] + + def get(self, key, default=None): + return self.mappings.get(key, default) diff --git a/pkgs/core/pomona/src/storage/deviceaction.py b/pkgs/core/pomona/src/storage/deviceaction.py new file mode 100644 index 0000000..9361b52 --- /dev/null +++ b/pkgs/core/pomona/src/storage/deviceaction.py @@ -0,0 +1,352 @@ +#!/usr/bin/python + +import copy + +from devices import StorageDevice, PartitionDevice +from formats import getFormat +from errors import * +from udev import * + +# The values are just hints as to the ordering. +# Eg: fsmod and devmod ordering depends on the mod (shrink -v- grow) +ACTION_TYPE_NONE = 0 +ACTION_TYPE_DESTROY = 1000 +ACTION_TYPE_RESIZE = 500 +ACTION_TYPE_MIGRATE = 250 +ACTION_TYPE_CREATE = 100 + +action_strings = {ACTION_TYPE_NONE: "None", + ACTION_TYPE_DESTROY: "Destroy", + ACTION_TYPE_RESIZE: "Resize", + ACTION_TYPE_MIGRATE: "Migrate", + ACTION_TYPE_CREATE: "Create"} + +ACTION_OBJECT_NONE = 0 +ACTION_OBJECT_FORMAT = 1 +ACTION_OBJECT_DEVICE = 2 + +object_strings = {ACTION_OBJECT_NONE: "None", + ACTION_OBJECT_FORMAT: "Format", + ACTION_OBJECT_DEVICE: "Device"} + +RESIZE_SHRINK = 88 +RESIZE_GROW = 89 + +resize_strings = {RESIZE_SHRINK: "Shrink", + RESIZE_GROW: "Grow"} + +def action_type_from_string(type_string): + if type_string is None: + return None + + for (k,v) in action_strings.items(): + if v.lower() == type_string.lower(): + return k + + return resize_type_from_string(type_string) + +def action_object_from_string(type_string): + if type_string is None: + return None + + for (k,v) in object_strings.items(): + if v.lower() == type_string.lower(): + return k + +def resize_type_from_string(type_string): + if type_string is None: + return None + + for (k,v) in resize_strings.items(): + if v.lower() == type_string.lower(): + return k + +class DeviceAction(object): + """ An action that will be carried out in the future on a Device. + + These classes represent actions to be performed on devices or + filesystems. + + The operand Device instance will be modified according to the + action, but no changes will be made to the underlying device or + filesystem until the DeviceAction instance's execute method is + called. The DeviceAction instance's cancel method should reverse + any modifications made to the Device instance's attributes. + + If the Device instance represents a pre-existing device, the + constructor should call any methods or set any attributes that the + action will eventually change. Device/DeviceFormat classes should verify + that the requested modifications are reasonable and raise an + exception if not. + + Only one action of any given type/object pair can exist for any + given device at any given time. This is enforced by the + DeviceTree. + + Basic usage: + + a = DeviceAction(dev) + a.execute() + + OR + + a = DeviceAction(dev) + a.cancel() + + + XXX should we back up the device with a deep copy for forcibly + cancelling actions? + + The downside is that we lose any checking or verification that + would get done when resetting the Device instance's attributes to + their original values. + + The upside is that we would be guaranteed to achieve a total + reversal. No chance of, eg: resizes ending up altering Device + size due to rounding or other miscalculation. +""" + type = ACTION_TYPE_NONE + obj = ACTION_OBJECT_NONE + + def __init__(self, installer, device): + self.installer = installer + if not isinstance(device, StorageDevice): + raise ValueError("arg 1 must be a StorageDevice instance") + self.device = device + + + def execute(self, intf=None): + """ perform the action """ + pass + + def cancel(self): + """ cancel the action """ + pass + + def isDestroy(self): + return self.type == ACTION_TYPE_DESTROY + + def isCreate(self): + return self.type == ACTION_TYPE_CREATE + + def isMigrate(self): + return self.type == ACTION_TYPE_MIGRATE + + def isResize(self): + return self.type == ACTION_TYPE_RESIZE + + def isShrink(self): + return (self.type == ACTION_TYPE_RESIZE and self.dir == RESIZE_SHRINK) + + def isGrow(self): + return (self.type == ACTION_TYPE_RESIZE and self.dir == RESIZE_GROW) + + def isDevice(self): + return self.obj == ACTION_OBJECT_DEVICE + + def isFormat(self): + return self.obj == ACTION_OBJECT_FORMAT + + def __str__(self): + s = "%s %s" % (action_strings[self.type], object_strings[self.obj]) + if self.isResize(): + s += " (%s)" % resize_strings[self.dir] + if self.isFormat(): + if self.device.format: + fmt_type = self.device.format.type + else: + fmt_type = None + s += " %s on" % fmt_type + if self.isMigrate(): + pass + s += " %s (%s)" % (self.device.name, self.device.type) + return s + +class ActionCreateDevice(DeviceAction): + """ Action representing the creation of a new device. """ + type = ACTION_TYPE_CREATE + obj = ACTION_OBJECT_DEVICE + + def __init__(self, installer, device): + # FIXME: assert device.fs is None + DeviceAction.__init__(self, installer, device) + + def execute(self, intf=None): + self.device.create(intf=intf) + + +class ActionDestroyDevice(DeviceAction): + """ An action representing the deletion of an existing device. """ + type = ACTION_TYPE_DESTROY + obj = ACTION_OBJECT_DEVICE + + def __init__(self, installer, device): + # XXX should we insist that device.fs be None? + DeviceAction.__init__(self, installer, device) + if device.exists: + device.teardown() + + def execute(self, intf=None): + self.device.destroy() + + +class ActionResizeDevice(DeviceAction): + """ An action representing the resizing of an existing device. """ + type = ACTION_TYPE_RESIZE + obj = ACTION_OBJECT_DEVICE + + def __init__(self, installer, device, newsize): + if device.currentSize == newsize: + raise ValueError("new size same as old size") + + if not device.resizable: + raise ValueError("device is not resizable") + + DeviceAction.__init__(self, installer, device) + if newsize > device.currentSize: + self.dir = RESIZE_GROW + else: + self.dir = RESIZE_SHRINK + self.origsize = device.targetSize + self.device.targetSize = newsize + + def execute(self, intf=None): + self.device.resize(intf=intf) + + def cancel(self): + self.device.targetSize = self.origsize + + +class ActionCreateFormat(DeviceAction): + """ An action representing creation of a new filesystem. """ + type = ACTION_TYPE_CREATE + obj = ACTION_OBJECT_FORMAT + + def __init__(self, installer, device, format=None): + DeviceAction.__init__(self, installer, device) + if format: + self.origFormat = device.format + if self.device.format.exists: + self.device.format.teardown() + self.device.format = format + else: + self.origFormat = getFormat(None, installer=installer) + + def execute(self, intf=None): + if isinstance(self.device, PartitionDevice): + if self.format.partedFlag is not None: + self.device.setFlag(self.format.partedFlag) + self.device.disk.commit() + + udev_settle() + self.device.setup() + self.device.format.create(intf=intf, + device=self.device.path, + options=self.device.formatArgs) + # Get the UUID now that the format is created + udev_settle() + self.device.updateSysfsPath() + info = udev_get_block_device("/sys%s" % self.device.sysfsPath) + self.device.format.uuid = udev_device_get_uuid(info) + + def cancel(self): + self.device.format = self.origFormat + + @property + def format(self): + return self.device.format + + +class ActionDestroyFormat(DeviceAction): + """ An action representing the removal of an existing filesystem. + + XXX this seems unnecessary + """ + type = ACTION_TYPE_DESTROY + obj = ACTION_OBJECT_FORMAT + + def __init__(self, installer, device): + DeviceAction.__init__(self, installer, device) + # Save a deep copy of the device stack this format occupies. + # This is necessary since the stack of devices and formats + # required to get to this format may get yanked out from under + # us between now and execute. + self._device = copy.deepcopy(device) + self.origFormat = self._device.format + if device.format.exists: + device.format.teardown() + self.device.format = None + + def execute(self, intf=None): + """ wipe the filesystem signature from the device """ + if self.origFormat: + if isinstance(self.device, PartitionDevice) and \ + self.origFormat.partedFlag is not None: + # unset partition flags and commit + self.device.unsetFlag(self.origFormat.partedFlag) + self.device.disk.commit() + udev_settle() + + # set up our copy of the original device stack since the + # reference we got may have had any number of things changed + # since then (most notably, formats removed by this very + # class' constructor) + self._device.setup() + self.origFormat.destroy() + udev_settle() + self._device.teardown() + + def cancel(self): + self.device.format = self.origFormat + + @property + def format(self): + return self.origFormat + + +class ActionResizeFormat(DeviceAction): + """ An action representing the resizing of an existing filesystem. + + XXX Do we even want to support resizing of a filesystem without + also resizing the device it resides on? + """ + type = ACTION_TYPE_RESIZE + obj = ACTION_OBJECT_FORMAT + + def __init__(self, installer, device, newsize): + if device.targetSize == newsize: + raise ValueError("new size same as old size") + + DeviceAction.__init__(self, installer, device) + if newsize > device.format.currentSize: + self.dir = RESIZE_GROW + else: + self.dir = RESIZE_SHRINK + self.origSize = self.device.format.targetSize + self.device.format.targetSize = newsize + + def execute(self, intf=None): + self.device.setup() + self.device.format.doResize(intf=intf) + + def cancel(self): + self.device.format.targetSize = self.origSize + +class ActionMigrateFormat(DeviceAction): + """ An action representing the migration of an existing filesystem. """ + type = ACTION_TYPE_MIGRATE + obj = ACTION_OBJECT_FORMAT + + def __init__(self, installer, device): + if not device.format.migratable or not device.format.exists: + raise ValueError("device format is not migratable") + + DeviceAction.__init__(self, installer, device) + self.device.format.migrate = True + + def execute(self, intf=None): + self.device.setup() + self.device.format.doMigrate(intf=intf) + + def cancel(self): + self.device.format.migrate = False diff --git a/pkgs/core/pomona/src/storage/devicelibs/__init__.py b/pkgs/core/pomona/src/storage/devicelibs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pkgs/core/pomona/src/storage/devicelibs/crypto.py b/pkgs/core/pomona/src/storage/devicelibs/crypto.py new file mode 100644 index 0000000..52c9edd --- /dev/null +++ b/pkgs/core/pomona/src/storage/devicelibs/crypto.py @@ -0,0 +1,109 @@ +# +# crypto.py +# +# 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/. +# +# Author(s): Dave Lehman dlehman@redhat.com +# Martin Sivak msivak@redhat.com +# + +import os +from pycryptsetup import CryptSetup + +from ..errors import * + +def askyes(question): + return True + +def dolog(priority, text): + pass + +def is_luks(device): + cs = CryptSetup(yesDialog = askyes, logFunc = dolog) + return cs.isLuks(device) + +def luks_uuid(device): + cs = CryptSetup(yesDialog = askyes, logFunc = dolog) + return cs.luksUUID(device).strip() + +def luks_status(name): + """True means active, False means inactive (or non-existent)""" + cs = CryptSetup(yesDialog = askyes, logFunc = dolog) + return cs.luksStatus(name)!=0 + +def luks_format(device, + passphrase=None, key_file=None, + cipher=None, key_size=None): + cs = CryptSetup(yesDialog = askyes, logFunc = dolog) + key_file_unlink = False + + if passphrase: + key_file = cs.prepare_passphrase_file(passphrase) + key_file_unlink = True + elif key_file and os.path.isfile(key_file): + pass + else: + raise ValueError("luks_format requires either a passphrase or a key file") + + #None is not considered as default value and pycryptsetup doesn't accept it + #so we need to filter out all Nones + kwargs = {} + kwargs["device"] = device + if cipher: kwargs["cipher"] = cipher + if key_file: kwargs["keyfile"] = key_file + if key_size: kwargs["keysize"] = key_size + + rc = cs.luksFormat(**kwargs) + if key_file_unlink: os.unlink(key_file) + + if rc: + raise CryptoError("luks_format failed for '%s'" % device) + +def luks_open(device, name, passphrase=None, key_file=None): + cs = CryptSetup(yesDialog = askyes, logFunc = dolog) + key_file_unlink = False + + if passphrase: + key_file = cs.prepare_passphrase_file(passphrase) + key_file_unlink = True + elif key_file and os.path.isfile(key_file): + pass + else: + raise ValueError("luks_open requires either a passphrase or a key file") + + rc = cs.luksOpen(device = device, name = name, keyfile = key_file) + if key_file_unlink: os.unlink(key_file) + if rc: + raise CryptoError("luks_open failed for %s (%s)" % (device, name)) + +def luks_close(name): + cs = CryptSetup(yesDialog = askyes, logFunc = dolog) + rc = cs.luksClose(name) + if rc: + raise CryptoError("luks_close failed for %s" % name) + +def luks_add_key(device, + new_passphrase=None, new_key_file=None, + passphrase=None, key_file=None): + cs = CryptSetup(yesDialog = askyes, logFunc = dolog) + return cs.addKey(device, new_passphrase, new_key_file, passphrase, key_file) + + +def luks_remove_key(device, + del_passphrase=None, del_key_file=None, + passphrase=None, key_file=None): + cs = CryptSetup(yesDialog = askyes, logFunc = dolog) + return cs.removeKey(device, del_passphrase, del_key_file, passphrase, key_file) diff --git a/pkgs/core/pomona/src/storage/devicelibs/lvm.py b/pkgs/core/pomona/src/storage/devicelibs/lvm.py new file mode 100644 index 0000000..20fa02a --- /dev/null +++ b/pkgs/core/pomona/src/storage/devicelibs/lvm.py @@ -0,0 +1,115 @@ +#!/usr/bin/python + +import os +import re + +import util + +MAX_LV_SLOTS = 256 + +def has_lvm(): + has_lvm = False + for path in os.environ["PATH"].split(":"): + if os.access("%s/lvm" % path, os.X_OK): + has_lvm = True + break + + if has_lvm: + has_lvm = False + for line in open("/proc/devices").readlines(): + if "device-mapper" in line.split(): + has_lvm = True + break + + return has_lvm + +# Start config_args handling code +# +# Theoretically we can handle all that can be handled with the LVM --config +# argument. For every time we call an lvm_cc (lvm compose config) funciton +# we regenerate the config_args with all global info. +config_args = [] # Holds the final argument list +config_args_data = { "filterRejects": [], # regular expressions to reject. + "filterAccepts": [] } # regexp to accept + +def _composeConfig(): + """lvm command accepts lvm.conf type arguments preceded by --config. """ + global config_args, config_args_data + config_args = [] + + filter_string = "" + rejects = config_args_data["filterRejects"] + # we don't need the accept for now. + # accepts = config_args_data["filterAccepts"] + # if len(accepts) > 0: + # for i in range(len(rejects)): + # filter_string = filter_string + (""a|%s|", " % accpets[i]) + + if len(rejects) > 0: + for i in range(len(rejects)): + filter_string = filter_string + (""r|%s|"," % rejects[i]) + + filter_string = " filter=[%s] " % filter_string.strip(",") + + # As we add config strings we should check them all. + if filter_string == "": + # Nothing was really done. + return + + # devices_string can have (inside the brackets) "dir", "scan", + # "preferred_names", "filter", "cache_dir", "write_cache_state", + # "types", "sysfs_scan", "md_component_detection". see man lvm.conf. + devices_string = " devices {%s} " % (filter_string) # strings can be added + config_string = devices_string # more strings can be added. + config_args = ["--config", config_string] + +def lvm_cc_addFilterRejectRegexp(regexp): + """ Add a regular expression to the --config string.""" + global config_args_data + config_args_data["filterRejects"].append(regexp) + + # compoes config once more. + _composeConfig() + +def lvm_cc_resetFilter(): + global config_args_data + config_args_data["filterRejects"] = [] + config_args_data["filterAccepts"] = [] +# End config_args handling code. + +# Names that should not be used int the creation of VGs +lvm_vg_blacklist = [] +def blacklistVG(name): + global lvm_vg_blacklist + lvm_vg_blacklist.append(name) + +def getPossiblePhysicalExtents(floor=0): + """Returns a list of integers representing the possible values for + the physical extent of a volume group. Value is in KB. + + floor - size (in KB) of smallest PE we care about. + """ + + possiblePE = [] + curpe = 8 + while curpe <= 16384*1024: + if curpe >= floor: + possiblePE.append(curpe) + curpe = curpe * 2 + + return possiblePE + +def getMaxLVSize(): + """ Return the maximum size (in MB) of a logical volume. """ + if util.getArch() in ("x86_64",): #64bit architectures + return (8*1024*1024*1024*1024) #Max is 8EiB (very large number..) + else: + return (16*1024*1024) #Max is 16TiB + +def safeLvmName(name): + tmp = name.strip() + tmp = tmp.replace("/", "_") + tmp = re.sub("[^0-9a-zA-Z._]", "", tmp) + tmp = tmp.lstrip("_") + + return tmp diff --git a/pkgs/core/pomona/src/storage/devicelibs/swap.py b/pkgs/core/pomona/src/storage/devicelibs/swap.py new file mode 100644 index 0000000..6c45d7d --- /dev/null +++ b/pkgs/core/pomona/src/storage/devicelibs/swap.py @@ -0,0 +1,85 @@ +import resource + +import util +import os + +from ..errors import * + +import gettext +_ = lambda x: gettext.ldgettext("pomona", x) + +def mkswap(device, label=''): + argv = [] + if label: + argv.extend(["-L", label]) + argv.append(device) + + rc = util.execWithRedirect("mkswap", argv, + stderr = "/dev/tty5", + stdout = "/dev/tty5", + searchPath=1) + + if rc: + raise SwapError("mkswap failed for '%s'" % device) + +def swapon(device, priority=None): + pagesize = resource.getpagesize() + buf = None + if pagesize > 2048: + num = pagesize + else: + num = 2048 + + try: + fd = os.open(device, os.O_RDONLY) + buf = os.read(fd, num) + except OSError: + pass + finally: + try: + os.close(fd) + except (OSError, UnboundLocalError): + pass + + if buf is not None and len(buf) == pagesize: + sig = buf[pagesize - 10:] + if sig == 'SWAP-SPACE': + raise OldSwapError + if sig == 'S1SUSPEND\x00' or sig == 'S2SUSPEND\x00': + raise SuspendError + + argv = [] + if isinstance(priority, int) and 0 <= priority <= 32767: + argv.extend(["-p", "%d" % priority]) + argv.append(device) + + rc = util.execWithRedirect("swapon", + argv, + stderr = "/dev/tty5", + stdout = "/dev/tty5", + searchPath=1) + + if rc: + raise SwapError("swapon failed for '%s'" % device) + +def swapoff(device): + rc = util.execWithRedirect("swapoff", [device], + stderr = "/dev/tty5", + stdout = "/dev/tty5", + searchPath=1) + + if rc: + raise SwapError("swapoff failed for '%s'" % device) + +def swapstatus(device): + lines = open("/proc/swaps").readlines() + status = False + for line in lines: + if not line.strip(): + continue + + if line.split()[0] == device: + status = True + break + + return status diff --git a/pkgs/core/pomona/src/storage/devices.py b/pkgs/core/pomona/src/storage/devices.py new file mode 100644 index 0000000..3628054 --- /dev/null +++ b/pkgs/core/pomona/src/storage/devices.py @@ -0,0 +1,1698 @@ +#/usr/bin/python + +import copy +import math +import parted +import _ped + +from errors import * +from formats import get_device_format_class, getFormat +from udev import * +from util import notify_kernel, numeric_type + +def devicePathToName(devicePath): + if devicePath.startswith("/dev/"): + name = devicePath[5:] + else: + name = devicePath + + if name.startswith("mapper/"): + name = name[7:] + + return name + +class Device(object): + """ A generic device. + + Device instances know which devices they depend upon (parents + attribute). They do not know which devices depend upon them, but + they do know whether or not they have any dependent devices + (isleaf attribute). + + A Device's setup method should set up all parent devices as well + as the device itself. It should not run the resident format's + setup method. + + Which Device types rely on their parents' formats being active? + DMCryptDevice + + A Device's teardown method should accept the keyword argument + recursive, which takes a boolean value and indicates whether or + not to recursively close parent devices. + + A Device's create method should create all parent devices as well + as the device itself. It should also run the Device's setup method + after creating the device. The create method should not create a + device's resident format. + + Which device type rely on their parents' formats to be created + before they can be created/assembled? + VolumeGroup + DMCryptDevice + + A Device's destroy method should destroy any resident format + before destroying the device itself. + + """ + _type = "generic device" + + def __init__(self, installer, name, parents=None, description=''): + """ Create a Device instance. + + Arguments: + + name -- the device name (generally a device node's basename) + + Keyword Arguments: + + parents -- a list of required Device instances + description -- a string describing the device + + """ + self.installer = installer + + self._name = name + if parents is None: + parents = [] + elif not isinstance(parents, list): + raise ValueError("parents must be a list of Device instances") + self.parents = parents + self.kids = 0 + self.description = description + + for parent in self.parents: + parent.addChild() + + def __deepcopy__(self, memo): + """ Create a deep copy of a Device instance. + + We can't do copy.deepcopy on parted objects, which is okay. + For these parted objects, we just do a shallow copy. + """ + new = self.__class__.__new__(self.__class__) + memo[id(self)] = new + shallow_copy_attrs = ('partedDisk', '_partedDevice', + '_partedPartition', '_origPartedDisk', + '_raidSet', 'installer', 'screen') + for (attr, value) in self.__dict__.items(): + if attr in shallow_copy_attrs: + setattr(new, attr, copy.copy(value)) + else: + setattr(new, attr, copy.deepcopy(value, memo)) + + return new + + def removeChild(self): + self.kids -= 1 + + def addChild(self): + self.kids += 1 + + def setup(self, intf=None): + """ Open, or set up, a device. """ + raise NotImplementedError("setup method not defined for Device") + + def teardown(self, recursive=None): + """ Close, or tear down, a device. """ + raise NotImplementedError("teardown method not defined for Device") + + def create(self, intf=None): + """ Create the device. """ + raise NotImplementedError("create method not defined for Device") + + def destroy(self): + """ Destroy the device. """ + raise NotImplementedError("destroy method not defined for Device") + + def setupParents(self): + """ Run setup method of all parent devices. """ + for parent in self.parents: + parent.setup() + + def teardownParents(self, recursive=None): + """ Run teardown method of all parent devices. """ + for parent in self.parents: + parent.teardown(recursive=recursive) + + def createParents(self): + """ Run create method of all parent devices. """ + self.installer.log.info("NOTE: recursive device creation disabled") + for parent in self.parents: + if not parent.exists: + raise DeviceError("parent device does not exist") + #parent.create() + + def dependsOn(self, dep): + """ Return True if this device depends on dep. """ + # XXX does a device depend on itself? + if dep in self.parents: + return True + + for parent in self.parents: + if parent.dependsOn(dep): + return True + + return False + + @property + def status(self): + """ This device's status. + + For now, this should return a boolean: + True the device is open and ready for use + False the device is not open + """ + return False + + @property + def name(self): + """ This device's name. """ + return self._name + + @property + def isleaf(self): + """ True if this device has no children. """ + return self.kids == 0 + + @property + def typeDescription(self): + """ String describing the device type. """ + return self._type + + @property + def type(self): + """ Device type. """ + return self._type + + @property + def mediaPresent(self): + return True + + +class StorageDevice(Device): + """ A generic storage device. + + A fully qualified path to the device node can be obtained via the + path attribute, although it is not guaranteed to be useful, or + even present, unless the StorageDevice's setup method has been + run. + + StorageDevice instances can optionally contain a filesystem, + represented by an FS instance. A StorageDevice's create method + should create a filesystem if one has been specified. + """ + _type = "storage device" + _devDir = "/dev" + sysfsBlockDir = "class/block" + _resizable = False + + def __init__(self, installer, device, format=None, + size=None, major=None, minor=None, + sysfsPath='', parents=None, exists=None): + """ Create a StorageDevice instance. + + Arguments: + + device -- the device name (generally a device node's basename) + + Keyword Arguments: + + size -- the device's size (units/format TBD) + major -- the device major + minor -- the device minor + sysfsPath -- sysfs device path + format -- a DeviceFormat instance + parents -- a list of required Device instances + description -- a string describing the device + + """ + self.installer = installer + + # allow specification of individual parents + if isinstance(parents, Device): + parents = [parents] + + Device.__init__(self, installer, device, parents=parents) + + self.uuid = None + self._format = None + self._size = numeric_type(size) + self.major = numeric_type(major) + self.minor = numeric_type(minor) + self.sysfsPath = sysfsPath + self.exists = exists + + # this may be handy for disk, dmraid, mpath, mdraid + self.diskLabel = None + + self.format = format + self.fstabComment = "" + self._targetSize = self._size + + self._partedDevice = None + + @property + def partedDevice(self): + if self.exists and self.status and not self._partedDevice: + # We aren't guaranteed to be able to get a device. In + # particular, built-in USB flash readers show up as devices but + # do not always have any media present, so parted won't be able + # to find a device. + try: + self._partedDevice = parted.Device(path=self.path) + except _ped.DeviceException: + pass + + return self._partedDevice + + def _getTargetSize(self): + return self._targetSize + + def _setTargetSize(self, newsize): + self._targetSize = newsize + + targetSize = property(lambda s: s._getTargetSize(), + lambda s, v: s._setTargetSize(v), + doc="Target size of this device") + + @property + def path(self): + """ Device node representing this device. """ + return "%s/%s" % (self._devDir, self.name) + + def updateSysfsPath(self): + """ Update this device's sysfs path. """ + sysfsName = self.name.replace("/", "!") + path = os.path.join("/sys", self.sysfsBlockDir, sysfsName) + self.sysfsPath = os.path.realpath(path)[4:] + self.installer.log.debug("%s sysfsPath set to %s" % (self.name, self.sysfsPath)) + + @property + def formatArgs(self): + """ Device-specific arguments to format creation program. """ + return [] + + @property + def resizable(self): + """ Can this type of device be resized? """ + return self._resizable and self.exists + + def notifyKernel(self): + """ Send a 'change' uevent to the kernel for this device. """ + if not self.exists: + self.installer.log.debug("Not sending change uevent for non-existent device") + return + + if not self.status: + self.installer.log.debug("Not sending change uevent for inactive device") + return + + path = os.path.normpath("/sys/%s" % self.sysfsPath) + try: + notify_kernel(path, action="change") + except Exception, e: + self.installer.log.warning("Failed to notify kernel of change: %s" % e) + + @property + def fstabSpec(self): + spec = self.path + if self.format and self.format.uuid: + spec = "UUID=%s" % self.format.uuid + return spec + + def resize(self, intf=None): + """ Resize the device. + + New size should already be set. + """ + raise NotImplementedError("resize method not defined for StorageDevice") + + def setup(self, intf=None): + """ Open, or set up, a device. """ + if not self.exists: + raise DeviceError("device has not been created") + + self.setupParents() + for parent in self.parents: + parent.format.setup() + + def teardown(self, recursive=None): + """ Close, or tear down, a device. """ + if not self.exists and not recursive: + raise DeviceError("device has not been created") + + if self.status and self.format.exists: + self.format.teardown() + udev_settle(timeout=10) + + if recursive: + self.teardownParents(recursive=recursive) + + def _getSize(self): + """ Get the device's size in MB, accounting for pending changes. """ + if self.exists and not self.mediaPresent: + return 0 + + if self.exists and self.partedDevice: + self._size = self.currentSize + + size = self._size + if self.exists and self.resizable and self.targetSize != size: + size = self.targetSize + + return size + + def _setSize(self, newsize): + """ Set the device's size to a new value. """ + if newsize > self.maxSize: + raise DeviceError("device cannot be larger than %s MB" % + (self.maxSize(),)) + self._size = newsize + + size = property(lambda x: x._getSize(), + lambda x, y: x._setSize(y), + doc="The device's size in MB, accounting for pending changes") + + @property + def currentSize(self): + """ The device's actual size. """ + size = 0 + if self.exists and self.partedDevice: + size = self.partedDevice.getSize() + elif self.exists: + size = self._size + return size + + @property + def minSize(self): + """ The minimum size this device can be. """ + if self.exists: + self.setup() + + if self.format.minSize: + return self.format.minSize + else: + return self.size + + @property + def maxSize(self): + """ The maximum size this device can be. """ + if self.format.maxSize > self.currentSize: + return self.currentSize + else: + return self.format.maxSize + + @property + def status(self): + """ This device's status. + + For now, this should return a boolean: + True the device is open and ready for use + False the device is not open + """ + if not self.exists: + return False + return os.access(self.path, os.W_OK) + + def _setFormat(self, format): + """ Set the Device's format. """ + if not format: + format = getFormat(None, installer=self.installer, device=self.path, exists=self.exists) + if self._format and self._format.status: + # FIXME: self.format.status doesn't mean much + raise DeviceError("Cannot replace active format") + + self._format = format + + def _getFormat(self): + return self._format + + format = property(lambda d: d._getFormat(), + lambda d,f: d._setFormat(f), + doc="The device's formatting.") + + def create(self, intf=None): + """ Create the device. """ + if self.exists: + raise DeviceError("device has already been created") + + self.createParents() + self.setupParents() + self.exists = True + self.setup() + + def destroy(self): + """ Destroy the device. """ + if not self.exists: + raise DeviceError("device has not been created") + + if not self.isleaf: + raise DeviceError("Cannot destroy non-leaf device") + + self.exists = False + + @property + def removable(self): + devpath = os.path.normpath("/sys/%s" % self.sysfsPath) + remfile = os.path.normpath("%s/removable" % devpath) + return (self.sysfsPath and os.path.exists(devpath) and + os.access(remfile, os.R_OK) and + open(remfile).readline().strip() == "1") + +class DiskDevice(StorageDevice): + """ A disk """ + _type = "disk" + + def __init__(self, installer, device, format=None, + size=None, major=None, minor=None, sysfsPath='', \ + parents=None, initcb=None, initlabel=None): + """ Create a DiskDevice instance. + + Arguments: + + device -- the device name (generally a device node's basename) + + Keyword Arguments: + + size -- the device's size (units/format TBD) + major -- the device major + minor -- the device minor + sysfsPath -- sysfs device path + format -- a DeviceFormat instance + parents -- a list of required Device instances + removable -- whether or not this is a removable device + + initcb -- the call back to be used when initiating disk. + initlabel -- whether to start with a fresh disklabel + + + DiskDevices always exist. + """ + self.installer = installer + StorageDevice.__init__(self, self.installer, device, format=format, + size=size, major=major, minor=minor, exists=True, + sysfsPath=sysfsPath, parents=parents) + + self.partedDisk = None + + if self.partedDevice: + if initlabel: + self.partedDisk = self.freshPartedDisk() + else: + try: + self.partedDisk = parted.Disk(device=self.partedDevice) + except _ped.DiskLabelException: + # if we have a cb function use it. else an error. + if initcb is not None and initcb(): + self.partedDisk = parted.freshDisk(device=self.partedDevice, \ + ty = platform.getPlatform(None).diskType) + else: + raise DeviceUserDeniedFormatError("User prefered to not format.") + + # We save the actual state of the disk here. Before the first + # modification (addPartition or removePartition) to the partition + # table we reset self.partedPartition to this state so we can + # perform the modifications one at a time. + if self.partedDisk: + self._origPartedDisk = self.partedDisk.duplicate() + else: + self._origPartedDisk = None + + def freshPartedDisk(self): + labelType = platform.getPlatform(None).diskType + return parted.freshDisk(device=self.partedDevice, ty=labelType) + + @property + def mediaPresent(self): + return self.partedDevice is not None + + @property + def model(self): + return getattr(self.partedDevice, "model", None) + + @property + def size(self): + """ The disk's size in MB """ + return super(DiskDevice, self).size + #size = property(StorageDevice._getSize) + + def resetPartedDisk(self): + """ Reset parted.Disk to reflect the actual layout of the disk. """ + self.partedDisk = self._origPartedDisk + + def removePartition(self, device): + if not self.mediaPresent: + raise DeviceError("Cannot remove partition from disk %s which has no media" % self.name) + + partition = self.partedDisk.getPartitionByPath(device.path) + if partition: + self.partedDisk.removePartition(partition) + + def addPartition(self, device): + if not self.mediaPresent: + raise DeviceError("cannot add partition to disk %s which has no media" % self.name) + + for part in self.partedDisk.partitions: + self.installer.log.debug("Disk %s: partition %s has geom %s" % (self.name, + part.getDeviceNodeName(), + part.geometry)) + + geometry = device.partedPartition.geometry + constraint = parted.Constraint(exactGeom=geometry) + partition = parted.Partition(disk=self.partedDisk, + type=device.partedPartition.type, + geometry=geometry) + self.partedDisk.addPartition(partition, constraint=constraint) + + def probe(self): + """ Probe for any missing information about this device. + + pyparted should be able to tell us anything we want to know. + size, disklabel type, maybe even partition layout + """ + if not self.diskLabel: + self.installer.log.debug("Setting %s diskLabel to %s" % (self.name, + self.partedDisk.type)) + self.diskLabel = self.partedDisk.type + + def commit(self, intf=None): + """ Commit changes to the device. """ + if not self.mediaPresent: + raise DeviceError("cannot commit to disk %s which has no media" % self.name) + + self.setupParents() + self.setup() + + # give committing 5 tries, failing that, raise an exception + attempt = 1 + maxTries = 5 + keepTrying = True + + while keepTrying and (attempt <= maxTries): + try: + self.partedDisk.commit() + keepTrying = False + except parted.DiskException as msg: + self.installer.log.warning(msg) + attempt += 1 + + if keepTrying: + raise DeviceError("cannot commit to disk %s after %d attempts" % (self.name, maxTries,)) + + # commit makes the kernel re-scan the partition table + udev_settle() + + def destroy(self): + """ Destroy the device. """ + if not self.mediaPresent: + raise DeviceError("cannot destroy disk %s which has no media" % self.name) + + self.partedDisk.deleteAllPartitions() + # this is perhaps a separate operation (wiping the disklabel) + self.partedDisk.clobber() + self.partedDisk.commit() + self.teardown() + + def setup(self, intf=None): + """ Open, or set up, a device. """ + if not os.path.exists(self.path): + raise DeviceError("device does not exist") + +class PartitionDevice(StorageDevice): + """ A disk partition. + + On types and flags... + + We don't need to deal with numerical partition types at all. The + only type we are concerned with is primary/logical/extended. Usage + specification is accomplished through the use of flags, which we + will set according to the partition's format. + """ + _type = "partition" + _resizable = True + + def __init__(self, installer, name, format=None, + size=None, grow=False, maxsize=None, + major=None, minor=None, bootable=None, + sysfsPath='', parents=None, exists=None, + partType=None, primary=False, weight=0): + """ Create a PartitionDevice instance. + + Arguments: + + name -- the device name (generally a device node's basename) + + Keyword Arguments: + + exists -- indicates whether this is an existing device + format -- the device's format (DeviceFormat instance) + + For existing partitions: + + parents -- the disk that contains this partition + major -- the device major + minor -- the device minor + sysfsPath -- sysfs device path + + For new partitions: + + partType -- primary,extended,&c (as parted constant) + grow -- whether or not to grow the partition + maxsize -- max size for growable partitions (in MB) + size -- the device's size (in MB) + bootable -- whether the partition is bootable + parents -- a list of potential containing disks + weight -- an initial sorting weight to assign + """ + self.req_disks = [] + self.req_partType = None + self.req_primary = None + self.req_grow = None + self.req_bootable = None + self.req_size = 0 + self.req_base_size = 0 + self.req_max_size = 0 + self.req_base_weight = 0 + + self._bootable = False + + StorageDevice.__init__(self, installer, name, format=format, size=size, + major=major, minor=minor, exists=exists, + sysfsPath=sysfsPath, parents=parents) + + if not exists: + # this is a request, not a partition -- it has no parents + self.req_disks = self.parents[:] + for dev in self.parents: + dev.removeChild() + self.parents = [] + + # FIXME: Validate partType, but only if this is a new partition + # Otherwise, overwrite it with the partition's type. + self._partType = None + self.partedFlags = {} + self._partedPartition = None + + # FIXME: Validate size, but only if this is a new partition. + # For existing partitions we will get the size from + # parted. + + if self.exists: + #self.partedPartition = parted.getPartitionByName(self.path) + self._partedPartition = self.disk.partedDisk.getPartitionByPath(self.path) + if not self._partedPartition: + raise DeviceError("cannot find parted partition instance") + + # collect information about the partition from parted + self.probe() + else: + # XXX It might be worthwhile to create a shit-simple + # PartitionRequest class and pass one to this constructor + # for new partitions. + self.req_name = name + self.req_partType = partType + self.req_primary = primary + self.req_max_size = numeric_type(maxsize) + self.req_grow = grow + self.req_bootable = bootable + + # req_size may be manipulated in the course of partitioning + self.req_size = self._size + + # req_base_size will always remain constant + self.req_base_size = self._size + + self.req_base_weight = weight + + def _setTargetSize(self, newsize): + if newsize != self.currentSize: + # change this partition's geometry in-memory so that other + # partitioning operations can complete (e.g., autopart) + self._targetSize = newsize + disk = self.disk.partedDisk + + # resize the partition's geometry in memory + (constraint, geometry) = self._computeResize(self.partedPartition) + disk.setPartitionGeometry(partition=self.partedPartition, + constraint=constraint, + start=geometry.start, end=geometry.end) + + @property + def path(self): + """ Device node representing this device. """ + if not self.parents: + # Bogus, but code in various places compares devices by path + # So we must return something unique + return self.name + + return "%s/%s" % (self.parents[0]._devDir, self.name) + + @property + def partType(self): + """ Get the partition's type (as parted constant). """ + try: + ptype = self.partedPartition.type + except AttributeError: + ptype = self._partType + + if not self.exists and ptype is None: + ptype = self.req_partType + + return ptype + + @property + def isExtended(self): + return self.partType & parted.PARTITION_EXTENDED + + @property + def isLogical(self): + return self.partType & parted.PARTITION_LOGICAL + + @property + def isPrimary(self): + return self.partType == parted.PARTITION_NORMAL + + @property + def isProtected(self): + return self.partType & parted.PARTITION_PROTECTED + + def _getPartedPartition(self): + return self._partedPartition + + def _setPartedPartition(self, partition): + """ Set this PartitionDevice's parted Partition instance. """ + if partition is None: + path = None + elif isinstance(partition, parted.Partition): + path = partition.path + else: + raise ValueError("partition must be a parted.Partition instance") + + self._partedPartition = partition + self.updateName() + + partedPartition = property(lambda d: d._getPartedPartition(), + lambda d,p: d._setPartedPartition(p)) + + def _getWeight(self): + return self.req_base_weight + + def _setWeight(self, weight): + self.req_base_weight = weight + + weight = property(lambda d: d._getWeight(), + lambda d,w: d._setWeight(w)) + + def updateSysfsPath(self): + """ Update this device's sysfs path. """ + if not self.parents: + self.sysfsPath = '' + + elif self.parents[0]._devDir == "/dev/mapper": + dm_node = dm.dm_node_from_name(self.name) + path = os.path.join("/sys", self.sysfsBlockDir, dm_node) + self.sysfsPath = os.path.realpath(path)[4:] + + else: + StorageDevice.updateSysfsPath(self) + + def updateName(self): + if self.partedPartition is None: + self._name = self.req_name + else: + self._name = \ + devicePathToName(self.partedPartition.getDeviceNodeName()) + + def dependsOn(self, dep): + """ Return True if this device depends on dep. """ + if isinstance(dep, PartitionDevice) and dep.isExtended and self.isLogical: + return True + + return Device.dependsOn(self, dep) + + def _setFormat(self, format): + """ Set the Device's format. """ + StorageDevice._setFormat(self, format) + + def _setBootable(self, bootable): + """ Set the bootable flag for this partition. """ + if self.partedPartition: + if self.flagAvailable(parted.PARTITION_BOOT): + if bootable: + self.setFlag(parted.PARTITION_BOOT) + else: + self.unsetFlag(parted.PARTITION_BOOT) + else: + raise DeviceError(_("boot flag not available for this " + "partition")) + + self._bootable = bootable + else: + self.req_bootable = bootable + + def _getBootable(self): + return self._bootable or self.req_bootable + + bootable = property(_getBootable, _setBootable) + + def flagAvailable(self, flag): + if not self.partedPartition: + return + + return self.partedPartition.isFlagAvailable(flag) + + def getFlag(self, flag): + if not self.partedPartition or not self.flagAvailable(flag): + return + + return self.partedPartition.getFlag(flag) + + def setFlag(self, flag): + if not self.partedPartition or not self.flagAvailable(flag): + return + + self.partedPartition.setFlag(flag) + + def unsetFlag(self, flag): + if not self.partedPartition or not self.flagAvailable(flag): + return + + self.partedPartition.unsetFlag(flag) + + def probe(self): + """ Probe for any missing information about this device. + + size, partition type, flags + """ + if not self.exists: + return + + # this is in MB + self._size = self.partedPartition.getSize() + self.targetSize = self._size + + self._partType = self.partedPartition.type + + self._bootable = self.getFlag(parted.PARTITION_BOOT) + + def create(self, intf=None): + """ Create the device. """ + if self.exists: + raise DeviceError("device already exists") + + self.createParents() + self.setupParents() + + self.disk.addPartition(self) + self.disk.commit() + + self.partedPartition = self.disk.partedDisk.getPartitionByPath(self.path) + + self.exists = True + self.setup() + + def _computeResize(self, partition): + # compute new size for partition + currentGeom = partition.geometry + currentDev = currentGeom.device + newLen = long(self.targetSize * 1024 * 1024) / currentDev.sectorSize + newGeometry = parted.Geometry(device=currentDev, + start=currentGeom.start, + length=newLen) + constraint = parted.Constraint(exactGeom=newGeometry) + + return (constraint, newGeometry) + + def resize(self, intf=None): + """ Resize the device. + + self.targetSize must be set to the new size. + """ + if self.targetSize != self.currentSize: + # partedDisk has been restored to _origPartedDisk, so + # recalculate resize geometry because we may have new + # partitions on the disk, which could change constraints + partition = self.disk.partedDisk.getPartitionByPath(self.path) + (constraint, geometry) = self._computeResize(partition) + + self.disk.partedDisk.setPartitionGeometry(partition=partition, + constraint=constraint, + start=geometry.start, + end=geometry.end) + + self.disk.commit() + self.notifyKernel() + + def destroy(self): + """ Destroy the device. """ + if not self.exists: + raise DeviceError("device has not been created") + + if not self.sysfsPath: + return + + if not self.isleaf: + raise DeviceError("Cannot destroy non-leaf device") + + self.setupParents() + self.disk.removePartition(self) + self.disk.commit() + + self.exists = False + + def _getSize(self): + """ Get the device's size. """ + size = self._size + if self.partedPartition: + # this defaults to MB + size = self.partedPartition.getSize() + return size + + def _setSize(self, newsize): + """ Set the device's size (for resize, not creation). + + Arguments: + + newsize -- the new size (in MB) + + """ + if not self.exists: + raise DeviceError("device does not exist") + + if newsize > self.disk.size: + raise ValueError("partition size would exceed disk size") + + # this defaults to MB + maxAvailableSize = self.partedPartition.getMaxAvailableSize() + + if newsize > maxAvailableSize: + raise ValueError("new size is greater than available space") + + # now convert the size to sectors and update the geometry + geometry = self.partedPartition.geometry + physicalSectorSize = geometry.device.physicalSectorSize + + new_length = (newsize * (1024 * 1024)) / physicalSectorSize + geometry.length = new_length + + def _getDisk(self): + """ The disk that contains this partition.""" + try: + disk = self.parents[0] + except IndexError: + disk = None + return disk + + def _setDisk(self, disk): + """Change the parent. + + Setting up a disk is not trivial. It has the potential to change + the underlying object. If necessary we must also change this object. + """ + if self.disk: + self.disk.removeChild() + + if disk: + self.parents = [disk] + disk.addChild() + else: + self.parents = [] + + disk = property(lambda p: p._getDisk(), lambda p,d: p._setDisk(d)) + + @property + def maxSize(self): + """ The maximum size this partition can be. """ + # XXX: this is MB by default + maxPartSize = self.partedPartition.getMaxAvailableSize() + + if self.format.maxSize > maxPartSize: + return maxPartSize + else: + return self.format.maxSize + +class OpticalDevice(StorageDevice): + """ An optical drive, eg: cdrom, dvd+r, &c. + + XXX Is this useful? + """ + _type = "cdrom" + + def __init__(self, installer, name, major=None, minor=None, exists=None, + format=None, parents=None, sysfsPath=''): + StorageDevice.__init__(self, installer, name, format=format, + major=major, minor=minor, exists=True, + parents=parents, sysfsPath=sysfsPath) + + @property + def mediaPresent(self): + """ Return a boolean indicating whether or not the device contains + media. + """ + if not self.exists: + raise DeviceError("device has not been created", self.path) + + try: + fd = os.open(self.path, os.O_RDONLY) + except OSError as e: + # errno 123 = No medium found + if e.errno == 123: + return False + else: + return True + else: + os.close(fd) + return True + + def eject(self): + """ Eject the drawer. """ + #import _isys + + if not self.exists: + raise DeviceError("device has not been created", self.path) + + # Make a best effort attempt to do the eject. If it fails, it's not + # critical. + fd = os.open(self.path, os.O_RDONLY | os.O_NONBLOCK) + + #try: + # _isys.ejectcdrom(fd) + #except SystemError as e: + # log.warning("error ejecting cdrom %s: %s" % (self.name, e)) + + os.close(fd) + +class DMDevice(StorageDevice): + """ A device-mapper device """ + _type = "dm" + _devDir = "/dev/mapper" + + def __init__(self, installer, name, format=None, size=None, dmUuid=None, + target=None, exists=None, parents=None, sysfsPath=''): + """ Create a DMDevice instance. + + Arguments: + + name -- the device name (generally a device node's basename) + + Keyword Arguments: + + target -- the device-mapper target type (string) + size -- the device's size (units/format TBD) + dmUuid -- the device's device-mapper UUID + sysfsPath -- sysfs device path + format -- a DeviceFormat instance + parents -- a list of required Device instances + exists -- indicates whether this is an existing device + """ + StorageDevice.__init__(self, installer, name, format=format, size=size, + exists=exists, + parents=parents, sysfsPath=sysfsPath) + self.target = target + self.dmUuid = dmUuid + + def __str__(self): + s = StorageDevice.__str__(self) + s += (" target = %(target)s dmUuid = %(dmUuid)s" % + {"target": self.target, "dmUuid": self.dmUuid}) + return s + + @property + def fstabSpec(self): + """ Return the device specifier for use in /etc/fstab. """ + return self.path + + def updateSysfsPath(self): + """ Update this device's sysfs path. """ + if not self.exists: + raise DeviceError("device has not been created") + + if self.status: + dm_node = self.getDMNode() + path = os.path.join("/sys", self.sysfsBlockDir, dm_node) + self.sysfsPath = os.path.realpath(path)[4:] + else: + self.sysfsPath = '' + + #def getTargetType(self): + # return dm.getDmTarget(name=self.name) + + def getDMNode(self): + """ Return the dm-X (eg: dm-0) device node for this device. """ + if not self.exists: + raise DeviceError("device has not been created") + + return dm.dm_node_from_name(self.name) + + def _setName(self, name): + """ Set the device's map name. """ + if self.status: + raise DeviceError("device is active") + + self._name = name + #self.sysfsPath = "/dev/disk/by-id/dm-name-%s" % self.name + + name = property(lambda d: d._name, + lambda d,n: d._setName(n)) + + +class LVMVolumeGroupDevice(DMDevice): + """ An LVM Volume Group + + XXX Maybe this should inherit from StorageDevice instead of + DMDevice since there's no actual device. + """ + _type = "lvmvg" + + def __init__(self, installer, name, parents, size=None, free=None, + peSize=None, peCount=None, peFree=None, pvCount=None, + lvNames=[], uuid=None, exists=None, sysfsPath=''): + """ Create a LVMVolumeGroupDevice instance. + + Arguments: + + name -- the device name (generally a device node's basename) + parents -- a list of physical volumes (StorageDevice) + + Keyword Arguments: + + peSize -- physical extent size (in MB) + exists -- indicates whether this is an existing device + sysfsPath -- sysfs device path + + For existing VG's only: + + size -- the VG's size (in MB) + free -- amount of free space in the VG + peFree -- number of free extents + peCount -- total number of extents + pvCount -- number of PVs in this VG + lvNames -- the names of this VG's LVs + uuid -- the VG's UUID + + """ + self.pvClass = get_device_format_class("lvmpv") + if not self.pvClass: + raise DeviceError("cannot find 'lvmpv' class") + + if isinstance(parents, list): + for dev in parents: + if not isinstance(dev.format, self.pvClass): + raise ValueError("constructor requires a list of PVs") + elif not isinstance(parents.format, self.pvClass): + raise ValueError("constructor requires a list of PVs") + + DMDevice.__init__(self, installer, name, parents=parents, + exists=exists, sysfsPath=sysfsPath) + + self.uuid = uuid + self.free = numeric_type(free) + self.peSize = numeric_type(peSize) + self.peCount = numeric_type(peCount) + self.peFree = numeric_type(peFree) + self.pvCount = numeric_type(pvCount) + self.lvNames = lvNames + + # circular references, here I come + self._lvs = [] + + # TODO: validate peSize if given + if not self.peSize: + self.peSize = 4.0 # MB + + #self.probe() + + def __str__(self): + s = DMDevice.__str__(self) + s += (" free = %(free)s PE Size = %(peSize)s PE Count = %(peCount)s\n" + " PE Free = %(peFree)s PV Count = %(pvCount)s\n" + " LV Names = %(lvNames)s modified = %(modified)s\n" + " extents = %(extents)s free space = %(freeSpace)s\n" + " free extents = %(freeExtents)s\n" + " PVs = %(pvs)s\n" + " LVs = %(lvs)s" % + {"free": self.free, "peSize": self.peSize, "peCount": self.peCount, + "peFree": self.peFree, "pvCount": self.pvCount, + "lvNames": self.lvNames, "modified": self.isModified, + "extents": self.extents, "freeSpace": self.freeSpace, + "freeExtents": self.freeExtents, "pvs": self.pvs, "lvs": self.lvs}) + return s + + def probe(self): + """ Probe for any information about this device. """ + if not self.exists: + raise DeviceError("device has not been created") + + @property + def status(self): + """ The device's status (True means active). """ + if not self.exists: + return False + + # certainly if any of this VG's LVs are active then so are we + for lv in self.lvs: + if lv.status: + return True + + # if any of our PVs are not active then we cannot be + for pv in self.pvs: + if not pv.status: + return False + + # if we are missing some of our PVs we cannot be active + if len(self.pvs) != self.pvCount: + return False + + return True + + def _addDevice(self, device): + """ Add a new physical volume device to the volume group. + + XXX This is for use by device probing routines and is not + intended for modification of the VG. + """ + if not self.exists: + raise DeviceError("device does not exist") + + if not isinstance(device.format, self.pvClass): + raise ValueError("addDevice requires a PV arg") + + if self.uuid and device.format.vgUuid != self.uuid: + raise ValueError("UUID mismatch") + + if device in self.pvs: + raise ValueError("device is already a member of this VG") + + self.parents.append(device) + device.addChild() + + # now see if the VG can be activated + if len(self.parents) == self.pvCount: + self.setup() + + def _removeDevice(self, device): + """ Remove a physical volume from the volume group. + + This is for cases like clearing of preexisting partitions. + """ + try: + self.parents.remove(device) + except ValueError, e: + raise ValueError("cannot remove non-member PV device from VG") + + device.removeChild() + + def setup(self, intf=None): + """ Open, or set up, a device. + + XXX we don't do anything like "vgchange -ay" because we don't + want all of the LVs activated, just the VG itself. + """ + if not self.exists: + raise DeviceError("device has not been created") + + if self.status: + return + + if len(self.parents) < self.pvCount: + raise DeviceError("cannot activate VG with missing PV(s)") + + self.setupParents() + + def teardown(self, recursive=None): + """ Close, or tear down, a device. """ + if not self.exists and not recursive: + raise DeviceError("device has not been created") + + if self.status: + lvm.vgdeactivate(self.name) + + if recursive: + self.teardownParents(recursive=recursive) + + def create(self, intf=None): + """ Create the device. """ + if self.exists: + raise DeviceError("device already exists") + + pv_list = [] + #for pv in self.parents: + # This is a little bit different from other devices in that + # for VG we need the PVs to be formatted before we can create + # the VG. + # pv.create() + # pv.format.create() + # pv_list.append(pv.path) + pv_list = [pv.path for pv in self.parents] + self.createParents() + self.setupParents() + lvm.vgcreate(self.name, pv_list, self.peSize) + # FIXME set / update self.uuid here + self.exists = True + self.setup() + + def destroy(self): + """ Destroy the device. """ + if not self.exists: + raise DeviceError("device has not been created") + + # set up the pvs since lvm needs access to them to do the vgremove + self.setupParents() + + # this sometimes fails for some reason. + try: + lvm.vgreduce(self.name, [], rm=True) + lvm.vgremove(self.name) + except lvm.LVMError: + raise DeviceError("Could not completely remove VG %s" % self.name) + finally: + self.notifyKernel() + self.exists = False + + def reduce(self, pv_list): + """ Remove the listed PVs from the VG. """ + if not self.exists: + raise DeviceError("device has not been created") + + lvm.vgreduce(self.name, pv_list) + # XXX do we need to notify the kernel? + + def _addLogVol(self, lv): + """ Add an LV to this VG. """ + if lv in self._lvs: + raise ValueError("lv is already part of this vg") + + # verify we have the space, then add it + # do not verify for growing vg (because of ks) + if not lv.exists and \ + not [pv for pv in self.pvs if getattr(pv, "req_grow", None)] and \ + lv.size > self.freeSpace: + raise DeviceError("new lv is too large to fit in free space") + + self._lvs.append(lv) + + def _removeLogVol(self, lv): + """ Remove an LV from this VG. """ + if lv not in self.lvs: + raise ValueError("specified lv is not part of this vg") + + self._lvs.remove(lv) + + def _addPV(self, pv): + """ Add a PV to this VG. """ + if pv in self.pvs: + raise ValueError("pv is already part of this vg") + + # for the time being we will not allow vgextend + if self.exists: + raise DeviceError("cannot add pv to existing vg") + + self.parents.append(pv) + pv.addChild() + + def _removePV(self, pv): + """ Remove an PV from this VG. """ + if not pv in self.pvs: + raise ValueError("specified pv is not part of this vg") + + # for the time being we will not allow vgreduce + if self.exists: + raise DeviceError("cannot remove pv from existing vg") + + self.parents.remove(pv) + pv.removeChild() + + # We can't rely on lvm to tell us about our size, free space, &c + # since we could have modifications queued, unless the VG and all of + # its PVs already exist. + # + # -- liblvm may contain support for in-memory devices + + @property + def isModified(self): + """ Return True if the VG has changes queued that LVM is unaware of. """ + modified = True + if self.exists and not filter(lambda d: not d.exists, self.pvs): + modified = False + + return modified + + @property + def size(self): + """ The size of this VG """ + # TODO: just ask lvm if isModified returns False + + # sum up the sizes of the PVs and align to pesize + size = 0 + for pv in self.pvs: + size += max(0, self.align(pv.size - pv.format.peStart)) + + return size + + @property + def extents(self): + """ Number of extents in this VG """ + # TODO: just ask lvm if isModified returns False + + return self.size / self.peSize + + @property + def freeSpace(self): + """ The amount of free space in this VG (in MB). """ + # TODO: just ask lvm if isModified returns False + + # total the sizes of any LVs + used = 0 + size = self.size + self.installer.log.debug("%s size is %dMB" % (self.name, size)) + for lv in self.lvs: + self.installer.log.debug("lv %s (%s) uses %dMB" % (lv.name, lv, lv.size)) + used += self.align(lv.size, roundup=True) + + free = self.size - used + self.installer.log.debug("vg %s has %dMB free" % (self.name, free)) + return free + + @property + def freeExtents(self): + """ The number of free extents in this VG. """ + # TODO: just ask lvm if isModified returns False + return self.freeSpace / self.peSize + + def align(self, size, roundup=None): + """ Align a size to a multiple of physical extent size. """ + size = numeric_type(size) + + if roundup: + round = math.ceil + else: + round = math.floor + + # we want Kbytes as a float for our math + size *= 1024.0 + pesize = self.peSize * 1024.0 + return long((round(size / pesize) * pesize) / 1024) + + @property + def pvs(self): + """ A list of this VG's PVs """ + return self.parents[:] # we don't want folks changing our list + + @property + def lvs(self): + """ A list of this VG's LVs """ + return self._lvs[:] # we don't want folks changing our list + + @property + def complete(self): + """Check if the vg has all its pvs in the system + Return True if complete. + """ + return len(self.pvs) == self.pvCount or not self.exists + +class LVMLogicalVolumeDevice(DMDevice): + """ An LVM Logical Volume """ + _type = "lvmlv" + _resizable = True + + def __init__(self, installer, name, vgdev, size=None, uuid=None, + format=None, exists=None, sysfsPath='', + grow=None, maxsize=None, percent=None): + """ Create a LVMLogicalVolumeDevice instance. + + Arguments: + + name -- the device name (generally a device node's basename) + vgdev -- volume group (LVMVolumeGroupDevice instance) + + Keyword Arguments: + + size -- the device's size (in MB) + uuid -- the device's UUID + sysfsPath -- sysfs device path + format -- a DeviceFormat instance + exists -- indicates whether this is an existing device + + For new (non-existent) LVs only: + + grow -- whether to grow this LV + maxsize -- maximum size for growable LV (in MB) + percent -- percent of VG space to take + + """ + if isinstance(vgdev, list): + if len(vgdev) != 1: + raise ValueError("constructor requires a single LVMVolumeGroupDevice instance") + elif not isinstance(vgdev[0], LVMVolumeGroupDevice): + raise ValueError("constructor requires a LVMVolumeGroupDevice instance") + elif not isinstance(vgdev, LVMVolumeGroupDevice): + raise ValueError("constructor requires a LVMVolumeGroupDevice instance") + DMDevice.__init__(self, installer, name, size=size, format=format, + sysfsPath=sysfsPath, parents=vgdev, + exists=exists) + + self.uuid = uuid + + self.req_grow = None + self.req_max_size = 0 + self.req_size = 0 + self.req_percent = 0 + + if not self.exists: + self.req_grow = grow + self.req_max_size = numeric_type(maxsize) + # XXX should we enforce that req_size be pe-aligned? + self.req_size = self._size + self.req_percent = numeric_type(percent) + + # here we go with the circular references + self.vg._addLogVol(self) + + def __str__(self): + s = DMDevice.__str__(self) + s += (" VG device = %(vgdev)r percent = %(percent)s" % + {"vgdev": self.vg, "percent": self.req_percent}) + return s + + def _setSize(self, size): + size = self.vg.align(numeric_type(size)) + self.installer.log.debug("Trying to set lv %s size to %dMB" % (self.name, size)) + if size <= (self.vg.freeSpace + self._size): + self._size = size + self.targetSize = size + else: + self.installer.log.debug("Failed to set size: %dMB short" % (size - (self.vg.freeSpace + self._size),)) + raise ValueError("Not enough free space in volume group") + + size = property(StorageDevice._getSize, _setSize) + + @property + def vg(self): + """ This Logical Volume's Volume Group. """ + return self.parents[0] + + @property + def path(self): + """ Device node representing this device. """ + # Thank you lvm for this lovely hack. + return "%s/%s-%s" % (self._devDir, self.vg.name.replace("-","--"), + self._name.replace("-","--")) + + def getDMNode(self): + """ Return the dm-X (eg: dm-0) device node for this device. """ + # Thank you lvm for this lovely hack. + if not self.exists: + raise DeviceError("Device has not been created", self.path) + + return dm.dm_node_from_name("%s-%s" % (self.vg.name.replace("-","--"), \ + self._name.replace("-","--"))) + + @property + def name(self): + """ This device's name. """ + return "%s-%s" % (self.vg.name, self._name) + + @property + def lvname(self): + """ The LV's name (not including VG name). """ + return self._name + + @property + def complete(self): + """ Test if vg exits and if it has all pvs. """ + return self.vg.complete + + def setup(self, intf=None): + """ Open, or set up, a device. """ + if not self.exists: + raise DeviceError("Device has not been created", self.path) + + if self.status: + return + + self.vg.setup() + lvm.lvactivate(self.vg.name, self._name) + + # we always probe since the device may not be set up when we want + # information about it + self._size = self.currentSize + + def teardown(self, recursive=None): + """ Close, or tear down, a device. """ + if not self.exists and not recursive: + raise DeviceError("Device has not been created", self.path) + + if self.status and self.format.exists: + self.format.teardown() + udev_settle(timeout=10) + + if self.status: + lvm.lvdeactivate(self.vg.name, self._name) + + if recursive: + # It's likely that teardown of a VG will fail due to other + # LVs being active (filesystems mounted, &c), so don't let + # it bring everything down. + try: + self.vg.teardown(recursive=recursive) + except Exception as e: + log.debug("vg %s teardown failed; continuing" % self.vg.name) + + def create(self, intf=None): + """ Create the device. """ + if self.exists: + raise DeviceError("Device already exists", self.path) + + self.createParents() + self.setupParents() + + # should we use --zero for safety's sake? + lvm.lvcreate(self.vg.name, self._name, self.size) + # FIXME set / update self.uuid here + self.exists = True + self.setup() + + def destroy(self): + """ Destroy the device. """ + if not self.exists: + raise DeviceError("Device has not been created", self.path) + + self.teardown() + # set up the vg's pvs so lvm can remove the lv + self.vg.setupParents() + lvm.lvremove(self.vg.name, self._name) + self.exists = False + + def resize(self, intf=None): + # XXX resize format probably, right? + if not self.exists: + raise DeviceError("Device has not been created", self.path) + + # Setup VG parents (in case they are dmraid partitions for example) + self.vg.setupParents() + + if self.format.exists: + self.format.teardown() + + udev_settle(timeout=10) + lvm.lvresize(self.vg.name, self._name, self.size) diff --git a/pkgs/core/pomona/src/storage/devicetree.py b/pkgs/core/pomona/src/storage/devicetree.py new file mode 100644 index 0000000..8d3a1e1 --- /dev/null +++ b/pkgs/core/pomona/src/storage/devicetree.py @@ -0,0 +1,536 @@ +#!/usr/bin/python + +import os +import block + +import formats + +from devicelibs import lvm +from devices import * +from errors import * +from udev import * + +class DeviceTree: + def __init__(self, installer): + self.installer = installer + self.storage = self.installer.ds.storage + + self._devices = [] + self._actions = [] + + self._ignoredDisks = [] + self.immutableDevices = [] + for disk in self.storage.ignoredDisks: + self.addIgnoredDisk(disk) + + def addIgnoredDisk(self, disk): + self._ignoredDisks.append(disk) + lvm.lvm_cc_addFilterRejectRegexp(disk) + + def populate(self): + """ Locate all storage devices. """ + # each iteration scans any devices that have appeared since the + # previous iteration + old_devices = [] + ignored_devices = [] + while True: + devices = [] + new_devices = udev_get_block_devices() + + for new_device in new_devices: + found = False + for old_device in old_devices: + if old_device['name'] == new_device['name']: + found = True + break + + if not found: + devices.append(new_device) + + if len(devices) == 0: + # nothing is changing -- we are finished building devices + break + + old_devices = new_devices + self.installer.log.info("Devices to scan: %s" % [d['name'] for d in devices]) + for dev in devices: + self.addUdevDevice(dev) + + # After having the complete tree we make sure that the system + # inconsistencies are ignored or resolved. + #for leaf in self.leaves: + # self._handleInconsistencies(leaf) + + #self.teardownAll() + try: + os.unlink("/etc/mdadm.conf") + except OSError: + pass + + @property + def devices(self): + """ Dict with device path keys and Device values. """ + devices = {} + + for device in self._devices: + if device.path in devices: + raise DeviceTreeError("duplicate paths in device tree") + + devices[device.path] = device + + return devices + + @property + def filesystems(self): + """ List of filesystems. """ + #""" Dict with mountpoint keys and filesystem values. """ + filesystems = [] + for dev in self.leaves: + if dev.format and getattr(dev.format, 'mountpoint', None): + filesystems.append(dev.format) + + return filesystems + + @property + def leaves(self): + """ List of all devices upon which no other devices exist. """ + leaves = [d for d in self._devices if d.isleaf] + return leaves + + def teardownAll(self): + """ Run teardown methods on all devices. """ + for device in self.leaves: + try: + device.teardown(recursive=True) + except (DeviceError, DeviceFormatError, LVMError) as e: + self.installer.log.info("Teardown of %s failed: %s" % (device.name, e)) + + def _addDevice(self, newdev): + """ Add a device to the tree. + + Raise ValueError if the device's identifier is already + in the list. + """ + if newdev.path in [d.path for d in self._devices]: + raise ValueError("device is already in tree") + + # make sure this device's parent devices are in the tree already + for parent in newdev.parents: + if parent not in self._devices: + raise DeviceTreeError("parent device not in tree") + + self._devices.append(newdev) + self.installer.log.info("Added %s (%s) to device tree" % (newdev.name, newdev.type)) + #self.installer.log.info(" Status: %s" % newdev.status) + #self.installer.log.info(" Format: %s" % newdev.format.type) + + def _removeDevice(self, dev, force=None, moddisk=True): + """ Remove a device from the tree. + + Only leaves may be removed. + """ + if dev not in self._devices: + raise ValueError("Device '%s' not in tree" % dev.name) + + if not dev.isleaf and not force: + self.installer.log.debug("%s has %d kids" % (dev.name, dev.kids)) + raise ValueError("Cannot remove non-leaf device '%s'" % dev.name) + + # if this is a partition we need to remove it from the parted.Disk + if moddisk and isinstance(dev, PartitionDevice) and \ + dev.disk is not None: + # if this partition hasn't been allocated it could not have + # a disk attribute + if dev.partedPartition.type == parted.PARTITION_EXTENDED and \ + len(dev.disk.partedDisk.getLogicalPartitions()) > 0: + raise ValueError("Cannot remove extended partition %s. " + "Logical partitions present." % dev.name) + + dev.disk.partedDisk.removePartition(dev.partedPartition) + + self._devices.remove(dev) + self.installer.log.debug("Removed %s (%s) from device tree" % (dev.name, + dev.type)) + + for parent in dev.parents: + # Will this cause issues with garbage collection? + # Do we care about garbage collection? At all? + parent.removeChild() + + def isIgnored(self, info): + """ Return True if info is a device we should ignore. + + Arguments: + + info -- a dict representing a udev db entry + + TODO: + + - filtering of SAN/FC devices + - filtering by driver? + + """ + sysfs_path = udev_device_get_sysfs_path(info) + name = udev_device_get_name(info) + if not sysfs_path: + return None + + if name in self._ignoredDisks: + return True + + for ignored in self._ignoredDisks: + if ignored == os.path.basename(os.path.dirname(sysfs_path)): + # this is a partition on a disk in the ignore list + return True + + # Ignore partitions found on the raw disks which are part of a + # dmraidset + for set in self.getDevicesByType("dm-raid array"): + for disk in set.parents: + if disk.name == os.path.basename(os.path.dirname(sysfs_path)): + return True + + # Ignore loop and ram devices, we normally already skip these in + # udev.py: enumerate_block_devices(), but we can still end up trying + # to add them to the tree when they are slaves of other devices, this + # happens for example with the livecd + if name.startswith("loop") or name.startswith("ram"): + return True + + # FIXME: check for virtual devices whose slaves are on the ignore list + + def getDeviceByName(self, name): + found = None + for device in self._devices: + if device.name == name: + found = device + break + return found + + def getDevicesByType(self, device_type): + # TODO: expand this to catch device format types + return [d for d in self._devices if d.type == device_type] + + def getDevicesByInstance(self, device_class): + return [d for d in self._devices if isinstance(d, device_class)] + + def registerAction(self, action): + """ Register an action to be performed at a later time. + + Modifications to the Device instance are handled before we + get here. + """ + if (action.isDestroy() or action.isResize() or \ + (action.isCreate() and action.isFormat())) and \ + action.device not in self._devices: + raise DeviceTreeError("device is not in the tree") + elif (action.isCreate() and action.isDevice()): + # this allows multiple create actions w/o destroy in between; + # we will clean it up before processing actions + #raise DeviceTreeError("device is already in the tree") + if action.device in self._devices: + self._removeDevice(action.device) + for d in self._devices: + if d.path == action.device.path: + self._removeDevice(d) + + if action.isCreate() and action.isDevice(): + self._addDevice(action.device) + elif action.isDestroy() and action.isDevice(): + self._removeDevice(action.device) + elif action.isCreate() and action.isFormat(): + if isinstance(action.device.format, formats.fs.FS) and \ + action.device.format.mountpoint in self.filesystems: + raise DeviceTreeError("mountpoint already in use") + + self.installer.log.debug("Registered action: %s" % action) + self._actions.append(action) + + def addUdevDevice(self, info): + # FIXME: this should be broken up into more discrete chunks + name = udev_device_get_name(info) + uuid = udev_device_get_uuid(info) + sysfs_path = udev_device_get_sysfs_path(info) + + if self.isIgnored(info): + self.installer.log.debug("Ignoring %s (%s)" % (name, sysfs_path)) + return + + self.installer.log.debug("Scanning %s (%s)..." % (name, sysfs_path)) + device = self.getDeviceByName(name) + + # + # The first step is to either look up or create the device + # + if udev_device_is_dm(info): + # try to look up the device + if device is None and uuid: + # try to find the device by uuid + device = self.getDeviceByUuid(uuid) + + if device is None: + device = self.addUdevDMDevice(info) + elif udev_device_is_md(info): + if device is None and uuid: + # try to find the device by uuid + device = self.getDeviceByUuid(uuid) + + if device is None: + device = self.addUdevMDDevice(info) + elif udev_device_is_cdrom(info): + if device is None: + device = self.addUdevOpticalDevice(info) + elif udev_device_is_dmraid(info): + # This is special handling to avoid the "unrecognized disklabel" + # code since dmraid member disks won't have a disklabel. We + # use a StorageDevice because DiskDevices need disklabels. + # Quite lame, but it doesn't matter much since we won't use + # the StorageDevice instances for anything. + if device is None: + device = StorageDevice(name, + major=udev_device_get_major(info), + minor=udev_device_get_minor(info), + sysfsPath=sysfs_path, exists=True) + self._addDevice(device) + elif udev_device_is_disk(info): + if device is None: + device = self.addUdevDiskDevice(info) + elif udev_device_is_partition(info): + if device is None: + device = self.addUdevPartitionDevice(info) + + # now handle the device's formatting + self.handleUdevDeviceFormat(info, device) + + def addUdevDiskDevice(self, info): + name = udev_device_get_name(info) + uuid = udev_device_get_uuid(info) + sysfs_path = udev_device_get_sysfs_path(info) + device = None + + try: + device = DiskDevice(self.installer, name, + major=udev_device_get_major(info), + minor=udev_device_get_minor(info), + sysfsPath=sysfs_path, + initlabel=False) + except DeviceUserDeniedFormatError: #drive not initialized? + self.addIgnoredDisk(name) + return + + self._addDevice(device) + return device + + def addUdevPartitionDevice(self, info): + name = udev_device_get_name(info) + uuid = udev_device_get_uuid(info) + sysfs_path = udev_device_get_sysfs_path(info) + device = None + + disk_name = os.path.basename(os.path.dirname(sysfs_path)) + disk = self.getDeviceByName(disk_name) + + if disk is None: + # create a device instance for the disk + path = os.path.dirname(os.path.realpath(sysfs_path)) + new_info = udev_get_block_device(path) + if new_info: + self.addUdevDevice(new_info) + disk = self.getDeviceByName(disk_name) + + if disk is None: + # if the current device is still not in + # the tree, something has gone wrong + self.installer.log.error("Failure scanning device %s" % disk_name) + return + + try: + device = PartitionDevice(self.installer, name, sysfsPath=sysfs_path, + major=udev_device_get_major(info), + minor=udev_device_get_minor(info), + exists=True, parents=[disk]) + except DeviceError: + # corner case sometime the kernel accepts a partition table + # which gets rejected by parted, in this case we will + # prompt to re-initialize the disk, so simply skip the + # faulty partitions. + return + + self._addDevice(device) + return device + + def addUdevOpticalDevice(self, info): + # Looks like if it has ID_INSTANCE=0:1 we can ignore it. + device = OpticalDevice(self.installer, udev_device_get_name(info), + major=udev_device_get_major(info), + minor=udev_device_get_minor(info), + sysfsPath=udev_device_get_sysfs_path(info)) + self._addDevice(device) + return device + + def handleUdevDeviceFormat(self, info, device): + #log.debug("%s" % info) + name = udev_device_get_name(info) + sysfs_path = udev_device_get_sysfs_path(info) + uuid = udev_device_get_uuid(info) + label = udev_device_get_label(info) + format_type = udev_device_get_format(info) + + format = None + if (not device) or (not format_type) or device.format.type: + # this device has no formatting or it has already been set up + # FIXME: this probably needs something special for disklabels + self.installer.log.debug("no type or existing type for %s, bailing" % (name,)) + return + + # set up the common arguments for the format constructor + args = [format_type] + kwargs = {"uuid": uuid, + "label": label, + "device": device.path, + "exists": True} + + # set up type-specific arguments for the format constructor + if format_type == "crypto_LUKS": + # luks/dmcrypt + kwargs["name"] = "luks-%s" % uuid + elif format_type == "linux_raid_member": + # mdraid + try: + kwargs["mdUuid"] = udev_device_get_md_uuid(info) + except KeyError: + self.installer.log.debug("mdraid member %s has no md uuid" % name) + elif format_type == "LVM2_member": + # lvm + try: + kwargs["vgName"] = udev_device_get_vg_name(info) + except KeyError as e: + self.installer.log.debug("PV %s has no vg_name" % name) + try: + kwargs["vgUuid"] = udev_device_get_vg_uuid(info) + except KeyError: + self.installer.log.debug("PV %s has no vg_uuid" % name) + try: + kwargs["peStart"] = udev_device_get_pv_pe_start(info) + except KeyError: + self.installer.log.debug("PV %s has no pe_start" % name) + + try: + self.installer.log.debug("type detected on '%s' is '%s'" % (name, format_type,)) + device.format = formats.getFormat(format_type, *args, **kwargs) + except FSError, e: + self.installer.log.debug("type '%s' on '%s' invalid, assuming no format - %s" % + (format_type, name, e,)) + device.format = formats.DeviceFormat(self.installer) + return + + # + # now do any special handling required for the device's format + # + #if device.format.type == "luks": + # self.handleUdevLUKSFormat(info, device) + #elif device.format.type == "mdmember": + # self.handleUdevMDMemberFormat(info, device) + #elif device.format.type == "dmraidmember": + # self.handleUdevDMRaidMemberFormat(info, device) + #elif device.format.type == "lvmpv": + # self.handleUdevLVMPVFormat(info, device) + + def handleUdevDMRaidMemberFormat(self, info, device): + name = udev_device_get_name(info) + sysfs_path = udev_device_get_sysfs_path(info) + uuid = udev_device_get_uuid(info) + major = udev_device_get_major(info) + minor = udev_device_get_minor(info) + + def _all_ignored(rss): + retval = True + for rs in rss: + if rs.name not in self._ignoredDisks: + retval = False + break + return retval + + # Have we already created the DMRaidArrayDevice? + rss = block.getRaidSetFromRelatedMem(uuid=uuid, name=name, + major=major, minor=minor) + if len(rss) == 0: + # we ignore the device in the hope that all the devices + # from this set will be ignored. + # FIXME: Can we reformat a raid device? + self.addIgnoredDisk(device.name) + return + + # We ignore the device if all the rss are in self._ignoredDisks + if _all_ignored(rss): + self.addIgnoredDisk(device.name) + return + + for rs in rss: + dm_array = self.getDeviceByName(rs.name) + if dm_array is not None: + # We add the new device. + dm_array._addDevice(device) + else: + # Activate the Raid set. + rs.activate(mknod=True) + + # Create the DMRaidArray + if self.zeroMbr: + cb = lambda: True + else: + cb = lambda: questionInitializeDisk(self.intf, + rs.name) + + # Create the DMRaidArray + if not self.clearPartDisks or \ + rs.name in self.clearPartDisks: + # if the disk contains protected partitions + # we will not wipe the disklabel even if + # clearpart --initlabel was specified + initlabel = self.reinitializeDisks + for protected in self.protectedPartitions: + disk_name = re.sub(r'p\d+$', '', protected) + if disk_name != protected and \ + disk_name == rs.name: + initlabel = False + break + + try: + dm_array = DMRaidArrayDevice(rs.name, + raidSet=rs, + parents=[device], + initcb=cb, + initlabel=initlabel) + + self._addDevice(dm_array) + # Use the rs's object on the device. + # pyblock can return the memebers of a set and the + # device has the attribute to hold it. But ATM we + # are not really using it. Commenting this out until + # we really need it. + #device.format.raidmem = block.getMemFromRaidSet(dm_array, + # major=major, minor=minor, uuid=uuid, name=name) + except DeviceUserDeniedFormatError: + # We should ignore the dmraid and its components + self.addIgnoredDisk(rs.name) + if _all_ignored(rss): + self.addIgnoredDisk(device.name) + rs.deactivate() + + def getDependentDevices(self, dep): + """ Return a list of devices that depend on dep. + + The list includes both direct and indirect dependents. + """ + dependents = [] + + # special handling for extended partitions since the logical + # partitions and their deps effectively depend on the extended + logicals = [] + if isinstance(dep, PartitionDevice) and dep.partType and \ + dep.isExtended: + # collect all of the logicals on the same disk + for part in self.getDevicesByInstance(PartitionDevice): + if part.partType and part.isLogical and part.disk == dep.disk: + logicals.append(part) diff --git a/pkgs/core/pomona/src/storage/errors.py b/pkgs/core/pomona/src/storage/errors.py new file mode 100644 index 0000000..7a02dc0 --- /dev/null +++ b/pkgs/core/pomona/src/storage/errors.py @@ -0,0 +1,107 @@ +#!/usr/bin/python + +class StorageError(Exception): + pass + +# Device +class DeviceError(StorageError): + pass + +class DeviceCreateError(DeviceError): + pass + +class DeviceDestroyError(DeviceError): + pass + +class DeviceResizeError(DeviceError): + pass + +class DeviceSetupError(DeviceError): + pass + +class DeviceTeardownError(DeviceError): + pass + +class DeviceUserDeniedFormatError(DeviceError): + pass + +# DeviceFormat +class DeviceFormatError(StorageError): + pass + +class FormatCreateError(DeviceFormatError): + pass + +class FormatDestroyError(DeviceFormatError): + pass + +class FormatSetupError(DeviceFormatError): + pass + +class FormatTeardownError(DeviceFormatError): + pass + +class DMRaidMemberError(DeviceFormatError): + pass + +class FSError(DeviceFormatError): + pass + +class FSResizeError(FSError): + pass + +class FSMigrateError(FSError): + pass + +class LUKSError(DeviceFormatError): + pass + +class MDMemberError(DeviceFormatError): + pass + +class PhysicalVolumeError(DeviceFormatError): + pass + +class SwapSpaceError(DeviceFormatError): + pass + +# devicelibs +class SwapError(StorageError): + pass + +class SuspendError(SwapError): + pass + +class OldSwapError(SwapError): + pass + +class MDRaidError(StorageError): + pass + +class DMError(StorageError): + pass + +class LVMError(StorageError): + pass + +class CryptoError(StorageError): + pass + +# DeviceTree +class DeviceTreeError(StorageError): + pass + +# DeviceAction +class DeviceActionError(StorageError): + pass + +# partitioning +class PartitioningError(StorageError): + pass + +class PartitioningWarning(StorageError): + pass + +# udev +class UdevError(StorageError): + pass diff --git a/pkgs/core/pomona/src/storage/formats/__init__.py b/pkgs/core/pomona/src/storage/formats/__init__.py new file mode 100644 index 0000000..f73f138 --- /dev/null +++ b/pkgs/core/pomona/src/storage/formats/__init__.py @@ -0,0 +1,318 @@ +#!/usr/bin/python + +import os +import copy + +device_formats = {} +def register_device_format(fmt_class): + if not issubclass(fmt_class, DeviceFormat): + raise ValueError("Argument must be a subclass of DeviceFormat") + device_formats[fmt_class._type] = fmt_class + +def getFormat(fmt_type, *args, **kwargs): + """ Return a DeviceFormat instance based on fmt_type and args. + + Given a device format type and a set of constructor arguments, + return a DeviceFormat instance. + + Return None if no suitable format class is found. + + Arguments: + + fmt_type -- the name of the format type (eg: 'ext3', 'swap') + + Keyword Arguments: + + The keyword arguments may vary according to the format type, + but here is the common set: + + device -- path to the device on which the format resides + uuid -- the UUID of the (preexisting) formatted device + exists -- whether or not the format exists on the device + + """ + fmt_class = get_device_format_class(fmt_type) + fmt = None + if fmt_class: + fmt = fmt_class(*args, **kwargs) + try: + className = fmt.__class__.__name__ + except AttributeError: + className = None + return fmt + +def get_device_format_class(fmt_type): + """ Return an appropriate format class based on fmt_type. """ + if not device_formats: + collect_device_format_classes() + + fmt = device_formats.get(fmt_type) + if not fmt: + for fmt_class in device_formats.values(): + if fmt_type and fmt_type == fmt_class._name: + fmt = fmt_class + break + elif fmt_type in fmt_class._udevTypes: + fmt = fmt_class + break + + # default to no formatting, AKA "Unknown" + if not fmt: + fmt = DeviceFormat + return fmt + +def collect_device_format_classes(): + """ Pick up all device format classes from this directory. + + Note: Modules must call register_device_format(FormatClass) in + order for the format class to be picked up. + """ + dir = os.path.dirname(__file__) + for module_file in os.listdir(dir): + # make sure we're not importing this module + if module_file.endswith(".py") and module_file != __file__: + mod_name = module_file[:-3] + try: + globals()[mod_name] = __import__(mod_name, globals(), locals(), [], -1) + except ImportError, e: + pass + +default_fstypes = ("ext4", "ext3", "ext2") +default_boot_fstypes = ("ext3", "ext2") +def get_default_filesystem_type(boot=None): + if boot: + fstypes = default_boot_fstypes + else: + fstypes = default_fstypes + + for fstype in fstypes: + try: + supported = get_device_format_class(fstype).supported + except AttributeError: + supported = None + + if supported: + return fstype + + raise DeviceFormatError("None of %s is supported by your kernel" % ",".join(fstypes)) + +class DeviceFormat(object): + """ Generic device format. """ + _type = None + _name = "Unknown" + _udevTypes = [] + partedFlag = None + _formattable = False # can be formatted + _supported = False # is supported + _resizable = False # can be resized + _bootable = False # can be used as boot + _migratable = False # can be migrated + _maxSize = 0 # maximum size in MB + _minSize = 0 # minimum size in MB + _dump = False + _check = False + + def __init__(self, installer, *args, **kwargs): + """ Create a DeviceFormat instance. + + Keyword Arguments: + + device -- path to the underlying device + uuid -- this format's UUID + exists -- indicates whether this is an existing format + + """ + self.installer = installer + + self.device = kwargs.get("device") + self.uuid = kwargs.get("uuid") + self.exists = kwargs.get("exists") + self.options = kwargs.get("options") + self._migrate = False + + def __deepcopy__(self, memo): + new = self.__class__.__new__(self.__class__) + memo[id(self)] = new + shallow_copy_attrs = ('installer', 'screen') + for (attr, value) in self.__dict__.items(): + if attr in shallow_copy_attrs: + setattr(new, attr, copy.copy(value)) + else: + setattr(new, attr, copy.deepcopy(value, memo)) + + return new + + def _setOptions(self, options): + self._options = options + + def _getOptions(self): + return self._options + + options = property(_getOptions, _setOptions) + + def _setDevice(self, devspec): + if devspec and not devspec.startswith("/"): + raise ValueError("device must be a fully qualified path: %s" % devspec) + self._device = devspec + + def _getDevice(self): + return self._device + + device = property(lambda f: f._getDevice(), + lambda f,d: f._setDevice(d), + doc="Full path the device this format occupies") + + @property + def name(self): + if self._name: + name = self._name + else: + name = self.type + return name + + @property + def type(self): + return self._type + + def probe(self): + pass + + def notifyKernel(self): + if not self.device: + return + + if self.device.startswith("/dev/mapper/"): + try: + name = dm_node_from_name(os.path.basename(self.device)) + except Exception, e: + self.installer.log.warning("Failed to get dm node for %s" % self.device) + return + elif self.device: + name = os.path.basename(self.device) + + path = get_sysfs_path_by_name(name) + try: + notify_kernel(path, action="change") + except Exception, e: + self.installer.log.warning("Failed to notify kernel of change: %s" % e) + + def create(self, *args, **kwargs): + # allow late specification of device path + device = kwargs.get("device") + if device: + self.device = device + + if not os.path.exists(self.device): + raise FormatCreateError("invalid device specification") + + def destroy(self, *args, **kwargs): + # zero out the 1MB at the beginning and end of the device in the + # hope that it will wipe any metadata from filesystems that + # previously occupied this device + self.installer.log.debug("Zeroing out beginning and end of %s..." % self.device) + try: + fd = os.open(self.device, os.O_RDWR) + buf = '\0' * 1024 * 1024 + os.write(fd, buf) + os.lseek(fd, -1024 * 1024, 2) + os.write(fd, buf) + os.close(fd) + except OSError as e: + if getattr(e, "errno", None) == 28: # No space left in device + pass + else: + self.installer.log.error("Error zeroing out %s: %s" % (self.device, e)) + os.close(fd) + except Exception as e: + self.installer.log.error("Error zeroing out %s: %s" % (self.device, e)) + os.close(fd) + + self.exists = False + + def setup(self, *args, **kwargs): + if not self.exists: + raise FormatSetupError("format has not been created") + + if self.status: + return + + # allow late specification of device path + device = kwargs.get("device") + if device: + self.device = device + + if not self.device or not os.path.exists(self.device): + raise FormatSetupError("invalid device specification") + + def teardown(self, *args, **kwargs): + pass + + @property + def status(self): + return (self.exists and + self.__class__ is not DeviceFormat and + isinstance(self.device, str) and + self.device and + os.path.exists(self.device)) + + @property + def formattable(self): + """ Can we create formats of this type? """ + return self._formattable + + @property + def supported(self): + """ Is this format a supported type? """ + return self._supported + + @property + def resizable(self): + """ Can formats of this type be resized? """ + return self._resizable + + @property + def bootable(self): + """ Is this format type suitable for a boot partition? """ + return self._bootable + + @property + def migratable(self): + """ Can formats of this type be migrated? """ + return self._migratable + + @property + def migrate(self): + return self._migrate + + @property + def linuxNative(self): + """ Is this format type native to linux? """ + return self._linuxNative + + @property + def mountable(self): + """ Is this something we can mount? """ + return False + + @property + def dump(self): + """ Whether or not this format will be dumped by dump(8). """ + return self._dump + + @property + def check(self): + """ Whether or not this format is checked on boot. """ + return self._check + + @property + def maxSize(self): + """ Maximum size (in MB) for this format type. """ + return self._maxSize + + @property + def minSize(self): + """ Minimum size (in MB) for this format type. """ + return self._minSize + + +collect_device_format_classes() diff --git a/pkgs/core/pomona/src/storage/formats/fs.py b/pkgs/core/pomona/src/storage/formats/fs.py new file mode 100644 index 0000000..2eace61 --- /dev/null +++ b/pkgs/core/pomona/src/storage/formats/fs.py @@ -0,0 +1,929 @@ +#!/usr/bin/python + +import os +import tempfile + +import isys + +import util + +from ..errors import * +from . import DeviceFormat, register_device_format + +import gettext +_ = lambda x: gettext.ldgettext("pomona", x) + +fs_configs = {} + +def get_kernel_filesystems(): + fs_list = [] + for line in open("/proc/filesystems").readlines(): + fs_list.append(line.split()[-1]) + return fs_list + +global kernel_filesystems +kernel_filesystems = get_kernel_filesystems() + +class FS(DeviceFormat): + """ Filesystem class. """ + _type = "Abstract Filesystem Class" # fs type name + _mountType = None # like _type but for passing to mount + _name = None + _mkfs = "" # mkfs utility + _modules = [] # kernel modules required for support + _resizefs = "" # resize utility + _labelfs = "" # labeling utility + _fsck = "" # fs check utility + _migratefs = "" # fs migration utility + _defaultFormatOptions = [] # default options passed to mkfs + _defaultMountOptions = ["defaults"] # default options passed to mount + _defaultLabelOptions = [] + _defaultCheckOptions = [] + _defaultMigrateOptions = [] + _migrationTarget = None + lostAndFoundContext = None + + def __init__(self, installer, *args, **kwargs): + """ Create a FS instance. + + Keyword Args: + + device -- path to the device containing the filesystem + mountpoint -- the filesystem's mountpoint + label -- the filesystem label + uuid -- the filesystem UUID + mountopts -- mount options for the filesystem + size -- the filesystem's size in MiB + exists -- indicates whether this is an existing filesystem + + """ + if self.__class__ is FS: + raise TypeError("FS is an abstract class.") + + self.installer = installer + + DeviceFormat.__init__(self, self.installer, *args, **kwargs) + # TODO: fsprofiles and other ways to add format args + self.mountpoint = kwargs.get("mountpoint") + self.mountopts = kwargs.get("mountopts") + self.label = kwargs.get("label") + + # filesystem size does not necessarily equal device size + self._size = kwargs.get("size") + self._mountpoint = None # the current mountpoint when mounted + if self.exists: + self._size = self._getExistingSize() + + self._targetSize = self._size + + if self.supported: + self.loadModule() + + def _setTargetSize(self, newsize): + """ Set a target size for this filesystem. """ + if not self.exists: + raise FSError("filesystem has not been created") + + if newsize is None: + # unset any outstanding resize request + self._targetSize = None + return + + if not self.minSize < newsize < self.maxSize: + raise ValueError("invalid target size request") + + self._targetSize = newsize + + def _getTargetSize(self): + """ Get this filesystem's target size. """ + return self._targetSize + + targetSize = property(_getTargetSize, _setTargetSize, + doc="Target size for this filesystem") + + def _getSize(self): + """ Get this filesystem's size. """ + size = self._size + if self.resizable and self.targetSize != size: + size = self.targetSize + return size + + size = property(_getSize, doc="This filesystem's size, accounting " + "for pending changes") + + def _getExistingSize(self): + """ Determine the size of this filesystem. Filesystem must + exist. + """ + size = 0 + + if self.mountable: + origMountPoint = self._mountpoint + + tmppath = tempfile.mkdtemp(prefix='getsize-', dir='/tmp') + self.mount(mountpoint=tmppath, options="ro") + buf = os.statvfs(tmppath) + self.unmount() + os.rmdir(tmppath) + + self._mountpoint = origMountPoint + + size = (buf.f_frsize * buf.f_blocks) / 1024.0 / 1024.0 + + return size + + @property + def currentSize(self): + """ The filesystem's current actual size. """ + size = 0 + if self.exists: + size = self._size + return float(size) + + def _getFormatOptions(self, options=None): + argv = [] + if options and isinstance(options, list): + argv.extend(options) + argv.extend(self.defaultFormatOptions) + argv.append(self.device) + return argv + + def doFormat(self, *args, **kwargs): + """ Create the filesystem. + + Arguments: + + None + + Keyword Arguments: + + intf -- InstallInterface instance + options -- list of options to pass to mkfs + + """ + intf = kwargs.get("intf") + options = kwargs.get("options") + + if self.exists: + raise FormatCreateError("filesystem already exists", self.device) + + if not self.formattable: + return + + if not self.mkfsProg: + return + + if self.exists: + return + + if not os.path.exists(self.device): + raise FormatCreateError("device does not exist", self.device) + + argv = self._getFormatOptions(options=options) + + self.installer.window = None + self.installer.window = self.installer.intf.progressWindow(_("Formatting"), + _("Creating filesystem on %s...") % (self.device,), + 100, pulse = True) + + try: + rc = util.execWithPulseProgress(self.mkfsProg, + argv, + stdout="/dev/tty5", + stderr="/dev/tty5", + progress=w) + except Exception as e: + raise FormatCreateError(e, self.device) + finally: + if self.installer.window: + self.installer.window.pop() + + if rc: + raise FormatCreateError("format failed: %s" % rc, self.device) + + self.exists = True + self.notifyKernel() + + def doMigrate(self, intf=None): + if not self.exists: + raise FSError("filesystem has not been created") + + if not self.migratable or not self.migrate: + return + + if not os.path.exists(self.device): + raise FSError("device does not exist") + + # if journal already exists skip + if isys.ext2HasJournal(self.device): + self.installer.log.info("Skipping migration of %s, has a journal already." % self.device) + return + + argv = self._defaultMigrateOptions[:] + argv.append(self.device) + try: + rc = util.execWithRedirect(self.migratefsProg, + argv, + stdout = "/dev/tty5", + stderr = "/dev/tty5", + searchPath = 1) + except Exception as e: + raise FSMigrateError("filesystem migration failed: %s" % e, self.device) + + if rc: + raise FSMigrateError("filesystem migration failed: %s" % rc, self.device) + + # the other option is to actually replace this instance with an + # instance of the new filesystem type. + self._type = self.migrationTarget + + @property + def resizeArgs(self): + argv = [self.device, "%d" % (self.targetSize,)] + return argv + + def doResize(self, *args, **kwargs): + """ Resize this filesystem to new size @newsize. + + Arguments: + + None + + Keyword Arguments: + + intf -- InstallInterface instance + + """ + intf = kwargs.get("intf") + + if not self.exists: + raise FSResizeError("filesystem does not exist", self.device) + + if not self.resizable: + raise FSResizeError("filesystem not resizable", self.device) + + if self.targetSize == self.currentSize: + return + + if not self.resizefsProg: + return + + if not os.path.exists(self.device): + raise FSResizeError("device does not exist", self.device) + + self.doCheck(intf=intf) + + w = None + if intf: + w = intf.progressWindow(_("Resizing"), + _("Resizing filesystem on %s...") + % (self.device,), + 100, pulse = True) + + try: + rc = util.execWithPulseProgress(self.resizefsProg, + self.resizeArgs, + stdout="/dev/tty5", + stderr="/dev/tty5", + progress=w) + except Exception as e: + raise FSResizeError(e, self.device) + finally: + if w: + w.pop() + + if rc: + raise FSResizeError("resize failed: %s" % rc, self.device) + + # XXX must be a smarter way to do this + self._size = self.targetSize + self.notifyKernel() + + def _getCheckArgs(self): + argv = [] + argv.extend(self.defaultCheckOptions) + argv.append(self.device) + return argv + + def doCheck(self, intf=None): + if not self.exists: + raise FSError("filesystem has not been created") + + if not self.fsckProg: + return + + if not os.path.exists(self.device): + raise FSError("device does not exist") + + w = None + if intf: + w = intf.progressWindow(_("Checking"), + _("Checking filesystem on %s...") + % (self.device), + 100, pulse = True) + + try: + rc = util.execWithPulseProgress(self.fsckProg, + self._getCheckArgs(), + stdout="/dev/tty5", + stderr="/dev/tty5", + progress = w) + except Exception as e: + raise FSError("filesystem check failed: %s" % e) + finally: + if w: + w.pop() + + if rc >= 4: + raise FSError("filesystem check failed: %s" % rc) + + def loadModule(self): + """Load whatever kernel module is required to support this filesystem.""" + global kernel_filesystems + + if not self._modules or self.mountType in kernel_filesystems: + return + + for module in self._modules: + try: + rc = util.execWithRedirect("modprobe", [module], + stdout="/dev/tty5", stderr="/dev/tty5", + searchPath=1) + except Exception as e: + self.installer.log.error("Could not load kernel module %s: %s" % (module, e)) + self._supported = False + return + + if rc: + self.installer.log.error("Could not load kernel module %s" % module) + self._supported = False + return + + # If we successfully loaded a kernel module, for this filesystem, we + # also need to update the list of supported filesystems. + kernel_filesystems = get_kernel_filesystems() + + def mount(self, *args, **kwargs): + """ Mount this filesystem. + + Arguments: + + None + + Keyword Arguments: + + options -- mount options (overrides all other option strings) + chroot -- prefix to apply to mountpoint + mountpoint -- mountpoint (overrides self.mountpoint) + """ + options = kwargs.get("options", "") + chroot = kwargs.get("chroot", "/") + mountpoint = kwargs.get("mountpoint") + + if not self.exists: + raise FSError("filesystem has not been created") + + if not mountpoint: + mountpoint = self.mountpoint + + if not mountpoint: + raise FSError("no mountpoint given") + + if self.status: + return + + if not isinstance(self, NoDevFS) and not os.path.exists(self.device): + raise FSError("device %s does not exist" % self.device) + + # XXX os.path.join is FUBAR: + # + # os.path.join("/mnt/foo", "/") -> "/" + # + #mountpoint = os.path.join(chroot, mountpoint) + mountpoint = os.path.normpath("%s/%s" % (chroot, mountpoint)) + util.mkdirChain(mountpoint) + + # passed in options override default options + if not options or not isinstance(options, str): + options = self.options + + try: + rc = isys.mount(self.device, mountpoint, + fstype=self.mountType, + options=options, + bindMount=isinstance(self, BindFS)) + except Exception as e: + raise FSError("mount failed: %s" % e) + + if rc: + raise FSError("mount failed: %s" % rc) + + self._mountpoint = mountpoint + + def unmount(self): + """ Unmount this filesystem. """ + if not self.exists: + raise FSError("filesystem has not been created") + + if not self._mountpoint: + # not mounted + return + + if not os.path.exists(self._mountpoint): + raise FSError("mountpoint does not exist") + + rc = isys.umount(self._mountpoint, removeDir = False) + if rc: + raise FSError("umount failed") + + self._mountpoint = None + + def _getLabelArgs(self, label): + argv = [] + argv.extend(self.defaultLabelOptions) + argv.extend([self.device, label]) + return argv + + def writeLabel(self, label): + """ Create a label for this filesystem. """ + if not self.exists: + raise FSError("filesystem has not been created") + + if not self.labelfsProg: + return + + if not os.path.exists(self.device): + raise FSError("device does not exist") + + argv = self._getLabelArgs(label) + rc = util.execWithRedirect(self.labelfsProg, + argv, + stderr="/dev/tty5", + searchPath=1) + if rc: + raise FSError("label failed") + + self.label = label + self.notifyKernel() + + @property + def isDirty(self): + return False + + @property + def mkfsProg(self): + """ Program used to create filesystems of this type. """ + return self._mkfs + + @property + def fsckProg(self): + """ Program used to check filesystems of this type. """ + return self._fsck + + @property + def resizefsProg(self): + """ Program used to resize filesystems of this type. """ + return self._resizefs + + @property + def labelfsProg(self): + """ Program used to manage labels for this filesystem type. """ + return self._labelfs + + @property + def migratefsProg(self): + """ Program used to migrate filesystems of this type. """ + return self._migratefs + + @property + def migrationTarget(self): + return self._migrationTarget + + @property + def utilsAvailable(self): + # we aren't checking for fsck because we shouldn't need it + for prog in [self.mkfsProg, self.resizefsProg, self.labelfsProg]: + if not prog: + continue + + if not filter(lambda d: os.access("%s/%s" % (d, prog), os.X_OK), + os.environ["PATH"].split(":")): + return False + + return True + + @property + def supported(self): + return self._supported and self.utilsAvailable + + @property + def mountable(self): + return (self.mountType in kernel_filesystems) or \ + (os.access("/sbin/mount.%s" % (self.mountType,), os.X_OK)) + + @property + def defaultFormatOptions(self): + """ Default options passed to mkfs for this filesystem type. """ + # return a copy to prevent modification + return self._defaultFormatOptions[:] + + @property + def defaultMountOptions(self): + """ Default options passed to mount for this filesystem type. """ + # return a copy to prevent modification + return self._defaultMountOptions[:] + + @property + def defaultLabelOptions(self): + """ Default options passed to labeler for this filesystem type. """ + # return a copy to prevent modification + return self._defaultLabelOptions[:] + + @property + def defaultCheckOptions(self): + """ Default options passed to checker for this filesystem type. """ + # return a copy to prevent modification + return self._defaultCheckOptions[:] + + def _getOptions(self): + options = ",".join(self.defaultMountOptions) + if self.mountopts: + # XXX should we clobber or append? + options = self.mountopts + return options + + def _setOptions(self, options): + self.mountopts = options + + options = property(_getOptions, _setOptions) + + @property + def migratable(self): + """ Can filesystems of this type be migrated? """ + return bool(self._migratable and self.migratefsProg and + filter(lambda d: os.access("%s/%s" + % (d, self.migratefsProg,), + os.X_OK), + os.environ["PATH"].split(":")) and + self.migrationTarget) + + def _setMigrate(self, migrate): + if not migrate: + self._migrate = migrate + return + + if self.migratable and self.exists: + self._migrate = migrate + else: + raise ValueError("Cannot set migrate on non-migratable filesystem") + + migrate = property(lambda f: f._migrate, lambda f,m: f._setMigrate(m)) + + @property + def type(self): + _type = self._type + if self.migrate: + _type = self.migrationTarget + + return _type + + @property + def mountType(self): + if not self._mountType: + self._mountType = self._type + + return self._mountType + + # These methods just wrap filesystem-specific methods in more + # generically named methods so filesystems and formatted devices + # like swap and LVM physical volumes can have a common API. + def create(self, *args, **kwargs): + if self.exists: + raise FSError("Filesystem already exists") + + DeviceFormat.create(self, *args, **kwargs) + + return self.doFormat(*args, **kwargs) + + def setup(self, *args, **kwargs): + """ Mount the filesystem. + + THe filesystem will be mounted at the directory indicated by + self.mountpoint. + """ + return self.mount(**kwargs) + + def teardown(self, *args, **kwargs): + return self.unmount(*args, **kwargs) + + @property + def status(self): + # FIXME check /proc/mounts or similar + if not self.exists: + return False + return self._mountpoint is not None + + +class Ext2FS(FS): + """ ext2 filesystem. """ + _type = "ext2" + _mkfs = "mke2fs" + _modules = ["ext2"] + _resizefs = "resize2fs" + _labelfs = "e2label" + _fsck = "e2fsck" + _formattable = True + _supported = True + _resizable = True + _bootable = True + _linuxNative = True + _maxSize = 8 * 1024 * 1024 + _minSize = 0 + _defaultFormatOptions = [] + _defaultMountOptions = ["defaults"] + _defaultCheckOptions = ["-f", "-p", "-C", "0"] + _dump = True + _check = True + _migratable = True + _migrationTarget = "ext3" + _migratefs = "tune2fs" + _defaultMigrateOptions = ["-j"] + + @property + def minSize(self): + """ Minimum size for this filesystem in MB. """ + size = self._minSize + if self.exists and os.path.exists(self.device): + buf = util.execWithCapture(self.resizefsProg, + ["-P", self.device], + stderr="/dev/tty5") + size = None + for line in buf.splitlines(): + if "minimum size of the filesystem:" not in line: + continue + + (text, sep, minSize) = line.partition(": ") + + size = int(minSize) / 1024.0 + + if size is None: + self.installer.log.warning("failed to get minimum size for %s filesystem " + "on %s" % (self.mountType, self.device)) + size = self._minSize + + return size + + @property + def isDirty(self): + return isys.ext2IsDirty(self.device) + + @property + def resizeArgs(self): + argv = ["-p", self.device, "%dM" % (self.targetSize,)] + return argv + +register_device_format(Ext2FS) + + +class Ext3FS(Ext2FS): + """ ext3 filesystem. """ + _type = "ext3" + _defaultFormatOptions = ["-t", "ext3"] + _migrationTarget = "ext4" + _modules = ["ext3"] + _defaultMigrateOptions = ["-O", "extents"] + + @property + def migratable(self): + """ Can filesystems of this type be migrated? """ + return (flags.cmdline.has_key("ext4migrate") and + Ext2FS.migratable) + +register_device_format(Ext3FS) + + +class Ext4FS(Ext3FS): + """ ext4 filesystem. """ + _type = "ext4" + _bootable = False + _defaultFormatOptions = ["-t", "ext4"] + _migratable = False + _modules = ["ext4"] + +register_device_format(Ext4FS) + + +class FATFS(FS): + """ FAT filesystem. """ + _type = "vfat" + _mkfs = "mkdosfs" + _modules = ["vfat"] + _labelfs = "dosfslabel" + _fsck = "dosfsck" + _formattable = True + _maxSize = 1024 * 1024 + _defaultMountOptions = ["umask=0077", "shortname=winnt"] + +register_device_format(FATFS) + + +class BTRFS(FS): + """ btrfs filesystem """ + _type = "btrfs" + _mkfs = "mkfs.btrfs" + _modules = ["btrfs"] + _resizefs = "btrfsctl" + _formattable = True + _linuxNative = True + _bootable = False + _maxLabelChars = 256 + _supported = True + _dump = True + _check = True + _maxSize = 16 * 1024 * 1024 + + def _getFormatOptions(self, options=None): + argv = [] + if options and isinstance(options, list): + argv.extend(options) + argv.extend(self.defaultFormatOptions) + if self.label: + argv.extend(["-L", self.label]) + argv.append(self.device) + return argv + + @property + def resizeArgs(self): + argv = ["-r", "%dm" % (self.targetSize,), self.device] + return argv + +register_device_format(BTRFS) + +class XFS(FS): + """ XFS filesystem """ + _type = "xfs" + _mkfs = "mkfs.xfs" + _modules = ["xfs"] + _labelfs = "xfs_admin" + _defaultFormatOptions = ["-f"] + _defaultLabelOptions = ["-L"] + _maxLabelChars = 16 + _maxSize = 16 * 1024 * 1024 + _formattable = True + _linuxNative = True + _supported = True + _dump = True + _check = True + +register_device_format(XFS) + +class NTFS(FS): + """ ntfs filesystem. """ + _type = "ntfs" + _resizefs = "ntfsresize" + _fsck = "ntfsresize" + _resizable = True + _minSize = 1 + _maxSize = 16 * 1024 * 1024 + _defaultMountOptions = ["defaults"] + _defaultCheckOptions = ["-c"] + + @property + def minSize(self): + """ The minimum filesystem size in megabytes. """ + size = self._minSize + if self.exists and os.path.exists(self.device): + minSize = None + buf = util.execWithCapture(self.resizefsProg, + ["-m", self.device], + stderr = "/dev/tty5") + for l in buf.split("\n"): + if not l.startswith("Minsize"): + continue + try: + min = l.split(":")[1].strip() + minSize = int(min) + 250 + except Exception, e: + minSize = None + self.installer.log.warning("Unable to parse output for minimum size on %s: %s" %(self.device, e)) + + if minSize is None: + self.installer.log.warning("Unable to discover minimum size of filesystem " + "on %s" %(self.device,)) + else: + size = minSize + + return size + + @property + def resizeArgs(self): + # You must supply at least two '-f' options to ntfsresize or + # the proceed question will be presented to you. + argv = ["-ff", "-s", "%dM" % (self.targetSize,), self.device] + return argv + +register_device_format(NTFS) + + +# if this isn't going to be mountable it might as well not be here +class NFS(FS): + """ NFS filesystem. """ + _type = "nfs" + _modules = ["nfs"] + + def _deviceCheck(self, devspec): + if devspec is not None and ":" not in devspec: + raise ValueError("device must be of the form <host>:<path>") + + @property + def mountable(self): + return False + + def _setDevice(self, devspec): + self._deviceCheck(devspec) + self._device = devspec + + def _getDevice(self): + return self._device + + device = property(lambda f: f._getDevice(), + lambda f,d: f._setDevice(d), + doc="Full path the device this format occupies") + +register_device_format(NFS) + + +class NFSv4(NFS): + """ NFSv4 filesystem. """ + _type = "nfs4" + _modules = ["nfs4"] + +register_device_format(NFSv4) + + +class Iso9660FS(FS): + """ ISO9660 filesystem. """ + _type = "iso9660" + _formattable = False + _supported = True + _resizable = False + _bootable = False + _linuxNative = False + _dump = False + _check = False + _migratable = False + _defaultMountOptions = ["ro"] + +register_device_format(Iso9660FS) + + +class NoDevFS(FS): + """ nodev filesystem base class """ + _type = "nodev" + + def __init__(self, *args, **kwargs): + FS.__init__(self, *args, **kwargs) + self.exists = True + self.device = self.type + + def _setDevice(self, devspec): + self._device = devspec + +register_device_format(NoDevFS) + + +class DevPtsFS(NoDevFS): + """ devpts filesystem. """ + _type = "devpts" + _defaultMountOptions = ["gid=5", "mode=620"] + +register_device_format(DevPtsFS) + + +# these don't really need to be here +class ProcFS(NoDevFS): + _type = "proc" + +register_device_format(ProcFS) + + +class SysFS(NoDevFS): + _type = "sysfs" + +register_device_format(SysFS) + + +class TmpFS(NoDevFS): + _type = "tmpfs" + +register_device_format(TmpFS) + + +class BindFS(FS): + _type = "bind" + + @property + def mountable(self): + return True + +register_device_format(BindFS) diff --git a/pkgs/core/pomona/src/storage/formats/luks.py b/pkgs/core/pomona/src/storage/formats/luks.py new file mode 100644 index 0000000..25d9db4 --- /dev/null +++ b/pkgs/core/pomona/src/storage/formats/luks.py @@ -0,0 +1,187 @@ +#!/usr/bin/python + +import os + +from ..errors import * +#from ..devicelibs import crypto +from . import DeviceFormat, register_device_format + +import gettext +_ = lambda x: gettext.ldgettext("pomona", x) + +class LUKS(DeviceFormat): + """ A LUKS device. """ + _type = "luks" + _name = "LUKS" + _udevTypes = ["crypto_LUKS"] + _formattable = True # can be formatted + _supported = False # is supported + _linuxNative = True # for clearpart + + def __init__(self, *args, **kwargs): + """ Create a LUKS instance. + + Keyword Arguments: + + device -- the path to the underlying device + name -- the name of the mapped device + uuid -- this device's UUID + passphrase -- device passphrase (string) + key_file -- path to a file containing a key (string) + cipher -- cipher mode string + key_size -- key size in bits + exists -- indicates whether this is an existing format + """ + DeviceFormat.__init__(self, *args, **kwargs) + self.cipher = kwargs.get("cipher") + self.key_size = kwargs.get("key_size") + self.mapName = kwargs.get("name") + + if not self.exists and not self.cipher: + self.cipher = "aes-xts-plain" + if not self.key_size: + # default to the max (512 bits) for aes-xts + self.key_size = 512 + + # FIXME: these should both be lists, but managing them will be a pain + self.__passphrase = kwargs.get("passphrase") + self._key_file = kwargs.get("key_file") + + if not self.mapName and self.exists and self.uuid: + self.mapName = "luks-%s" % self.uuid + elif not self.mapName and self.device: + self.mapName = "luks-%s" % os.path.basename(self.device) + + def _setPassphrase(self, passphrase): + """ Set the passphrase used to access this device. """ + self.__passphrase = passphrase + + passphrase = property(fset=_setPassphrase) + + @property + def hasKey(self): + return (self.__passphrase or + (self._key_file and os.access(self._key_file, os.R_OK))) + + @property + def configured(self): + """ To be ready we need a key or passphrase and a map name. """ + return self.hasKey and self.mapName + + @property + def status(self): + if not self.exists or not self.mapName: + return False + return os.path.exists("/dev/mapper/%s" % self.mapName) + + def probe(self): + """ Probe for any missing information about this format. + + cipher mode, key size + """ + raise NotImplementedError("Probe method not defined for LUKS") + + def setup(self, *args, **kwargs): + """ Open, or set up, the format. """ + if not self.configured: + raise LUKSError("luks device not configured") + + if self.status: + return + + DeviceFormat.setup(self, *args, **kwargs) + crypto.luks_open(self.device, self.mapName, + passphrase=self.__passphrase, + key_file=self._key_file) + + def teardown(self, *args, **kwargs): + """ Close, or tear down, the format. """ + if not self.exists: + raise LUKSError("format has not been created") + + if self.status: + log.debug("unmapping %s" % self.mapName) + crypto.luks_close(self.mapName) + + def create(self, *args, **kwargs): + """ Create the format. """ + if not self.hasKey: + raise LUKSError("luks device has no key/passphrase") + + DeviceFormat.create(self, *args, **kwargs) + crypto.luks_format(self.device, + passphrase=self.__passphrase, + key_file=self._key_file, + cipher=self.cipher, + key_size=self.key_size) + + self.uuid = crypto.luks_uuid(self.device) + self.exists = True + self.mapName = "luks-%s" % self.uuid + self.notifyKernel() + + def destroy(self, *args, **kwargs): + """ Create the format. """ + self.teardown() + DeviceFormat.destroy(self, *args, **kwargs) + + @property + def keyFile(self): + """ Path to key file to be used in /etc/crypttab """ + return self._key_file + + def addKeyFromFile(self, keyfile): + """ Add a new key from a file. + + Add the contents of the specified key file to an available key + slot in the LUKS header. + """ + if not self.exists: + raise LUKSError("Format has not been created") + + crypto.luks_add_key(self.device, + passphrase=self.__passphrase, + key_file=self._key_file, + new_key_file=keyfile) + + def addPassphrase(self, passphrase): + """ Add a new passphrase. + + Add the specified passphrase to an available key slot in the + LUKS header. + """ + if not self.exists: + raise LUKSError("Format has not been created") + + crypto.luks_add_key(self.device, + passphrase=self.__passphrase, + key_file=self._key_file, + new_passphrase=passphrase) + + def removeKeyFromFile(self, keyfile): + """ Remove a key contained in a file. + + Remove key contained in the specified key file from the LUKS + header. + """ + if not self.exists: + raise LUKSError("Format has not been created") + + crypto.luks_remove_key(self.device, + passphrase=self.__passphrase, + key_file=self._key_file, + del_key_file=keyfile) + + + def removePassphrase(self, passphrase): + """ Remove the specified passphrase from the LUKS header. """ + if not self.exists: + raise LUKSError("Format has not been created") + + crypto.luks_remove_key(self.device, + passphrase=self.__passphrase, + key_file=self._key_file, + del_passphrase=passphrase) + + +register_device_format(LUKS) diff --git a/pkgs/core/pomona/src/storage/formats/lvmpv.py b/pkgs/core/pomona/src/storage/formats/lvmpv.py new file mode 100644 index 0000000..cccff87 --- /dev/null +++ b/pkgs/core/pomona/src/storage/formats/lvmpv.py @@ -0,0 +1,85 @@ +#!/usr/bin/python + +from parted import PARTITION_LVM + +from . import DeviceFormat, register_device_format +from ..errors import * +from ..devicelibs import lvm + +class LVMPhysicalVolume(DeviceFormat): + """ An LVM physical volume. """ + _type = "lvmpv" + _name = "physical volume (LVM)" + _udevTypes = ["LVM2_member"] + partedFlag = PARTITION_LVM + _formattable = True # can be formatted + _supported = True # is supported + _linuxNative = True # for clearpart + + def __init__(self, *args, **kwargs): + """ Create an LVMPhysicalVolume instance. + + Keyword Arguments: + + device -- path to the underlying device + uuid -- this PV's uuid (not the VG uuid) + vgName -- the name of the VG this PV belongs to + vgUuid -- the UUID of the VG this PV belongs to + peStart -- offset of first physical extent + exists -- indicates whether this is an existing format + + """ + DeviceFormat.__init__(self, *args, **kwargs) + self.vgName = kwargs.get("vgName") + self.vgUuid = kwargs.get("vgUuid") + # liblvm may be able to tell us this at some point, even + # for not-yet-created devices + self.peStart = kwargs.get("peStart", 0.1875) # in MB + + def probe(self): + """ Probe for any missing information about this device. """ + if not self.exists: + raise PhysicalVolumeError("format has not been created") + + #info = lvm.pvinfo(self.device) + #self.vgName = info['vg_name'] + #self.vgUuid = info['vg_uuid'] + + def create(self, *args, **kwargs): + """ Create the format. """ + DeviceFormat.create(self, *args, **kwargs) + # Consider use of -Z|--zero + # -f|--force or -y|--yes may be required + + # lvm has issues with persistence of metadata, so here comes the + # hammer... + DeviceFormat.destroy(self, *args, **kwargs) + + lvm.pvcreate(self.device) + self.exists = True + self.notifyKernel() + + def destroy(self, *args, **kwargs): + """ Destroy the format. """ + if not self.exists: + raise PhysicalVolumeError("format has not been created") + + if self.status: + raise PhysicalVolumeError("device is active") + + # FIXME: verify path exists? + try: + lvm.pvremove(self.device) + except LVMError: + DeviceFormat.destroy(self, *args, **kwargs) + + self.exists = False + self.notifyKernel() + + @property + def status(self): + # XXX hack + return (self.exists and self.vgName and + os.path.isdir("/dev/mapper/%s" % self.vgName)) + +register_device_format(LVMPhysicalVolume) diff --git a/pkgs/core/pomona/src/storage/formats/swap.py b/pkgs/core/pomona/src/storage/formats/swap.py new file mode 100644 index 0000000..487d365 --- /dev/null +++ b/pkgs/core/pomona/src/storage/formats/swap.py @@ -0,0 +1,112 @@ +#!/usr/bin/python + +from parted import PARTITION_SWAP + +from . import DeviceFormat, register_device_format +from ..devicelibs import swap + +class SwapSpace(DeviceFormat): + """ Swap space """ + _type = "swap" + _name = None + _udevTypes = ["swap"] + partedFlag = PARTITION_SWAP + _formattable = True # can be formatted + _supported = True # is supported + _linuxNative = True # for clearpart + + def __init__(self, installer, *args, **kwargs): + """ Create a SwapSpace instance. + + Keyword Arguments: + + device -- path to the underlying device + uuid -- this swap space's uuid + label -- this swap space's label + priority -- this swap space's priority + exists -- indicates whether this is an existing format + + """ + self.installer = installer + DeviceFormat.__init__(self, self.installer, *args, **kwargs) + + self.priority = kwargs.get("priority") + self.label = kwargs.get("label") + + def _setPriority(self, priority): + if priority is None: + self._priority = None + return + + if not isinstance(priority, int) or not 0 <= priority <= 32767: + raise ValueError("swap priority must be an integer between 0 and 32767") + + self._priority = priority + + def _getPriority(self): + return self._priority + + priority = property(_getPriority, _setPriority, + doc="The priority of the swap device") + + def _getOptions(self): + opts = "" + if self.priority is not None: + opts += "pri=%d" % self.priority + + return opts + + def _setOptions(self, opts): + if not opts: + self.priority = None + return + + for option in opts.split(","): + (opt, equals, arg) = option.partition("=") + if equals and opt == "pri": + try: + self.priority = int(arg) + except ValueError: + self.installer.log.info("invalid value for swap priority: %s" % arg) + + options = property(_getOptions, _setOptions, + doc="The swap device's fstab options string") + + @property + def status(self): + """ Device status. """ + return self.exists and swap.swapstatus(self.device) + + def setup(self, *args, **kwargs): + """ Open, or set up, a device. """ + if not self.exists: + raise SwapSpaceError("format has not been created") + + if self.status: + return + + DeviceFormat.setup(self, *args, **kwargs) + swap.swapon(self.device, priority=self.priority) + + def teardown(self, *args, **kwargs): + """ Close, or tear down, a device. """ + if not self.exists: + raise SwapSpaceError("format has not been created") + + if self.status: + swap.swapoff(self.device) + + def create(self, *args, **kwargs): + """ Create the device. """ + if self.exists: + raise SwapSpaceError("format already exists") + + if self.status: + raise SwapSpaceError("device exists and is active") + + DeviceFormat.create(self, *args, **kwargs) + swap.mkswap(self.device, label=self.label) + self.exists = True + + +register_device_format(SwapSpace) diff --git a/pkgs/core/pomona/src/storage/partitioning.py b/pkgs/core/pomona/src/storage/partitioning.py new file mode 100644 index 0000000..0fb61d9 --- /dev/null +++ b/pkgs/core/pomona/src/storage/partitioning.py @@ -0,0 +1,1059 @@ +#!/usr/bin/python + +import os +import parted + +from constants import * +from errors import * + +import gettext +_ = lambda x: gettext.ldgettext("pomona", x) + +def doAutoPartition(installer): + if installer.dispatch.dir == DISPATCH_BACK: + installer.ds.storage.reset() + return + + disks = [] + devs = [] + + if installer.ds.storage.doAutoPart: + clearPartitions(installer) + (disks, devs) = _createFreeSpacePartitions(installer) + + if disks == []: + installer.intf.messageWindow(_("Error Partitioning"), + _("Could not find enough free space " + "for automatic partitioning, please " + "use another partitioning method.")) + return DISPATCH_BACK + + _schedulePartitions(installer, disks) + + # run the autopart function to allocate and grow partitions + try: + doPartitioning(installer) + + if installer.ds.storage.doAutoPart: + _scheduleLVs(installer, devs) + + # grow LVs + growLVM(installer) + except PartitioningWarning as msg: + installer.intf.messageWindow(_("Warnings During Automatic Partitioning"), + _("Following warnings occurred during automatic " + "partitioning:\n\n%s") % (msg,),) + log.warning(msg) + except PartitioningError as msg: + # restore drives to original state + installer.ds.storage.reset() + #installer.dispatch.skipStep("partition", skip = 0) + installer.intf.messageWindow(_("Error Partitioning"), + _("Could not allocate requested partitions: \n\n" + "%s.%s") % (msg, extra)) + return + + # now do a full check of the requests + (errors, warnings) = installer.ds.storage.sanityCheck() + if warnings: + for warning in warnings: + installer.log.warning(warning) + if errors: + errortxt = "\n".join(errors) + installer.intf.messageWindow(_("Automatic Partitioning Errors"), + _("The following errors occurred with your " + "partitioning:\n\n%s\n\n" + "This can happen if there is not enough " + "space on your hard drive(s) for the " + "installation.\n\n" + "Press 'OK' to choose a different partitioning option.") + % (errortxt,),) + + installer.ds.storage.reset() + #XXX return DISPATCH_BACK + return INSTALL_OK + +def doPartitioning(installer): + """ Allocate and grow partitions. + + When this function returns without error, all PartitionDevice + instances must have their parents set to the disk they are + allocated on, and their partedPartition attribute set to the + appropriate parted.Partition instance from their containing + disk. All req_xxxx attributes must be unchanged. + + Arguments: + + storage - Main anaconda Storage instance + + Keyword arguments: + + exclusiveDisks -- list of names of disks to use + + """ + storage = installer.ds.storage + disks = storage.disks + + exclusiveDisks = storage.clearDisks + if exclusiveDisks: + disks = [d for d in disks if d.name in exclusiveDisks] + + for disk in disks: + disk.setup() + + partitions = storage.partitions + for part in partitions: + part.req_bootable = False + if not part.exists: + # start over with flexible-size requests + part.req_size = part.req_base_size + + # FIXME: isn't there a better place for this to happen? + #try: + # bootDev = anaconda.platform.bootDevice() + #except DeviceError: + # bootDev = None + + #if bootDev: + # bootDev.req_bootable = True + + # FIXME: make sure non-existent partitions have empty parents list + allocatePartitions(installer, disks, partitions) + growPartitions(installer, disks, partitions) + # The number and thus the name of partitions may have changed now, + # allocatePartitions() takes care of this for new partitions, but not + # for pre-existing ones, so we update the name of all partitions here + for part in partitions: + part.updateName() + + # XXX hack -- if we created any extended partitions we need to add + # them to the tree now + for disk in disks: + extended = disk.partedDisk.getExtendedPartition() + if not extended: + continue + + extendedName = devicePathToName(extended.getDeviceNodeName()) + device = storage.devicetree.getDeviceByName(extendedName) + if device: + if not device.exists: + # created by us, update partedPartition + device.partedPartition = extended + continue + + # This is a little odd because normally instantiating a partition + # that does not exist means leaving self.parents empty and instead + # populating self.req_disks. In this case, we need to skip past + # that since this partition is already defined. + device = PartitionDevice(extendedName, parents=disk) + device.parents = [disk] + device.partedPartition = extended + storage.createDevice(device) + +def clearPartitions(installer): + """ Clear partitions and dependent devices from disks. + + Arguments: + + storage -- a storage.Storage instance + + Keyword arguments: + + None + + NOTES: + + - Needs some error handling, especially for the parted bits. + + """ + storage = installer.ds.storage + + # we are only interested in partitions that physically exist + partitions = [p for p in storage.partitions if p.exists] + disks = [] # a list of disks from which we've removed partitions + clearparts = [] # list of partitions we'll remove + for part in partitions: + # if we got a list of disks to clear, make sure this one's on it + if storage.clearDisks and part.disk.name not in storage.clearDisks: + continue + + # don't clear partitions holding install media + #if part.name in storage.protectedPartitions: + # continue + + # we don't want to fool with extended partitions, freespace + if part.partType not in (parted.PARTITION_NORMAL, parted.PARTITION_LOGICAL): + continue + + # XXX is there any argument for not removing incomplete devices? + # -- maybe some RAID devices + devices = storage.deviceDeps(part) + while devices: + installer.log.debug("Devices to remove: %s" % ([d.name for d in devices],)) + leaves = [d for d in devices if d.isleaf] + installer.log.debug("Leaves to remove: %s" % ([d.name for d in leaves],)) + for leaf in leaves: + storage.destroyDevice(leaf) + devices.remove(leaf) + + #installer.log.debug("Partitions left: %s" % [p.getDeviceNodeName() for p in part.partedPartition.disk.partitions]) + disk_name = os.path.basename(part.partedPartition.disk.device.path) + if disk_name not in disks: + disks.append(disk_name) + + clearparts.append(part) + + for part in clearparts: + storage.destroyDevice(part) + + # now remove any empty extended partitions + removeEmptyExtendedPartitions(installer) + +def removeEmptyExtendedPartitions(installer): + storage = installer.ds.storage + for disk in storage.disks: + #installer.log.debug("Checking whether disk %s has an empty extended" % disk.name) + extended = disk.partedDisk.getExtendedPartition() + logical_parts = disk.partedDisk.getLogicalPartitions() + #installer.log.debug("Extended is %s ; logicals is %s" % (extended, [p.getDeviceNodeName() for p in logical_parts])) + if extended and not logical_parts: + installer.log.debug("Removing empty extended partition from %s" % disk.name) + extended_name = devicePathToName(extended.getDeviceNodeName()) + extended = storage.devicetree.getDeviceByName(extended_name) + storage.destroyDevice(extended) + #disk.partedDisk.removePartition(extended.partedPartition) + +def _createFreeSpacePartitions(installer): + # get a list of disks that have at least one free space region of at + # least 100MB + disks = [] + for disk in installer.ds.storage.disks: + if disk.name not in installer.ds.storage.clearDisks: + continue + + partedDisk = disk.partedDisk + part = disk.partedDisk.getFirstPartition() + while part: + if not part.type & parted.PARTITION_FREESPACE: + part = part.nextPartition() + continue + + if part.getSize(unit="MB") > 100: + disks.append(disk) + break + + part = part.nextPartition() + + # create a separate pv partition for each disk with free space + devs = [] + for disk in disks: + if installer.ds.storage.encryptedAutoPart: + fmt_type = "luks" + else: + fmt_type = "lvmpv" + part = installer.ds.storage.newPartition(fmt_type=fmt_type, + size=1, grow=True, + disks=[disk]) + installer.ds.storage.createDevice(part) + devs.append(part) + + return (disks, devs) + +def _schedulePartitions(installer, disks): + # + # Convert storage.autoPartitionRequests into Device instances and + # schedule them for creation + # + # First pass is for partitions only. We'll do LVs later. + # + for request in installer.ds.storage.autoPartitionRequests: + if request.asVol: + continue + + if request.fstype is None: + request.fstype = installer.ds.storage.defaultFSType + + dev = installer.ds.storage.newPartition(fmt_type=request.fstype, + size=request.size, + grow=request.grow, + maxsize=request.maxSize, + mountpoint=request.mountpoint, + disks=disks, + weight=request.weight) + + # schedule the device for creation + installer.ds.storage.createDevice(dev) + + # make sure preexisting broken lvm/raid configs get out of the way + return + +def allocatePartitions(installer, disks, partitions): + """ Allocate partitions based on requested features. + + Non-existing partitions are sorted according to their requested + attributes, and then allocated. + + The basic approach to sorting is that the more specifically- + defined a request is, the earlier it will be allocated. See + the function partitionCompare for details on the sorting + criteria. + + The PartitionDevice instances will have their name and parents + attributes set once they have been allocated. + """ + #installer.log.debug("disks=%s ; partitions=%s" % (disks, partitions)) + new_partitions = [p for p in partitions if not p.exists] + new_partitions.sort(cmp=partitionCompare) + + # XXX is this needed anymore? + partedDisks = {} + for disk in disks: + if disk.path not in partedDisks.keys(): + partedDisks[disk.path] = disk.partedDisk #.duplicate() + + # remove all newly added partitions from the disk + installer.log.debug("Removing all non-preexisting from disk(s)") + for _part in new_partitions: + if _part.partedPartition: + if _part.isExtended: + continue # these get removed last + #_part.disk.partedDisk.removePartition(_part.partedPartition) + partedDisk = partedDisks[_part.disk.partedDisk.device.path] + installer.log.debug("Removing part %s (%s) from disk %s (%s)" % + (_part.partedPartition.path, + [p.path for p in _part.partedPartition.disk.partitions], + partedDisk.device.path, + [p.path for p in partedDisk.partitions])) + + partedDisk.removePartition(_part.partedPartition) + _part.partedPartition = None + _part.disk = None + + # remove empty extended so it doesn't interfere + extended = partedDisk.getExtendedPartition() + if extended and not partedDisk.getLogicalPartitions(): + installer.log.debug("Removing empty extended partition") + #partedDisk.minimizeExtendedPartition() + partedDisk.removePartition(extended) + + for _part in new_partitions: + if _part.partedPartition and _part.isExtended: + # ignore new extendeds as they are implicit requests + continue + + # obtain the set of candidate disks + req_disks = [] + if _part.disk: + # we have a already selected a disk for this request + req_disks = [_part.disk] + elif _part.req_disks: + # use the requested disk set + req_disks = _part.req_disks + else: + # no disks specified means any disk will do + req_disks = disks + + #installer.log.debug("allocating partition: %s ; disks: %s ; boot: %s ; " + # "primary: %s ; size: %dMB ; grow: %s ; max_size: %s" % + # (_part.name, req_disks, _part.req_bootable, _part.req_primary, + # _part.req_size, _part.req_grow, _part.req_max_size)) + free = None + use_disk = None + part_type = None + # loop through disks + for _disk in req_disks: + disk = partedDisks[_disk.path] + #for p in disk.partitions: + # installer.log.debug("disk %s: part %s" % (disk.device.path, p.path)) + sectorSize = disk.device.physicalSectorSize + best = None + + #installer.log.debug("Checking freespace on %s" % _disk.name) + + new_part_type = getNextPartitionType(disk) + if new_part_type is None: + # can't allocate any more partitions on this disk + installer.log.debug("No free partition slots on %s" % _disk.name) + continue + + if _part.req_primary and new_part_type != parted.PARTITION_NORMAL: + # we need a primary slot and none are free on this disk + installer.log.debug("No primary slots available on %s" % _disk.name) + continue + + best = getBestFreeSpaceRegion(installer, disk, + new_part_type, + _part.req_size, + best_free=free, + boot=_part.req_bootable) + + if best == free and not _part.req_primary and \ + new_part_type == parted.PARTITION_NORMAL: + # see if we can do better with a logical partition + installer.log.debug("Not enough free space for primary -- trying logical") + new_part_type = getNextPartitionType(disk, no_primary=True) + if new_part_type: + best = getBestFreeSpaceRegion(disk, + new_part_type, + _part.req_size, + best_free=free, + boot=_part.req_bootable) + + if best and free != best: + # now we know we are choosing a new free space, + # so update the disk and part type + #installer.log.debug("Updating use_disk to %s (%s), type: %s" + # % (_disk, _disk.name, new_part_type)) + part_type = new_part_type + use_disk = _disk + installer.log.debug("New free: %s (%d-%d / %dMB)" % (best.device.path, + best.start, + best.end, + best.getSize())) + free = best + + if free and _part.req_bootable: + # if this is a bootable partition we want to + # use the first freespace region large enough + # to satisfy the request + installer.log.debug("Found free space for bootable request") + break + + if free is None: + raise PartitioningError("Not enough free space on disks") + + _disk = use_disk + disk = _disk.partedDisk + + # create the extended partition if needed + # TODO: move to a function (disk, free) + if part_type == parted.PARTITION_EXTENDED: + installer.log.debug("Creating extended partition") + geometry = parted.Geometry(device=disk.device, + start=free.start, + length=free.length, + end=free.end) + extended = parted.Partition(disk=disk, + type=parted.PARTITION_EXTENDED, + geometry=geometry) + constraint = parted.Constraint(device=disk.device) + # FIXME: we should add this to the tree as well + disk.addPartition(extended, constraint) + + # end proposed function + + # now the extended partition exists, so set type to logical + part_type = parted.PARTITION_LOGICAL + + # recalculate freespace + installer.log.debug("Recalculating free space") + free = getBestFreeSpaceRegion(disk, + part_type, + _part.req_size, + boot=_part.req_bootable) + if not free: + raise PartitioningError("Not enough free space after " + "creating extended partition") + + # create minimum geometry for this request + # req_size is in MB + sectors_per_track = disk.device.biosGeometry[2] + length = (_part.req_size * (1024 * 1024)) / sectorSize + new_geom = parted.Geometry(device=disk.device, + start=max(sectors_per_track, free.start), + length=length) + + # create maximum and minimum geometries for constraint + start = max(0 , free.start - 1) + max_geom = parted.Geometry(device=disk.device, + start=start, + length=min(length + 1, disk.device.length - start)) + min_geom = parted.Geometry(device=disk.device, + start=free.start + 1, + length=length-1) + + + # create the partition and add it to the disk + partition = parted.Partition(disk=disk, + type=part_type, + geometry=new_geom) + constraint = parted.Constraint(maxGeom=max_geom, minGeom=min_geom) + disk.addPartition(partition=partition, + constraint=constraint) + installer.log.debug("Created partition %s of %dMB and added it to %s" % + (partition.getDeviceNodeName(), partition.getSize(), disk.device.path)) + + # this one sets the name + _part.partedPartition = partition + _part.disk = _disk + + # parted modifies the partition in the process of adding it to + # the disk, so we need to grab the latest version... + _part.partedPartition = disk.getPartitionByPath(_part.path) + +def growPartitions(installer, disks, partitions): + """ Grow all growable partition requests. + + All requests should know what disk they will be on by the time + this function is called. This is reflected in the + PartitionDevice's disk attribute. Note that the req_disks + attribute remains unchanged. + + The total available free space is summed up for each disk and + partition requests are allocated a maximum percentage of the + available free space on their disk based on their own base size. + + Each attempted size means calling allocatePartitions again with + one request's size having changed. + + After taking into account several factors that may limit the + maximum size of a requested partition, we arrive at a firm + maximum number of sectors by which a request can potentially grow. + + An initial attempt is made to allocate the full maximum size. If + this fails, we begin a rough binary search with a maximum of three + iterations to settle on a new size. + + Arguments: + + disks -- a list of all usable disks (DiskDevice instances) + partitions -- a list of all partitions (PartitionDevice + instances) + """ + #installer.log.debug("growPartitions: disks=%s, partitions=%s" % + # ([d.name for d in disks], [p.name for p in partitions])) + all_growable = [p for p in partitions if p.req_grow] + if not all_growable: + return + + # sort requests by base size in decreasing order + all_growable.sort(key=lambda p: p.req_size, reverse=True) + + installer.log.debug("Growable requests are %s" % [p.name for p in all_growable]) + + for disk in disks: + installer.log.debug("Growing requests on %s" % disk.name) + for p in disk.partedDisk.partitions: + installer.log.debug(" %s: %s (%dMB)" % (disk.name, p.getDeviceNodeName(), + p.getSize())) + sectorSize = disk.partedDisk.device.physicalSectorSize + # get a list of free space regions on the disk + free = disk.partedDisk.getFreeSpaceRegions() + if not free: + installer.log.debug("No free space on %s" % disk.name) + continue + + # sort the free regions in decreasing order of size + free.sort(key=lambda r: r.length, reverse=True) + disk_free = reduce(lambda x,y: x + y, [f.length for f in free]) + installer.log.debug("Total free: %d sectors ; largest: %d sectors (%dMB)" + % (disk_free, free[0].length, free[0].getSize())) + + # make a list of partitions currently allocated on this disk + # -- they're already sorted + growable = [] + disk_total = 0 + for part in all_growable: + #log.debug("checking if part %s (%s) is on this disk" % (part.name, + # part.disk.name)) + if part.disk == disk: + growable.append(part) + disk_total += part.partedPartition.geometry.length + installer.log.debug("Add %s (%dMB/%d sectors) to growable total" + % (part.name, part.partedPartition.getSize(), + part.partedPartition.geometry.length)) + installer.log.debug("Growable total is now %d sectors" % disk_total) + + # now we loop through the partitions... + # this first loop is to identify obvious chunks of free space that + # will be left over due to max size + leftover = 0 + limited = {} + unlimited_total = 0 + for part in growable: + # calculate max number of sectors this request can grow + req_sectors = part.partedPartition.geometry.length + share = float(req_sectors) / float(disk_total) + max_grow = (share * disk_free) + max_sectors = req_sectors + max_grow + limited[part.name] = False + + if part.req_max_size: + req_max_sect = (part.req_max_size * (1024 * 1024)) / sectorSize + if req_max_sect < max_sectors: + mb = ((max_sectors - req_max_sect) * sectorSize) / (1024*1024) + + installer.log.debug("Adding %dMB to leftovers from %s" + % (mb, part.name)) + leftover += (max_sectors - req_max_sect) + limited[part.name] = True + + if not limited[part.name]: + unlimited_total += req_sectors + + # now we loop through the partitions... + for part in growable: + # calculate max number of sectors this request can grow + req_sectors = part.partedPartition.geometry.length + share = float(req_sectors) / float(disk_total) + max_grow = (share * disk_free) + if not limited[part.name]: + leftover_share = float(req_sectors) / float(unlimited_total) + max_grow += leftover_share * leftover + max_sectors = req_sectors + max_grow + max_mb = (max_sectors * sectorSize) / (1024 * 1024) + + installer.log.debug("%s: base_size=%dMB, max_size=%sMB" % + (part.name, part.req_base_size, part.req_max_size)) + installer.log.debug("%s: current_size=%dMB (%d sectors)" % + (part.name, part.partedPartition.getSize(), + part.partedPartition.geometry.length)) + installer.log.debug("%s: %dMB (%d sectors, or %d%% of %d)" % + (part.name, max_mb, max_sectors, share * 100, disk_free)) + + installer.log.debug("Checking constraints on max size...") + # don't grow beyond the request's maximum size + if part.req_max_size: + installer.log.debug("max_size: %dMB" % part.req_max_size) + # FIXME: round down to nearest cylinder boundary + req_max_sect = (part.req_max_size * (1024 * 1024)) / sectorSize + if req_max_sect < max_sectors: + max_grow -= (max_sectors - req_max_sect) + max_sectors = req_sectors + max_grow + + # don't grow beyond the resident filesystem's max size + if part.format.maxSize > 0: + installer.log.debug("Format maxsize: %dMB" % part.format.maxSize) + # FIXME: round down to nearest cylinder boundary + fs_max_sect = (part.format.maxSize * (1024 * 1024)) / sectorSize + if fs_max_sect < max_sectors: + max_grow -= (max_sectors - fs_max_sect) + max_sectors = req_sectors + max_grow + + # we can only grow as much as the largest free region on the disk + if free[0].length < max_grow: + installer.log.debug("Largest free region: %d sectors (%dMB)" % + (free[0].length, free[0].getSize())) + # FIXME: round down to nearest cylinder boundary + max_grow = free[0].length + max_sectors = req_sectors + max_grow + + # Now, we try to grow this partition as close to max_grow + # sectors as we can. + # + # We could call allocatePartitions after modifying this + # request and saving the original value of part.req_size, + # or we could try to use disk.maximizePartition(). + max_size = (max_sectors * sectorSize) / (1024 * 1024) + orig_size = part.req_size + # try the max size to begin with + installer.log.debug("Attempting to allocate maximum size: %dMB" % max_size) + part.req_size = max_size + try: + allocatePartitions(installer, disks, partitions) + except PartitioningError, e: + installer.log.debug("Max size attempt failed: %s (%dMB)" % (part.name, + max_size)) + part.req_size = orig_size + else: + continue + + installer.log.debug("Starting binary search: size=%d max_size=%d" % (part.req_size, max_size)) + count = 0 + op_func = add + increment = max_grow + last_good_size = part.req_size + last_outcome = None + while count < 3: + last_size = part.req_size + increment /= 2 + req_sectors = op_func(req_sectors, increment) + part.req_size = (req_sectors * sectorSize) / (1024 * 1024) + installer.log.debug("Attempting size=%dMB" % part.req_size) + count += 1 + try: + allocatePartitions(disks, partitions) + except PartitioningError, e: + installer.log.debug("Attempt at %dMB failed" % part.req_size) + op_func = sub + last_outcome = False + else: + op_func = add + last_good_size = part.req_size + last_outcome = True + + if not last_outcome: + part.req_size = last_good_size + installer.log.debug("Backing up to size=%dMB" % part.req_size) + try: + allocatePartitions(disks, partitions) + except PartitioningError, e: + raise PartitioningError("Failed to grow partitions") + + # reset all requests to their original requested size + for part in partitions: + if part.exists: + continue + part.req_size = part.req_base_size + +def growLVM(installer): + """ Grow LVs according to the sizes of the PVs. """ + storage = installer.ds.storage + for vg in storage.vgs: + total_free = vg.freeSpace + if not total_free: + installer.log.debug("vg %s has no free space" % vg.name) + continue + + installer.log.debug("vg %s: %dMB free ; lvs: %s" % (vg.name, vg.freeSpace, + [l.lvname for l in vg.lvs])) + + # figure out how much to grow each LV + grow_amounts = {} + lv_total = vg.size - total_free + installer.log.debug("used: %dMB ; vg.size: %dMB" % (lv_total, vg.size)) + + # This first loop is to calculate percentage-based growth + # amounts. These are based on total free space. + lvs = vg.lvs + lvs.sort(cmp=lvCompare) + for lv in lvs: + if not lv.req_grow or not lv.req_percent: + continue + + portion = (lv.req_percent * 0.01) + grow = portion * vg.vgFree + new_size = lv.req_size + grow + if lv.req_max_size and new_size > lv.req_max_size: + grow -= (new_size - lv.req_max_size) + + if lv.format.maxSize and lv.format.maxSize < new_size: + grow -= (new_size - lv.format.maxSize) + + # clamp growth amount to a multiple of vg extent size + grow_amounts[lv.name] = vg.align(grow) + total_free -= grow + lv_total += grow + + # This second loop is to calculate non-percentage-based growth + # amounts. These are based on free space remaining after + # calculating percentage-based growth amounts. + + # keep a tab on space not allocated due to format or requested + # maximums -- we'll dole it out to subsequent requests + leftover = 0 + for lv in lvs: + installer.log.debug("Checking lv %s: req_grow: %s ; req_percent: %s" + % (lv.name, lv.req_grow, lv.req_percent)) + if not lv.req_grow or lv.req_percent: + continue + + portion = float(lv.req_size) / float(lv_total) + grow = portion * total_free + installer.log.debug("grow is %dMB" % grow) + + todo = lvs[lvs.index(lv):] + unallocated = reduce(lambda x,y: x+y, + [l.req_size for l in todo + if l.req_grow and not l.req_percent]) + extra_portion = float(lv.req_size) / float(unallocated) + extra = extra_portion * leftover + installer.log.debug("%s getting %dMB (%d%%) of %dMB leftover space" + % (lv.name, extra, extra_portion * 100, leftover)) + leftover -= extra + grow += extra + installer.log.debug("grow is now %dMB" % grow) + max_size = lv.req_size + grow + if lv.req_max_size and max_size > lv.req_max_size: + max_size = lv.req_max_size + + if lv.format.maxSize and max_size > lv.format.maxSize: + max_size = lv.format.maxSize + + installer.log.debug("max size is %dMB" % max_size) + max_size = max_size + leftover += (lv.req_size + grow) - max_size + grow = max_size - lv.req_size + installer.log.debug("lv %s gets %dMB" % (lv.name, vg.align(grow))) + grow_amounts[lv.name] = vg.align(grow) + + if not grow_amounts: + installer.log.debug("No growable lvs in vg %s" % vg.name) + continue + + # now grow the lvs by the amounts we've calculated above + for lv in lvs: + if lv.name not in grow_amounts.keys(): + continue + lv.size += grow_amounts[lv.name] + + # now there shouldn't be any free space left, but if there is we + # should allocate it to one of the LVs + vg_free = vg.freeSpace + installer.log.debug("vg %s has %dMB free" % (vg.name, vg_free)) + if vg_free: + for lv in lvs: + if not lv.req_grow: + continue + + if lv.req_max_size and lv.size == lv.req_max_size: + continue + + if lv.format.maxSize and lv.size == lv.format.maxSize: + continue + + # first come, first served + projected = lv.size + vg.freeSpace + if lv.req_max_size and projected > lv.req_max_size: + projected = lv.req_max_size + + if lv.format.maxSize and projected > lv.format.maxSize: + projected = lv.format.maxSize + + installer.log.debug("Giving leftover %dMB to %s" % (projected - lv.size, + lv.name)) + lv.size = projected + +def partitionCompare(part1, part2): + """ More specifically defined partitions come first. + + < 1 => x < y + 0 => x == y + > 1 => x > y + """ + ret = 0 + + if part1.req_base_weight: + ret -= part1.req_base_weight + + if part2.req_base_weight: + ret += part2.req_base_weight + + # bootable partitions to the front + ret -= cmp(part1.req_bootable, part2.req_bootable) * 1000 + + # more specific disk specs to the front of the list + ret += cmp(len(part1.parents), len(part2.parents)) * 500 + + # primary-only to the front of the list + ret -= cmp(part1.req_primary, part2.req_primary) * 200 + + # larger requests go to the front of the list + ret -= cmp(part1.size, part2.size) * 100 + + # fixed size requests to the front + ret += cmp(part1.req_grow, part2.req_grow) * 50 + + # potentially larger growable requests go to the front + if part1.req_grow and part2.req_grow: + if not part1.req_max_size and part2.req_max_size: + ret -= 25 + elif part1.req_max_size and not part2.req_max_size: + ret += 25 + else: + ret -= cmp(part1.req_max_size, part2.req_max_size) * 25 + + if ret > 0: + ret = 1 + elif ret < 0: + ret = -1 + + return ret + +def lvCompare(lv1, lv2): + """ More specifically defined lvs come first. + + < 1 => x < y + 0 => x == y + > 1 => x > y + """ + ret = 0 + + # larger requests go to the front of the list + ret -= cmp(lv1.size, lv2.size) * 100 + + # fixed size requests to the front + ret += cmp(lv1.req_grow, lv2.req_grow) * 50 + + # potentially larger growable requests go to the front + if lv1.req_grow and lv2.req_grow: + if not lv1.req_max_size and lv2.req_max_size: + ret -= 25 + elif lv1.req_max_size and not lv2.req_max_size: + ret += 25 + else: + ret -= cmp(lv1.req_max_size, lv2.req_max_size) * 25 + + if ret > 0: + ret = 1 + elif ret < 0: + ret = -1 + + return ret + +def getNextPartitionType(disk, no_primary=None): + """ Find the type of partition to create next on a disk. + + Return a parted partition type value representing the type of the + next partition we will create on this disk. + + If there is only one free primary partition and we can create an + extended partition, we do that. + + If there are free primary slots and an extended partition we will + recommend creating a primary partition. This can be overridden + with the keyword argument no_primary. + + Arguments: + + disk -- a parted.Disk instance representing the disk + + Keyword arguments: + + no_primary -- given a choice between primary and logical + partitions, prefer logical + + """ + part_type = None + extended = disk.getExtendedPartition() + supports_extended = disk.supportsFeature(parted.DISK_TYPE_EXTENDED) + logical_count = len(disk.getLogicalPartitions()) + max_logicals = disk.getMaxLogicalPartitions() + primary_count = disk.primaryPartitionCount + + if primary_count == disk.maxPrimaryPartitionCount and \ + extended and logical_count < max_logicals: + part_type = parted.PARTITION_LOGICAL + elif primary_count == (disk.maxPrimaryPartitionCount - 1) and \ + not extended and supports_extended: + # last chance to create an extended partition + part_type = parted.PARTITION_EXTENDED + elif no_primary and extended and logical_count < max_logicals: + # create a logical even though we could presumably create a + # primary instead + part_type = parted.PARTITION_LOGICAL + elif not no_primary: + # XXX there is a possiblity that the only remaining free space on + # the disk lies within the extended partition, but we will + # try to create a primary first + part_type = parted.PARTITION_NORMAL + + return part_type + +def getBestFreeSpaceRegion(installer, disk, part_type, req_size, + boot=None, best_free=None): + """ Return the "best" free region on the specified disk. + + For non-boot partitions, we return the largest free region on the + disk. For boot partitions, we return the first region that is + large enough to hold the partition. + + Partition type (parted's PARTITION_NORMAL, PARTITION_LOGICAL) is + taken into account when locating a suitable free region. + + For locating the best region from among several disks, the keyword + argument best_free allows the specification of a current "best" + free region with which to compare the best from this disk. The + overall best region is returned. + + Arguments: + + disk -- the disk (a parted.Disk instance) + part_type -- the type of partition we want to allocate + (one of parted's partition type constants) + req_size -- the requested size of the partition (in MB) + + Keyword arguments: + + boot -- indicates whether this will be a bootable partition + (boolean) + best_free -- current best free region for this partition + + """ + #installer.log.debug("getBestFreeSpaceRegion: disk=%s part_type=%d req_size=%dMB boot=%s best=%s" % + # (disk.device.path, part_type, req_size, boot, best_free)) + extended = disk.getExtendedPartition() + for _range in disk.getFreeSpaceRegions(): + if extended: + # find out if there is any overlap between this region and the + # extended partition + installer.log.debug("Looking for intersection between extended (%d-%d) and free (%d-%d)" % + (extended.geometry.start, extended.geometry.end, _range.start, _range.end)) + + # parted.Geometry.overlapsWith can handle this + try: + free_geom = extended.geometry.intersect(_range) + except ArithmeticError, e: + # this freespace region does not lie within the extended + # partition's geometry + free_geom = None + + if (free_geom and part_type == parted.PARTITION_NORMAL) or \ + (not free_geom and part_type == parted.PARTITION_LOGICAL): + installer.log.debug("Free region not suitable for request") + continue + + if part_type == parted.PARTITION_NORMAL: + # we're allocating a primary and the region is not within + # the extended, so we use the original region + free_geom = _range + else: + free_geom = _range + + installer.log.debug("Current free range on %s is %d-%d (%dMB)" % (disk.device.path, + free_geom.start, + free_geom.end, + free_geom.getSize())) + free_size = free_geom.getSize() + + if req_size <= free_size: + if not best_free or free_geom.length > best_free.length: + best_free = free_geom + + if boot: + # if this is a bootable partition we want to + # use the first freespace region large enough + # to satisfy the request + break + + return best_free + +def _scheduleLVs(installer, devs): + if installer.ds.storage.encryptedAutoPart: + pvs = [] + for dev in devs: + pv = LUKSDevice("luks-%s" % dev.name, + format=getFormat("lvmpv", device=dev.path), + size=dev.size, + parents=dev) + pvs.append(pv) + installer.ds.storage.createDevice(pv) + else: + pvs = devs + + # create a vg containing all of the autopart pvs + vg = installer.ds.storage.newVG(pvs=pvs) + installer.ds.storage.createDevice(vg) + + # + # Convert storage.autoPartitionRequests into Device instances and + # schedule them for creation. + # + # Second pass, for LVs only. + for request in installer.ds.storage.autoPartitionRequests: + if not request.asVol: + continue + + if request.fstype is None: + request.fstype = installer.ds.storage.defaultFSType + + # FIXME: move this to a function and handle exceptions + dev = installer.ds.storage.newLV(vg=vg, + fmt_type=request.fstype, + mountpoint=request.mountpoint, + grow=request.grow, + maxsize=request.maxSize, + size=request.size) + + # schedule the device for creation + installer.ds.storage.createDevice(dev) diff --git a/pkgs/core/pomona/src/storage/udev.py b/pkgs/core/pomona/src/storage/udev.py new file mode 100644 index 0000000..a9a7377 --- /dev/null +++ b/pkgs/core/pomona/src/storage/udev.py @@ -0,0 +1,305 @@ +#!/usr/bin/python + +import os +import sys + +import util + +def udev_settle(timeout=None): + argv = ["settle"] + if timeout: + argv.append("--timeout=%d" % int(timeout)) + + util.execWithRedirect("udevadm", argv, stderr="/dev/null", searchPath=1) + +def udev_trigger(subsystem=None): + argv = ["trigger"] + if subsystem: + argv.append("--subsystem-match=%s" % subsystem) + + util.execWithRedirect("udevadm", argv, stderr="/dev/null", searchPath=1) + +def udev_get_block_devices(): + #udev_settle(timeout=30) + entries = [] + for path in enumerate_block_devices(): + entry = udev_get_block_device(path) + if entry: + entries.append(entry) + return entries + +def __is_blacklisted_blockdev(dev_name): + """Is this a blockdev we never want for an install?""" + if dev_name.startswith("loop") or dev_name.startswith("ram") or dev_name.startswith("fd"): + return True + + if os.path.exists("/sys/class/block/%s/device/model" %(dev_name,)): + model = open("/sys/class/block/%s/device/model" %(dev_name,)).read() + for bad in ("IBM *STMF KERNEL", "SCEI Flash-5", "DGC LUNZ"): + if model.find(bad) != -1: + return True + + return False + +def enumerate_block_devices(): + top_dir = "/sys/class/block" + devices = [] + for dev_name in os.listdir(top_dir): + if __is_blacklisted_blockdev(dev_name): + continue + full_path = os.path.join(top_dir, dev_name) + link_ref = os.readlink(full_path) + real_path = os.path.join(top_dir, link_ref) + sysfs_path = os.path.normpath(real_path) + devices.append(sysfs_path) + return devices + +def udev_get_block_device(sysfs_path): + if not os.path.exists(sysfs_path): + return None + + db_entry = sysfs_path[4:].replace("/", "\x2f") + db_root = "/dev/.udev/db" + db_path = os.path.normpath("%s/%s" % (db_root, db_entry)) + if not os.access(db_path, os.R_OK): + return None + + entry = open(db_path).read() + dev = udev_parse_block_entry(entry) + if dev: + # XXX why do we do this? is /sys going to move during installation? + dev['sysfs_path'] = sysfs_path[4:] # strip off the leading '/sys' + dev = udev_parse_uevent_file(dev) + + # now add in the contents of the uevent file since they're handy + return dev + +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_parse_block_entry(buf): + dev = {'name': None, + 'symlinks': []} + + for line in buf.splitlines(): + line.strip() + (tag, sep, val) = line.partition(":") + if not sep: + continue + + if tag == "N": + dev['name'] = val + elif tag == "S": + dev['symlinks'].append(val) + elif tag == "E": + if val.count("=") > 1 and val.count(" ") > 0: + # eg: LVM2_LV_NAME when querying the VG for its LVs + vars = val.split() + vals = [] + var_name = None + for (index, subval) in enumerate(vars): + (var_name, sep, var_val) = subval.partition("=") + if sep: + vals.append(var_val) + + dev[var_name] = vals + else: + (var_name, sep, var_val) = val.partition("=") + if not sep: + continue + + if var_val.count(" "): + # eg: DEVLINKS + var_val = var_val.split() + + dev[var_name] = var_val + + if dev.get("name"): + return dev + +# These are functions for retrieving specific pieces of information from +# udev database entries. +def udev_device_get_name(udev_info): + """ Return the best name for a device based on the udev db data. """ + return udev_info.get("DM_NAME", udev_info["name"]) + +def udev_device_get_format(udev_info): + """ Return a device's format type as reported by udev. """ + return udev_info.get("ID_FS_TYPE") + +def udev_device_get_uuid(udev_info): + """ Get the UUID from the device's format as reported by udev. """ + md_uuid = udev_info.get("MD_UUID") + uuid = udev_info.get("ID_FS_UUID") + # we don't want to return the array's uuid as a member's uuid + if uuid and not md_uuid == uuid: + return udev_info.get("ID_FS_UUID") + +def udev_device_get_label(udev_info): + """ Get the label from the device's format as reported by udev. """ + return udev_info.get("ID_FS_LABEL") + +def udev_device_is_dm(info): + """ Return True if the device is a device-mapper device. """ + return info.has_key("DM_NAME") + +def udev_device_is_md(info): + """ Return True is the device is an mdraid array device. """ + return info.has_key("MD_METADATA") + +def udev_device_is_cdrom(info): + """ Return True if the device is an optical drive. """ + # FIXME: how can we differentiate USB drives from CD-ROM drives? + # -- USB drives also generate a sdX device. + return info.get("ID_CDROM") == "1" + +def udev_device_is_disk(info): + """ Return True is the device is a disk. """ + has_range = os.path.exists("/sys/%s/range" % info['sysfs_path']) + return info.get("DEVTYPE") == "disk" or has_range + +def udev_device_is_partition(info): + has_start = os.path.exists("/sys/%s/start" % info['sysfs_path']) + return info.get("DEVTYPE") == "partition" or has_start + +def udev_device_get_sysfs_path(info): + return info['sysfs_path'] + +def udev_device_get_major(info): + return int(info["MAJOR"]) + +def udev_device_get_minor(info): + return int(info["MINOR"]) + +def udev_device_get_md_level(info): + return info["MD_LEVEL"] + +def udev_device_get_md_devices(info): + return int(info["MD_DEVICES"]) + +def udev_device_get_md_uuid(info): + return info["MD_UUID"] + +def udev_device_get_vg_name(info): + return info['LVM2_VG_NAME'] + +def udev_device_get_vg_uuid(info): + return info['LVM2_VG_UUID'] + +def udev_device_get_vg_size(info): + # lvm's decmial precision is not configurable, so we tell it to use + # KB and convert to MB here + return float(info['LVM2_VG_SIZE']) / 1024 + +def udev_device_get_vg_free(info): + # lvm's decmial precision is not configurable, so we tell it to use + # KB and convert to MB here + return float(info['LVM2_VG_FREE']) / 1024 + +def udev_device_get_vg_extent_size(info): + # lvm's decmial precision is not configurable, so we tell it to use + # KB and convert to MB here + return float(info['LVM2_VG_EXTENT_SIZE']) / 1024 + +def udev_device_get_vg_extent_count(info): + return int(info['LVM2_VG_EXTENT_COUNT']) + +def udev_device_get_vg_free_extents(info): + return int(info['LVM2_VG_FREE_COUNT']) + +def udev_device_get_vg_pv_count(info): + return int(info['LVM2_PV_COUNT']) + +def udev_device_get_pv_pe_start(info): + # lvm's decmial precision is not configurable, so we tell it to use + # KB and convert to MB here + return float(info['LVM2_PE_START']) / 1024 + +def udev_device_get_lv_names(info): + names = info['LVM2_LV_NAME'] + if not names: + names = [] + elif not isinstance(names, list): + names = [names] + return names + +def udev_device_get_lv_uuids(info): + uuids = info['LVM2_LV_UUID'] + if not uuids: + uuids = [] + elif not isinstance(uuids, list): + uuids = [uuids] + return uuids + +def udev_device_get_lv_sizes(info): + # lvm's decmial precision is not configurable, so we tell it to use + # KB and convert to MB here + sizes = info['LVM2_LV_SIZE'] + if not sizes: + sizes = [] + elif not isinstance(sizes, list): + sizes = [sizes] + + return [float(s) / 1024 for s in sizes] + +def udev_device_is_dmraid(info): + # Note that this function does *not* identify raid sets. + # Tests to see if device is parto of a dmraid set. + # dmraid and mdriad have the same ID_FS_USAGE string, ID_FS_TYPE has a + # string that describes the type of dmraid (isw_raid_member...), I don't + # want to maintain a list and mdraid's ID_FS_TYPE='linux_raid_member', so + # dmraid will be everything that is raid and not linux_raid_member + #from formats.dmraid import DMRaidMember + #if info.has_key("ID_FS_TYPE") and \ + # info["ID_FS_TYPE"] in DMRaidMember._udevTypes: + # return True + # + return False + +def udev_device_get_dmraid_partition_disk(info): + try: + p_index = info["DM_NAME"].rindex("p") + except (KeyError, AttributeError, ValueError): + return None + + if not info["DM_NAME"][p_index+1:].isdigit(): + return None + + return info["DM_NAME"][:p_index] + +def udev_device_is_dmraid_partition(info, devicetree): + #diskname = udev_device_get_dmraid_partition_disk(info) + #dmraid_devices = devicetree.getDevicesByType("dm-raid array") + # + #for device in dmraid_devices: + # if diskname == device.name: + # return True + # + return False + +if __name__ == "__main__": + for device in udev_get_block_devices(): + print udev_device_get_name(device) + print " Label :", udev_device_get_label(device) + print " UUID :", udev_device_get_uuid(device) + print " Format :", udev_device_get_format(device) + print " Is disk :", udev_device_is_disk(device) + print " Is cdrom:", udev_device_is_cdrom(device) + print " Is part :", udev_device_is_partition(device) + print " Is dm :", udev_device_is_dm(device) + print " Is md :", udev_device_is_md(device) + #syspath = "/sys" + udev_device_get_sysfs_path(device) + #for (key, value) in udev_get_block_device(syspath).items(): + # print " (%s : %s)" % (key, value,) + print diff --git a/pkgs/core/pomona/src/storage_old/__init__.py b/pkgs/core/pomona/src/storage_old/__init__.py deleted file mode 100644 index a6cc2e7..0000000 --- a/pkgs/core/pomona/src/storage_old/__init__.py +++ /dev/null @@ -1,1176 +0,0 @@ -#!/usr/bin/python - -from devicetree import DeviceTree - -from deviceaction import * -from devicelibs import lvm -from devicelibs.lvm import safeLvmName -from devices import * -from formats import get_default_filesystem_type -from udev import * - -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -def storageInitialize(installer): - storage = installer.ds.storage - - storage.shutdown() - - if installer.dispatch.dir == DISPATCH_BACK: - return - - # XXX I don't understand why I have to do this - udev_trigger(subsystem="block") - - #XXX Determine our cdrom drive/usb key here and add it to protectedPartiotions - storage.reset() - -class Storage(object): - def __init__(self, installer): - self.installer = installer - - self.protectedDisks = [] - self.clearDisks = [] - self.ignoredDisks = [] - - self.defaultFSType = get_default_filesystem_type() - self.defaultBootFSType = get_default_filesystem_type(boot=True) - - self.doAutoPartition = False - self.encryptedAutoPart = False - #self.autoPartitionRequests = [] - self.autoPartitionRequests = [PartSpec(mountpoint="/", fstype=self.defaultFSType, size=1024, grow=True), - PartSpec(mountpoint="/boot", fstype=self.defaultFSType, size=75, grow=False),] - - #self.devicetree = DeviceTree(self.installer) - self.devicetree = None - - self._nextID = 0 - - def shutdown(self): - self.installer.log.debug("Shutting down storage...") - - def reset(self): - """ Reset storage configuration to reflect actual system state. - - This should rescan from scratch but not clobber user-obtained - information like passphrases - """ - #for device in self.devices: - # if device.format.type == "luks" and device.format.exists: - # self.__luksDevs[device.format.uuid] = device.format._LUKS__passphrase - - self.installer.window = self.installer.intf.waitWindow(_("Finding Devices"), - _("Finding storage devices...")) - self.devicetree = DeviceTree(self.installer) - self.devicetree.populate() - self.fsset = FSSet(self.installer) - self.installer.window.pop() - - def checkNoDisks(self): - """Check that there are valid disk devices.""" - if not self.disks: - self.installer.intf.messageWindow(_("No Drives Found"), - _("An error has occurred - no valid devices were " - "found on which to create new file systems. " - "Please check your hardware for the cause " - "of this problem.")) - return True - return False - - def sanityCheck(self): - """ Run a series of tests to verify the storage configuration. - - This function is called at the end of partitioning so that - we can make sure you don't have anything silly (like no /, - a really small /, etc). Returns (errors, warnings) where - each is a list of strings. - """ - checkSizes = [('/usr', 250), ('/tmp', 50), ('/var', 384), - ('/home', 100), ('/boot', 75)] - warnings = [] - errors = [] - - filesystems = self.fsset.mountpoints - root = self.fsset.rootDevice - swaps = self.fsset.swapDevices - #try: - # boot = self.anaconda.platform.bootDevice() - #except DeviceError: - # boot = None - boot = None - - if not root: - errors.append(_("You have not defined a root partition (/), " - "which is required for installation of %s " - "to continue.") % (PRODUCT_NAME,)) - - if root and root.size < 250: - warnings.append(_("Your root partition is less than 250 " - "megabytes which is usually too small to " - "install %s.") % (PRODUCT_NAME,)) - - recommended_size = 1024 - if (root and root.size < recommended_size): - errors.append(_("Your / partition is less than %s " - "megabytes which is lower than recommended " - "for a normal %s install.") - %(recommended_size, PRODUCT_NAME)) - - # livecds have to have the rootfs type match up - #if (root and - # self.installer.backend.rootFsType and - # root.format.type != self.installer.backend.rootFsType): - # errors.append(_("Your / partition does not match the " - # "the live image you are installing from. " - # "It must be formatted as %s.") - # % (self.anaconda.backend.rootFsType,)) - - for (mount, size) in checkSizes: - if mount in filesystems and filesystems[mount].size < size: - warnings.append(_("Your %s partition is less than %s " - "megabytes which is lower than recommended " - "for a normal %s install.") - %(mount, size, PRODUCT_NAME)) - - usb_disks = [] - firewire_disks = [] - #for disk in self.disks: - # if isys.driveUsesModule(disk.name, ["usb-storage", "ub"]): - # usb_disks.append(disk) - # elif isys.driveUsesModule(disk.name, ["sbp2", "firewire-sbp2"]): - # firewire_disks.append(disk) - - uses_usb = False - uses_firewire = False - for device in filesystems.values(): - for disk in usb_disks: - if device.dependsOn(disk): - uses_usb = True - break - - for disk in firewire_disks: - if device.dependsOn(disk): - uses_firewire = True - break - - if uses_usb: - warnings.append(_("Installing on a USB device. This may " - "or may not produce a working system.")) - if uses_firewire: - warnings.append(_("Installing on a FireWire device. This may " - "or may not produce a working system.")) - - if not boot: - errors.append(_("You have not created a boot partition.")) - - if (boot and boot.type == "mdarray" and - boot.level != 1): - errors.append(_("Bootable partitions can only be on RAID1 " - "devices.")) - - # can't have bootable partition on LV - if boot and boot.type == "lvmlv": - errors.append(_("Bootable partitions cannot be on a " - "logical volume.")) - - # most arches can't have boot on RAID - if boot and boot.type == "mdarray" and not self.anaconda.platform.supportsMdRaidBoot: - errors.append(_("Bootable partitions cannot be on a RAID " - "device.")) - - # Lots of filesystems types don't support /boot. - if boot and not boot.format.bootable: - errors.append(_("Bootable partitions cannot be on an %s " - "filesystem.") % boot.format.name) - - # vfat /boot is insane. - if (boot and boot == root and boot.format.type == "vfat"): - errors.append(_("Bootable partitions cannot be on an %s " - "filesystem.") % boot.format.type) - - if (boot and filter(lambda d: d.type == "luks/dm-crypt", - self.deviceDeps(boot))): - errors.append(_("Bootable partitions cannot be on an " - "encrypted block device")) - - if not swaps: - warnings.append(_("You have not specified a swap partition. " - "Although not strictly required in all cases, " - "it will significantly improve performance for " - "most installations.")) - - return (errors, warnings) - - def deviceDeps(self, device): - return self.devicetree.getDependentDevices(device) - - @property - def nextID(self): - id = self._nextID - self._nextID += 1 - return id - - @property - def disks(self): - """ A list of the disks in the device tree. - - Ignored disks are not included, as are disks with no media present. - - This is based on the current state of the device tree and - does not necessarily reflect the actual on-disk state of the - system's disks. - """ - disks = [] - devices = self.devicetree.devices - for d in devices: - if isinstance(devices[d], DiskDevice) and devices[d].mediaPresent: - disks.append(devices[d]) - disks.sort(key=lambda d: d.name) - return disks - - @property - def devices(self): - """ A list of all the devices in the device tree. """ - devices = self.devicetree.devices.values() - devices.sort(key=lambda d: d.path) - return devices - - @property - def partitions(self): - """ A list of the partitions in the device tree. - - This is based on the current state of the device tree and - does not necessarily reflect the actual on-disk state of the - system's disks. - """ - partitions = self.devicetree.getDevicesByInstance(PartitionDevice) - partitions.sort(key=lambda d: d.name) - return partitions - - @property - def vgs(self): - """ A list of the LVM Volume Groups in the device tree. - - This is based on the current state of the device tree and - does not necessarily reflect the actual on-disk state of the - system's disks. - """ - vgs = self.devicetree.getDevicesByType("lvmvg") - vgs.sort(key=lambda d: d.name) - return vgs - - def createDevice(self, device): - """ Schedule creation of a device. - - TODO: We could do some things here like assign the next - available raid minor if one isn't already set. - """ - self.devicetree.registerAction(ActionCreateDevice(self.installer, device)) - if device.format.type: - self.devicetree.registerAction(ActionCreateFormat(self.installer, device)) - - def destroyDevice(self, device): - """ Schedule destruction of a device. """ - if device.format.exists and device.format.type: - # schedule destruction of any formatting while we're at it - self.devicetree.registerAction(ActionDestroyFormat(self.installer, device)) - - action = ActionDestroyDevice(self.installer, device) - self.devicetree.registerAction(action) - - def newPartition(self, *args, **kwargs): - """ Return a new PartitionDevice instance for configuring. """ - if kwargs.has_key("fmt_type"): - kwargs["format"] = getFormat(kwargs.pop("fmt_type"), installer=self.installer, - mountpoint=kwargs.pop("mountpoint", None)) - - if kwargs.has_key("disks"): - parents = kwargs.pop("disks") - if isinstance(parents, Device): - kwargs["parents"] = [parents] - else: - kwargs["parents"] = parents - - if kwargs.has_key("name"): - name = kwargs.pop("name") - else: - name = "req%d" % self.nextID - - return PartitionDevice(self.installer, name, *args, **kwargs) - - def newVG(self, *args, **kwargs): - """ Return a new LVMVolumeGroupDevice instance. """ - pvs = kwargs.pop("pvs", []) - for pv in pvs: - if pv not in self.devices: - raise ValueError("pv is not in the device tree") - - if kwargs.has_key("name"): - name = kwargs.pop("name") - else: - # XXX name = self.createSuggestedVGName(self.anaconda.id.network) - name = self.createSuggestedVGName(None) - - if name in [d.name for d in self.devices]: - raise ValueError("name already in use") - - return LVMVolumeGroupDevice(self.installer, name, pvs, *args, **kwargs) - - def newLV(self, *args, **kwargs): - """ Return a new LVMLogicalVolumeDevice instance. """ - if kwargs.has_key("vg"): - vg = kwargs.pop("vg") - - mountpoint = kwargs.pop("mountpoint", None) - if kwargs.has_key("fmt_type"): - kwargs["format"] = getFormat(kwargs.pop("fmt_type"), - installer=self.installer, - mountpoint=mountpoint) - - if kwargs.has_key("name"): - name = kwargs.pop("name") - else: - if kwargs.get("format") and kwargs["format"].type == "swap": - swap = True - else: - swap = False - name = self.createSuggestedLVName(vg, - swap=swap, - mountpoint=mountpoint) - - if name in [d.name for d in self.devices]: - raise ValueError("Name already in use") - - return LVMLogicalVolumeDevice(self.installer, name, vg, *args, **kwargs) - - def createSuggestedVGName(self, network): - """ Return a reasonable, unused VG name. """ - # try to create a volume group name incorporating the hostname - #hn = network.hostname # XXX - hn = "%s.localdomain" % PROCUCT_SNAME - vgnames = [vg.name for vg in self.vgs] - if hn is not None and hn != '': - if hn == 'localhost' or hn == 'localhost.localdomain': - vgtemplate = "VolGroup" - elif hn.find('.') != -1: - hn = safeLvmName(hn) - vgtemplate = "vg_%s" % (hn.split('.')[0].lower(),) - else: - hn = safeLvmName(hn) - vgtemplate = "vg_%s" % (hn.lower(),) - else: - vgtemplate = "VolGroup" - - if vgtemplate not in vgnames and \ - vgtemplate not in lvm.lvm_vg_blacklist: - return vgtemplate - else: - i = 0 - while 1: - tmpname = "%s%02d" % (vgtemplate, i,) - if not tmpname in vgnames and \ - tmpname not in lvm.lvm_vg_blacklist: - break - - i += 1 - if i > 99: - tmpname = "" - - return tmpname - - def createSuggestedLVName(self, vg, swap=None, mountpoint=None): - """ Return a suitable, unused name for a new logical volume. """ - # FIXME: this is not at all guaranteed to work - if mountpoint: - # try to incorporate the mountpoint into the name - if mountpoint == '/': - lvtemplate = 'lv_root' - else: - tmp = safeLvmName(mountpoint) - lvtemplate = "lv_%s" % (tmp,) - else: - if swap: - if len([s for s in self.swaps if s in vg.lvs]): - idx = len([s for s in self.swaps if s in vg.lvs]) - while True: - lvtemplate = "lv_swap%02d" % idx - if lvtemplate in [lv.lvname for lv in vg.lvs]: - idx += 1 - else: - break - else: - lvtemplate = "lv_swap" - else: - idx = len(vg.lvs) - while True: - lvtemplate = "LogVol%02d" % idx - if lvtemplate in [l.lvname for l in vg.lvs]: - idx += 1 - else: - break - - return lvtemplate - - def deviceImmutable(self, device): - """ Return any reason the device cannot be modified/removed. - - Return False if the device can be removed. - - Devices that cannot be removed include: - - - protected partitions - - devices that are part of an md array or lvm vg - - extended partition containing logical partitions that - meet any of the above criteria - - """ - if not isinstance(device, Device): - raise ValueError("arg1 (%s) must be a Device instance" % device) - - if device.name in self.protectedDisks: - return _("This partition is holding the data for the hard " - "drive install.") - elif device.format.type == "mdmember": - for array in self.mdarrays: - if array.dependsOn(device): - if array.minor is not None: - return _("This device is part of the RAID " - "device %s.") % (array.path,) - else: - return _("This device is part of a RAID device.") - elif device.format.type == "lvmpv": - for vg in self.vgs: - if vg.dependsOn(device): - if vg.name is not None: - return _("This device is part of the LVM " - "volume group '%s'.") % (vg.name,) - else: - return _("This device is part of a LVM volume " - "group.") - elif device.format.type == "luks": - try: - luksdev = self.devicetree.getChildren(device)[0] - except IndexError: - pass - else: - return self.deviceImmutable(luksdev) - elif isinstance(device, PartitionDevice) and device.isExtended: - reasons = {} - for dep in self.deviceDeps(device): - reason = self.deviceImmutable(dep) - if reason: - reasons[dep.path] = reason - if reasons: - msg = _("This device is an extended partition which " - "contains logical partitions that cannot be " - "deleted:\n\n") - for dev in reasons: - msg += "%s: %s" % (dev, reasons[dev]) - return msg - - for i in self.devicetree.immutableDevices: - if i[0] == device.name: - return i[1] - - return False - - -class FSSet(object): - """ A class to represent a set of filesystems. """ - def __init__(self, installer): - self.installer = installer - self.devicetree = installer.ds.storage.devicetree - self.cryptTab = None - self.blkidTab = None - self.origFStab = None - self.active = False - self._dev = None - self._devpts = None - self._sysfs = None - self._proc = None - self._devshm = None - - @property - def sysfs(self): - if not self._sysfs: - self._sysfs = NoDevice(format=getFormat("sysfs", - device="sys", - mountpoint="/sys")) - return self._sysfs - - @property - def dev(self): - if not self._dev: - self._dev = DirectoryDevice("/dev", format=getFormat("bind", - device="/dev", - mountpoint="/dev", - exists=True), - exists=True) - - return self._dev - - @property - def devpts(self): - if not self._devpts: - self._devpts = NoDevice(format=getFormat("devpts", - device="devpts", - mountpoint="/dev/pts")) - return self._devpts - - @property - def proc(self): - if not self._proc: - self._proc = NoDevice(format=getFormat("proc", - device="proc", - mountpoint="/proc")) - return self._proc - - @property - def devshm(self): - if not self._devshm: - self._devshm = NoDevice(format=getFormat("tmpfs", - device="tmpfs", - mountpoint="/dev/shm")) - return self._devshm - - @property - def devices(self): - devices = self.devicetree.devices.values() - devices.sort(key=lambda d: d.path) - return devices - - @property - def mountpoints(self): - filesystems = {} - for device in self.devices: - if device.format.mountable and device.format.mountpoint: - filesystems[device.format.mountpoint] = device - return filesystems - - def _parseOneLine(self, (devspec, mountpoint, fstype, options, dump, passno)): - # find device in the tree - device = self.devicetree.resolveDevice(devspec, - cryptTab=self.cryptTab, - blkidTab=self.blkidTab) - if device: - # fall through to the bottom of this block - pass - elif devspec.startswith("/dev/loop"): - # FIXME: create devices.LoopDevice - self.installer.log.warning("completely ignoring your loop mount") - elif ":" in devspec: - # NFS -- preserve but otherwise ignore - device = NFSDevice(devspec, - format=getFormat(fstype, - device=devspec)) - elif devspec.startswith("/") and fstype == "swap": - # swap file - device = FileDevice(devspec, - parents=get_containing_device(devspec, self.devicetree), - format=getFormat(fstype, - device=devspec, - exists=True), - exists=True) - elif fstype == "bind" or "bind" in options: - # bind mount... set fstype so later comparison won't - # turn up false positives - fstype = "bind" - device = FileDevice(devspec, - parents=get_containing_device(devspec, self.devicetree), - exists=True) - device.format = getFormat("bind", - device=device.path, - exists=True) - elif mountpoint in ("/proc", "/sys", "/dev/shm", "/dev/pts"): - # drop these now -- we'll recreate later - return None - else: - # nodev filesystem -- preserve or drop completely? - format = getFormat(fstype) - if devspec == "none" or \ - isinstance(format, get_device_format_class("nodev")): - device = NoDevice(format) - else: - device = StorageDevice(devspec) - - if device is None: - self.installer.log.error("failed to resolve %s (%s) from fstab" % (devspec, - fstype)) - return None - - # make sure, if we're using a device from the tree, that - # the device's format we found matches what's in the fstab - fmt = getFormat(fstype, device=device.path) - if fmt.type != device.format.type: - self.installer.log.warning("scanned format (%s) differs from fstab " - "format (%s)" % (device.format.type, fstype)) - - if device.format.mountable: - device.format.mountpoint = mountpoint - device.format.mountopts = options - - # is this useful? - try: - device.format.options = options - except AttributeError: - pass - - return device - - def parseFSTab(self, chroot=""): - """ parse /etc/fstab - - preconditions: - all storage devices have been scanned, including filesystems - postconditions: - - FIXME: control which exceptions we raise - - XXX do we care about bind mounts? - how about nodev mounts? - loop mounts? - """ - if not chroot or not os.path.isdir(chroot): - chroot = "" - - path = "%s/etc/fstab" % chroot - if not os.access(path, os.R_OK): - # XXX should we raise an exception instead? - self.installer.log.info("cannot open %s for read" % path) - return - - blkidTab = BlkidTab(self.installer, chroot=chroot) - try: - blkidTab.parse() - self.installer.log.debug("blkid.tab devs: %s" % blkidTab.devices.keys()) - except Exception as e: - self.installer.log.info("error parsing blkid.tab: %s" % e) - blkidTab = None - - cryptTab = CryptTab(self.devicetree, blkidTab=blkidTab, chroot=chroot) - try: - cryptTab.parse(chroot=chroot) - self.installer.log.debug("crypttab maps: %s" % cryptTab.mappings.keys()) - except Exception as e: - self.installer.log.info("error parsing crypttab: %s" % e) - cryptTab = None - - self.blkidTab = blkidTab - self.cryptTab = cryptTab - - with open(path) as f: - self.installer.log.debug("parsing %s" % path) - - lines = f.readlines() - - # save the original file - self.origFStab = ''.join(lines) - - for line in lines: - # strip off comments - (line, pound, comment) = line.partition("#") - fields = line.split() - - if not 4 <= len(fields) <= 6: - continue - elif len(fields) == 4: - fields.extend([0, 0]) - elif len(fields) == 5: - fields.append(0) - - (devspec, mountpoint, fstype, options, dump, passno) = fields - - try: - device = self._parseOneLine((devspec, mountpoint, fstype, options, dump, passno)) - except Exception as e: - raise Exception("fstab entry %s is malformed: %s" % (devspec, e)) - - if not device: - continue - - if device not in self.devicetree.devices.values(): - self.devicetree._addDevice(device) - - def fsFreeSpace(self, chroot='/'): - space = [] - for device in self.devices: - if not device.format.mountable or \ - not device.format.status: - continue - - path = "%s/%s" % (chroot, device.format.mountpoint) - try: - space.append((device.format.mountpoint, - isys.pathSpaceAvailable(path))) - except SystemError: - self.installer.log.error("failed to calculate free space for %s" % (device.format.mountpoint,)) - - space.sort(key=lambda s: s[1]) - return space - - def mtab(self): - format = "%s %s %s %s 0 0\n" - mtab = "" - devices = self.mountpoints.values() + self.swapDevices - devices.extend([self.devshm, self.devpts, self.sysfs, self.proc]) - devices.sort(key=lambda d: getattr(d.format, "mountpoint", None)) - for device in devices: - if not device.format.status: - continue - if not device.format.mountable: - continue - if device.format.mountpoint: - options = device.format.mountopts - if options: - options = options.replace("defaults,", "") - options = options.replace("defaults", "") - - if options: - options = "rw," + options - else: - options = "rw" - mtab = mtab + format % (device.path, - device.format.mountpoint, - device.format.type, - options) - return mtab - - def turnOnSwap(self): - intf = self.installer.intf - for device in self.swapDevices: - try: - device.setup() - device.format.setup() - except SuspendError: - if intf: - msg = _("The swap device:\n\n %s\n\n" - "in your /etc/fstab file is currently in " - "use as a software suspend device, " - "which means your system is hibernating. " - "If you are performing a new install, " - "make sure the installer is set " - "to format all swap devices.") \ - % device.path - intf.messageWindow(_("Error"), msg) - sys.exit(0) - except DeviceError as msg: - if intf: - err = _("Error enabling swap device %s: %s\n\n" - "This most likely means this swap " - "device has not been initialized.\n\n" - "Press OK to exit the installer.") % \ - (device.path, msg) - intf.messageWindow(_("Error"), err) - sys.exit(0) - - def mountFilesystems(self, installer, raiseErrors=None, readOnly=None, - skipRoot=False): - intf = installer.intf - devices = self.mountpoints.values() + self.swapDevices - devices.extend([self.dev, self.devshm, self.devpts, self.sysfs, self.proc]) - devices.sort(key=lambda d: getattr(d.format, "mountpoint", None)) - - for device in devices: - if not device.format.mountable or not device.format.mountpoint: - continue - - if skipRoot and device.format.mountpoint == "/": - continue - - options = device.format.options - if "noauto" in options.split(","): - continue - - try: - device.setup() - except Exception as msg: - # FIXME: need an error popup - continue - - if readOnly: - options = "%s,%s" % (options, readOnly) - - try: - device.format.setup(options=options, - chroot=installer.rootPath) - except OSError as (num, msg): - if intf: - if num == errno.EEXIST: - intf.messageWindow(_("Invalid mount point"), - _("An error occurred when trying " - "to create %s. Some element of " - "this path is not a directory. " - "This is a fatal error and the " - "install cannot continue.\n\n" - "Press <Enter> to exit the " - "installer.") - % (device.format.mountpoint,)) - else: - intf.messageWindow(_("Invalid mount point"), - _("An error occurred when trying " - "to create %s: %s. This is " - "a fatal error and the install " - "cannot continue.\n\n" - "Press <Enter> to exit the " - "installer.") - % (device.format.mountpoint, msg)) - self.installer.log.error("OSError: (%d) %s" % (num, msg) ) - sys.exit(0) - except SystemError as (num, msg): - if raiseErrors: - raise - if intf and not device.format.linuxNative: - ret = intf.messageWindow(_("Unable to mount filesystem"), - _("An error occurred mounting " - "device %s as %s. You may " - "continue installation, but " - "there may be problems.") % - (device.path, - device.format.mountpoint), - type="custom", - custom_icon="warning", - custom_buttons=[_("_Exit installer"), - _("_Continue")]) - - if ret == 0: - sys.exit(0) - else: - continue - - self.installer.log.error("SystemError: (%d) %s" % (num, msg) ) - sys.exit(0) - except FSError as msg: - if intf: - intf.messageWindow(_("Unable to mount filesystem"), - _("An error occurred mounting " - "device %s as %s: %s. This is " - "a fatal error and the install " - "cannot continue.\n\n" - "Press <Enter> to exit the " - "installer.") - % (device.path, - device.format.mountpoint, - msg)) - self.installer.log.error("FSError: %s" % msg) - sys.exit(0) - - self.active = True - - def umountFilesystems(self, instPath, ignoreErrors=True, swapoff=True): - devices = self.mountpoints.values() + self.swapDevices - devices.extend([self.dev, self.devshm, self.devpts, self.sysfs, self.proc]) - devices.sort(key=lambda d: getattr(d.format, "mountpoint", None)) - devices.reverse() - for device in devices: - if not device.format.mountable and \ - (device.format.type != "swap" or swapoff): - continue - - device.format.teardown() - device.teardown() - - self.active = False - - def createSwapFile(self, rootPath, device, size): - """ Create and activate a swap file under rootPath. """ - filename = "/SWAP" - count = 0 - basedir = os.path.normpath("%s/%s" % (rootPath, - device.format.mountpoint)) - while os.path.exists("%s/%s" % (basedir, filename)) or \ - self.devicetree.getDeviceByName(filename): - file = os.path.normpath("%s/%s" % (basedir, filename)) - count += 1 - filename = "/SWAP-%d" % count - - dev = FileDevice(filename, - size=size, - parents=[device], - format=getFormat("swap", device=filename)) - dev.create() - dev.setup() - dev.format.create() - dev.format.setup() - # nasty, nasty - self.devicetree._addDevice(dev) - - def mkDevRoot(self, instPath): - root = self.rootDevice - dev = "%s/%s" % (instPath, root.path) - if not os.path.exists("%s/dev/root" %(instPath,)) and os.path.exists(dev): - rdev = os.stat(dev).st_rdev - os.mknod("%s/dev/root" % (instPath,), stat.S_IFBLK | 0600, rdev) - - @property - def swapDevices(self): - swaps = [] - for device in self.devices: - if device.format.type == "swap": - swaps.append(device) - return swaps - - @property - def rootDevice(self): - for device in self.devices: - try: - mountpoint = device.format.mountpoint - except AttributeError: - mountpoint = None - - if mountpoint == "/": - return device - - @property - def migratableDevices(self): - """ List of devices whose filesystems can be migrated. """ - migratable = [] - for device in self.devices: - if device.format.migratable and device.format.exists: - migratable.append(device) - - return migratable - - def write(self, instPath): - """ write out all config files based on the set of filesystems """ - # /etc/fstab - fstab_path = os.path.normpath("%s/etc/fstab" % instPath) - fstab = self.fstab() - open(fstab_path, "w").write(fstab) - - # /etc/crypttab - crypttab_path = os.path.normpath("%s/etc/crypttab" % instPath) - crypttab = self.crypttab() - open(crypttab_path, "w").write(crypttab) - - # /etc/mdadm.conf - mdadm_path = os.path.normpath("%s/etc/mdadm.conf" % instPath) - mdadm_conf = self.mdadmConf() - open(mdadm_path, "w").write(mdadm_conf) - - def crypttab(self): - # if we are upgrading, do we want to update crypttab? - # gut reaction says no, but plymouth needs the names to be very - # specific for passphrase prompting - if not self.cryptTab: - self.cryptTab = CryptTab(self.devicetree) - self.cryptTab.populate() - - devices = self.mountpoints.values() + self.swapDevices - - # prune crypttab -- only mappings required by one or more entries - for name in self.cryptTab.mappings.keys(): - keep = False - mapInfo = self.cryptTab[name] - cryptoDev = mapInfo['device'] - for device in devices: - if device == cryptoDev or device.dependsOn(cryptoDev): - keep = True - break - - if not keep: - del self.cryptTab.mappings[name] - - return self.cryptTab.crypttab() - - def mdadmConf(self): - """ Return the contents of mdadm.conf. """ - arrays = self.devicetree.getDevicesByType("mdarray") - conf = "" - devices = self.mountpoints.values() + self.swapDevices - for array in arrays: - writeConf = False - for device in devices: - if device == array or device.dependsOn(array): - writeConf = True - break - - if writeConf: - conf += array.mdadmConfEntry - - return conf - - def fstab (self): - format = "%-23s %-23s %-7s %-15s %d %d\n" - fstab = """ -# -# /etc/fstab -# Created by pomona on %s -# -# Accessible filesystems, by reference, are maintained under '/dev/disk' -# See man pages fstab(5), findfs(8), mount(8) and/or vol_id(8) for more info -# -""" % time.asctime() - - devices = self.mountpoints.values() + self.swapDevices - devices.extend([self.devshm, self.devpts, self.sysfs, self.proc]) - netdevs = self.devicetree.getDevicesByInstance(NetworkStorageDevice) - for device in devices: - # why the hell do we put swap in the fstab, anyway? - if not device.format.mountable and device.format.type != "swap": - continue - - fstype = device.format.type - if fstype == "swap": - mountpoint = "swap" - options = device.format.options - else: - mountpoint = device.format.mountpoint - options = device.format.mountopts - if not mountpoint: - self.installer.log.warning("%s filesystem on %s has no mountpoint" % \ - (fstype, device.path)) - continue - - options = options or "defaults" - for netdev in netdevs: - if device.dependsOn(netdev): - options = options + ",_netdev" - break - devspec = device.fstabSpec - dump = device.format.dump - if device.format.check and mountpoint == "/": - passno = 1 - elif device.format.check: - passno = 2 - else: - passno = 0 - fstab = fstab + device.fstabComment - fstab = fstab + format % (devspec, mountpoint, fstype, - options, dump, passno) - return fstab - -class PartSpec(object): - def __init__(self, mountpoint=None, fstype=None, size=None, maxSize=None, - grow=False, asVol=False, weight=0): - self.mountpoint = mountpoint - self.fstype = fstype - self.size = size - self.maxSize = maxSize - self.grow = grow - self.asVol = asVol - self.weight = weight - - -class BlkidTab(object): - """ Dictionary-like interface to blkid.tab with device path keys """ - def __init__(self, installer, chroot=""): - self.installer = installer - self.chroot = chroot - self.devices = {} - - def parse(self): - path = "%s/etc/blkid/blkid.tab" % self.chroot - self.installer.log.debug("parsing %s" % path) - with open(path) as f: - for line in f.readlines(): - # this is pretty ugly, but an XML parser is more work than - # is justifiable for this purpose - if not line.startswith("<device "): - continue - - line = line[len("<device "):-len("</device>\n")] - (data, sep, device) = line.partition(">") - if not device: - continue - - self.devices[device] = {} - for pair in data.split(): - try: - (key, value) = pair.split("=") - except ValueError: - continue - - self.devices[device][key] = value[1:-1] # strip off quotes - - def __getitem__(self, key): - return self.devices[key] - - def get(self, key, default=None): - return self.devices.get(key, default) - - -class CryptTab(object): - """ Dictionary-like interface to crypttab entries with map name keys """ - def __init__(self, devicetree, blkidTab=None, chroot=""): - self.devicetree = devicetree - self.blkidTab = blkidTab - self.chroot = chroot - self.mappings = {} - - def parse(self, chroot=""): - """ Parse /etc/crypttab from an existing installation. """ - if not chroot or not os.path.isdir(chroot): - chroot = "" - - path = "%s/etc/crypttab" % chroot - log.debug("parsing %s" % path) - with open(path) as f: - if not self.blkidTab: - try: - self.blkidTab = BlkidTab(chroot=chroot) - self.blkidTab.parse() - except Exception: - self.blkidTab = None - - for line in f.readlines(): - (line, pound, comment) = line.partition("#") - fields = line.split() - if not 2 <= len(fields) <= 4: - continue - elif len(fields) == 2: - fields.extend(['none', '']) - elif len(fields) == 3: - fields.append('') - - (name, devspec, keyfile, options) = fields - - # resolve devspec to a device in the tree - device = self.devicetree.resolveDevice(devspec, - blkidTab=self.blkidTab) - if device: - self.mappings[name] = {"device": device, - "keyfile": keyfile, - "options": options} - - def populate(self): - """ Populate the instance based on the device tree's contents. """ - for device in self.devicetree.devices.values(): - # XXX should we put them all in there or just the ones that - # are part of a device containing swap or a filesystem? - # - # Put them all in here -- we can filter from FSSet - if device.format.type != "luks": - continue - - key_file = device.format.keyFile - if not key_file: - key_file = "none" - - options = device.format.options - if not options: - options = "" - - self.mappings[device.format.mapName] = {"device": device, - "keyfile": key_file, - "options": options} - - def crypttab(self): - """ Write out /etc/crypttab """ - crypttab = "" - for name in self.mappings: - entry = self[name] - crypttab += "%s UUID=%s %s %s\n" % (name, - entry['device'].format.uuid, - entry['keyfile'], - entry['options']) - return crypttab - - def __getitem__(self, key): - return self.mappings[key] - - def get(self, key, default=None): - return self.mappings.get(key, default) diff --git a/pkgs/core/pomona/src/storage_old/deviceaction.py b/pkgs/core/pomona/src/storage_old/deviceaction.py deleted file mode 100644 index 9361b52..0000000 --- a/pkgs/core/pomona/src/storage_old/deviceaction.py +++ /dev/null @@ -1,352 +0,0 @@ -#!/usr/bin/python - -import copy - -from devices import StorageDevice, PartitionDevice -from formats import getFormat -from errors import * -from udev import * - -# The values are just hints as to the ordering. -# Eg: fsmod and devmod ordering depends on the mod (shrink -v- grow) -ACTION_TYPE_NONE = 0 -ACTION_TYPE_DESTROY = 1000 -ACTION_TYPE_RESIZE = 500 -ACTION_TYPE_MIGRATE = 250 -ACTION_TYPE_CREATE = 100 - -action_strings = {ACTION_TYPE_NONE: "None", - ACTION_TYPE_DESTROY: "Destroy", - ACTION_TYPE_RESIZE: "Resize", - ACTION_TYPE_MIGRATE: "Migrate", - ACTION_TYPE_CREATE: "Create"} - -ACTION_OBJECT_NONE = 0 -ACTION_OBJECT_FORMAT = 1 -ACTION_OBJECT_DEVICE = 2 - -object_strings = {ACTION_OBJECT_NONE: "None", - ACTION_OBJECT_FORMAT: "Format", - ACTION_OBJECT_DEVICE: "Device"} - -RESIZE_SHRINK = 88 -RESIZE_GROW = 89 - -resize_strings = {RESIZE_SHRINK: "Shrink", - RESIZE_GROW: "Grow"} - -def action_type_from_string(type_string): - if type_string is None: - return None - - for (k,v) in action_strings.items(): - if v.lower() == type_string.lower(): - return k - - return resize_type_from_string(type_string) - -def action_object_from_string(type_string): - if type_string is None: - return None - - for (k,v) in object_strings.items(): - if v.lower() == type_string.lower(): - return k - -def resize_type_from_string(type_string): - if type_string is None: - return None - - for (k,v) in resize_strings.items(): - if v.lower() == type_string.lower(): - return k - -class DeviceAction(object): - """ An action that will be carried out in the future on a Device. - - These classes represent actions to be performed on devices or - filesystems. - - The operand Device instance will be modified according to the - action, but no changes will be made to the underlying device or - filesystem until the DeviceAction instance's execute method is - called. The DeviceAction instance's cancel method should reverse - any modifications made to the Device instance's attributes. - - If the Device instance represents a pre-existing device, the - constructor should call any methods or set any attributes that the - action will eventually change. Device/DeviceFormat classes should verify - that the requested modifications are reasonable and raise an - exception if not. - - Only one action of any given type/object pair can exist for any - given device at any given time. This is enforced by the - DeviceTree. - - Basic usage: - - a = DeviceAction(dev) - a.execute() - - OR - - a = DeviceAction(dev) - a.cancel() - - - XXX should we back up the device with a deep copy for forcibly - cancelling actions? - - The downside is that we lose any checking or verification that - would get done when resetting the Device instance's attributes to - their original values. - - The upside is that we would be guaranteed to achieve a total - reversal. No chance of, eg: resizes ending up altering Device - size due to rounding or other miscalculation. -""" - type = ACTION_TYPE_NONE - obj = ACTION_OBJECT_NONE - - def __init__(self, installer, device): - self.installer = installer - if not isinstance(device, StorageDevice): - raise ValueError("arg 1 must be a StorageDevice instance") - self.device = device - - - def execute(self, intf=None): - """ perform the action """ - pass - - def cancel(self): - """ cancel the action """ - pass - - def isDestroy(self): - return self.type == ACTION_TYPE_DESTROY - - def isCreate(self): - return self.type == ACTION_TYPE_CREATE - - def isMigrate(self): - return self.type == ACTION_TYPE_MIGRATE - - def isResize(self): - return self.type == ACTION_TYPE_RESIZE - - def isShrink(self): - return (self.type == ACTION_TYPE_RESIZE and self.dir == RESIZE_SHRINK) - - def isGrow(self): - return (self.type == ACTION_TYPE_RESIZE and self.dir == RESIZE_GROW) - - def isDevice(self): - return self.obj == ACTION_OBJECT_DEVICE - - def isFormat(self): - return self.obj == ACTION_OBJECT_FORMAT - - def __str__(self): - s = "%s %s" % (action_strings[self.type], object_strings[self.obj]) - if self.isResize(): - s += " (%s)" % resize_strings[self.dir] - if self.isFormat(): - if self.device.format: - fmt_type = self.device.format.type - else: - fmt_type = None - s += " %s on" % fmt_type - if self.isMigrate(): - pass - s += " %s (%s)" % (self.device.name, self.device.type) - return s - -class ActionCreateDevice(DeviceAction): - """ Action representing the creation of a new device. """ - type = ACTION_TYPE_CREATE - obj = ACTION_OBJECT_DEVICE - - def __init__(self, installer, device): - # FIXME: assert device.fs is None - DeviceAction.__init__(self, installer, device) - - def execute(self, intf=None): - self.device.create(intf=intf) - - -class ActionDestroyDevice(DeviceAction): - """ An action representing the deletion of an existing device. """ - type = ACTION_TYPE_DESTROY - obj = ACTION_OBJECT_DEVICE - - def __init__(self, installer, device): - # XXX should we insist that device.fs be None? - DeviceAction.__init__(self, installer, device) - if device.exists: - device.teardown() - - def execute(self, intf=None): - self.device.destroy() - - -class ActionResizeDevice(DeviceAction): - """ An action representing the resizing of an existing device. """ - type = ACTION_TYPE_RESIZE - obj = ACTION_OBJECT_DEVICE - - def __init__(self, installer, device, newsize): - if device.currentSize == newsize: - raise ValueError("new size same as old size") - - if not device.resizable: - raise ValueError("device is not resizable") - - DeviceAction.__init__(self, installer, device) - if newsize > device.currentSize: - self.dir = RESIZE_GROW - else: - self.dir = RESIZE_SHRINK - self.origsize = device.targetSize - self.device.targetSize = newsize - - def execute(self, intf=None): - self.device.resize(intf=intf) - - def cancel(self): - self.device.targetSize = self.origsize - - -class ActionCreateFormat(DeviceAction): - """ An action representing creation of a new filesystem. """ - type = ACTION_TYPE_CREATE - obj = ACTION_OBJECT_FORMAT - - def __init__(self, installer, device, format=None): - DeviceAction.__init__(self, installer, device) - if format: - self.origFormat = device.format - if self.device.format.exists: - self.device.format.teardown() - self.device.format = format - else: - self.origFormat = getFormat(None, installer=installer) - - def execute(self, intf=None): - if isinstance(self.device, PartitionDevice): - if self.format.partedFlag is not None: - self.device.setFlag(self.format.partedFlag) - self.device.disk.commit() - - udev_settle() - self.device.setup() - self.device.format.create(intf=intf, - device=self.device.path, - options=self.device.formatArgs) - # Get the UUID now that the format is created - udev_settle() - self.device.updateSysfsPath() - info = udev_get_block_device("/sys%s" % self.device.sysfsPath) - self.device.format.uuid = udev_device_get_uuid(info) - - def cancel(self): - self.device.format = self.origFormat - - @property - def format(self): - return self.device.format - - -class ActionDestroyFormat(DeviceAction): - """ An action representing the removal of an existing filesystem. - - XXX this seems unnecessary - """ - type = ACTION_TYPE_DESTROY - obj = ACTION_OBJECT_FORMAT - - def __init__(self, installer, device): - DeviceAction.__init__(self, installer, device) - # Save a deep copy of the device stack this format occupies. - # This is necessary since the stack of devices and formats - # required to get to this format may get yanked out from under - # us between now and execute. - self._device = copy.deepcopy(device) - self.origFormat = self._device.format - if device.format.exists: - device.format.teardown() - self.device.format = None - - def execute(self, intf=None): - """ wipe the filesystem signature from the device """ - if self.origFormat: - if isinstance(self.device, PartitionDevice) and \ - self.origFormat.partedFlag is not None: - # unset partition flags and commit - self.device.unsetFlag(self.origFormat.partedFlag) - self.device.disk.commit() - udev_settle() - - # set up our copy of the original device stack since the - # reference we got may have had any number of things changed - # since then (most notably, formats removed by this very - # class' constructor) - self._device.setup() - self.origFormat.destroy() - udev_settle() - self._device.teardown() - - def cancel(self): - self.device.format = self.origFormat - - @property - def format(self): - return self.origFormat - - -class ActionResizeFormat(DeviceAction): - """ An action representing the resizing of an existing filesystem. - - XXX Do we even want to support resizing of a filesystem without - also resizing the device it resides on? - """ - type = ACTION_TYPE_RESIZE - obj = ACTION_OBJECT_FORMAT - - def __init__(self, installer, device, newsize): - if device.targetSize == newsize: - raise ValueError("new size same as old size") - - DeviceAction.__init__(self, installer, device) - if newsize > device.format.currentSize: - self.dir = RESIZE_GROW - else: - self.dir = RESIZE_SHRINK - self.origSize = self.device.format.targetSize - self.device.format.targetSize = newsize - - def execute(self, intf=None): - self.device.setup() - self.device.format.doResize(intf=intf) - - def cancel(self): - self.device.format.targetSize = self.origSize - -class ActionMigrateFormat(DeviceAction): - """ An action representing the migration of an existing filesystem. """ - type = ACTION_TYPE_MIGRATE - obj = ACTION_OBJECT_FORMAT - - def __init__(self, installer, device): - if not device.format.migratable or not device.format.exists: - raise ValueError("device format is not migratable") - - DeviceAction.__init__(self, installer, device) - self.device.format.migrate = True - - def execute(self, intf=None): - self.device.setup() - self.device.format.doMigrate(intf=intf) - - def cancel(self): - self.device.format.migrate = False diff --git a/pkgs/core/pomona/src/storage_old/devicelibs/__init__.py b/pkgs/core/pomona/src/storage_old/devicelibs/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pkgs/core/pomona/src/storage_old/devicelibs/crypto.py b/pkgs/core/pomona/src/storage_old/devicelibs/crypto.py deleted file mode 100644 index 52c9edd..0000000 --- a/pkgs/core/pomona/src/storage_old/devicelibs/crypto.py +++ /dev/null @@ -1,109 +0,0 @@ -# -# crypto.py -# -# 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/. -# -# Author(s): Dave Lehman dlehman@redhat.com -# Martin Sivak msivak@redhat.com -# - -import os -from pycryptsetup import CryptSetup - -from ..errors import * - -def askyes(question): - return True - -def dolog(priority, text): - pass - -def is_luks(device): - cs = CryptSetup(yesDialog = askyes, logFunc = dolog) - return cs.isLuks(device) - -def luks_uuid(device): - cs = CryptSetup(yesDialog = askyes, logFunc = dolog) - return cs.luksUUID(device).strip() - -def luks_status(name): - """True means active, False means inactive (or non-existent)""" - cs = CryptSetup(yesDialog = askyes, logFunc = dolog) - return cs.luksStatus(name)!=0 - -def luks_format(device, - passphrase=None, key_file=None, - cipher=None, key_size=None): - cs = CryptSetup(yesDialog = askyes, logFunc = dolog) - key_file_unlink = False - - if passphrase: - key_file = cs.prepare_passphrase_file(passphrase) - key_file_unlink = True - elif key_file and os.path.isfile(key_file): - pass - else: - raise ValueError("luks_format requires either a passphrase or a key file") - - #None is not considered as default value and pycryptsetup doesn't accept it - #so we need to filter out all Nones - kwargs = {} - kwargs["device"] = device - if cipher: kwargs["cipher"] = cipher - if key_file: kwargs["keyfile"] = key_file - if key_size: kwargs["keysize"] = key_size - - rc = cs.luksFormat(**kwargs) - if key_file_unlink: os.unlink(key_file) - - if rc: - raise CryptoError("luks_format failed for '%s'" % device) - -def luks_open(device, name, passphrase=None, key_file=None): - cs = CryptSetup(yesDialog = askyes, logFunc = dolog) - key_file_unlink = False - - if passphrase: - key_file = cs.prepare_passphrase_file(passphrase) - key_file_unlink = True - elif key_file and os.path.isfile(key_file): - pass - else: - raise ValueError("luks_open requires either a passphrase or a key file") - - rc = cs.luksOpen(device = device, name = name, keyfile = key_file) - if key_file_unlink: os.unlink(key_file) - if rc: - raise CryptoError("luks_open failed for %s (%s)" % (device, name)) - -def luks_close(name): - cs = CryptSetup(yesDialog = askyes, logFunc = dolog) - rc = cs.luksClose(name) - if rc: - raise CryptoError("luks_close failed for %s" % name) - -def luks_add_key(device, - new_passphrase=None, new_key_file=None, - passphrase=None, key_file=None): - cs = CryptSetup(yesDialog = askyes, logFunc = dolog) - return cs.addKey(device, new_passphrase, new_key_file, passphrase, key_file) - - -def luks_remove_key(device, - del_passphrase=None, del_key_file=None, - passphrase=None, key_file=None): - cs = CryptSetup(yesDialog = askyes, logFunc = dolog) - return cs.removeKey(device, del_passphrase, del_key_file, passphrase, key_file) diff --git a/pkgs/core/pomona/src/storage_old/devicelibs/lvm.py b/pkgs/core/pomona/src/storage_old/devicelibs/lvm.py deleted file mode 100644 index 20fa02a..0000000 --- a/pkgs/core/pomona/src/storage_old/devicelibs/lvm.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/python - -import os -import re - -import util - -MAX_LV_SLOTS = 256 - -def has_lvm(): - has_lvm = False - for path in os.environ["PATH"].split(":"): - if os.access("%s/lvm" % path, os.X_OK): - has_lvm = True - break - - if has_lvm: - has_lvm = False - for line in open("/proc/devices").readlines(): - if "device-mapper" in line.split(): - has_lvm = True - break - - return has_lvm - -# Start config_args handling code -# -# Theoretically we can handle all that can be handled with the LVM --config -# argument. For every time we call an lvm_cc (lvm compose config) funciton -# we regenerate the config_args with all global info. -config_args = [] # Holds the final argument list -config_args_data = { "filterRejects": [], # regular expressions to reject. - "filterAccepts": [] } # regexp to accept - -def _composeConfig(): - """lvm command accepts lvm.conf type arguments preceded by --config. """ - global config_args, config_args_data - config_args = [] - - filter_string = "" - rejects = config_args_data["filterRejects"] - # we don't need the accept for now. - # accepts = config_args_data["filterAccepts"] - # if len(accepts) > 0: - # for i in range(len(rejects)): - # filter_string = filter_string + (""a|%s|", " % accpets[i]) - - if len(rejects) > 0: - for i in range(len(rejects)): - filter_string = filter_string + (""r|%s|"," % rejects[i]) - - filter_string = " filter=[%s] " % filter_string.strip(",") - - # As we add config strings we should check them all. - if filter_string == "": - # Nothing was really done. - return - - # devices_string can have (inside the brackets) "dir", "scan", - # "preferred_names", "filter", "cache_dir", "write_cache_state", - # "types", "sysfs_scan", "md_component_detection". see man lvm.conf. - devices_string = " devices {%s} " % (filter_string) # strings can be added - config_string = devices_string # more strings can be added. - config_args = ["--config", config_string] - -def lvm_cc_addFilterRejectRegexp(regexp): - """ Add a regular expression to the --config string.""" - global config_args_data - config_args_data["filterRejects"].append(regexp) - - # compoes config once more. - _composeConfig() - -def lvm_cc_resetFilter(): - global config_args_data - config_args_data["filterRejects"] = [] - config_args_data["filterAccepts"] = [] -# End config_args handling code. - -# Names that should not be used int the creation of VGs -lvm_vg_blacklist = [] -def blacklistVG(name): - global lvm_vg_blacklist - lvm_vg_blacklist.append(name) - -def getPossiblePhysicalExtents(floor=0): - """Returns a list of integers representing the possible values for - the physical extent of a volume group. Value is in KB. - - floor - size (in KB) of smallest PE we care about. - """ - - possiblePE = [] - curpe = 8 - while curpe <= 16384*1024: - if curpe >= floor: - possiblePE.append(curpe) - curpe = curpe * 2 - - return possiblePE - -def getMaxLVSize(): - """ Return the maximum size (in MB) of a logical volume. """ - if util.getArch() in ("x86_64",): #64bit architectures - return (8*1024*1024*1024*1024) #Max is 8EiB (very large number..) - else: - return (16*1024*1024) #Max is 16TiB - -def safeLvmName(name): - tmp = name.strip() - tmp = tmp.replace("/", "_") - tmp = re.sub("[^0-9a-zA-Z._]", "", tmp) - tmp = tmp.lstrip("_") - - return tmp diff --git a/pkgs/core/pomona/src/storage_old/devicelibs/swap.py b/pkgs/core/pomona/src/storage_old/devicelibs/swap.py deleted file mode 100644 index 57a4065..0000000 --- a/pkgs/core/pomona/src/storage_old/devicelibs/swap.py +++ /dev/null @@ -1,85 +0,0 @@ -import resource - -import util -import os - -from ..errors import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -def mkswap(device, label=''): - argv = [] - if label: - argv.extend(["-L", label]) - argv.append(device) - - rc = util.execWithRedirect("mkswap", argv, - stderr = "/dev/tty5", - stdout = "/dev/tty5", - searchPath=1) - - if rc: - raise SwapError("mkswap failed for '%s'" % device) - -def swapon(device, priority=None): - pagesize = resource.getpagesize() - buf = None - if pagesize > 2048: - num = pagesize - else: - num = 2048 - - try: - fd = os.open(device, os.O_RDONLY) - buf = os.read(fd, num) - except OSError: - pass - finally: - try: - os.close(fd) - except (OSError, UnboundLocalError): - pass - - if buf is not None and len(buf) == pagesize: - sig = buf[pagesize - 10:] - if sig == 'SWAP-SPACE': - raise OldSwapError - if sig == 'S1SUSPEND\x00' or sig == 'S2SUSPEND\x00': - raise SuspendError - - argv = [] - if isinstance(priority, int) and 0 <= priority <= 32767: - argv.extend(["-p", "%d" % priority]) - argv.append(device) - - rc = util.execWithRedirect("swapon", - argv, - stderr = "/dev/tty5", - stdout = "/dev/tty5", - searchPath=1) - - if rc: - raise SwapError("swapon failed for '%s'" % device) - -def swapoff(device): - rc = util.execWithRedirect("swapoff", [device], - stderr = "/dev/tty5", - stdout = "/dev/tty5", - searchPath=1) - - if rc: - raise SwapError("swapoff failed for '%s'" % device) - -def swapstatus(device): - lines = open("/proc/swaps").readlines() - status = False - for line in lines: - if not line.strip(): - continue - - if line.split()[0] == device: - status = True - break - - return status diff --git a/pkgs/core/pomona/src/storage_old/devices.py b/pkgs/core/pomona/src/storage_old/devices.py deleted file mode 100644 index e1ba7de..0000000 --- a/pkgs/core/pomona/src/storage_old/devices.py +++ /dev/null @@ -1,1698 +0,0 @@ -#/usr/bin/python - -import copy -import math -import parted -import _ped - -from errors import * -from formats import get_device_format_class, getFormat -from udev import * -from util import notify_kernel, numeric_type - -def devicePathToName(devicePath): - if devicePath.startswith("/dev/"): - name = devicePath[5:] - else: - name = devicePath - - if name.startswith("mapper/"): - name = name[7:] - - return name - -class Device(object): - """ A generic device. - - Device instances know which devices they depend upon (parents - attribute). They do not know which devices depend upon them, but - they do know whether or not they have any dependent devices - (isleaf attribute). - - A Device's setup method should set up all parent devices as well - as the device itself. It should not run the resident format's - setup method. - - Which Device types rely on their parents' formats being active? - DMCryptDevice - - A Device's teardown method should accept the keyword argument - recursive, which takes a boolean value and indicates whether or - not to recursively close parent devices. - - A Device's create method should create all parent devices as well - as the device itself. It should also run the Device's setup method - after creating the device. The create method should not create a - device's resident format. - - Which device type rely on their parents' formats to be created - before they can be created/assembled? - VolumeGroup - DMCryptDevice - - A Device's destroy method should destroy any resident format - before destroying the device itself. - - """ - _type = "generic device" - - def __init__(self, installer, name, parents=None, description=''): - """ Create a Device instance. - - Arguments: - - name -- the device name (generally a device node's basename) - - Keyword Arguments: - - parents -- a list of required Device instances - description -- a string describing the device - - """ - self.installer = installer - - self._name = name - if parents is None: - parents = [] - elif not isinstance(parents, list): - raise ValueError("parents must be a list of Device instances") - self.parents = parents - self.kids = 0 - self.description = description - - for parent in self.parents: - parent.addChild() - - def __deepcopy__(self, memo): - """ Create a deep copy of a Device instance. - - We can't do copy.deepcopy on parted objects, which is okay. - For these parted objects, we just do a shallow copy. - """ - new = self.__class__.__new__(self.__class__) - memo[id(self)] = new - shallow_copy_attrs = ('partedDisk', '_partedDevice', - '_partedPartition', '_origPartedDisk', - '_raidSet', 'installer', 'screen') - for (attr, value) in self.__dict__.items(): - if attr in shallow_copy_attrs: - setattr(new, attr, copy.copy(value)) - else: - setattr(new, attr, copy.deepcopy(value, memo)) - - return new - - def removeChild(self): - self.kids -= 1 - - def addChild(self): - self.kids += 1 - - def setup(self, intf=None): - """ Open, or set up, a device. """ - raise NotImplementedError("setup method not defined for Device") - - def teardown(self, recursive=None): - """ Close, or tear down, a device. """ - raise NotImplementedError("teardown method not defined for Device") - - def create(self, intf=None): - """ Create the device. """ - raise NotImplementedError("create method not defined for Device") - - def destroy(self): - """ Destroy the device. """ - raise NotImplementedError("destroy method not defined for Device") - - def setupParents(self): - """ Run setup method of all parent devices. """ - for parent in self.parents: - parent.setup() - - def teardownParents(self, recursive=None): - """ Run teardown method of all parent devices. """ - for parent in self.parents: - parent.teardown(recursive=recursive) - - def createParents(self): - """ Run create method of all parent devices. """ - self.installer.log.info("NOTE: recursive device creation disabled") - for parent in self.parents: - if not parent.exists: - raise DeviceError("parent device does not exist") - #parent.create() - - def dependsOn(self, dep): - """ Return True if this device depends on dep. """ - # XXX does a device depend on itself? - if dep in self.parents: - return True - - for parent in self.parents: - if parent.dependsOn(dep): - return True - - return False - - @property - def status(self): - """ This device's status. - - For now, this should return a boolean: - True the device is open and ready for use - False the device is not open - """ - return False - - @property - def name(self): - """ This device's name. """ - return self._name - - @property - def isleaf(self): - """ True if this device has no children. """ - return self.kids == 0 - - @property - def typeDescription(self): - """ String describing the device type. """ - return self._type - - @property - def type(self): - """ Device type. """ - return self._type - - @property - def mediaPresent(self): - return True - - -class StorageDevice(Device): - """ A generic storage device. - - A fully qualified path to the device node can be obtained via the - path attribute, although it is not guaranteed to be useful, or - even present, unless the StorageDevice's setup method has been - run. - - StorageDevice instances can optionally contain a filesystem, - represented by an FS instance. A StorageDevice's create method - should create a filesystem if one has been specified. - """ - _type = "storage device" - _devDir = "/dev" - sysfsBlockDir = "class/block" - _resizable = False - - def __init__(self, installer, device, format=None, - size=None, major=None, minor=None, - sysfsPath='', parents=None, exists=None): - """ Create a StorageDevice instance. - - Arguments: - - device -- the device name (generally a device node's basename) - - Keyword Arguments: - - size -- the device's size (units/format TBD) - major -- the device major - minor -- the device minor - sysfsPath -- sysfs device path - format -- a DeviceFormat instance - parents -- a list of required Device instances - description -- a string describing the device - - """ - self.installer = installer - - # allow specification of individual parents - if isinstance(parents, Device): - parents = [parents] - - Device.__init__(self, installer, device, parents=parents) - - self.uuid = None - self._format = None - self._size = numeric_type(size) - self.major = numeric_type(major) - self.minor = numeric_type(minor) - self.sysfsPath = sysfsPath - self.exists = exists - - # this may be handy for disk, dmraid, mpath, mdraid - self.diskLabel = None - - self.format = format - self.fstabComment = "" - self._targetSize = self._size - - self._partedDevice = None - - @property - def partedDevice(self): - if self.exists and self.status and not self._partedDevice: - # We aren't guaranteed to be able to get a device. In - # particular, built-in USB flash readers show up as devices but - # do not always have any media present, so parted won't be able - # to find a device. - try: - self._partedDevice = parted.Device(path=self.path) - except _ped.DeviceException: - pass - - return self._partedDevice - - def _getTargetSize(self): - return self._targetSize - - def _setTargetSize(self, newsize): - self._targetSize = newsize - - targetSize = property(lambda s: s._getTargetSize(), - lambda s, v: s._setTargetSize(v), - doc="Target size of this device") - - @property - def path(self): - """ Device node representing this device. """ - return "%s/%s" % (self._devDir, self.name) - - def updateSysfsPath(self): - """ Update this device's sysfs path. """ - sysfsName = self.name.replace("/", "!") - path = os.path.join("/sys", self.sysfsBlockDir, sysfsName) - self.sysfsPath = os.path.realpath(path)[4:] - self.installer.log.debug("%s sysfsPath set to %s" % (self.name, self.sysfsPath)) - - @property - def formatArgs(self): - """ Device-specific arguments to format creation program. """ - return [] - - @property - def resizable(self): - """ Can this type of device be resized? """ - return self._resizable and self.exists - - def notifyKernel(self): - """ Send a 'change' uevent to the kernel for this device. """ - if not self.exists: - self.installer.log.debug("Not sending change uevent for non-existent device") - return - - if not self.status: - self.installer.log.debug("Not sending change uevent for inactive device") - return - - path = os.path.normpath("/sys/%s" % self.sysfsPath) - try: - notify_kernel(path, action="change") - except Exception, e: - self.installer.log.warning("Failed to notify kernel of change: %s" % e) - - @property - def fstabSpec(self): - spec = self.path - if self.format and self.format.uuid: - spec = "UUID=%s" % self.format.uuid - return spec - - def resize(self, intf=None): - """ Resize the device. - - New size should already be set. - """ - raise NotImplementedError("resize method not defined for StorageDevice") - - def setup(self, intf=None): - """ Open, or set up, a device. """ - if not self.exists: - raise DeviceError("device has not been created") - - self.setupParents() - for parent in self.parents: - parent.format.setup() - - def teardown(self, recursive=None): - """ Close, or tear down, a device. """ - if not self.exists and not recursive: - raise DeviceError("device has not been created") - - if self.status and self.format.exists: - self.format.teardown() - udev_settle(timeout=10) - - if recursive: - self.teardownParents(recursive=recursive) - - def _getSize(self): - """ Get the device's size in MB, accounting for pending changes. """ - if self.exists and not self.mediaPresent: - return 0 - - if self.exists and self.partedDevice: - self._size = self.currentSize - - size = self._size - if self.exists and self.resizable and self.targetSize != size: - size = self.targetSize - - return size - - def _setSize(self, newsize): - """ Set the device's size to a new value. """ - if newsize > self.maxSize: - raise DeviceError("device cannot be larger than %s MB" % - (self.maxSize(),)) - self._size = newsize - - size = property(lambda x: x._getSize(), - lambda x, y: x._setSize(y), - doc="The device's size in MB, accounting for pending changes") - - @property - def currentSize(self): - """ The device's actual size. """ - size = 0 - if self.exists and self.partedDevice: - size = self.partedDevice.getSize() - elif self.exists: - size = self._size - return size - - @property - def minSize(self): - """ The minimum size this device can be. """ - if self.exists: - self.setup() - - if self.format.minSize: - return self.format.minSize - else: - return self.size - - @property - def maxSize(self): - """ The maximum size this device can be. """ - if self.format.maxSize > self.currentSize: - return self.currentSize - else: - return self.format.maxSize - - @property - def status(self): - """ This device's status. - - For now, this should return a boolean: - True the device is open and ready for use - False the device is not open - """ - if not self.exists: - return False - return os.access(self.path, os.W_OK) - - def _setFormat(self, format): - """ Set the Device's format. """ - if not format: - format = getFormat(None, installer=self.installer, device=self.path, exists=self.exists) - if self._format and self._format.status: - # FIXME: self.format.status doesn't mean much - raise DeviceError("Cannot replace active format") - - self._format = format - - def _getFormat(self): - return self._format - - format = property(lambda d: d._getFormat(), - lambda d,f: d._setFormat(f), - doc="The device's formatting.") - - def create(self, intf=None): - """ Create the device. """ - if self.exists: - raise DeviceError("device has already been created") - - self.createParents() - self.setupParents() - self.exists = True - self.setup() - - def destroy(self): - """ Destroy the device. """ - if not self.exists: - raise DeviceError("device has not been created") - - if not self.isleaf: - raise DeviceError("Cannot destroy non-leaf device") - - self.exists = False - - @property - def removable(self): - devpath = os.path.normpath("/sys/%s" % self.sysfsPath) - remfile = os.path.normpath("%s/removable" % devpath) - return (self.sysfsPath and os.path.exists(devpath) and - os.access(remfile, os.R_OK) and - open(remfile).readline().strip() == "1") - -class DiskDevice(StorageDevice): - """ A disk """ - _type = "disk" - - def __init__(self, installer, device, format=None, - size=None, major=None, minor=None, sysfsPath='', \ - parents=None, initcb=None, initlabel=None): - """ Create a DiskDevice instance. - - Arguments: - - device -- the device name (generally a device node's basename) - - Keyword Arguments: - - size -- the device's size (units/format TBD) - major -- the device major - minor -- the device minor - sysfsPath -- sysfs device path - format -- a DeviceFormat instance - parents -- a list of required Device instances - removable -- whether or not this is a removable device - - initcb -- the call back to be used when initiating disk. - initlabel -- whether to start with a fresh disklabel - - - DiskDevices always exist. - """ - self.installer = installer - StorageDevice.__init__(self, self.installer, device, format=format, - size=size, major=major, minor=minor, exists=True, - sysfsPath=sysfsPath, parents=parents) - - self.partedDisk = None - - if self.partedDevice: - if initlabel: - self.partedDisk = self.freshPartedDisk() - else: - try: - self.partedDisk = parted.Disk(device=self.partedDevice) - except _ped.DiskLabelException: - # if we have a cb function use it. else an error. - if initcb is not None and initcb(): - self.partedDisk = parted.freshDisk(device=self.partedDevice, \ - ty = platform.getPlatform(None).diskType) - else: - raise DeviceUserDeniedFormatError("User prefered to not format.") - - # We save the actual state of the disk here. Before the first - # modification (addPartition or removePartition) to the partition - # table we reset self.partedPartition to this state so we can - # perform the modifications one at a time. - if self.partedDisk: - self._origPartedDisk = self.partedDisk.duplicate() - else: - self._origPartedDisk = None - - def freshPartedDisk(self): - labelType = platform.getPlatform(None).diskType - return parted.freshDisk(device=self.partedDevice, ty=labelType) - - @property - def mediaPresent(self): - return self.partedDevice is not None - - @property - def model(self): - return getattr(self.partedDevice, "model", None) - - @property - def size(self): - """ The disk's size in MB """ - return super(DiskDevice, self).size - #size = property(StorageDevice._getSize) - - def resetPartedDisk(self): - """ Reset parted.Disk to reflect the actual layout of the disk. """ - self.partedDisk = self._origPartedDisk - - def removePartition(self, device): - if not self.mediaPresent: - raise DeviceError("Cannot remove partition from disk %s which has no media" % self.name) - - partition = self.partedDisk.getPartitionByPath(device.path) - if partition: - self.partedDisk.removePartition(partition) - - def addPartition(self, device): - if not self.mediaPresent: - raise DeviceError("cannot add partition to disk %s which has no media" % self.name) - - for part in self.partedDisk.partitions: - self.installer.log.debug("Disk %s: partition %s has geom %s" % (self.name, - part.getDeviceNodeName(), - part.geometry)) - - geometry = device.partedPartition.geometry - constraint = parted.Constraint(exactGeom=geometry) - partition = parted.Partition(disk=self.partedDisk, - type=device.partedPartition.type, - geometry=geometry) - self.partedDisk.addPartition(partition, constraint=constraint) - - def probe(self): - """ Probe for any missing information about this device. - - pyparted should be able to tell us anything we want to know. - size, disklabel type, maybe even partition layout - """ - if not self.diskLabel: - self.installer.log.debug("Setting %s diskLabel to %s" % (self.name, - self.partedDisk.type)) - self.diskLabel = self.partedDisk.type - - def commit(self, intf=None): - """ Commit changes to the device. """ - if not self.mediaPresent: - raise DeviceError("cannot commit to disk %s which has no media" % self.name) - - self.setupParents() - self.setup() - - # give committing 5 tries, failing that, raise an exception - attempt = 1 - maxTries = 5 - keepTrying = True - - while keepTrying and (attempt <= maxTries): - try: - self.partedDisk.commit() - keepTrying = False - except parted.DiskException as msg: - self.installer.log.warning(msg) - attempt += 1 - - if keepTrying: - raise DeviceError("cannot commit to disk %s after %d attempts" % (self.name, maxTries,)) - - # commit makes the kernel re-scan the partition table - udev_settle() - - def destroy(self): - """ Destroy the device. """ - if not self.mediaPresent: - raise DeviceError("cannot destroy disk %s which has no media" % self.name) - - self.partedDisk.deleteAllPartitions() - # this is perhaps a separate operation (wiping the disklabel) - self.partedDisk.clobber() - self.partedDisk.commit() - self.teardown() - - def setup(self, intf=None): - """ Open, or set up, a device. """ - if not os.path.exists(self.path): - raise DeviceError("device does not exist") - -class PartitionDevice(StorageDevice): - """ A disk partition. - - On types and flags... - - We don't need to deal with numerical partition types at all. The - only type we are concerned with is primary/logical/extended. Usage - specification is accomplished through the use of flags, which we - will set according to the partition's format. - """ - _type = "partition" - _resizable = True - - def __init__(self, installer, name, format=None, - size=None, grow=False, maxsize=None, - major=None, minor=None, bootable=None, - sysfsPath='', parents=None, exists=None, - partType=None, primary=False, weight=0): - """ Create a PartitionDevice instance. - - Arguments: - - name -- the device name (generally a device node's basename) - - Keyword Arguments: - - exists -- indicates whether this is an existing device - format -- the device's format (DeviceFormat instance) - - For existing partitions: - - parents -- the disk that contains this partition - major -- the device major - minor -- the device minor - sysfsPath -- sysfs device path - - For new partitions: - - partType -- primary,extended,&c (as parted constant) - grow -- whether or not to grow the partition - maxsize -- max size for growable partitions (in MB) - size -- the device's size (in MB) - bootable -- whether the partition is bootable - parents -- a list of potential containing disks - weight -- an initial sorting weight to assign - """ - self.req_disks = [] - self.req_partType = None - self.req_primary = None - self.req_grow = None - self.req_bootable = None - self.req_size = 0 - self.req_base_size = 0 - self.req_max_size = 0 - self.req_base_weight = 0 - - self._bootable = False - - StorageDevice.__init__(self, installer, name, format=format, size=size, - major=major, minor=minor, exists=exists, - sysfsPath=sysfsPath, parents=parents) - - if not exists: - # this is a request, not a partition -- it has no parents - self.req_disks = self.parents[:] - for dev in self.parents: - dev.removeChild() - self.parents = [] - - # FIXME: Validate partType, but only if this is a new partition - # Otherwise, overwrite it with the partition's type. - self._partType = None - self.partedFlags = {} - self._partedPartition = None - - # FIXME: Validate size, but only if this is a new partition. - # For existing partitions we will get the size from - # parted. - - if self.exists: - #self.partedPartition = parted.getPartitionByName(self.path) - self._partedPartition = self.disk.partedDisk.getPartitionByPath(self.path) - if not self._partedPartition: - raise DeviceError("cannot find parted partition instance") - - # collect information about the partition from parted - self.probe() - else: - # XXX It might be worthwhile to create a shit-simple - # PartitionRequest class and pass one to this constructor - # for new partitions. - self.req_name = name - self.req_partType = partType - self.req_primary = primary - self.req_max_size = numeric_type(maxsize) - self.req_grow = grow - self.req_bootable = bootable - - # req_size may be manipulated in the course of partitioning - self.req_size = self._size - - # req_base_size will always remain constant - self.req_base_size = self._size - - self.req_base_weight = weight - - def _setTargetSize(self, newsize): - if newsize != self.currentSize: - # change this partition's geometry in-memory so that other - # partitioning operations can complete (e.g., autopart) - self._targetSize = newsize - disk = self.disk.partedDisk - - # resize the partition's geometry in memory - (constraint, geometry) = self._computeResize(self.partedPartition) - disk.setPartitionGeometry(partition=self.partedPartition, - constraint=constraint, - start=geometry.start, end=geometry.end) - - @property - def path(self): - """ Device node representing this device. """ - if not self.parents: - # Bogus, but code in various places compares devices by path - # So we must return something unique - return self.name - - return "%s/%s" % (self.parents[0]._devDir, self.name) - - @property - def partType(self): - """ Get the partition's type (as parted constant). """ - try: - ptype = self.partedPartition.type - except AttributeError: - ptype = self._partType - - if not self.exists and ptype is None: - ptype = self.req_partType - - return ptype - - @property - def isExtended(self): - return self.partType & parted.PARTITION_EXTENDED - - @property - def isLogical(self): - return self.partType & parted.PARTITION_LOGICAL - - @property - def isPrimary(self): - return self.partType == parted.PARTITION_NORMAL - - @property - def isProtected(self): - return self.partType & parted.PARTITION_PROTECTED - - def _getPartedPartition(self): - return self._partedPartition - - def _setPartedPartition(self, partition): - """ Set this PartitionDevice's parted Partition instance. """ - if partition is None: - path = None - elif isinstance(partition, parted.Partition): - path = partition.path - else: - raise ValueError("partition must be a parted.Partition instance") - - self._partedPartition = partition - self.updateName() - - partedPartition = property(lambda d: d._getPartedPartition(), - lambda d,p: d._setPartedPartition(p)) - - def _getWeight(self): - return self.req_base_weight - - def _setWeight(self, weight): - self.req_base_weight = weight - - weight = property(lambda d: d._getWeight(), - lambda d,w: d._setWeight(w)) - - def updateSysfsPath(self): - """ Update this device's sysfs path. """ - if not self.parents: - self.sysfsPath = '' - - elif self.parents[0]._devDir == "/dev/mapper": - dm_node = dm.dm_node_from_name(self.name) - path = os.path.join("/sys", self.sysfsBlockDir, dm_node) - self.sysfsPath = os.path.realpath(path)[4:] - - else: - StorageDevice.updateSysfsPath(self) - - def updateName(self): - if self.partedPartition is None: - self._name = self.req_name - else: - self._name = \ - devicePathToName(self.partedPartition.getDeviceNodeName()) - - def dependsOn(self, dep): - """ Return True if this device depends on dep. """ - if isinstance(dep, PartitionDevice) and dep.isExtended and self.isLogical: - return True - - return Device.dependsOn(self, dep) - - def _setFormat(self, format): - """ Set the Device's format. """ - StorageDevice._setFormat(self, format) - - def _setBootable(self, bootable): - """ Set the bootable flag for this partition. """ - if self.partedPartition: - if self.flagAvailable(parted.PARTITION_BOOT): - if bootable: - self.setFlag(parted.PARTITION_BOOT) - else: - self.unsetFlag(parted.PARTITION_BOOT) - else: - raise DeviceError(_("boot flag not available for this " - "partition")) - - self._bootable = bootable - else: - self.req_bootable = bootable - - def _getBootable(self): - return self._bootable or self.req_bootable - - bootable = property(_getBootable, _setBootable) - - def flagAvailable(self, flag): - if not self.partedPartition: - return - - return self.partedPartition.isFlagAvailable(flag) - - def getFlag(self, flag): - if not self.partedPartition or not self.flagAvailable(flag): - return - - return self.partedPartition.getFlag(flag) - - def setFlag(self, flag): - if not self.partedPartition or not self.flagAvailable(flag): - return - - self.partedPartition.setFlag(flag) - - def unsetFlag(self, flag): - if not self.partedPartition or not self.flagAvailable(flag): - return - - self.partedPartition.unsetFlag(flag) - - def probe(self): - """ Probe for any missing information about this device. - - size, partition type, flags - """ - if not self.exists: - return - - # this is in MB - self._size = self.partedPartition.getSize() - self.targetSize = self._size - - self._partType = self.partedPartition.type - - self._bootable = self.getFlag(parted.PARTITION_BOOT) - - def create(self, intf=None): - """ Create the device. """ - if self.exists: - raise DeviceError("device already exists") - - self.createParents() - self.setupParents() - - self.disk.addPartition(self) - self.disk.commit() - - self.partedPartition = self.disk.partedDisk.getPartitionByPath(self.path) - - self.exists = True - self.setup() - - def _computeResize(self, partition): - # compute new size for partition - currentGeom = partition.geometry - currentDev = currentGeom.device - newLen = long(self.targetSize * 1024 * 1024) / currentDev.sectorSize - newGeometry = parted.Geometry(device=currentDev, - start=currentGeom.start, - length=newLen) - constraint = parted.Constraint(exactGeom=newGeometry) - - return (constraint, newGeometry) - - def resize(self, intf=None): - """ Resize the device. - - self.targetSize must be set to the new size. - """ - if self.targetSize != self.currentSize: - # partedDisk has been restored to _origPartedDisk, so - # recalculate resize geometry because we may have new - # partitions on the disk, which could change constraints - partition = self.disk.partedDisk.getPartitionByPath(self.path) - (constraint, geometry) = self._computeResize(partition) - - self.disk.partedDisk.setPartitionGeometry(partition=partition, - constraint=constraint, - start=geometry.start, - end=geometry.end) - - self.disk.commit() - self.notifyKernel() - - def destroy(self): - """ Destroy the device. """ - if not self.exists: - raise DeviceError("device has not been created") - - if not self.sysfsPath: - return - - if not self.isleaf: - raise DeviceError("Cannot destroy non-leaf device") - - self.setupParents() - self.disk.removePartition(self) - self.disk.commit() - - self.exists = False - - def _getSize(self): - """ Get the device's size. """ - size = self._size - if self.partedPartition: - # this defaults to MB - size = self.partedPartition.getSize() - return size - - def _setSize(self, newsize): - """ Set the device's size (for resize, not creation). - - Arguments: - - newsize -- the new size (in MB) - - """ - if not self.exists: - raise DeviceError("device does not exist") - - if newsize > self.disk.size: - raise ValueError("partition size would exceed disk size") - - # this defaults to MB - maxAvailableSize = self.partedPartition.getMaxAvailableSize() - - if newsize > maxAvailableSize: - raise ValueError("new size is greater than available space") - - # now convert the size to sectors and update the geometry - geometry = self.partedPartition.geometry - physicalSectorSize = geometry.device.physicalSectorSize - - new_length = (newsize * (1024 * 1024)) / physicalSectorSize - geometry.length = new_length - - def _getDisk(self): - """ The disk that contains this partition.""" - try: - disk = self.parents[0] - except IndexError: - disk = None - return disk - - def _setDisk(self, disk): - """Change the parent. - - Setting up a disk is not trivial. It has the potential to change - the underlying object. If necessary we must also change this object. - """ - if self.disk: - self.disk.removeChild() - - if disk: - self.parents = [disk] - disk.addChild() - else: - self.parents = [] - - disk = property(lambda p: p._getDisk(), lambda p,d: p._setDisk(d)) - - @property - def maxSize(self): - """ The maximum size this partition can be. """ - # XXX: this is MB by default - maxPartSize = self.partedPartition.getMaxAvailableSize() - - if self.format.maxSize > maxPartSize: - return maxPartSize - else: - return self.format.maxSize - -class OpticalDevice(StorageDevice): - """ An optical drive, eg: cdrom, dvd+r, &c. - - XXX Is this useful? - """ - _type = "cdrom" - - def __init__(self, installer, name, major=None, minor=None, exists=None, - format=None, parents=None, sysfsPath=''): - StorageDevice.__init__(self, installer, name, format=format, - major=major, minor=minor, exists=True, - parents=parents, sysfsPath=sysfsPath) - - @property - def mediaPresent(self): - """ Return a boolean indicating whether or not the device contains - media. - """ - if not self.exists: - raise DeviceError("device has not been created", self.path) - - try: - fd = os.open(self.path, os.O_RDONLY) - except OSError as e: - # errno 123 = No medium found - if e.errno == 123: - return False - else: - return True - else: - os.close(fd) - return True - - def eject(self): - """ Eject the drawer. """ - #import _isys - - if not self.exists: - raise DeviceError("device has not been created", self.path) - - # Make a best effort attempt to do the eject. If it fails, it's not - # critical. - fd = os.open(self.path, os.O_RDONLY | os.O_NONBLOCK) - - #try: - # _isys.ejectcdrom(fd) - #except SystemError as e: - # log.warning("error ejecting cdrom %s: %s" % (self.name, e)) - - os.close(fd) - -class DMDevice(StorageDevice): - """ A device-mapper device """ - _type = "dm" - _devDir = "/dev/mapper" - - def __init__(self, installer, name, format=None, size=None, dmUuid=None, - target=None, exists=None, parents=None, sysfsPath=''): - """ Create a DMDevice instance. - - Arguments: - - name -- the device name (generally a device node's basename) - - Keyword Arguments: - - target -- the device-mapper target type (string) - size -- the device's size (units/format TBD) - dmUuid -- the device's device-mapper UUID - sysfsPath -- sysfs device path - format -- a DeviceFormat instance - parents -- a list of required Device instances - exists -- indicates whether this is an existing device - """ - StorageDevice.__init__(self, installer, name, format=format, size=size, - exists=exists, - parents=parents, sysfsPath=sysfsPath) - self.target = target - self.dmUuid = dmUuid - - def __str__(self): - s = StorageDevice.__str__(self) - s += (" target = %(target)s dmUuid = %(dmUuid)s" % - {"target": self.target, "dmUuid": self.dmUuid}) - return s - - @property - def fstabSpec(self): - """ Return the device specifier for use in /etc/fstab. """ - return self.path - - def updateSysfsPath(self): - """ Update this device's sysfs path. """ - if not self.exists: - raise DeviceError("device has not been created") - - if self.status: - dm_node = self.getDMNode() - path = os.path.join("/sys", self.sysfsBlockDir, dm_node) - self.sysfsPath = os.path.realpath(path)[4:] - else: - self.sysfsPath = '' - - #def getTargetType(self): - # return dm.getDmTarget(name=self.name) - - def getDMNode(self): - """ Return the dm-X (eg: dm-0) device node for this device. """ - if not self.exists: - raise DeviceError("device has not been created") - - return dm.dm_node_from_name(self.name) - - def _setName(self, name): - """ Set the device's map name. """ - if self.status: - raise DeviceError("device is active") - - self._name = name - #self.sysfsPath = "/dev/disk/by-id/dm-name-%s" % self.name - - name = property(lambda d: d._name, - lambda d,n: d._setName(n)) - - -class LVMVolumeGroupDevice(DMDevice): - """ An LVM Volume Group - - XXX Maybe this should inherit from StorageDevice instead of - DMDevice since there's no actual device. - """ - _type = "lvmvg" - - def __init__(self, installer, name, parents, size=None, free=None, - peSize=None, peCount=None, peFree=None, pvCount=None, - lvNames=[], uuid=None, exists=None, sysfsPath=''): - """ Create a LVMVolumeGroupDevice instance. - - Arguments: - - name -- the device name (generally a device node's basename) - parents -- a list of physical volumes (StorageDevice) - - Keyword Arguments: - - peSize -- physical extent size (in MB) - exists -- indicates whether this is an existing device - sysfsPath -- sysfs device path - - For existing VG's only: - - size -- the VG's size (in MB) - free -- amount of free space in the VG - peFree -- number of free extents - peCount -- total number of extents - pvCount -- number of PVs in this VG - lvNames -- the names of this VG's LVs - uuid -- the VG's UUID - - """ - self.pvClass = get_device_format_class("lvmpv") - if not self.pvClass: - raise DeviceError("cannot find 'lvmpv' class") - - if isinstance(parents, list): - for dev in parents: - if not isinstance(dev.format, self.pvClass): - raise ValueError("constructor requires a list of PVs") - elif not isinstance(parents.format, self.pvClass): - raise ValueError("constructor requires a list of PVs") - - DMDevice.__init__(self, installer, name, parents=parents, - exists=exists, sysfsPath=sysfsPath) - - self.uuid = uuid - self.free = numeric_type(free) - self.peSize = numeric_type(peSize) - self.peCount = numeric_type(peCount) - self.peFree = numeric_type(peFree) - self.pvCount = numeric_type(pvCount) - self.lvNames = lvNames - - # circular references, here I come - self._lvs = [] - - # TODO: validate peSize if given - if not self.peSize: - self.peSize = 4.0 # MB - - #self.probe() - - def __str__(self): - s = DMDevice.__str__(self) - s += (" free = %(free)s PE Size = %(peSize)s PE Count = %(peCount)s\n" - " PE Free = %(peFree)s PV Count = %(pvCount)s\n" - " LV Names = %(lvNames)s modified = %(modified)s\n" - " extents = %(extents)s free space = %(freeSpace)s\n" - " free extents = %(freeExtents)s\n" - " PVs = %(pvs)s\n" - " LVs = %(lvs)s" % - {"free": self.free, "peSize": self.peSize, "peCount": self.peCount, - "peFree": self.peFree, "pvCount": self.pvCount, - "lvNames": self.lvNames, "modified": self.isModified, - "extents": self.extents, "freeSpace": self.freeSpace, - "freeExtents": self.freeExtents, "pvs": self.pvs, "lvs": self.lvs}) - return s - - def probe(self): - """ Probe for any information about this device. """ - if not self.exists: - raise DeviceError("device has not been created") - - @property - def status(self): - """ The device's status (True means active). """ - if not self.exists: - return False - - # certainly if any of this VG's LVs are active then so are we - for lv in self.lvs: - if lv.status: - return True - - # if any of our PVs are not active then we cannot be - for pv in self.pvs: - if not pv.status: - return False - - # if we are missing some of our PVs we cannot be active - if len(self.pvs) != self.pvCount: - return False - - return True - - def _addDevice(self, device): - """ Add a new physical volume device to the volume group. - - XXX This is for use by device probing routines and is not - intended for modification of the VG. - """ - if not self.exists: - raise DeviceError("device does not exist") - - if not isinstance(device.format, self.pvClass): - raise ValueError("addDevice requires a PV arg") - - if self.uuid and device.format.vgUuid != self.uuid: - raise ValueError("UUID mismatch") - - if device in self.pvs: - raise ValueError("device is already a member of this VG") - - self.parents.append(device) - device.addChild() - - # now see if the VG can be activated - if len(self.parents) == self.pvCount: - self.setup() - - def _removeDevice(self, device): - """ Remove a physical volume from the volume group. - - This is for cases like clearing of preexisting partitions. - """ - try: - self.parents.remove(device) - except ValueError, e: - raise ValueError("cannot remove non-member PV device from VG") - - device.removeChild() - - def setup(self, intf=None): - """ Open, or set up, a device. - - XXX we don't do anything like "vgchange -ay" because we don't - want all of the LVs activated, just the VG itself. - """ - if not self.exists: - raise DeviceError("device has not been created") - - if self.status: - return - - if len(self.parents) < self.pvCount: - raise DeviceError("cannot activate VG with missing PV(s)") - - self.setupParents() - - def teardown(self, recursive=None): - """ Close, or tear down, a device. """ - if not self.exists and not recursive: - raise DeviceError("device has not been created") - - if self.status: - lvm.vgdeactivate(self.name) - - if recursive: - self.teardownParents(recursive=recursive) - - def create(self, intf=None): - """ Create the device. """ - if self.exists: - raise DeviceError("device already exists") - - pv_list = [] - #for pv in self.parents: - # This is a little bit different from other devices in that - # for VG we need the PVs to be formatted before we can create - # the VG. - # pv.create() - # pv.format.create() - # pv_list.append(pv.path) - pv_list = [pv.path for pv in self.parents] - self.createParents() - self.setupParents() - lvm.vgcreate(self.name, pv_list, self.peSize) - # FIXME set / update self.uuid here - self.exists = True - self.setup() - - def destroy(self): - """ Destroy the device. """ - if not self.exists: - raise DeviceError("device has not been created") - - # set up the pvs since lvm needs access to them to do the vgremove - self.setupParents() - - # this sometimes fails for some reason. - try: - lvm.vgreduce(self.name, [], rm=True) - lvm.vgremove(self.name) - except lvm.LVMError: - raise DeviceError("Could not completely remove VG %s" % self.name) - finally: - self.notifyKernel() - self.exists = False - - def reduce(self, pv_list): - """ Remove the listed PVs from the VG. """ - if not self.exists: - raise DeviceError("device has not been created") - - lvm.vgreduce(self.name, pv_list) - # XXX do we need to notify the kernel? - - def _addLogVol(self, lv): - """ Add an LV to this VG. """ - if lv in self._lvs: - raise ValueError("lv is already part of this vg") - - # verify we have the space, then add it - # do not verify for growing vg (because of ks) - if not lv.exists and \ - not [pv for pv in self.pvs if getattr(pv, "req_grow", None)] and \ - lv.size > self.freeSpace: - raise DeviceError("new lv is too large to fit in free space") - - self._lvs.append(lv) - - def _removeLogVol(self, lv): - """ Remove an LV from this VG. """ - if lv not in self.lvs: - raise ValueError("specified lv is not part of this vg") - - self._lvs.remove(lv) - - def _addPV(self, pv): - """ Add a PV to this VG. """ - if pv in self.pvs: - raise ValueError("pv is already part of this vg") - - # for the time being we will not allow vgextend - if self.exists: - raise DeviceError("cannot add pv to existing vg") - - self.parents.append(pv) - pv.addChild() - - def _removePV(self, pv): - """ Remove an PV from this VG. """ - if not pv in self.pvs: - raise ValueError("specified pv is not part of this vg") - - # for the time being we will not allow vgreduce - if self.exists: - raise DeviceError("cannot remove pv from existing vg") - - self.parents.remove(pv) - pv.removeChild() - - # We can't rely on lvm to tell us about our size, free space, &c - # since we could have modifications queued, unless the VG and all of - # its PVs already exist. - # - # -- liblvm may contain support for in-memory devices - - @property - def isModified(self): - """ Return True if the VG has changes queued that LVM is unaware of. """ - modified = True - if self.exists and not filter(lambda d: not d.exists, self.pvs): - modified = False - - return modified - - @property - def size(self): - """ The size of this VG """ - # TODO: just ask lvm if isModified returns False - - # sum up the sizes of the PVs and align to pesize - size = 0 - for pv in self.pvs: - size += max(0, self.align(pv.size - pv.format.peStart)) - - return size - - @property - def extents(self): - """ Number of extents in this VG """ - # TODO: just ask lvm if isModified returns False - - return self.size / self.peSize - - @property - def freeSpace(self): - """ The amount of free space in this VG (in MB). """ - # TODO: just ask lvm if isModified returns False - - # total the sizes of any LVs - used = 0 - size = self.size - self.installer.log.debug("%s size is %dMB" % (self.name, size)) - for lv in self.lvs: - self.installer.log.debug("lv %s (%s) uses %dMB" % (lv.name, lv, lv.size)) - used += self.align(lv.size, roundup=True) - - free = self.size - used - self.installer.log.debug("vg %s has %dMB free" % (self.name, free)) - return free - - @property - def freeExtents(self): - """ The number of free extents in this VG. """ - # TODO: just ask lvm if isModified returns False - return self.freeSpace / self.peSize - - def align(self, size, roundup=None): - """ Align a size to a multiple of physical extent size. """ - size = numeric_type(size) - - if roundup: - round = math.ceil - else: - round = math.floor - - # we want Kbytes as a float for our math - size *= 1024.0 - pesize = self.peSize * 1024.0 - return long((round(size / pesize) * pesize) / 1024) - - @property - def pvs(self): - """ A list of this VG's PVs """ - return self.parents[:] # we don't want folks changing our list - - @property - def lvs(self): - """ A list of this VG's LVs """ - return self._lvs[:] # we don't want folks changing our list - - @property - def complete(self): - """Check if the vg has all its pvs in the system - Return True if complete. - """ - return len(self.pvs) == self.pvCount or not self.exists - -class LVMLogicalVolumeDevice(DMDevice): - """ An LVM Logical Volume """ - _type = "lvmlv" - _resizable = True - - def __init__(self, installer, name, vgdev, size=None, uuid=None, - format=None, exists=None, sysfsPath='', - grow=None, maxsize=None, percent=None): - """ Create a LVMLogicalVolumeDevice instance. - - Arguments: - - name -- the device name (generally a device node's basename) - vgdev -- volume group (LVMVolumeGroupDevice instance) - - Keyword Arguments: - - size -- the device's size (in MB) - uuid -- the device's UUID - sysfsPath -- sysfs device path - format -- a DeviceFormat instance - exists -- indicates whether this is an existing device - - For new (non-existent) LVs only: - - grow -- whether to grow this LV - maxsize -- maximum size for growable LV (in MB) - percent -- percent of VG space to take - - """ - if isinstance(vgdev, list): - if len(vgdev) != 1: - raise ValueError("constructor requires a single LVMVolumeGroupDevice instance") - elif not isinstance(vgdev[0], LVMVolumeGroupDevice): - raise ValueError("constructor requires a LVMVolumeGroupDevice instance") - elif not isinstance(vgdev, LVMVolumeGroupDevice): - raise ValueError("constructor requires a LVMVolumeGroupDevice instance") - DMDevice.__init__(self, installer, name, size=size, format=format, - sysfsPath=sysfsPath, parents=vgdev, - exists=exists) - - self.uuid = uuid - - self.req_grow = None - self.req_max_size = 0 - self.req_size = 0 - self.req_percent = 0 - - if not self.exists: - self.req_grow = grow - self.req_max_size = numeric_type(maxsize) - # XXX should we enforce that req_size be pe-aligned? - self.req_size = self._size - self.req_percent = numeric_type(percent) - - # here we go with the circular references - self.vg._addLogVol(self) - - def __str__(self): - s = DMDevice.__str__(self) - s += (" VG device = %(vgdev)r percent = %(percent)s" % - {"vgdev": self.vg, "percent": self.req_percent}) - return s - - def _setSize(self, size): - size = self.vg.align(numeric_type(size)) - self.installer.log.debug("Trying to set lv %s size to %dMB" % (self.name, size)) - if size <= (self.vg.freeSpace + self._size): - self._size = size - self.targetSize = size - else: - self.installer.log.debug("Failed to set size: %dMB short" % (size - (self.vg.freeSpace + self._size),)) - raise ValueError("Not enough free space in volume group") - - size = property(StorageDevice._getSize, _setSize) - - @property - def vg(self): - """ This Logical Volume's Volume Group. """ - return self.parents[0] - - @property - def path(self): - """ Device node representing this device. """ - # Thank you lvm for this lovely hack. - return "%s/%s-%s" % (self._devDir, self.vg.name.replace("-","--"), - self._name.replace("-","--")) - - def getDMNode(self): - """ Return the dm-X (eg: dm-0) device node for this device. """ - # Thank you lvm for this lovely hack. - if not self.exists: - raise DeviceError("Device has not been created", self.path) - - return dm.dm_node_from_name("%s-%s" % (self.vg.name.replace("-","--"), \ - self._name.replace("-","--"))) - - @property - def name(self): - """ This device's name. """ - return "%s-%s" % (self.vg.name, self._name) - - @property - def lvname(self): - """ The LV's name (not including VG name). """ - return self._name - - @property - def complete(self): - """ Test if vg exits and if it has all pvs. """ - return self.vg.complete - - def setup(self, intf=None): - """ Open, or set up, a device. """ - if not self.exists: - raise DeviceError("Device has not been created", self.path) - - if self.status: - return - - self.vg.setup() - lvm.lvactivate(self.vg.name, self._name) - - # we always probe since the device may not be set up when we want - # information about it - self._size = self.currentSize - - def teardown(self, recursive=None): - """ Close, or tear down, a device. """ - if not self.exists and not recursive: - raise DeviceError("Device has not been created", self.path) - - if self.status and self.format.exists: - self.format.teardown() - udev_settle(timeout=10) - - if self.status: - lvm.lvdeactivate(self.vg.name, self._name) - - if recursive: - # It's likely that teardown of a VG will fail due to other - # LVs being active (filesystems mounted, &c), so don't let - # it bring everything down. - try: - self.vg.teardown(recursive=recursive) - except Exception as e: - log.debug("vg %s teardown failed; continuing" % self.vg.name) - - def create(self, intf=None): - """ Create the device. """ - if self.exists: - raise DeviceError("Device already exists", self.path) - - self.createParents() - self.setupParents() - - # should we use --zero for safety's sake? - lvm.lvcreate(self.vg.name, self._name, self.size) - # FIXME set / update self.uuid here - self.exists = True - self.setup() - - def destroy(self): - """ Destroy the device. """ - if not self.exists: - raise DeviceError("Device has not been created", self.path) - - self.teardown() - # set up the vg's pvs so lvm can remove the lv - self.vg.setupParents() - lvm.lvremove(self.vg.name, self._name) - self.exists = False - - def resize(self, intf=None): - # XXX resize format probably, right? - if not self.exists: - raise DeviceError("Device has not been created", self.path) - - # Setup VG parents (in case they are dmraid partitions for example) - self.vg.setupParents() - - if self.format.exists: - self.format.teardown() - - udev_settle(timeout=10) - lvm.lvresize(self.vg.name, self._name, self.size) diff --git a/pkgs/core/pomona/src/storage_old/devicetree.py b/pkgs/core/pomona/src/storage_old/devicetree.py deleted file mode 100644 index 042941c..0000000 --- a/pkgs/core/pomona/src/storage_old/devicetree.py +++ /dev/null @@ -1,536 +0,0 @@ -#!/usr/bin/python - -import os -import block - -import formats - -from devicelibs import lvm -from devices import * -from errors import * -from udev import * - -class DeviceTree: - def __init__(self, installer): - self.installer = installer - self.storage = self.installer.ds.storage - - self._devices = [] - self._actions = [] - - self._ignoredDisks = [] - self.immutableDevices = [] - for disk in self.storage.ignoredDisks: - self.addIgnoredDisk(disk) - - def addIgnoredDisk(self, disk): - self._ignoredDisks.append(disk) - lvm.lvm_cc_addFilterRejectRegexp(disk) - - def populate(self): - """ Locate all storage devices. """ - # each iteration scans any devices that have appeared since the - # previous iteration - old_devices = [] - ignored_devices = [] - while True: - devices = [] - new_devices = udev_get_block_devices() - - for new_device in new_devices: - found = False - for old_device in old_devices: - if old_device['name'] == new_device['name']: - found = True - break - - if not found: - devices.append(new_device) - - if len(devices) == 0: - # nothing is changing -- we are finished building devices - break - - old_devices = new_devices - self.installer.log.info("Devices to scan: %s" % [d['name'] for d in devices]) - for dev in devices: - self.addUdevDevice(dev) - - # After having the complete tree we make sure that the system - # inconsistencies are ignored or resolved. - #for leaf in self.leaves: - # self._handleInconsistencies(leaf) - - #self.teardownAll() - try: - os.unlink("/etc/mdadm.conf") - except OSError: - pass - - @property - def devices(self): - """ Dict with device path keys and Device values. """ - devices = {} - - for device in self._devices: - if device.path in devices: - raise DeviceTreeError("duplicate paths in device tree") - - devices[device.path] = device - - return devices - - @property - def filesystems(self): - """ List of filesystems. """ - #""" Dict with mountpoint keys and filesystem values. """ - filesystems = [] - for dev in self.leaves: - if dev.format and getattr(dev.format, 'mountpoint', None): - filesystems.append(dev.format) - - return filesystems - - @property - def leaves(self): - """ List of all devices upon which no other devices exist. """ - leaves = [d for d in self._devices if d.isleaf] - return leaves - - def teardownAll(self): - """ Run teardown methods on all devices. """ - for device in self.leaves: - try: - device.teardown(recursive=True) - except (DeviceError, DeviceFormatError, LVMError) as e: - self.installer.log.info("Teardown of %s failed: %s" % (device.name, e)) - - def _addDevice(self, newdev): - """ Add a device to the tree. - - Raise ValueError if the device's identifier is already - in the list. - """ - if newdev.path in [d.path for d in self._devices]: - raise ValueError("device is already in tree") - - # make sure this device's parent devices are in the tree already - for parent in newdev.parents: - if parent not in self._devices: - raise DeviceTreeError("parent device not in tree") - - self._devices.append(newdev) - self.installer.log.info("Added %s (%s) to device tree" % (newdev.name, newdev.type)) - #self.installer.log.info(" Status: %s" % newdev.status) - #self.installer.log.info(" Format: %s" % newdev.format.type) - - def _removeDevice(self, dev, force=None, moddisk=True): - """ Remove a device from the tree. - - Only leaves may be removed. - """ - if dev not in self._devices: - raise ValueError("Device '%s' not in tree" % dev.name) - - if not dev.isleaf and not force: - self.installer.log.debug("%s has %d kids" % (dev.name, dev.kids)) - raise ValueError("Cannot remove non-leaf device '%s'" % dev.name) - - # if this is a partition we need to remove it from the parted.Disk - if moddisk and isinstance(dev, PartitionDevice) and \ - dev.disk is not None: - # if this partition hasn't been allocated it could not have - # a disk attribute - if dev.partedPartition.type == parted.PARTITION_EXTENDED and \ - len(dev.disk.partedDisk.getLogicalPartitions()) > 0: - raise ValueError("Cannot remove extended partition %s. " - "Logical partitions present." % dev.name) - - dev.disk.partedDisk.removePartition(dev.partedPartition) - - self._devices.remove(dev) - self.installer.log.debug("Removed %s (%s) from device tree" % (dev.name, - dev.type)) - - for parent in dev.parents: - # Will this cause issues with garbage collection? - # Do we care about garbage collection? At all? - parent.removeChild() - - def isIgnored(self, info): - """ Return True if info is a device we should ignore. - - Arguments: - - info -- a dict representing a udev db entry - - TODO: - - - filtering of SAN/FC devices - - filtering by driver? - - """ - sysfs_path = udev_device_get_sysfs_path(info) - name = udev_device_get_name(info) - if not sysfs_path: - return None - - if name in self._ignoredDisks: - return True - - for ignored in self._ignoredDisks: - if ignored == os.path.basename(os.path.dirname(sysfs_path)): - # this is a partition on a disk in the ignore list - return True - - # Ignore partitions found on the raw disks which are part of a - # dmraidset - for set in self.getDevicesByType("dm-raid array"): - for disk in set.parents: - if disk.name == os.path.basename(os.path.dirname(sysfs_path)): - return True - - # Ignore loop and ram devices, we normally already skip these in - # udev.py: enumerate_block_devices(), but we can still end up trying - # to add them to the tree when they are slaves of other devices, this - # happens for example with the livecd - if name.startswith("loop") or name.startswith("ram"): - return True - - # FIXME: check for virtual devices whose slaves are on the ignore list - - def getDeviceByName(self, name): - found = None - for device in self._devices: - if device.name == name: - found = device - break - return found - - def getDevicesByType(self, device_type): - # TODO: expand this to catch device format types - return [d for d in self._devices if d.type == device_type] - - def getDevicesByInstance(self, device_class): - return [d for d in self._devices if isinstance(d, device_class)] - - def registerAction(self, action): - """ Register an action to be performed at a later time. - - Modifications to the Device instance are handled before we - get here. - """ - if (action.isDestroy() or action.isResize() or \ - (action.isCreate() and action.isFormat())) and \ - action.device not in self._devices: - raise DeviceTreeError("device is not in the tree") - elif (action.isCreate() and action.isDevice()): - # this allows multiple create actions w/o destroy in between; - # we will clean it up before processing actions - #raise DeviceTreeError("device is already in the tree") - if action.device in self._devices: - self._removeDevice(action.device) - for d in self._devices: - if d.path == action.device.path: - self._removeDevice(d) - - if action.isCreate() and action.isDevice(): - self._addDevice(action.device) - elif action.isDestroy() and action.isDevice(): - self._removeDevice(action.device) - elif action.isCreate() and action.isFormat(): - if isinstance(action.device.format, formats.fs.FS) and \ - action.device.format.mountpoint in self.filesystems: - raise DeviceTreeError("mountpoint already in use") - - self.installer.log.debug("Registered action: %s" % action) - self._actions.append(action) - - def addUdevDevice(self, info): - # FIXME: this should be broken up into more discrete chunks - name = udev_device_get_name(info) - uuid = udev_device_get_uuid(info) - sysfs_path = udev_device_get_sysfs_path(info) - - if self.isIgnored(info): - self.installer.log.debug("Ignoring %s (%s)" % (name, sysfs_path)) - return - - self.installer.log.debug("Scanning %s (%s)..." % (name, sysfs_path)) - device = self.getDeviceByName(name) - - # - # The first step is to either look up or create the device - # - if udev_device_is_dm(info): - # try to look up the device - if device is None and uuid: - # try to find the device by uuid - device = self.getDeviceByUuid(uuid) - - if device is None: - device = self.addUdevDMDevice(info) - elif udev_device_is_md(info): - if device is None and uuid: - # try to find the device by uuid - device = self.getDeviceByUuid(uuid) - - if device is None: - device = self.addUdevMDDevice(info) - elif udev_device_is_cdrom(info): - if device is None: - device = self.addUdevOpticalDevice(info) - elif udev_device_is_dmraid(info): - # This is special handling to avoid the "unrecognized disklabel" - # code since dmraid member disks won't have a disklabel. We - # use a StorageDevice because DiskDevices need disklabels. - # Quite lame, but it doesn't matter much since we won't use - # the StorageDevice instances for anything. - if device is None: - device = StorageDevice(name, - major=udev_device_get_major(info), - minor=udev_device_get_minor(info), - sysfsPath=sysfs_path, exists=True) - self._addDevice(device) - elif udev_device_is_disk(info): - if device is None: - device = self.addUdevDiskDevice(info) - elif udev_device_is_partition(info): - if device is None: - device = self.addUdevPartitionDevice(info) - - # now handle the device's formatting - self.handleUdevDeviceFormat(info, device) - - def addUdevDiskDevice(self, info): - name = udev_device_get_name(info) - uuid = udev_device_get_uuid(info) - sysfs_path = udev_device_get_sysfs_path(info) - device = None - - try: - device = DiskDevice(self.installer, name, - major=udev_device_get_major(info), - minor=udev_device_get_minor(info), - sysfsPath=sysfs_path, - initlabel=False) - except DeviceUserDeniedFormatError: #drive not initialized? - self.addIgnoredDisk(name) - return - - self._addDevice(device) - return device - - def addUdevPartitionDevice(self, info): - name = udev_device_get_name(info) - uuid = udev_device_get_uuid(info) - sysfs_path = udev_device_get_sysfs_path(info) - device = None - - disk_name = os.path.basename(os.path.dirname(sysfs_path)) - disk = self.getDeviceByName(disk_name) - - if disk is None: - # create a device instance for the disk - path = os.path.dirname(os.path.realpath(sysfs_path)) - new_info = udev_get_block_device(path) - if new_info: - self.addUdevDevice(new_info) - disk = self.getDeviceByName(disk_name) - - if disk is None: - # if the current device is still not in - # the tree, something has gone wrong - self.installer.log.error("Failure scanning device %s" % disk_name) - return - - try: - device = PartitionDevice(self.installer, name, sysfsPath=sysfs_path, - major=udev_device_get_major(info), - minor=udev_device_get_minor(info), - exists=True, parents=[disk]) - except DeviceError: - # corner case sometime the kernel accepts a partition table - # which gets rejected by parted, in this case we will - # prompt to re-initialize the disk, so simply skip the - # faulty partitions. - return - - self._addDevice(device) - return device - - def addUdevOpticalDevice(self, info): - # Looks like if it has ID_INSTANCE=0:1 we can ignore it. - device = OpticalDevice(self.installer, udev_device_get_name(info), - major=udev_device_get_major(info), - minor=udev_device_get_minor(info), - sysfsPath=udev_device_get_sysfs_path(info)) - self._addDevice(device) - return device - - def handleUdevDeviceFormat(self, info, device): - #log.debug("%s" % info) - name = udev_device_get_name(info) - sysfs_path = udev_device_get_sysfs_path(info) - uuid = udev_device_get_uuid(info) - label = udev_device_get_label(info) - format_type = udev_device_get_format(info) - - format = None - if (not device) or (not format_type) or device.format.type: - # this device has no formatting or it has already been set up - # FIXME: this probably needs something special for disklabels - self.installer.log.debug("no type or existing type for %s, bailing" % (name,)) - return - - # set up the common arguments for the format constructor - args = [format_type] - kwargs = {"uuid": uuid, - "label": label, - "device": device.path, - "exists": True} - - # set up type-specific arguments for the format constructor - if format_type == "crypto_LUKS": - # luks/dmcrypt - kwargs["name"] = "luks-%s" % uuid - elif format_type == "linux_raid_member": - # mdraid - try: - kwargs["mdUuid"] = udev_device_get_md_uuid(info) - except KeyError: - self.installer.log.debug("mdraid member %s has no md uuid" % name) - elif format_type == "LVM2_member": - # lvm - try: - kwargs["vgName"] = udev_device_get_vg_name(info) - except KeyError as e: - self.installer.log.debug("PV %s has no vg_name" % name) - try: - kwargs["vgUuid"] = udev_device_get_vg_uuid(info) - except KeyError: - self.installer.log.debug("PV %s has no vg_uuid" % name) - try: - kwargs["peStart"] = udev_device_get_pv_pe_start(info) - except KeyError: - self.installer.log.debug("PV %s has no pe_start" % name) - - try: - self.installer.log.debug("type detected on '%s' is '%s'" % (name, format_type,)) - device.format = formats.getFormat(format_type, *args, **kwargs) - except FSError, e: - self.installer.log.debug("type '%s' on '%s' invalid, assuming no format - %s" % - (format_type, name, e,)) - device.format = formats.DeviceFormat(self.installer) - return - - # - # now do any special handling required for the device's format - # - #if device.format.type == "luks": - # self.handleUdevLUKSFormat(info, device) - #elif device.format.type == "mdmember": - # self.handleUdevMDMemberFormat(info, device) - #elif device.format.type == "dmraidmember": - # self.handleUdevDMRaidMemberFormat(info, device) - #elif device.format.type == "lvmpv": - # self.handleUdevLVMPVFormat(info, device) - - def handleUdevDMRaidMemberFormat(self, info, device): - name = udev_device_get_name(info) - sysfs_path = udev_device_get_sysfs_path(info) - uuid = udev_device_get_uuid(info) - major = udev_device_get_major(info) - minor = udev_device_get_minor(info) - - def _all_ignored(rss): - retval = True - for rs in rss: - if rs.name not in self._ignoredDisks: - retval = False - break - return retval - - # Have we already created the DMRaidArrayDevice? - rss = block.getRaidSetFromRelatedMem(uuid=uuid, name=name, - major=major, minor=minor) - if len(rss) == 0: - # we ignore the device in the hope that all the devices - # from this set will be ignored. - # FIXME: Can we reformat a raid device? - self.addIgnoredDisk(device.name) - return - - # We ignore the device if all the rss are in self._ignoredDisks - if _all_ignored(rss): - self.addIgnoredDisk(device.name) - return - - for rs in rss: - dm_array = self.getDeviceByName(rs.name) - if dm_array is not None: - # We add the new device. - dm_array._addDevice(device) - else: - # Activate the Raid set. - rs.activate(mknod=True) - - # Create the DMRaidArray - if self.zeroMbr: - cb = lambda: True - else: - cb = lambda: questionInitializeDisk(self.intf, - rs.name) - - # Create the DMRaidArray - if not self.clearPartDisks or \ - rs.name in self.clearPartDisks: - # if the disk contains protected partitions - # we will not wipe the disklabel even if - # clearpart --initlabel was specified - initlabel = self.reinitializeDisks - for protected in self.protectedPartitions: - disk_name = re.sub(r'p\d+$', '', protected) - if disk_name != protected and \ - disk_name == rs.name: - initlabel = False - break - - try: - dm_array = DMRaidArrayDevice(rs.name, - raidSet=rs, - parents=[device], - initcb=cb, - initlabel=initlabel) - - self._addDevice(dm_array) - # Use the rs's object on the device. - # pyblock can return the memebers of a set and the - # device has the attribute to hold it. But ATM we - # are not really using it. Commenting this out until - # we really need it. - #device.format.raidmem = block.getMemFromRaidSet(dm_array, - # major=major, minor=minor, uuid=uuid, name=name) - except DeviceUserDeniedFormatError: - # We should ignore the dmraid and its components - self.addIgnoredDisk(rs.name) - if _all_ignored(rss): - self.addIgnoredDisk(device.name) - rs.deactivate() - - def getDependentDevices(self, dep): - """ Return a list of devices that depend on dep. - - The list includes both direct and indirect dependents. - """ - dependents = [] - - # special handling for extended partitions since the logical - # partitions and their deps effectively depend on the extended - logicals = [] - if isinstance(dep, PartitionDevice) and dep.partType and \ - dep.isExtended: - # collect all of the logicals on the same disk - for part in self.getDevicesByInstance(PartitionDevice): - if part.partType and part.isLogical and part.disk == dep.disk: - logicals.append(part) diff --git a/pkgs/core/pomona/src/storage_old/errors.py b/pkgs/core/pomona/src/storage_old/errors.py deleted file mode 100644 index 7a02dc0..0000000 --- a/pkgs/core/pomona/src/storage_old/errors.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/python - -class StorageError(Exception): - pass - -# Device -class DeviceError(StorageError): - pass - -class DeviceCreateError(DeviceError): - pass - -class DeviceDestroyError(DeviceError): - pass - -class DeviceResizeError(DeviceError): - pass - -class DeviceSetupError(DeviceError): - pass - -class DeviceTeardownError(DeviceError): - pass - -class DeviceUserDeniedFormatError(DeviceError): - pass - -# DeviceFormat -class DeviceFormatError(StorageError): - pass - -class FormatCreateError(DeviceFormatError): - pass - -class FormatDestroyError(DeviceFormatError): - pass - -class FormatSetupError(DeviceFormatError): - pass - -class FormatTeardownError(DeviceFormatError): - pass - -class DMRaidMemberError(DeviceFormatError): - pass - -class FSError(DeviceFormatError): - pass - -class FSResizeError(FSError): - pass - -class FSMigrateError(FSError): - pass - -class LUKSError(DeviceFormatError): - pass - -class MDMemberError(DeviceFormatError): - pass - -class PhysicalVolumeError(DeviceFormatError): - pass - -class SwapSpaceError(DeviceFormatError): - pass - -# devicelibs -class SwapError(StorageError): - pass - -class SuspendError(SwapError): - pass - -class OldSwapError(SwapError): - pass - -class MDRaidError(StorageError): - pass - -class DMError(StorageError): - pass - -class LVMError(StorageError): - pass - -class CryptoError(StorageError): - pass - -# DeviceTree -class DeviceTreeError(StorageError): - pass - -# DeviceAction -class DeviceActionError(StorageError): - pass - -# partitioning -class PartitioningError(StorageError): - pass - -class PartitioningWarning(StorageError): - pass - -# udev -class UdevError(StorageError): - pass diff --git a/pkgs/core/pomona/src/storage_old/formats/__init__.py b/pkgs/core/pomona/src/storage_old/formats/__init__.py deleted file mode 100644 index f73f138..0000000 --- a/pkgs/core/pomona/src/storage_old/formats/__init__.py +++ /dev/null @@ -1,318 +0,0 @@ -#!/usr/bin/python - -import os -import copy - -device_formats = {} -def register_device_format(fmt_class): - if not issubclass(fmt_class, DeviceFormat): - raise ValueError("Argument must be a subclass of DeviceFormat") - device_formats[fmt_class._type] = fmt_class - -def getFormat(fmt_type, *args, **kwargs): - """ Return a DeviceFormat instance based on fmt_type and args. - - Given a device format type and a set of constructor arguments, - return a DeviceFormat instance. - - Return None if no suitable format class is found. - - Arguments: - - fmt_type -- the name of the format type (eg: 'ext3', 'swap') - - Keyword Arguments: - - The keyword arguments may vary according to the format type, - but here is the common set: - - device -- path to the device on which the format resides - uuid -- the UUID of the (preexisting) formatted device - exists -- whether or not the format exists on the device - - """ - fmt_class = get_device_format_class(fmt_type) - fmt = None - if fmt_class: - fmt = fmt_class(*args, **kwargs) - try: - className = fmt.__class__.__name__ - except AttributeError: - className = None - return fmt - -def get_device_format_class(fmt_type): - """ Return an appropriate format class based on fmt_type. """ - if not device_formats: - collect_device_format_classes() - - fmt = device_formats.get(fmt_type) - if not fmt: - for fmt_class in device_formats.values(): - if fmt_type and fmt_type == fmt_class._name: - fmt = fmt_class - break - elif fmt_type in fmt_class._udevTypes: - fmt = fmt_class - break - - # default to no formatting, AKA "Unknown" - if not fmt: - fmt = DeviceFormat - return fmt - -def collect_device_format_classes(): - """ Pick up all device format classes from this directory. - - Note: Modules must call register_device_format(FormatClass) in - order for the format class to be picked up. - """ - dir = os.path.dirname(__file__) - for module_file in os.listdir(dir): - # make sure we're not importing this module - if module_file.endswith(".py") and module_file != __file__: - mod_name = module_file[:-3] - try: - globals()[mod_name] = __import__(mod_name, globals(), locals(), [], -1) - except ImportError, e: - pass - -default_fstypes = ("ext4", "ext3", "ext2") -default_boot_fstypes = ("ext3", "ext2") -def get_default_filesystem_type(boot=None): - if boot: - fstypes = default_boot_fstypes - else: - fstypes = default_fstypes - - for fstype in fstypes: - try: - supported = get_device_format_class(fstype).supported - except AttributeError: - supported = None - - if supported: - return fstype - - raise DeviceFormatError("None of %s is supported by your kernel" % ",".join(fstypes)) - -class DeviceFormat(object): - """ Generic device format. """ - _type = None - _name = "Unknown" - _udevTypes = [] - partedFlag = None - _formattable = False # can be formatted - _supported = False # is supported - _resizable = False # can be resized - _bootable = False # can be used as boot - _migratable = False # can be migrated - _maxSize = 0 # maximum size in MB - _minSize = 0 # minimum size in MB - _dump = False - _check = False - - def __init__(self, installer, *args, **kwargs): - """ Create a DeviceFormat instance. - - Keyword Arguments: - - device -- path to the underlying device - uuid -- this format's UUID - exists -- indicates whether this is an existing format - - """ - self.installer = installer - - self.device = kwargs.get("device") - self.uuid = kwargs.get("uuid") - self.exists = kwargs.get("exists") - self.options = kwargs.get("options") - self._migrate = False - - def __deepcopy__(self, memo): - new = self.__class__.__new__(self.__class__) - memo[id(self)] = new - shallow_copy_attrs = ('installer', 'screen') - for (attr, value) in self.__dict__.items(): - if attr in shallow_copy_attrs: - setattr(new, attr, copy.copy(value)) - else: - setattr(new, attr, copy.deepcopy(value, memo)) - - return new - - def _setOptions(self, options): - self._options = options - - def _getOptions(self): - return self._options - - options = property(_getOptions, _setOptions) - - def _setDevice(self, devspec): - if devspec and not devspec.startswith("/"): - raise ValueError("device must be a fully qualified path: %s" % devspec) - self._device = devspec - - def _getDevice(self): - return self._device - - device = property(lambda f: f._getDevice(), - lambda f,d: f._setDevice(d), - doc="Full path the device this format occupies") - - @property - def name(self): - if self._name: - name = self._name - else: - name = self.type - return name - - @property - def type(self): - return self._type - - def probe(self): - pass - - def notifyKernel(self): - if not self.device: - return - - if self.device.startswith("/dev/mapper/"): - try: - name = dm_node_from_name(os.path.basename(self.device)) - except Exception, e: - self.installer.log.warning("Failed to get dm node for %s" % self.device) - return - elif self.device: - name = os.path.basename(self.device) - - path = get_sysfs_path_by_name(name) - try: - notify_kernel(path, action="change") - except Exception, e: - self.installer.log.warning("Failed to notify kernel of change: %s" % e) - - def create(self, *args, **kwargs): - # allow late specification of device path - device = kwargs.get("device") - if device: - self.device = device - - if not os.path.exists(self.device): - raise FormatCreateError("invalid device specification") - - def destroy(self, *args, **kwargs): - # zero out the 1MB at the beginning and end of the device in the - # hope that it will wipe any metadata from filesystems that - # previously occupied this device - self.installer.log.debug("Zeroing out beginning and end of %s..." % self.device) - try: - fd = os.open(self.device, os.O_RDWR) - buf = '\0' * 1024 * 1024 - os.write(fd, buf) - os.lseek(fd, -1024 * 1024, 2) - os.write(fd, buf) - os.close(fd) - except OSError as e: - if getattr(e, "errno", None) == 28: # No space left in device - pass - else: - self.installer.log.error("Error zeroing out %s: %s" % (self.device, e)) - os.close(fd) - except Exception as e: - self.installer.log.error("Error zeroing out %s: %s" % (self.device, e)) - os.close(fd) - - self.exists = False - - def setup(self, *args, **kwargs): - if not self.exists: - raise FormatSetupError("format has not been created") - - if self.status: - return - - # allow late specification of device path - device = kwargs.get("device") - if device: - self.device = device - - if not self.device or not os.path.exists(self.device): - raise FormatSetupError("invalid device specification") - - def teardown(self, *args, **kwargs): - pass - - @property - def status(self): - return (self.exists and - self.__class__ is not DeviceFormat and - isinstance(self.device, str) and - self.device and - os.path.exists(self.device)) - - @property - def formattable(self): - """ Can we create formats of this type? """ - return self._formattable - - @property - def supported(self): - """ Is this format a supported type? """ - return self._supported - - @property - def resizable(self): - """ Can formats of this type be resized? """ - return self._resizable - - @property - def bootable(self): - """ Is this format type suitable for a boot partition? """ - return self._bootable - - @property - def migratable(self): - """ Can formats of this type be migrated? """ - return self._migratable - - @property - def migrate(self): - return self._migrate - - @property - def linuxNative(self): - """ Is this format type native to linux? """ - return self._linuxNative - - @property - def mountable(self): - """ Is this something we can mount? """ - return False - - @property - def dump(self): - """ Whether or not this format will be dumped by dump(8). """ - return self._dump - - @property - def check(self): - """ Whether or not this format is checked on boot. """ - return self._check - - @property - def maxSize(self): - """ Maximum size (in MB) for this format type. """ - return self._maxSize - - @property - def minSize(self): - """ Minimum size (in MB) for this format type. """ - return self._minSize - - -collect_device_format_classes() diff --git a/pkgs/core/pomona/src/storage_old/formats/fs.py b/pkgs/core/pomona/src/storage_old/formats/fs.py deleted file mode 100644 index 2eace61..0000000 --- a/pkgs/core/pomona/src/storage_old/formats/fs.py +++ /dev/null @@ -1,929 +0,0 @@ -#!/usr/bin/python - -import os -import tempfile - -import isys - -import util - -from ..errors import * -from . import DeviceFormat, register_device_format - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -fs_configs = {} - -def get_kernel_filesystems(): - fs_list = [] - for line in open("/proc/filesystems").readlines(): - fs_list.append(line.split()[-1]) - return fs_list - -global kernel_filesystems -kernel_filesystems = get_kernel_filesystems() - -class FS(DeviceFormat): - """ Filesystem class. """ - _type = "Abstract Filesystem Class" # fs type name - _mountType = None # like _type but for passing to mount - _name = None - _mkfs = "" # mkfs utility - _modules = [] # kernel modules required for support - _resizefs = "" # resize utility - _labelfs = "" # labeling utility - _fsck = "" # fs check utility - _migratefs = "" # fs migration utility - _defaultFormatOptions = [] # default options passed to mkfs - _defaultMountOptions = ["defaults"] # default options passed to mount - _defaultLabelOptions = [] - _defaultCheckOptions = [] - _defaultMigrateOptions = [] - _migrationTarget = None - lostAndFoundContext = None - - def __init__(self, installer, *args, **kwargs): - """ Create a FS instance. - - Keyword Args: - - device -- path to the device containing the filesystem - mountpoint -- the filesystem's mountpoint - label -- the filesystem label - uuid -- the filesystem UUID - mountopts -- mount options for the filesystem - size -- the filesystem's size in MiB - exists -- indicates whether this is an existing filesystem - - """ - if self.__class__ is FS: - raise TypeError("FS is an abstract class.") - - self.installer = installer - - DeviceFormat.__init__(self, self.installer, *args, **kwargs) - # TODO: fsprofiles and other ways to add format args - self.mountpoint = kwargs.get("mountpoint") - self.mountopts = kwargs.get("mountopts") - self.label = kwargs.get("label") - - # filesystem size does not necessarily equal device size - self._size = kwargs.get("size") - self._mountpoint = None # the current mountpoint when mounted - if self.exists: - self._size = self._getExistingSize() - - self._targetSize = self._size - - if self.supported: - self.loadModule() - - def _setTargetSize(self, newsize): - """ Set a target size for this filesystem. """ - if not self.exists: - raise FSError("filesystem has not been created") - - if newsize is None: - # unset any outstanding resize request - self._targetSize = None - return - - if not self.minSize < newsize < self.maxSize: - raise ValueError("invalid target size request") - - self._targetSize = newsize - - def _getTargetSize(self): - """ Get this filesystem's target size. """ - return self._targetSize - - targetSize = property(_getTargetSize, _setTargetSize, - doc="Target size for this filesystem") - - def _getSize(self): - """ Get this filesystem's size. """ - size = self._size - if self.resizable and self.targetSize != size: - size = self.targetSize - return size - - size = property(_getSize, doc="This filesystem's size, accounting " - "for pending changes") - - def _getExistingSize(self): - """ Determine the size of this filesystem. Filesystem must - exist. - """ - size = 0 - - if self.mountable: - origMountPoint = self._mountpoint - - tmppath = tempfile.mkdtemp(prefix='getsize-', dir='/tmp') - self.mount(mountpoint=tmppath, options="ro") - buf = os.statvfs(tmppath) - self.unmount() - os.rmdir(tmppath) - - self._mountpoint = origMountPoint - - size = (buf.f_frsize * buf.f_blocks) / 1024.0 / 1024.0 - - return size - - @property - def currentSize(self): - """ The filesystem's current actual size. """ - size = 0 - if self.exists: - size = self._size - return float(size) - - def _getFormatOptions(self, options=None): - argv = [] - if options and isinstance(options, list): - argv.extend(options) - argv.extend(self.defaultFormatOptions) - argv.append(self.device) - return argv - - def doFormat(self, *args, **kwargs): - """ Create the filesystem. - - Arguments: - - None - - Keyword Arguments: - - intf -- InstallInterface instance - options -- list of options to pass to mkfs - - """ - intf = kwargs.get("intf") - options = kwargs.get("options") - - if self.exists: - raise FormatCreateError("filesystem already exists", self.device) - - if not self.formattable: - return - - if not self.mkfsProg: - return - - if self.exists: - return - - if not os.path.exists(self.device): - raise FormatCreateError("device does not exist", self.device) - - argv = self._getFormatOptions(options=options) - - self.installer.window = None - self.installer.window = self.installer.intf.progressWindow(_("Formatting"), - _("Creating filesystem on %s...") % (self.device,), - 100, pulse = True) - - try: - rc = util.execWithPulseProgress(self.mkfsProg, - argv, - stdout="/dev/tty5", - stderr="/dev/tty5", - progress=w) - except Exception as e: - raise FormatCreateError(e, self.device) - finally: - if self.installer.window: - self.installer.window.pop() - - if rc: - raise FormatCreateError("format failed: %s" % rc, self.device) - - self.exists = True - self.notifyKernel() - - def doMigrate(self, intf=None): - if not self.exists: - raise FSError("filesystem has not been created") - - if not self.migratable or not self.migrate: - return - - if not os.path.exists(self.device): - raise FSError("device does not exist") - - # if journal already exists skip - if isys.ext2HasJournal(self.device): - self.installer.log.info("Skipping migration of %s, has a journal already." % self.device) - return - - argv = self._defaultMigrateOptions[:] - argv.append(self.device) - try: - rc = util.execWithRedirect(self.migratefsProg, - argv, - stdout = "/dev/tty5", - stderr = "/dev/tty5", - searchPath = 1) - except Exception as e: - raise FSMigrateError("filesystem migration failed: %s" % e, self.device) - - if rc: - raise FSMigrateError("filesystem migration failed: %s" % rc, self.device) - - # the other option is to actually replace this instance with an - # instance of the new filesystem type. - self._type = self.migrationTarget - - @property - def resizeArgs(self): - argv = [self.device, "%d" % (self.targetSize,)] - return argv - - def doResize(self, *args, **kwargs): - """ Resize this filesystem to new size @newsize. - - Arguments: - - None - - Keyword Arguments: - - intf -- InstallInterface instance - - """ - intf = kwargs.get("intf") - - if not self.exists: - raise FSResizeError("filesystem does not exist", self.device) - - if not self.resizable: - raise FSResizeError("filesystem not resizable", self.device) - - if self.targetSize == self.currentSize: - return - - if not self.resizefsProg: - return - - if not os.path.exists(self.device): - raise FSResizeError("device does not exist", self.device) - - self.doCheck(intf=intf) - - w = None - if intf: - w = intf.progressWindow(_("Resizing"), - _("Resizing filesystem on %s...") - % (self.device,), - 100, pulse = True) - - try: - rc = util.execWithPulseProgress(self.resizefsProg, - self.resizeArgs, - stdout="/dev/tty5", - stderr="/dev/tty5", - progress=w) - except Exception as e: - raise FSResizeError(e, self.device) - finally: - if w: - w.pop() - - if rc: - raise FSResizeError("resize failed: %s" % rc, self.device) - - # XXX must be a smarter way to do this - self._size = self.targetSize - self.notifyKernel() - - def _getCheckArgs(self): - argv = [] - argv.extend(self.defaultCheckOptions) - argv.append(self.device) - return argv - - def doCheck(self, intf=None): - if not self.exists: - raise FSError("filesystem has not been created") - - if not self.fsckProg: - return - - if not os.path.exists(self.device): - raise FSError("device does not exist") - - w = None - if intf: - w = intf.progressWindow(_("Checking"), - _("Checking filesystem on %s...") - % (self.device), - 100, pulse = True) - - try: - rc = util.execWithPulseProgress(self.fsckProg, - self._getCheckArgs(), - stdout="/dev/tty5", - stderr="/dev/tty5", - progress = w) - except Exception as e: - raise FSError("filesystem check failed: %s" % e) - finally: - if w: - w.pop() - - if rc >= 4: - raise FSError("filesystem check failed: %s" % rc) - - def loadModule(self): - """Load whatever kernel module is required to support this filesystem.""" - global kernel_filesystems - - if not self._modules or self.mountType in kernel_filesystems: - return - - for module in self._modules: - try: - rc = util.execWithRedirect("modprobe", [module], - stdout="/dev/tty5", stderr="/dev/tty5", - searchPath=1) - except Exception as e: - self.installer.log.error("Could not load kernel module %s: %s" % (module, e)) - self._supported = False - return - - if rc: - self.installer.log.error("Could not load kernel module %s" % module) - self._supported = False - return - - # If we successfully loaded a kernel module, for this filesystem, we - # also need to update the list of supported filesystems. - kernel_filesystems = get_kernel_filesystems() - - def mount(self, *args, **kwargs): - """ Mount this filesystem. - - Arguments: - - None - - Keyword Arguments: - - options -- mount options (overrides all other option strings) - chroot -- prefix to apply to mountpoint - mountpoint -- mountpoint (overrides self.mountpoint) - """ - options = kwargs.get("options", "") - chroot = kwargs.get("chroot", "/") - mountpoint = kwargs.get("mountpoint") - - if not self.exists: - raise FSError("filesystem has not been created") - - if not mountpoint: - mountpoint = self.mountpoint - - if not mountpoint: - raise FSError("no mountpoint given") - - if self.status: - return - - if not isinstance(self, NoDevFS) and not os.path.exists(self.device): - raise FSError("device %s does not exist" % self.device) - - # XXX os.path.join is FUBAR: - # - # os.path.join("/mnt/foo", "/") -> "/" - # - #mountpoint = os.path.join(chroot, mountpoint) - mountpoint = os.path.normpath("%s/%s" % (chroot, mountpoint)) - util.mkdirChain(mountpoint) - - # passed in options override default options - if not options or not isinstance(options, str): - options = self.options - - try: - rc = isys.mount(self.device, mountpoint, - fstype=self.mountType, - options=options, - bindMount=isinstance(self, BindFS)) - except Exception as e: - raise FSError("mount failed: %s" % e) - - if rc: - raise FSError("mount failed: %s" % rc) - - self._mountpoint = mountpoint - - def unmount(self): - """ Unmount this filesystem. """ - if not self.exists: - raise FSError("filesystem has not been created") - - if not self._mountpoint: - # not mounted - return - - if not os.path.exists(self._mountpoint): - raise FSError("mountpoint does not exist") - - rc = isys.umount(self._mountpoint, removeDir = False) - if rc: - raise FSError("umount failed") - - self._mountpoint = None - - def _getLabelArgs(self, label): - argv = [] - argv.extend(self.defaultLabelOptions) - argv.extend([self.device, label]) - return argv - - def writeLabel(self, label): - """ Create a label for this filesystem. """ - if not self.exists: - raise FSError("filesystem has not been created") - - if not self.labelfsProg: - return - - if not os.path.exists(self.device): - raise FSError("device does not exist") - - argv = self._getLabelArgs(label) - rc = util.execWithRedirect(self.labelfsProg, - argv, - stderr="/dev/tty5", - searchPath=1) - if rc: - raise FSError("label failed") - - self.label = label - self.notifyKernel() - - @property - def isDirty(self): - return False - - @property - def mkfsProg(self): - """ Program used to create filesystems of this type. """ - return self._mkfs - - @property - def fsckProg(self): - """ Program used to check filesystems of this type. """ - return self._fsck - - @property - def resizefsProg(self): - """ Program used to resize filesystems of this type. """ - return self._resizefs - - @property - def labelfsProg(self): - """ Program used to manage labels for this filesystem type. """ - return self._labelfs - - @property - def migratefsProg(self): - """ Program used to migrate filesystems of this type. """ - return self._migratefs - - @property - def migrationTarget(self): - return self._migrationTarget - - @property - def utilsAvailable(self): - # we aren't checking for fsck because we shouldn't need it - for prog in [self.mkfsProg, self.resizefsProg, self.labelfsProg]: - if not prog: - continue - - if not filter(lambda d: os.access("%s/%s" % (d, prog), os.X_OK), - os.environ["PATH"].split(":")): - return False - - return True - - @property - def supported(self): - return self._supported and self.utilsAvailable - - @property - def mountable(self): - return (self.mountType in kernel_filesystems) or \ - (os.access("/sbin/mount.%s" % (self.mountType,), os.X_OK)) - - @property - def defaultFormatOptions(self): - """ Default options passed to mkfs for this filesystem type. """ - # return a copy to prevent modification - return self._defaultFormatOptions[:] - - @property - def defaultMountOptions(self): - """ Default options passed to mount for this filesystem type. """ - # return a copy to prevent modification - return self._defaultMountOptions[:] - - @property - def defaultLabelOptions(self): - """ Default options passed to labeler for this filesystem type. """ - # return a copy to prevent modification - return self._defaultLabelOptions[:] - - @property - def defaultCheckOptions(self): - """ Default options passed to checker for this filesystem type. """ - # return a copy to prevent modification - return self._defaultCheckOptions[:] - - def _getOptions(self): - options = ",".join(self.defaultMountOptions) - if self.mountopts: - # XXX should we clobber or append? - options = self.mountopts - return options - - def _setOptions(self, options): - self.mountopts = options - - options = property(_getOptions, _setOptions) - - @property - def migratable(self): - """ Can filesystems of this type be migrated? """ - return bool(self._migratable and self.migratefsProg and - filter(lambda d: os.access("%s/%s" - % (d, self.migratefsProg,), - os.X_OK), - os.environ["PATH"].split(":")) and - self.migrationTarget) - - def _setMigrate(self, migrate): - if not migrate: - self._migrate = migrate - return - - if self.migratable and self.exists: - self._migrate = migrate - else: - raise ValueError("Cannot set migrate on non-migratable filesystem") - - migrate = property(lambda f: f._migrate, lambda f,m: f._setMigrate(m)) - - @property - def type(self): - _type = self._type - if self.migrate: - _type = self.migrationTarget - - return _type - - @property - def mountType(self): - if not self._mountType: - self._mountType = self._type - - return self._mountType - - # These methods just wrap filesystem-specific methods in more - # generically named methods so filesystems and formatted devices - # like swap and LVM physical volumes can have a common API. - def create(self, *args, **kwargs): - if self.exists: - raise FSError("Filesystem already exists") - - DeviceFormat.create(self, *args, **kwargs) - - return self.doFormat(*args, **kwargs) - - def setup(self, *args, **kwargs): - """ Mount the filesystem. - - THe filesystem will be mounted at the directory indicated by - self.mountpoint. - """ - return self.mount(**kwargs) - - def teardown(self, *args, **kwargs): - return self.unmount(*args, **kwargs) - - @property - def status(self): - # FIXME check /proc/mounts or similar - if not self.exists: - return False - return self._mountpoint is not None - - -class Ext2FS(FS): - """ ext2 filesystem. """ - _type = "ext2" - _mkfs = "mke2fs" - _modules = ["ext2"] - _resizefs = "resize2fs" - _labelfs = "e2label" - _fsck = "e2fsck" - _formattable = True - _supported = True - _resizable = True - _bootable = True - _linuxNative = True - _maxSize = 8 * 1024 * 1024 - _minSize = 0 - _defaultFormatOptions = [] - _defaultMountOptions = ["defaults"] - _defaultCheckOptions = ["-f", "-p", "-C", "0"] - _dump = True - _check = True - _migratable = True - _migrationTarget = "ext3" - _migratefs = "tune2fs" - _defaultMigrateOptions = ["-j"] - - @property - def minSize(self): - """ Minimum size for this filesystem in MB. """ - size = self._minSize - if self.exists and os.path.exists(self.device): - buf = util.execWithCapture(self.resizefsProg, - ["-P", self.device], - stderr="/dev/tty5") - size = None - for line in buf.splitlines(): - if "minimum size of the filesystem:" not in line: - continue - - (text, sep, minSize) = line.partition(": ") - - size = int(minSize) / 1024.0 - - if size is None: - self.installer.log.warning("failed to get minimum size for %s filesystem " - "on %s" % (self.mountType, self.device)) - size = self._minSize - - return size - - @property - def isDirty(self): - return isys.ext2IsDirty(self.device) - - @property - def resizeArgs(self): - argv = ["-p", self.device, "%dM" % (self.targetSize,)] - return argv - -register_device_format(Ext2FS) - - -class Ext3FS(Ext2FS): - """ ext3 filesystem. """ - _type = "ext3" - _defaultFormatOptions = ["-t", "ext3"] - _migrationTarget = "ext4" - _modules = ["ext3"] - _defaultMigrateOptions = ["-O", "extents"] - - @property - def migratable(self): - """ Can filesystems of this type be migrated? """ - return (flags.cmdline.has_key("ext4migrate") and - Ext2FS.migratable) - -register_device_format(Ext3FS) - - -class Ext4FS(Ext3FS): - """ ext4 filesystem. """ - _type = "ext4" - _bootable = False - _defaultFormatOptions = ["-t", "ext4"] - _migratable = False - _modules = ["ext4"] - -register_device_format(Ext4FS) - - -class FATFS(FS): - """ FAT filesystem. """ - _type = "vfat" - _mkfs = "mkdosfs" - _modules = ["vfat"] - _labelfs = "dosfslabel" - _fsck = "dosfsck" - _formattable = True - _maxSize = 1024 * 1024 - _defaultMountOptions = ["umask=0077", "shortname=winnt"] - -register_device_format(FATFS) - - -class BTRFS(FS): - """ btrfs filesystem """ - _type = "btrfs" - _mkfs = "mkfs.btrfs" - _modules = ["btrfs"] - _resizefs = "btrfsctl" - _formattable = True - _linuxNative = True - _bootable = False - _maxLabelChars = 256 - _supported = True - _dump = True - _check = True - _maxSize = 16 * 1024 * 1024 - - def _getFormatOptions(self, options=None): - argv = [] - if options and isinstance(options, list): - argv.extend(options) - argv.extend(self.defaultFormatOptions) - if self.label: - argv.extend(["-L", self.label]) - argv.append(self.device) - return argv - - @property - def resizeArgs(self): - argv = ["-r", "%dm" % (self.targetSize,), self.device] - return argv - -register_device_format(BTRFS) - -class XFS(FS): - """ XFS filesystem """ - _type = "xfs" - _mkfs = "mkfs.xfs" - _modules = ["xfs"] - _labelfs = "xfs_admin" - _defaultFormatOptions = ["-f"] - _defaultLabelOptions = ["-L"] - _maxLabelChars = 16 - _maxSize = 16 * 1024 * 1024 - _formattable = True - _linuxNative = True - _supported = True - _dump = True - _check = True - -register_device_format(XFS) - -class NTFS(FS): - """ ntfs filesystem. """ - _type = "ntfs" - _resizefs = "ntfsresize" - _fsck = "ntfsresize" - _resizable = True - _minSize = 1 - _maxSize = 16 * 1024 * 1024 - _defaultMountOptions = ["defaults"] - _defaultCheckOptions = ["-c"] - - @property - def minSize(self): - """ The minimum filesystem size in megabytes. """ - size = self._minSize - if self.exists and os.path.exists(self.device): - minSize = None - buf = util.execWithCapture(self.resizefsProg, - ["-m", self.device], - stderr = "/dev/tty5") - for l in buf.split("\n"): - if not l.startswith("Minsize"): - continue - try: - min = l.split(":")[1].strip() - minSize = int(min) + 250 - except Exception, e: - minSize = None - self.installer.log.warning("Unable to parse output for minimum size on %s: %s" %(self.device, e)) - - if minSize is None: - self.installer.log.warning("Unable to discover minimum size of filesystem " - "on %s" %(self.device,)) - else: - size = minSize - - return size - - @property - def resizeArgs(self): - # You must supply at least two '-f' options to ntfsresize or - # the proceed question will be presented to you. - argv = ["-ff", "-s", "%dM" % (self.targetSize,), self.device] - return argv - -register_device_format(NTFS) - - -# if this isn't going to be mountable it might as well not be here -class NFS(FS): - """ NFS filesystem. """ - _type = "nfs" - _modules = ["nfs"] - - def _deviceCheck(self, devspec): - if devspec is not None and ":" not in devspec: - raise ValueError("device must be of the form <host>:<path>") - - @property - def mountable(self): - return False - - def _setDevice(self, devspec): - self._deviceCheck(devspec) - self._device = devspec - - def _getDevice(self): - return self._device - - device = property(lambda f: f._getDevice(), - lambda f,d: f._setDevice(d), - doc="Full path the device this format occupies") - -register_device_format(NFS) - - -class NFSv4(NFS): - """ NFSv4 filesystem. """ - _type = "nfs4" - _modules = ["nfs4"] - -register_device_format(NFSv4) - - -class Iso9660FS(FS): - """ ISO9660 filesystem. """ - _type = "iso9660" - _formattable = False - _supported = True - _resizable = False - _bootable = False - _linuxNative = False - _dump = False - _check = False - _migratable = False - _defaultMountOptions = ["ro"] - -register_device_format(Iso9660FS) - - -class NoDevFS(FS): - """ nodev filesystem base class """ - _type = "nodev" - - def __init__(self, *args, **kwargs): - FS.__init__(self, *args, **kwargs) - self.exists = True - self.device = self.type - - def _setDevice(self, devspec): - self._device = devspec - -register_device_format(NoDevFS) - - -class DevPtsFS(NoDevFS): - """ devpts filesystem. """ - _type = "devpts" - _defaultMountOptions = ["gid=5", "mode=620"] - -register_device_format(DevPtsFS) - - -# these don't really need to be here -class ProcFS(NoDevFS): - _type = "proc" - -register_device_format(ProcFS) - - -class SysFS(NoDevFS): - _type = "sysfs" - -register_device_format(SysFS) - - -class TmpFS(NoDevFS): - _type = "tmpfs" - -register_device_format(TmpFS) - - -class BindFS(FS): - _type = "bind" - - @property - def mountable(self): - return True - -register_device_format(BindFS) diff --git a/pkgs/core/pomona/src/storage_old/formats/luks.py b/pkgs/core/pomona/src/storage_old/formats/luks.py deleted file mode 100644 index 25d9db4..0000000 --- a/pkgs/core/pomona/src/storage_old/formats/luks.py +++ /dev/null @@ -1,187 +0,0 @@ -#!/usr/bin/python - -import os - -from ..errors import * -#from ..devicelibs import crypto -from . import DeviceFormat, register_device_format - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -class LUKS(DeviceFormat): - """ A LUKS device. """ - _type = "luks" - _name = "LUKS" - _udevTypes = ["crypto_LUKS"] - _formattable = True # can be formatted - _supported = False # is supported - _linuxNative = True # for clearpart - - def __init__(self, *args, **kwargs): - """ Create a LUKS instance. - - Keyword Arguments: - - device -- the path to the underlying device - name -- the name of the mapped device - uuid -- this device's UUID - passphrase -- device passphrase (string) - key_file -- path to a file containing a key (string) - cipher -- cipher mode string - key_size -- key size in bits - exists -- indicates whether this is an existing format - """ - DeviceFormat.__init__(self, *args, **kwargs) - self.cipher = kwargs.get("cipher") - self.key_size = kwargs.get("key_size") - self.mapName = kwargs.get("name") - - if not self.exists and not self.cipher: - self.cipher = "aes-xts-plain" - if not self.key_size: - # default to the max (512 bits) for aes-xts - self.key_size = 512 - - # FIXME: these should both be lists, but managing them will be a pain - self.__passphrase = kwargs.get("passphrase") - self._key_file = kwargs.get("key_file") - - if not self.mapName and self.exists and self.uuid: - self.mapName = "luks-%s" % self.uuid - elif not self.mapName and self.device: - self.mapName = "luks-%s" % os.path.basename(self.device) - - def _setPassphrase(self, passphrase): - """ Set the passphrase used to access this device. """ - self.__passphrase = passphrase - - passphrase = property(fset=_setPassphrase) - - @property - def hasKey(self): - return (self.__passphrase or - (self._key_file and os.access(self._key_file, os.R_OK))) - - @property - def configured(self): - """ To be ready we need a key or passphrase and a map name. """ - return self.hasKey and self.mapName - - @property - def status(self): - if not self.exists or not self.mapName: - return False - return os.path.exists("/dev/mapper/%s" % self.mapName) - - def probe(self): - """ Probe for any missing information about this format. - - cipher mode, key size - """ - raise NotImplementedError("Probe method not defined for LUKS") - - def setup(self, *args, **kwargs): - """ Open, or set up, the format. """ - if not self.configured: - raise LUKSError("luks device not configured") - - if self.status: - return - - DeviceFormat.setup(self, *args, **kwargs) - crypto.luks_open(self.device, self.mapName, - passphrase=self.__passphrase, - key_file=self._key_file) - - def teardown(self, *args, **kwargs): - """ Close, or tear down, the format. """ - if not self.exists: - raise LUKSError("format has not been created") - - if self.status: - log.debug("unmapping %s" % self.mapName) - crypto.luks_close(self.mapName) - - def create(self, *args, **kwargs): - """ Create the format. """ - if not self.hasKey: - raise LUKSError("luks device has no key/passphrase") - - DeviceFormat.create(self, *args, **kwargs) - crypto.luks_format(self.device, - passphrase=self.__passphrase, - key_file=self._key_file, - cipher=self.cipher, - key_size=self.key_size) - - self.uuid = crypto.luks_uuid(self.device) - self.exists = True - self.mapName = "luks-%s" % self.uuid - self.notifyKernel() - - def destroy(self, *args, **kwargs): - """ Create the format. """ - self.teardown() - DeviceFormat.destroy(self, *args, **kwargs) - - @property - def keyFile(self): - """ Path to key file to be used in /etc/crypttab """ - return self._key_file - - def addKeyFromFile(self, keyfile): - """ Add a new key from a file. - - Add the contents of the specified key file to an available key - slot in the LUKS header. - """ - if not self.exists: - raise LUKSError("Format has not been created") - - crypto.luks_add_key(self.device, - passphrase=self.__passphrase, - key_file=self._key_file, - new_key_file=keyfile) - - def addPassphrase(self, passphrase): - """ Add a new passphrase. - - Add the specified passphrase to an available key slot in the - LUKS header. - """ - if not self.exists: - raise LUKSError("Format has not been created") - - crypto.luks_add_key(self.device, - passphrase=self.__passphrase, - key_file=self._key_file, - new_passphrase=passphrase) - - def removeKeyFromFile(self, keyfile): - """ Remove a key contained in a file. - - Remove key contained in the specified key file from the LUKS - header. - """ - if not self.exists: - raise LUKSError("Format has not been created") - - crypto.luks_remove_key(self.device, - passphrase=self.__passphrase, - key_file=self._key_file, - del_key_file=keyfile) - - - def removePassphrase(self, passphrase): - """ Remove the specified passphrase from the LUKS header. """ - if not self.exists: - raise LUKSError("Format has not been created") - - crypto.luks_remove_key(self.device, - passphrase=self.__passphrase, - key_file=self._key_file, - del_passphrase=passphrase) - - -register_device_format(LUKS) diff --git a/pkgs/core/pomona/src/storage_old/formats/lvmpv.py b/pkgs/core/pomona/src/storage_old/formats/lvmpv.py deleted file mode 100644 index cccff87..0000000 --- a/pkgs/core/pomona/src/storage_old/formats/lvmpv.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/python - -from parted import PARTITION_LVM - -from . import DeviceFormat, register_device_format -from ..errors import * -from ..devicelibs import lvm - -class LVMPhysicalVolume(DeviceFormat): - """ An LVM physical volume. """ - _type = "lvmpv" - _name = "physical volume (LVM)" - _udevTypes = ["LVM2_member"] - partedFlag = PARTITION_LVM - _formattable = True # can be formatted - _supported = True # is supported - _linuxNative = True # for clearpart - - def __init__(self, *args, **kwargs): - """ Create an LVMPhysicalVolume instance. - - Keyword Arguments: - - device -- path to the underlying device - uuid -- this PV's uuid (not the VG uuid) - vgName -- the name of the VG this PV belongs to - vgUuid -- the UUID of the VG this PV belongs to - peStart -- offset of first physical extent - exists -- indicates whether this is an existing format - - """ - DeviceFormat.__init__(self, *args, **kwargs) - self.vgName = kwargs.get("vgName") - self.vgUuid = kwargs.get("vgUuid") - # liblvm may be able to tell us this at some point, even - # for not-yet-created devices - self.peStart = kwargs.get("peStart", 0.1875) # in MB - - def probe(self): - """ Probe for any missing information about this device. """ - if not self.exists: - raise PhysicalVolumeError("format has not been created") - - #info = lvm.pvinfo(self.device) - #self.vgName = info['vg_name'] - #self.vgUuid = info['vg_uuid'] - - def create(self, *args, **kwargs): - """ Create the format. """ - DeviceFormat.create(self, *args, **kwargs) - # Consider use of -Z|--zero - # -f|--force or -y|--yes may be required - - # lvm has issues with persistence of metadata, so here comes the - # hammer... - DeviceFormat.destroy(self, *args, **kwargs) - - lvm.pvcreate(self.device) - self.exists = True - self.notifyKernel() - - def destroy(self, *args, **kwargs): - """ Destroy the format. """ - if not self.exists: - raise PhysicalVolumeError("format has not been created") - - if self.status: - raise PhysicalVolumeError("device is active") - - # FIXME: verify path exists? - try: - lvm.pvremove(self.device) - except LVMError: - DeviceFormat.destroy(self, *args, **kwargs) - - self.exists = False - self.notifyKernel() - - @property - def status(self): - # XXX hack - return (self.exists and self.vgName and - os.path.isdir("/dev/mapper/%s" % self.vgName)) - -register_device_format(LVMPhysicalVolume) diff --git a/pkgs/core/pomona/src/storage_old/formats/swap.py b/pkgs/core/pomona/src/storage_old/formats/swap.py deleted file mode 100644 index 487d365..0000000 --- a/pkgs/core/pomona/src/storage_old/formats/swap.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/python - -from parted import PARTITION_SWAP - -from . import DeviceFormat, register_device_format -from ..devicelibs import swap - -class SwapSpace(DeviceFormat): - """ Swap space """ - _type = "swap" - _name = None - _udevTypes = ["swap"] - partedFlag = PARTITION_SWAP - _formattable = True # can be formatted - _supported = True # is supported - _linuxNative = True # for clearpart - - def __init__(self, installer, *args, **kwargs): - """ Create a SwapSpace instance. - - Keyword Arguments: - - device -- path to the underlying device - uuid -- this swap space's uuid - label -- this swap space's label - priority -- this swap space's priority - exists -- indicates whether this is an existing format - - """ - self.installer = installer - DeviceFormat.__init__(self, self.installer, *args, **kwargs) - - self.priority = kwargs.get("priority") - self.label = kwargs.get("label") - - def _setPriority(self, priority): - if priority is None: - self._priority = None - return - - if not isinstance(priority, int) or not 0 <= priority <= 32767: - raise ValueError("swap priority must be an integer between 0 and 32767") - - self._priority = priority - - def _getPriority(self): - return self._priority - - priority = property(_getPriority, _setPriority, - doc="The priority of the swap device") - - def _getOptions(self): - opts = "" - if self.priority is not None: - opts += "pri=%d" % self.priority - - return opts - - def _setOptions(self, opts): - if not opts: - self.priority = None - return - - for option in opts.split(","): - (opt, equals, arg) = option.partition("=") - if equals and opt == "pri": - try: - self.priority = int(arg) - except ValueError: - self.installer.log.info("invalid value for swap priority: %s" % arg) - - options = property(_getOptions, _setOptions, - doc="The swap device's fstab options string") - - @property - def status(self): - """ Device status. """ - return self.exists and swap.swapstatus(self.device) - - def setup(self, *args, **kwargs): - """ Open, or set up, a device. """ - if not self.exists: - raise SwapSpaceError("format has not been created") - - if self.status: - return - - DeviceFormat.setup(self, *args, **kwargs) - swap.swapon(self.device, priority=self.priority) - - def teardown(self, *args, **kwargs): - """ Close, or tear down, a device. """ - if not self.exists: - raise SwapSpaceError("format has not been created") - - if self.status: - swap.swapoff(self.device) - - def create(self, *args, **kwargs): - """ Create the device. """ - if self.exists: - raise SwapSpaceError("format already exists") - - if self.status: - raise SwapSpaceError("device exists and is active") - - DeviceFormat.create(self, *args, **kwargs) - swap.mkswap(self.device, label=self.label) - self.exists = True - - -register_device_format(SwapSpace) diff --git a/pkgs/core/pomona/src/storage_old/partitioning.py b/pkgs/core/pomona/src/storage_old/partitioning.py deleted file mode 100644 index d7672a6..0000000 --- a/pkgs/core/pomona/src/storage_old/partitioning.py +++ /dev/null @@ -1,1059 +0,0 @@ -#!/usr/bin/python - -import os -import parted - -from constants import * -from errors import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -def doAutoPartition(installer): - if installer.dispatch.dir == DISPATCH_BACK: - installer.ds.storage.reset() - return - - disks = [] - devs = [] - - if installer.ds.storage.doAutoPart: - clearPartitions(installer) - (disks, devs) = _createFreeSpacePartitions(installer) - - if disks == []: - installer.intf.messageWindow(_("Error Partitioning"), - _("Could not find enough free space " - "for automatic partitioning, please " - "use another partitioning method.")) - return DISPATCH_BACK - - _schedulePartitions(installer, disks) - - # run the autopart function to allocate and grow partitions - try: - doPartitioning(installer) - - if installer.ds.storage.doAutoPart: - _scheduleLVs(installer, devs) - - # grow LVs - growLVM(installer) - except PartitioningWarning as msg: - installer.intf.messageWindow(_("Warnings During Automatic Partitioning"), - _("Following warnings occurred during automatic " - "partitioning:\n\n%s") % (msg,),) - log.warning(msg) - except PartitioningError as msg: - # restore drives to original state - installer.ds.storage.reset() - #installer.dispatch.skipStep("partition", skip = 0) - installer.intf.messageWindow(_("Error Partitioning"), - _("Could not allocate requested partitions: \n\n" - "%s.%s") % (msg, extra)) - return - - # now do a full check of the requests - (errors, warnings) = installer.ds.storage.sanityCheck() - if warnings: - for warning in warnings: - installer.log.warning(warning) - if errors: - errortxt = "\n".join(errors) - installer.intf.messageWindow(_("Automatic Partitioning Errors"), - _("The following errors occurred with your " - "partitioning:\n\n%s\n\n" - "This can happen if there is not enough " - "space on your hard drive(s) for the " - "installation.\n\n" - "Press 'OK' to choose a different partitioning option.") - % (errortxt,),) - - installer.ds.storage.reset() - #XXX return DISPATCH_BACK - return INSTALL_OK - -def doPartitioning(installer): - """ Allocate and grow partitions. - - When this function returns without error, all PartitionDevice - instances must have their parents set to the disk they are - allocated on, and their partedPartition attribute set to the - appropriate parted.Partition instance from their containing - disk. All req_xxxx attributes must be unchanged. - - Arguments: - - storage - Main anaconda Storage instance - - Keyword arguments: - - exclusiveDisks -- list of names of disks to use - - """ - storage = installer.ds.storage - disks = storage.disks - - exclusiveDisks = storage.clearDisks - if exclusiveDisks: - disks = [d for d in disks if d.name in exclusiveDisks] - - for disk in disks: - disk.setup() - - partitions = storage.partitions - for part in partitions: - part.req_bootable = False - if not part.exists: - # start over with flexible-size requests - part.req_size = part.req_base_size - - # FIXME: isn't there a better place for this to happen? - #try: - # bootDev = anaconda.platform.bootDevice() - #except DeviceError: - # bootDev = None - - #if bootDev: - # bootDev.req_bootable = True - - # FIXME: make sure non-existent partitions have empty parents list - allocatePartitions(installer, disks, partitions) - growPartitions(installer, disks, partitions) - # The number and thus the name of partitions may have changed now, - # allocatePartitions() takes care of this for new partitions, but not - # for pre-existing ones, so we update the name of all partitions here - for part in partitions: - part.updateName() - - # XXX hack -- if we created any extended partitions we need to add - # them to the tree now - for disk in disks: - extended = disk.partedDisk.getExtendedPartition() - if not extended: - continue - - extendedName = devicePathToName(extended.getDeviceNodeName()) - device = storage.devicetree.getDeviceByName(extendedName) - if device: - if not device.exists: - # created by us, update partedPartition - device.partedPartition = extended - continue - - # This is a little odd because normally instantiating a partition - # that does not exist means leaving self.parents empty and instead - # populating self.req_disks. In this case, we need to skip past - # that since this partition is already defined. - device = PartitionDevice(extendedName, parents=disk) - device.parents = [disk] - device.partedPartition = extended - storage.createDevice(device) - -def clearPartitions(installer): - """ Clear partitions and dependent devices from disks. - - Arguments: - - storage -- a storage.Storage instance - - Keyword arguments: - - None - - NOTES: - - - Needs some error handling, especially for the parted bits. - - """ - storage = installer.ds.storage - - # we are only interested in partitions that physically exist - partitions = [p for p in storage.partitions if p.exists] - disks = [] # a list of disks from which we've removed partitions - clearparts = [] # list of partitions we'll remove - for part in partitions: - # if we got a list of disks to clear, make sure this one's on it - if storage.clearDisks and part.disk.name not in storage.clearDisks: - continue - - # don't clear partitions holding install media - #if part.name in storage.protectedPartitions: - # continue - - # we don't want to fool with extended partitions, freespace - if part.partType not in (parted.PARTITION_NORMAL, parted.PARTITION_LOGICAL): - continue - - # XXX is there any argument for not removing incomplete devices? - # -- maybe some RAID devices - devices = storage.deviceDeps(part) - while devices: - installer.log.debug("Devices to remove: %s" % ([d.name for d in devices],)) - leaves = [d for d in devices if d.isleaf] - installer.log.debug("Leaves to remove: %s" % ([d.name for d in leaves],)) - for leaf in leaves: - storage.destroyDevice(leaf) - devices.remove(leaf) - - #installer.log.debug("Partitions left: %s" % [p.getDeviceNodeName() for p in part.partedPartition.disk.partitions]) - disk_name = os.path.basename(part.partedPartition.disk.device.path) - if disk_name not in disks: - disks.append(disk_name) - - clearparts.append(part) - - for part in clearparts: - storage.destroyDevice(part) - - # now remove any empty extended partitions - removeEmptyExtendedPartitions(installer) - -def removeEmptyExtendedPartitions(installer): - storage = installer.ds.storage - for disk in storage.disks: - #installer.log.debug("Checking whether disk %s has an empty extended" % disk.name) - extended = disk.partedDisk.getExtendedPartition() - logical_parts = disk.partedDisk.getLogicalPartitions() - #installer.log.debug("Extended is %s ; logicals is %s" % (extended, [p.getDeviceNodeName() for p in logical_parts])) - if extended and not logical_parts: - installer.log.debug("Removing empty extended partition from %s" % disk.name) - extended_name = devicePathToName(extended.getDeviceNodeName()) - extended = storage.devicetree.getDeviceByName(extended_name) - storage.destroyDevice(extended) - #disk.partedDisk.removePartition(extended.partedPartition) - -def _createFreeSpacePartitions(installer): - # get a list of disks that have at least one free space region of at - # least 100MB - disks = [] - for disk in installer.ds.storage.disks: - if disk.name not in installer.ds.storage.clearDisks: - continue - - partedDisk = disk.partedDisk - part = disk.partedDisk.getFirstPartition() - while part: - if not part.type & parted.PARTITION_FREESPACE: - part = part.nextPartition() - continue - - if part.getSize(unit="MB") > 100: - disks.append(disk) - break - - part = part.nextPartition() - - # create a separate pv partition for each disk with free space - devs = [] - for disk in disks: - if installer.ds.storage.encryptedAutoPart: - fmt_type = "luks" - else: - fmt_type = "lvmpv" - part = installer.ds.storage.newPartition(fmt_type=fmt_type, - size=1, grow=True, - disks=[disk]) - installer.ds.storage.createDevice(part) - devs.append(part) - - return (disks, devs) - -def _schedulePartitions(installer, disks): - # - # Convert storage.autoPartitionRequests into Device instances and - # schedule them for creation - # - # First pass is for partitions only. We'll do LVs later. - # - for request in installer.ds.storage.autoPartitionRequests: - if request.asVol: - continue - - if request.fstype is None: - request.fstype = installer.ds.storage.defaultFSType - - dev = installer.ds.storage.newPartition(fmt_type=request.fstype, - size=request.size, - grow=request.grow, - maxsize=request.maxSize, - mountpoint=request.mountpoint, - disks=disks, - weight=request.weight) - - # schedule the device for creation - installer.ds.storage.createDevice(dev) - - # make sure preexisting broken lvm/raid configs get out of the way - return - -def allocatePartitions(installer, disks, partitions): - """ Allocate partitions based on requested features. - - Non-existing partitions are sorted according to their requested - attributes, and then allocated. - - The basic approach to sorting is that the more specifically- - defined a request is, the earlier it will be allocated. See - the function partitionCompare for details on the sorting - criteria. - - The PartitionDevice instances will have their name and parents - attributes set once they have been allocated. - """ - #installer.log.debug("disks=%s ; partitions=%s" % (disks, partitions)) - new_partitions = [p for p in partitions if not p.exists] - new_partitions.sort(cmp=partitionCompare) - - # XXX is this needed anymore? - partedDisks = {} - for disk in disks: - if disk.path not in partedDisks.keys(): - partedDisks[disk.path] = disk.partedDisk #.duplicate() - - # remove all newly added partitions from the disk - installer.log.debug("Removing all non-preexisting from disk(s)") - for _part in new_partitions: - if _part.partedPartition: - if _part.isExtended: - continue # these get removed last - #_part.disk.partedDisk.removePartition(_part.partedPartition) - partedDisk = partedDisks[_part.disk.partedDisk.device.path] - installer.log.debug("Removing part %s (%s) from disk %s (%s)" % - (_part.partedPartition.path, - [p.path for p in _part.partedPartition.disk.partitions], - partedDisk.device.path, - [p.path for p in partedDisk.partitions])) - - partedDisk.removePartition(_part.partedPartition) - _part.partedPartition = None - _part.disk = None - - # remove empty extended so it doesn't interfere - extended = partedDisk.getExtendedPartition() - if extended and not partedDisk.getLogicalPartitions(): - installer.log.debug("Removing empty extended partition") - #partedDisk.minimizeExtendedPartition() - partedDisk.removePartition(extended) - - for _part in new_partitions: - if _part.partedPartition and _part.isExtended: - # ignore new extendeds as they are implicit requests - continue - - # obtain the set of candidate disks - req_disks = [] - if _part.disk: - # we have a already selected a disk for this request - req_disks = [_part.disk] - elif _part.req_disks: - # use the requested disk set - req_disks = _part.req_disks - else: - # no disks specified means any disk will do - req_disks = disks - - #installer.log.debug("allocating partition: %s ; disks: %s ; boot: %s ; " - # "primary: %s ; size: %dMB ; grow: %s ; max_size: %s" % - # (_part.name, req_disks, _part.req_bootable, _part.req_primary, - # _part.req_size, _part.req_grow, _part.req_max_size)) - free = None - use_disk = None - part_type = None - # loop through disks - for _disk in req_disks: - disk = partedDisks[_disk.path] - #for p in disk.partitions: - # installer.log.debug("disk %s: part %s" % (disk.device.path, p.path)) - sectorSize = disk.device.physicalSectorSize - best = None - - #installer.log.debug("Checking freespace on %s" % _disk.name) - - new_part_type = getNextPartitionType(disk) - if new_part_type is None: - # can't allocate any more partitions on this disk - installer.log.debug("No free partition slots on %s" % _disk.name) - continue - - if _part.req_primary and new_part_type != parted.PARTITION_NORMAL: - # we need a primary slot and none are free on this disk - installer.log.debug("No primary slots available on %s" % _disk.name) - continue - - best = getBestFreeSpaceRegion(installer, disk, - new_part_type, - _part.req_size, - best_free=free, - boot=_part.req_bootable) - - if best == free and not _part.req_primary and \ - new_part_type == parted.PARTITION_NORMAL: - # see if we can do better with a logical partition - installer.log.debug("Not enough free space for primary -- trying logical") - new_part_type = getNextPartitionType(disk, no_primary=True) - if new_part_type: - best = getBestFreeSpaceRegion(disk, - new_part_type, - _part.req_size, - best_free=free, - boot=_part.req_bootable) - - if best and free != best: - # now we know we are choosing a new free space, - # so update the disk and part type - #installer.log.debug("Updating use_disk to %s (%s), type: %s" - # % (_disk, _disk.name, new_part_type)) - part_type = new_part_type - use_disk = _disk - installer.log.debug("New free: %s (%d-%d / %dMB)" % (best.device.path, - best.start, - best.end, - best.getSize())) - free = best - - if free and _part.req_bootable: - # if this is a bootable partition we want to - # use the first freespace region large enough - # to satisfy the request - installer.log.debug("Found free space for bootable request") - break - - if free is None: - raise PartitioningError("Not enough free space on disks") - - _disk = use_disk - disk = _disk.partedDisk - - # create the extended partition if needed - # TODO: move to a function (disk, free) - if part_type == parted.PARTITION_EXTENDED: - installer.log.debug("Creating extended partition") - geometry = parted.Geometry(device=disk.device, - start=free.start, - length=free.length, - end=free.end) - extended = parted.Partition(disk=disk, - type=parted.PARTITION_EXTENDED, - geometry=geometry) - constraint = parted.Constraint(device=disk.device) - # FIXME: we should add this to the tree as well - disk.addPartition(extended, constraint) - - # end proposed function - - # now the extended partition exists, so set type to logical - part_type = parted.PARTITION_LOGICAL - - # recalculate freespace - installer.log.debug("Recalculating free space") - free = getBestFreeSpaceRegion(disk, - part_type, - _part.req_size, - boot=_part.req_bootable) - if not free: - raise PartitioningError("Not enough free space after " - "creating extended partition") - - # create minimum geometry for this request - # req_size is in MB - sectors_per_track = disk.device.biosGeometry[2] - length = (_part.req_size * (1024 * 1024)) / sectorSize - new_geom = parted.Geometry(device=disk.device, - start=max(sectors_per_track, free.start), - length=length) - - # create maximum and minimum geometries for constraint - start = max(0 , free.start - 1) - max_geom = parted.Geometry(device=disk.device, - start=start, - length=min(length + 1, disk.device.length - start)) - min_geom = parted.Geometry(device=disk.device, - start=free.start + 1, - length=length-1) - - - # create the partition and add it to the disk - partition = parted.Partition(disk=disk, - type=part_type, - geometry=new_geom) - constraint = parted.Constraint(maxGeom=max_geom, minGeom=min_geom) - disk.addPartition(partition=partition, - constraint=constraint) - installer.log.debug("Created partition %s of %dMB and added it to %s" % - (partition.getDeviceNodeName(), partition.getSize(), disk.device.path)) - - # this one sets the name - _part.partedPartition = partition - _part.disk = _disk - - # parted modifies the partition in the process of adding it to - # the disk, so we need to grab the latest version... - _part.partedPartition = disk.getPartitionByPath(_part.path) - -def growPartitions(installer, disks, partitions): - """ Grow all growable partition requests. - - All requests should know what disk they will be on by the time - this function is called. This is reflected in the - PartitionDevice's disk attribute. Note that the req_disks - attribute remains unchanged. - - The total available free space is summed up for each disk and - partition requests are allocated a maximum percentage of the - available free space on their disk based on their own base size. - - Each attempted size means calling allocatePartitions again with - one request's size having changed. - - After taking into account several factors that may limit the - maximum size of a requested partition, we arrive at a firm - maximum number of sectors by which a request can potentially grow. - - An initial attempt is made to allocate the full maximum size. If - this fails, we begin a rough binary search with a maximum of three - iterations to settle on a new size. - - Arguments: - - disks -- a list of all usable disks (DiskDevice instances) - partitions -- a list of all partitions (PartitionDevice - instances) - """ - #installer.log.debug("growPartitions: disks=%s, partitions=%s" % - # ([d.name for d in disks], [p.name for p in partitions])) - all_growable = [p for p in partitions if p.req_grow] - if not all_growable: - return - - # sort requests by base size in decreasing order - all_growable.sort(key=lambda p: p.req_size, reverse=True) - - installer.log.debug("Growable requests are %s" % [p.name for p in all_growable]) - - for disk in disks: - installer.log.debug("Growing requests on %s" % disk.name) - for p in disk.partedDisk.partitions: - installer.log.debug(" %s: %s (%dMB)" % (disk.name, p.getDeviceNodeName(), - p.getSize())) - sectorSize = disk.partedDisk.device.physicalSectorSize - # get a list of free space regions on the disk - free = disk.partedDisk.getFreeSpaceRegions() - if not free: - installer.log.debug("No free space on %s" % disk.name) - continue - - # sort the free regions in decreasing order of size - free.sort(key=lambda r: r.length, reverse=True) - disk_free = reduce(lambda x,y: x + y, [f.length for f in free]) - installer.log.debug("Total free: %d sectors ; largest: %d sectors (%dMB)" - % (disk_free, free[0].length, free[0].getSize())) - - # make a list of partitions currently allocated on this disk - # -- they're already sorted - growable = [] - disk_total = 0 - for part in all_growable: - #log.debug("checking if part %s (%s) is on this disk" % (part.name, - # part.disk.name)) - if part.disk == disk: - growable.append(part) - disk_total += part.partedPartition.geometry.length - installer.log.debug("Add %s (%dMB/%d sectors) to growable total" - % (part.name, part.partedPartition.getSize(), - part.partedPartition.geometry.length)) - installer.log.debug("Growable total is now %d sectors" % disk_total) - - # now we loop through the partitions... - # this first loop is to identify obvious chunks of free space that - # will be left over due to max size - leftover = 0 - limited = {} - unlimited_total = 0 - for part in growable: - # calculate max number of sectors this request can grow - req_sectors = part.partedPartition.geometry.length - share = float(req_sectors) / float(disk_total) - max_grow = (share * disk_free) - max_sectors = req_sectors + max_grow - limited[part.name] = False - - if part.req_max_size: - req_max_sect = (part.req_max_size * (1024 * 1024)) / sectorSize - if req_max_sect < max_sectors: - mb = ((max_sectors - req_max_sect) * sectorSize) / (1024*1024) - - installer.log.debug("Adding %dMB to leftovers from %s" - % (mb, part.name)) - leftover += (max_sectors - req_max_sect) - limited[part.name] = True - - if not limited[part.name]: - unlimited_total += req_sectors - - # now we loop through the partitions... - for part in growable: - # calculate max number of sectors this request can grow - req_sectors = part.partedPartition.geometry.length - share = float(req_sectors) / float(disk_total) - max_grow = (share * disk_free) - if not limited[part.name]: - leftover_share = float(req_sectors) / float(unlimited_total) - max_grow += leftover_share * leftover - max_sectors = req_sectors + max_grow - max_mb = (max_sectors * sectorSize) / (1024 * 1024) - - installer.log.debug("%s: base_size=%dMB, max_size=%sMB" % - (part.name, part.req_base_size, part.req_max_size)) - installer.log.debug("%s: current_size=%dMB (%d sectors)" % - (part.name, part.partedPartition.getSize(), - part.partedPartition.geometry.length)) - installer.log.debug("%s: %dMB (%d sectors, or %d%% of %d)" % - (part.name, max_mb, max_sectors, share * 100, disk_free)) - - installer.log.debug("Checking constraints on max size...") - # don't grow beyond the request's maximum size - if part.req_max_size: - installer.log.debug("max_size: %dMB" % part.req_max_size) - # FIXME: round down to nearest cylinder boundary - req_max_sect = (part.req_max_size * (1024 * 1024)) / sectorSize - if req_max_sect < max_sectors: - max_grow -= (max_sectors - req_max_sect) - max_sectors = req_sectors + max_grow - - # don't grow beyond the resident filesystem's max size - if part.format.maxSize > 0: - installer.log.debug("Format maxsize: %dMB" % part.format.maxSize) - # FIXME: round down to nearest cylinder boundary - fs_max_sect = (part.format.maxSize * (1024 * 1024)) / sectorSize - if fs_max_sect < max_sectors: - max_grow -= (max_sectors - fs_max_sect) - max_sectors = req_sectors + max_grow - - # we can only grow as much as the largest free region on the disk - if free[0].length < max_grow: - installer.log.debug("Largest free region: %d sectors (%dMB)" % - (free[0].length, free[0].getSize())) - # FIXME: round down to nearest cylinder boundary - max_grow = free[0].length - max_sectors = req_sectors + max_grow - - # Now, we try to grow this partition as close to max_grow - # sectors as we can. - # - # We could call allocatePartitions after modifying this - # request and saving the original value of part.req_size, - # or we could try to use disk.maximizePartition(). - max_size = (max_sectors * sectorSize) / (1024 * 1024) - orig_size = part.req_size - # try the max size to begin with - installer.log.debug("Attempting to allocate maximum size: %dMB" % max_size) - part.req_size = max_size - try: - allocatePartitions(installer, disks, partitions) - except PartitioningError, e: - installer.log.debug("Max size attempt failed: %s (%dMB)" % (part.name, - max_size)) - part.req_size = orig_size - else: - continue - - installer.log.debug("Starting binary search: size=%d max_size=%d" % (part.req_size, max_size)) - count = 0 - op_func = add - increment = max_grow - last_good_size = part.req_size - last_outcome = None - while count < 3: - last_size = part.req_size - increment /= 2 - req_sectors = op_func(req_sectors, increment) - part.req_size = (req_sectors * sectorSize) / (1024 * 1024) - installer.log.debug("Attempting size=%dMB" % part.req_size) - count += 1 - try: - allocatePartitions(disks, partitions) - except PartitioningError, e: - installer.log.debug("Attempt at %dMB failed" % part.req_size) - op_func = sub - last_outcome = False - else: - op_func = add - last_good_size = part.req_size - last_outcome = True - - if not last_outcome: - part.req_size = last_good_size - installer.log.debug("Backing up to size=%dMB" % part.req_size) - try: - allocatePartitions(disks, partitions) - except PartitioningError, e: - raise PartitioningError("Failed to grow partitions") - - # reset all requests to their original requested size - for part in partitions: - if part.exists: - continue - part.req_size = part.req_base_size - -def growLVM(installer): - """ Grow LVs according to the sizes of the PVs. """ - storage = installer.ds.storage - for vg in storage.vgs: - total_free = vg.freeSpace - if not total_free: - installer.log.debug("vg %s has no free space" % vg.name) - continue - - installer.log.debug("vg %s: %dMB free ; lvs: %s" % (vg.name, vg.freeSpace, - [l.lvname for l in vg.lvs])) - - # figure out how much to grow each LV - grow_amounts = {} - lv_total = vg.size - total_free - installer.log.debug("used: %dMB ; vg.size: %dMB" % (lv_total, vg.size)) - - # This first loop is to calculate percentage-based growth - # amounts. These are based on total free space. - lvs = vg.lvs - lvs.sort(cmp=lvCompare) - for lv in lvs: - if not lv.req_grow or not lv.req_percent: - continue - - portion = (lv.req_percent * 0.01) - grow = portion * vg.vgFree - new_size = lv.req_size + grow - if lv.req_max_size and new_size > lv.req_max_size: - grow -= (new_size - lv.req_max_size) - - if lv.format.maxSize and lv.format.maxSize < new_size: - grow -= (new_size - lv.format.maxSize) - - # clamp growth amount to a multiple of vg extent size - grow_amounts[lv.name] = vg.align(grow) - total_free -= grow - lv_total += grow - - # This second loop is to calculate non-percentage-based growth - # amounts. These are based on free space remaining after - # calculating percentage-based growth amounts. - - # keep a tab on space not allocated due to format or requested - # maximums -- we'll dole it out to subsequent requests - leftover = 0 - for lv in lvs: - installer.log.debug("Checking lv %s: req_grow: %s ; req_percent: %s" - % (lv.name, lv.req_grow, lv.req_percent)) - if not lv.req_grow or lv.req_percent: - continue - - portion = float(lv.req_size) / float(lv_total) - grow = portion * total_free - installer.log.debug("grow is %dMB" % grow) - - todo = lvs[lvs.index(lv):] - unallocated = reduce(lambda x,y: x+y, - [l.req_size for l in todo - if l.req_grow and not l.req_percent]) - extra_portion = float(lv.req_size) / float(unallocated) - extra = extra_portion * leftover - installer.log.debug("%s getting %dMB (%d%%) of %dMB leftover space" - % (lv.name, extra, extra_portion * 100, leftover)) - leftover -= extra - grow += extra - installer.log.debug("grow is now %dMB" % grow) - max_size = lv.req_size + grow - if lv.req_max_size and max_size > lv.req_max_size: - max_size = lv.req_max_size - - if lv.format.maxSize and max_size > lv.format.maxSize: - max_size = lv.format.maxSize - - installer.log.debug("max size is %dMB" % max_size) - max_size = max_size - leftover += (lv.req_size + grow) - max_size - grow = max_size - lv.req_size - installer.log.debug("lv %s gets %dMB" % (lv.name, vg.align(grow))) - grow_amounts[lv.name] = vg.align(grow) - - if not grow_amounts: - installer.log.debug("No growable lvs in vg %s" % vg.name) - continue - - # now grow the lvs by the amounts we've calculated above - for lv in lvs: - if lv.name not in grow_amounts.keys(): - continue - lv.size += grow_amounts[lv.name] - - # now there shouldn't be any free space left, but if there is we - # should allocate it to one of the LVs - vg_free = vg.freeSpace - installer.log.debug("vg %s has %dMB free" % (vg.name, vg_free)) - if vg_free: - for lv in lvs: - if not lv.req_grow: - continue - - if lv.req_max_size and lv.size == lv.req_max_size: - continue - - if lv.format.maxSize and lv.size == lv.format.maxSize: - continue - - # first come, first served - projected = lv.size + vg.freeSpace - if lv.req_max_size and projected > lv.req_max_size: - projected = lv.req_max_size - - if lv.format.maxSize and projected > lv.format.maxSize: - projected = lv.format.maxSize - - installer.log.debug("Giving leftover %dMB to %s" % (projected - lv.size, - lv.name)) - lv.size = projected - -def partitionCompare(part1, part2): - """ More specifically defined partitions come first. - - < 1 => x < y - 0 => x == y - > 1 => x > y - """ - ret = 0 - - if part1.req_base_weight: - ret -= part1.req_base_weight - - if part2.req_base_weight: - ret += part2.req_base_weight - - # bootable partitions to the front - ret -= cmp(part1.req_bootable, part2.req_bootable) * 1000 - - # more specific disk specs to the front of the list - ret += cmp(len(part1.parents), len(part2.parents)) * 500 - - # primary-only to the front of the list - ret -= cmp(part1.req_primary, part2.req_primary) * 200 - - # larger requests go to the front of the list - ret -= cmp(part1.size, part2.size) * 100 - - # fixed size requests to the front - ret += cmp(part1.req_grow, part2.req_grow) * 50 - - # potentially larger growable requests go to the front - if part1.req_grow and part2.req_grow: - if not part1.req_max_size and part2.req_max_size: - ret -= 25 - elif part1.req_max_size and not part2.req_max_size: - ret += 25 - else: - ret -= cmp(part1.req_max_size, part2.req_max_size) * 25 - - if ret > 0: - ret = 1 - elif ret < 0: - ret = -1 - - return ret - -def lvCompare(lv1, lv2): - """ More specifically defined lvs come first. - - < 1 => x < y - 0 => x == y - > 1 => x > y - """ - ret = 0 - - # larger requests go to the front of the list - ret -= cmp(lv1.size, lv2.size) * 100 - - # fixed size requests to the front - ret += cmp(lv1.req_grow, lv2.req_grow) * 50 - - # potentially larger growable requests go to the front - if lv1.req_grow and lv2.req_grow: - if not lv1.req_max_size and lv2.req_max_size: - ret -= 25 - elif lv1.req_max_size and not lv2.req_max_size: - ret += 25 - else: - ret -= cmp(lv1.req_max_size, lv2.req_max_size) * 25 - - if ret > 0: - ret = 1 - elif ret < 0: - ret = -1 - - return ret - -def getNextPartitionType(disk, no_primary=None): - """ Find the type of partition to create next on a disk. - - Return a parted partition type value representing the type of the - next partition we will create on this disk. - - If there is only one free primary partition and we can create an - extended partition, we do that. - - If there are free primary slots and an extended partition we will - recommend creating a primary partition. This can be overridden - with the keyword argument no_primary. - - Arguments: - - disk -- a parted.Disk instance representing the disk - - Keyword arguments: - - no_primary -- given a choice between primary and logical - partitions, prefer logical - - """ - part_type = None - extended = disk.getExtendedPartition() - supports_extended = disk.supportsFeature(parted.DISK_TYPE_EXTENDED) - logical_count = len(disk.getLogicalPartitions()) - max_logicals = disk.getMaxLogicalPartitions() - primary_count = disk.primaryPartitionCount - - if primary_count == disk.maxPrimaryPartitionCount and \ - extended and logical_count < max_logicals: - part_type = parted.PARTITION_LOGICAL - elif primary_count == (disk.maxPrimaryPartitionCount - 1) and \ - not extended and supports_extended: - # last chance to create an extended partition - part_type = parted.PARTITION_EXTENDED - elif no_primary and extended and logical_count < max_logicals: - # create a logical even though we could presumably create a - # primary instead - part_type = parted.PARTITION_LOGICAL - elif not no_primary: - # XXX there is a possiblity that the only remaining free space on - # the disk lies within the extended partition, but we will - # try to create a primary first - part_type = parted.PARTITION_NORMAL - - return part_type - -def getBestFreeSpaceRegion(installer, disk, part_type, req_size, - boot=None, best_free=None): - """ Return the "best" free region on the specified disk. - - For non-boot partitions, we return the largest free region on the - disk. For boot partitions, we return the first region that is - large enough to hold the partition. - - Partition type (parted's PARTITION_NORMAL, PARTITION_LOGICAL) is - taken into account when locating a suitable free region. - - For locating the best region from among several disks, the keyword - argument best_free allows the specification of a current "best" - free region with which to compare the best from this disk. The - overall best region is returned. - - Arguments: - - disk -- the disk (a parted.Disk instance) - part_type -- the type of partition we want to allocate - (one of parted's partition type constants) - req_size -- the requested size of the partition (in MB) - - Keyword arguments: - - boot -- indicates whether this will be a bootable partition - (boolean) - best_free -- current best free region for this partition - - """ - #installer.log.debug("getBestFreeSpaceRegion: disk=%s part_type=%d req_size=%dMB boot=%s best=%s" % - # (disk.device.path, part_type, req_size, boot, best_free)) - extended = disk.getExtendedPartition() - for _range in disk.getFreeSpaceRegions(): - if extended: - # find out if there is any overlap between this region and the - # extended partition - installer.log.debug("Looking for intersection between extended (%d-%d) and free (%d-%d)" % - (extended.geometry.start, extended.geometry.end, _range.start, _range.end)) - - # parted.Geometry.overlapsWith can handle this - try: - free_geom = extended.geometry.intersect(_range) - except ArithmeticError, e: - # this freespace region does not lie within the extended - # partition's geometry - free_geom = None - - if (free_geom and part_type == parted.PARTITION_NORMAL) or \ - (not free_geom and part_type == parted.PARTITION_LOGICAL): - installer.log.debug("Free region not suitable for request") - continue - - if part_type == parted.PARTITION_NORMAL: - # we're allocating a primary and the region is not within - # the extended, so we use the original region - free_geom = _range - else: - free_geom = _range - - installer.log.debug("Current free range on %s is %d-%d (%dMB)" % (disk.device.path, - free_geom.start, - free_geom.end, - free_geom.getSize())) - free_size = free_geom.getSize() - - if req_size <= free_size: - if not best_free or free_geom.length > best_free.length: - best_free = free_geom - - if boot: - # if this is a bootable partition we want to - # use the first freespace region large enough - # to satisfy the request - break - - return best_free - -def _scheduleLVs(installer, devs): - if installer.ds.storage.encryptedAutoPart: - pvs = [] - for dev in devs: - pv = LUKSDevice("luks-%s" % dev.name, - format=getFormat("lvmpv", device=dev.path), - size=dev.size, - parents=dev) - pvs.append(pv) - installer.ds.storage.createDevice(pv) - else: - pvs = devs - - # create a vg containing all of the autopart pvs - vg = installer.ds.storage.newVG(pvs=pvs) - installer.ds.storage.createDevice(vg) - - # - # Convert storage.autoPartitionRequests into Device instances and - # schedule them for creation. - # - # Second pass, for LVs only. - for request in installer.ds.storage.autoPartitionRequests: - if not request.asVol: - continue - - if request.fstype is None: - request.fstype = installer.ds.storage.defaultFSType - - # FIXME: move this to a function and handle exceptions - dev = installer.ds.storage.newLV(vg=vg, - fmt_type=request.fstype, - mountpoint=request.mountpoint, - grow=request.grow, - maxsize=request.maxSize, - size=request.size) - - # schedule the device for creation - installer.ds.storage.createDevice(dev) diff --git a/pkgs/core/pomona/src/storage_old/udev.py b/pkgs/core/pomona/src/storage_old/udev.py deleted file mode 100644 index a9a7377..0000000 --- a/pkgs/core/pomona/src/storage_old/udev.py +++ /dev/null @@ -1,305 +0,0 @@ -#!/usr/bin/python - -import os -import sys - -import util - -def udev_settle(timeout=None): - argv = ["settle"] - if timeout: - argv.append("--timeout=%d" % int(timeout)) - - util.execWithRedirect("udevadm", argv, stderr="/dev/null", searchPath=1) - -def udev_trigger(subsystem=None): - argv = ["trigger"] - if subsystem: - argv.append("--subsystem-match=%s" % subsystem) - - util.execWithRedirect("udevadm", argv, stderr="/dev/null", searchPath=1) - -def udev_get_block_devices(): - #udev_settle(timeout=30) - entries = [] - for path in enumerate_block_devices(): - entry = udev_get_block_device(path) - if entry: - entries.append(entry) - return entries - -def __is_blacklisted_blockdev(dev_name): - """Is this a blockdev we never want for an install?""" - if dev_name.startswith("loop") or dev_name.startswith("ram") or dev_name.startswith("fd"): - return True - - if os.path.exists("/sys/class/block/%s/device/model" %(dev_name,)): - model = open("/sys/class/block/%s/device/model" %(dev_name,)).read() - for bad in ("IBM *STMF KERNEL", "SCEI Flash-5", "DGC LUNZ"): - if model.find(bad) != -1: - return True - - return False - -def enumerate_block_devices(): - top_dir = "/sys/class/block" - devices = [] - for dev_name in os.listdir(top_dir): - if __is_blacklisted_blockdev(dev_name): - continue - full_path = os.path.join(top_dir, dev_name) - link_ref = os.readlink(full_path) - real_path = os.path.join(top_dir, link_ref) - sysfs_path = os.path.normpath(real_path) - devices.append(sysfs_path) - return devices - -def udev_get_block_device(sysfs_path): - if not os.path.exists(sysfs_path): - return None - - db_entry = sysfs_path[4:].replace("/", "\x2f") - db_root = "/dev/.udev/db" - db_path = os.path.normpath("%s/%s" % (db_root, db_entry)) - if not os.access(db_path, os.R_OK): - return None - - entry = open(db_path).read() - dev = udev_parse_block_entry(entry) - if dev: - # XXX why do we do this? is /sys going to move during installation? - dev['sysfs_path'] = sysfs_path[4:] # strip off the leading '/sys' - dev = udev_parse_uevent_file(dev) - - # now add in the contents of the uevent file since they're handy - return dev - -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_parse_block_entry(buf): - dev = {'name': None, - 'symlinks': []} - - for line in buf.splitlines(): - line.strip() - (tag, sep, val) = line.partition(":") - if not sep: - continue - - if tag == "N": - dev['name'] = val - elif tag == "S": - dev['symlinks'].append(val) - elif tag == "E": - if val.count("=") > 1 and val.count(" ") > 0: - # eg: LVM2_LV_NAME when querying the VG for its LVs - vars = val.split() - vals = [] - var_name = None - for (index, subval) in enumerate(vars): - (var_name, sep, var_val) = subval.partition("=") - if sep: - vals.append(var_val) - - dev[var_name] = vals - else: - (var_name, sep, var_val) = val.partition("=") - if not sep: - continue - - if var_val.count(" "): - # eg: DEVLINKS - var_val = var_val.split() - - dev[var_name] = var_val - - if dev.get("name"): - return dev - -# These are functions for retrieving specific pieces of information from -# udev database entries. -def udev_device_get_name(udev_info): - """ Return the best name for a device based on the udev db data. """ - return udev_info.get("DM_NAME", udev_info["name"]) - -def udev_device_get_format(udev_info): - """ Return a device's format type as reported by udev. """ - return udev_info.get("ID_FS_TYPE") - -def udev_device_get_uuid(udev_info): - """ Get the UUID from the device's format as reported by udev. """ - md_uuid = udev_info.get("MD_UUID") - uuid = udev_info.get("ID_FS_UUID") - # we don't want to return the array's uuid as a member's uuid - if uuid and not md_uuid == uuid: - return udev_info.get("ID_FS_UUID") - -def udev_device_get_label(udev_info): - """ Get the label from the device's format as reported by udev. """ - return udev_info.get("ID_FS_LABEL") - -def udev_device_is_dm(info): - """ Return True if the device is a device-mapper device. """ - return info.has_key("DM_NAME") - -def udev_device_is_md(info): - """ Return True is the device is an mdraid array device. """ - return info.has_key("MD_METADATA") - -def udev_device_is_cdrom(info): - """ Return True if the device is an optical drive. """ - # FIXME: how can we differentiate USB drives from CD-ROM drives? - # -- USB drives also generate a sdX device. - return info.get("ID_CDROM") == "1" - -def udev_device_is_disk(info): - """ Return True is the device is a disk. """ - has_range = os.path.exists("/sys/%s/range" % info['sysfs_path']) - return info.get("DEVTYPE") == "disk" or has_range - -def udev_device_is_partition(info): - has_start = os.path.exists("/sys/%s/start" % info['sysfs_path']) - return info.get("DEVTYPE") == "partition" or has_start - -def udev_device_get_sysfs_path(info): - return info['sysfs_path'] - -def udev_device_get_major(info): - return int(info["MAJOR"]) - -def udev_device_get_minor(info): - return int(info["MINOR"]) - -def udev_device_get_md_level(info): - return info["MD_LEVEL"] - -def udev_device_get_md_devices(info): - return int(info["MD_DEVICES"]) - -def udev_device_get_md_uuid(info): - return info["MD_UUID"] - -def udev_device_get_vg_name(info): - return info['LVM2_VG_NAME'] - -def udev_device_get_vg_uuid(info): - return info['LVM2_VG_UUID'] - -def udev_device_get_vg_size(info): - # lvm's decmial precision is not configurable, so we tell it to use - # KB and convert to MB here - return float(info['LVM2_VG_SIZE']) / 1024 - -def udev_device_get_vg_free(info): - # lvm's decmial precision is not configurable, so we tell it to use - # KB and convert to MB here - return float(info['LVM2_VG_FREE']) / 1024 - -def udev_device_get_vg_extent_size(info): - # lvm's decmial precision is not configurable, so we tell it to use - # KB and convert to MB here - return float(info['LVM2_VG_EXTENT_SIZE']) / 1024 - -def udev_device_get_vg_extent_count(info): - return int(info['LVM2_VG_EXTENT_COUNT']) - -def udev_device_get_vg_free_extents(info): - return int(info['LVM2_VG_FREE_COUNT']) - -def udev_device_get_vg_pv_count(info): - return int(info['LVM2_PV_COUNT']) - -def udev_device_get_pv_pe_start(info): - # lvm's decmial precision is not configurable, so we tell it to use - # KB and convert to MB here - return float(info['LVM2_PE_START']) / 1024 - -def udev_device_get_lv_names(info): - names = info['LVM2_LV_NAME'] - if not names: - names = [] - elif not isinstance(names, list): - names = [names] - return names - -def udev_device_get_lv_uuids(info): - uuids = info['LVM2_LV_UUID'] - if not uuids: - uuids = [] - elif not isinstance(uuids, list): - uuids = [uuids] - return uuids - -def udev_device_get_lv_sizes(info): - # lvm's decmial precision is not configurable, so we tell it to use - # KB and convert to MB here - sizes = info['LVM2_LV_SIZE'] - if not sizes: - sizes = [] - elif not isinstance(sizes, list): - sizes = [sizes] - - return [float(s) / 1024 for s in sizes] - -def udev_device_is_dmraid(info): - # Note that this function does *not* identify raid sets. - # Tests to see if device is parto of a dmraid set. - # dmraid and mdriad have the same ID_FS_USAGE string, ID_FS_TYPE has a - # string that describes the type of dmraid (isw_raid_member...), I don't - # want to maintain a list and mdraid's ID_FS_TYPE='linux_raid_member', so - # dmraid will be everything that is raid and not linux_raid_member - #from formats.dmraid import DMRaidMember - #if info.has_key("ID_FS_TYPE") and \ - # info["ID_FS_TYPE"] in DMRaidMember._udevTypes: - # return True - # - return False - -def udev_device_get_dmraid_partition_disk(info): - try: - p_index = info["DM_NAME"].rindex("p") - except (KeyError, AttributeError, ValueError): - return None - - if not info["DM_NAME"][p_index+1:].isdigit(): - return None - - return info["DM_NAME"][:p_index] - -def udev_device_is_dmraid_partition(info, devicetree): - #diskname = udev_device_get_dmraid_partition_disk(info) - #dmraid_devices = devicetree.getDevicesByType("dm-raid array") - # - #for device in dmraid_devices: - # if diskname == device.name: - # return True - # - return False - -if __name__ == "__main__": - for device in udev_get_block_devices(): - print udev_device_get_name(device) - print " Label :", udev_device_get_label(device) - print " UUID :", udev_device_get_uuid(device) - print " Format :", udev_device_get_format(device) - print " Is disk :", udev_device_is_disk(device) - print " Is cdrom:", udev_device_is_cdrom(device) - print " Is part :", udev_device_is_partition(device) - print " Is dm :", udev_device_is_dm(device) - print " Is md :", udev_device_is_md(device) - #syspath = "/sys" + udev_device_get_sysfs_path(device) - #for (key, value) in udev_get_block_device(syspath).items(): - # print " (%s : %s)" % (key, value,) - print diff --git a/pkgs/core/pomona/src/storage_test.py b/pkgs/core/pomona/src/storage_test.py deleted file mode 100755 index c6a0b23..0000000 --- a/pkgs/core/pomona/src/storage_test.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/python - -import sys - -import storage diff --git a/pkgs/core/pomona/src/text.py b/pkgs/core/pomona/src/text.py new file mode 100644 index 0000000..2719311 --- /dev/null +++ b/pkgs/core/pomona/src/text.py @@ -0,0 +1,131 @@ +#!/usr/bin/python + +import string + +from snack import * +from constants import * + +import gettext +_ = lambda x: gettext.ldgettext("pomona", x) + +class TextWindow: + def __init__(self, screen): + self.screen = screen + + def pop(self): + self.screen.popWindow() + self.screen.refresh() + + def refresh(self): + self.screen.refresh() + + +class WaitWindow(TextWindow): + def setText(self, text): + self.t.setText(text) + self.g.draw() + self.screen.refresh() + + def __init__(self, screen, title, text, width): + TextWindow.__init__(self, screen) + + if width is None: + width = 40 + if (len(text) < width): + width = len(text) + + self.t = TextboxReflowed(width, text) + + self.g = GridForm(self.screen, title, 1, 1) + self.g.add(self.t, 0, 0) + self.g.draw() + self.screen.refresh() + + +class OkCancelWindow: + def getrc(self): + return self.rc + + def __init__(self, screen, title, text): + rc = ButtonChoiceWindow(screen, title, text, buttons=[TEXT_OK_BUTTON, _("Cancel")]) + if rc == string.lower(_("Cancel")): + self.rc = 1 + else: + self.rc = 0 + + +class ExceptionWindow(TextWindow): + def __init__ (self, short, long=None, screen=None): + TextWindow.__init__(self, screen) + self.text = "%s\n\n" % short + self.buttons=[TEXT_OK_BUTTON] + + def run(self): + self.rc = ButtonChoiceWindow(self.screen, _("Exception Occurred"), + self.text, self.buttons, width=60) + + def getrc(self): + return 0 + + +class TextInterface: + def __init__(self, log): + self.log = log + self.screen = SnackScreen() + + self.setRootline(SCREEN_ROOTLINE) + self.setHelpline(SCREEN_HELPLINE) + + def __del__(self): + if self.screen: + self.screen.finish() + + def setRootline(self, msg): + self.screen.drawRootText (0, 0, string.center(msg, self.screen.width)) + self.log.debug("Set rootline text: %s" % msg) + + def setHelpline(self, msg): + self.screen.pushHelpLine(string.center(msg, self.screen.width)) + self.log.debug("Set helpline text: %s" % msg) + + + ### WINDOW DEFINITIONS ### + + def waitWindow(self, title, text, width=None): + return WaitWindow(self.screen, title, text, width) + + def exceptionWindow(self, short, long): + self.log.critical(short) + return ExceptionWindow(short, long, self.screen) + + def messageWindow(self, title, text, type="ok", default = None, + custom_icon=None, custom_buttons=[]): + if type == "ok": + ButtonChoiceWindow(self.screen, title, text, buttons=[TEXT_OK_BUTTON]) + + elif type == "yesno": + if default and default == "no": + btnlist = [TEXT_NO_BUTTON, TEXT_YES_BUTTON] + else: + btnlist = [TEXT_YES_BUTTON, TEXT_NO_BUTTON] + rc = ButtonChoiceWindow(self.screen, title, text, buttons=btnlist) + if rc == "yes": + return 1 + else: + return 0 + + elif type == "custom": + tmpbut = [] + for but in custom_buttons: + tmpbut.append(string.replace(but,"_","")) + rc = ButtonChoiceWindow(self.screen, title, text, width=60, buttons=tmpbut) + + idx = 0 + for b in tmpbut: + if string.lower(b) == rc: + return idx + idx = idx + 1 + return 0 + + else: + return OkCancelWindow(self.screen, title, text) diff --git a/pkgs/core/pomona/src/timezone.py b/pkgs/core/pomona/src/timezone.py deleted file mode 100644 index 1cfb6f8..0000000 --- a/pkgs/core/pomona/src/timezone.py +++ /dev/null @@ -1,51 +0,0 @@ -# -# timezone.py - timezone install data -# -# Copyright 2001 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -import shutil - -import logging -log = logging.getLogger("pomona") - -def bool(val): - if val: return "true" - return "false" - -class Timezone: - def write(self, instPath): - fromFile = instPath + "/usr/share/zoneinfo/" + self.tz - - try: - shutil.copyfile(fromFile, instPath + "/etc/localtime") - except OSError, (errno, msg): - log.error("Error copying timezone (from %s): %s" % (fromFile, msg)) - - f = open(instPath + "/etc/sysconfig/clock", "w") - - f.write('ZONE="%s"\n' % self.tz) - f.write("UTC=%s\n" % bool(self.utc)) - f.write("ARC=%s\n" % bool(self.arc)) - - f.close() - - def getTimezoneInfo(self): - return (self.tz, self.utc, self.arc) - - def setTimezoneInfo(self, timezone, asUtc = 0, asArc = 0): - self.tz = timezone - self.utc = asUtc - self.arc = asArc - - def __init__(self): - self.tz = "America/New_York" - self.utc = 0 - self.arc = 0 diff --git a/pkgs/core/pomona/src/tui.py b/pkgs/core/pomona/src/tui.py deleted file mode 100644 index b362a4d..0000000 --- a/pkgs/core/pomona/src/tui.py +++ /dev/null @@ -1,414 +0,0 @@ - -from snack import * -import sys, os -import isys -import parted -import signal -import time -import iutil -import imputil -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) -N_ = lambda x: x - -import logging -log = logging.getLogger("pomona") - -stepToClasses = { - "accounts" : ("tui_userauth", "RootPasswordWindow"), - "bootloader" : ("tui_bootloader", ("BootloaderChoiceWindow", - "BootloaderAppendWindow", - "BootloaderPasswordWindow")), - "bootloaderadvanced" : ("tui_bootloader", ("BootloaderImagesWindow", - "BootloaderLocationWindow")), - "complete" : ("tui_complete", "FinishedWindow"), - "confirminstall" : ("tui_confirm", "BeginInstallWindow"), - "install" : ("tui_progress", "setupForInstall"), - "keyboard" : ("tui_keyboard", "KeyboardWindow"), - "language" : ("tui_language", "LanguageWindow"), - "network" : ("tui_network", "HostnameWindow"), - "partition": ("tui_partition", "PartitionWindow"), - "parttype" : ("tui_partition", "PartitionTypeWindow"), - "timezone" : ("tui_timezone", "TimezoneWindow"), - "welcome" : ("tui_welcome", "WelcomeWindow"), -} - -class WaitWindow: - def pop(self): - self.screen.popWindow() - self.screen.refresh() - - def refresh(self): - self.screen.refresh() - - def set_text(self, text): - self.t.setText(text) - self.g.draw() - self.screen.refresh() - - def __init__(self, screen, title, text, width): - self.screen = screen - if width is None: - width = 40 - if (len(text) < width): - width = len(text) - - self.t = TextboxReflowed(width, text) - - self.g = GridForm(self.screen, title, 1, 1) - self.g.add(self.t, 0, 0) - self.g.draw() - self.screen.refresh() - -class ProgressWindow: - def pop(self): - self.screen.popWindow() - self.screen.refresh() - del self.scale - self.scale = None - - def set(self, amount): - self.scale.set(int(float(amount) * self.multiplier)) - self.screen.refresh() - - def refresh(self): - pass - - def __init__(self, screen, title, text, total, updpct = 0.05): - self.multiplier = 1 - if total == 1.0: - self.multiplier = 100 - self.screen = screen - width = 55 - if (len(text) > width): width = len(text) - - t = TextboxReflowed(width, text) - - g = GridForm(self.screen, title, 1, 2) - g.add(t, 0, 0, (0, 0, 0, 1), anchorLeft=1) - - self.scale = Scale(int(width), int(float(total) * self.multiplier)) - g.add(self.scale, 0, 1) - - g.draw() - self.screen.refresh() - -class OkCancelWindow: - def getrc(self): - return self.rc - - def __init__(self, screen, title, text): - rc = ButtonChoiceWindow(screen, title, text, buttons=[TEXT_OK_BUTTON, _("Cancel")]) - if rc == string.lower(_("Cancel")): - self.rc = 1 - else: - self.rc = 0 - -class ExceptionWindow: - def __init__ (self, shortTraceback, longTracebackFile=None, screen=None): - self.text = "%s\n\n" % shortTraceback - self.screen = screen - - self.buttons=[TEXT_OK_BUTTON] - - def run(self): - log.info ("in run, screen = %s" % self.screen) - self.rc = ButtonChoiceWindow(self.screen, _("Exception Occurred"), - self.text, self.buttons) - - def getrc(self): - return 0 - - def pop(self): - self.screen.popWindow() - self.screen.refresh() - -class InstallInterface: - def __init__(self): - signal.signal(signal.SIGINT, signal.SIG_IGN) - signal.signal(signal.SIGTSTP, signal.SIG_IGN) - log.info("Starting the TUI...") - self.screen = SnackScreen() - self.showingHelpOnHelp = 0 - - def __del__(self): - if self.screen: - self.screen.finish() - - def shutdown(self): - log.info("Shutting down the TUI...") - self.screen.finish() - self.screen = None - - def run(self, pomona): - self.console = pomona.id.console - - self.screen.helpCallback(self.helpWindow) - - if not self.isRealConsole(): - self.screen.suspendCallback(spawnShell, self.screen) - - # draw the frame after setting up the fallback - self.drawFrame() - - pomona.id.fsset.registerMessageWindow(self.messageWindow) - pomona.id.fsset.registerProgressWindow(self.progressWindow) - pomona.id.fsset.registerWaitWindow(self.waitWindow) - - parted.exception_set_handler(self.partedExceptionWindow) - - lastrc = INSTALL_OK - (step, instance) = pomona.dispatch.currentStep() - while step: - (file, classNames) = stepToClasses[step] - - if type(classNames) != type(()): - classNames = (classNames,) - - if lastrc == INSTALL_OK: - step = 0 - else: - step = len(classNames) - 1 - - while step >= 0 and step < len(classNames): - # reget the args. they could change (especially direction) - (foo, args) = pomona.dispatch.currentStep() - nextWindow = None - - while 1: - try: - found = imputil.imp.find_module(file) - loaded = imputil.imp.load_module(classNames[step], - found[0], found[1], - found[2]) - nextWindow = loaded.__dict__[classNames[step]] - break - except ImportError, e: - rc = ButtonChoiceWindow(self.screen, _("Error!"), - _("An error occurred when attempting " - "to load an pomona interface " - "component.\n\nclassName = %s\n\n" - "Error: %s") - % (classNames[step],e), - buttons=[_("Exit"), _("Retry")]) - - if rc == string.lower(_("Exit")): - sys.exit(0) - - win = nextWindow() - - #log.info("TUI running step %s (class %s, file %s)" % (step, classNames, file)) - - rc = win(self.screen, instance) - - if rc == INSTALL_NOOP: - rc = lastrc - - if rc == INSTALL_BACK: - step = step - 1 - pomona.dispatch.dir = DISPATCH_BACK - elif rc == INSTALL_OK: - step = step + 1 - pomona.dispatch.dir = DISPATCH_FORWARD - - lastrc = rc - - if step == -1: - if not pomona.dispatch.canGoBack(): - ButtonChoiceWindow(self.screen, _("Cancelled"), - _("I can't go to the previous step " - "from here. You will have to try " - "again."), - buttons=[_("OK")]) - pomona.dispatch.gotoPrev() - else: - pomona.dispatch.gotoNext() - - (step, args) = pomona.dispatch.currentStep() - - self.screen.finish() - - def drawFrame(self): - self.screen.drawRootText (0, 0, self.screen.width * " ") - self.screen.drawRootText (0, 0, _("Welcome to %s") % name) - - if (os.access("/usr/share/pomona/help/C/s1-help-screens-lang.txt", os.R_OK)): - self.screen.pushHelpLine(_(" <F1> for help | <Tab> between elements | <Space> selects | <F12> next screen")) - else: - self.screen.pushHelpLine(_(" <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen")) - - def setScreen(self, screen): - self.screen = screen - - def beep(self): - # no-op. could call newtBell() if it was bound - pass - - def isRealConsole(self): - """Returns True if this is a _real_ console that can do things, False - for non-real consoles such as serial, i/p virtual consoles or xen.""" - #if flags.serial or flags.virtpconsole: - # return False - if isys.isPsudoTTY(0): - return False - if isys.isVioConsole(): - return False - if os.path.exists("/proc/xen"): # this keys us that we're a xen guest - return False - return True - - def helpWindow(self, screen, key): - log.info("Pressed help key: %s" % key) - if key == "helponhelp": - if self.showingHelpOnHelp: - return None - else: - self.showingHelpOnHelp = 1 - try: - f = None - found = 0 - for path in ("./text-", "/usr/share/pomona/"): - if found: - break - for lang in self.console.getCurrentLangSearchList(): - fn = "%shelp/%s/s1-help-screens-%s.txt" % (path, lang, key,) - try: - f = open(fn) - except IOError, msg: - continue - found = 1 - break - - if not f: - ButtonChoiceWindow(screen, _("Help not available"), - _("No help is available for this " - "step of the install."), - buttons=[TEXT_OK_BUTTON]) - return None - - lines = f.readlines() - for l in lines: - l = l.replace("@IPFIRE@", name) - l = l.replace("@VERSION@", version) - while not string.strip(l[0]): - l = l[1:] - title = string.strip(l[0]) - l = l[1:] - while not string.strip(l[0]): - l = l[1:] - f.close() - - height = 10 - scroll = 1 - if len(l) < height: - height = len(l) - scroll = 0 - - width = len(title) + 6 - stream = "" - for line in l: - line = string.strip(line) - stream = stream + line + "\n" - if len(line) > width: - width = len(line) - - bb = ButtonBar(screen, [TEXT_OK_BUTTON]) - t = Textbox(width, height, stream, scroll=scroll) - - g = GridFormHelp(screen, title, "helponhelp", 1, 2) - g.add(t, 0, 0, padding=(0, 0, 0, 1)) - g.add(bb, 0, 1, growx=1) - - g.runOnce() - self.showingHelpOnHelp = 0 - except: - import traceback - (type, value, tb) = sys.exc_info() - from string import joinfields - list = traceback.format_exception(type, value, tb) - text = joinfields(list, "") - win = self.exceptionWindow(text, "XXX HAVE A LOOK AT THIS tui.py ~328") - win.run() - rc = win.getrc() - if rc == 0: - os._exit(1) - - def progressWindow(self, title, text, total, updpct = 0.05): - return ProgressWindow(self.screen, title, text, total, updpct) - - def waitWindow(self, title, text, width=None): - return WaitWindow(self.screen, title, text, width) - - def exceptionWindow(self, shortText, longTextFile): - log.critical(shortText) - exnWin = ExceptionWindow(shortText, longTextFile, self.screen) - return exnWin - - def messageWindow(self, title, text, type="ok", default = None, - custom_icon=None, custom_buttons=[]): - if type == "ok": - ButtonChoiceWindow(self.screen, title, text, - buttons=[TEXT_OK_BUTTON]) - elif type == "yesno": - if default and default == "no": - btnlist = [TEXT_NO_BUTTON, TEXT_YES_BUTTON] - else: - btnlist = [TEXT_YES_BUTTON, TEXT_NO_BUTTON] - rc = ButtonChoiceWindow(self.screen, title, text, buttons=btnlist) - if rc == "yes": - return 1 - else: - return 0 - elif type == "custom": - tmpbut = [] - for but in custom_buttons: - tmpbut.append(string.replace(but,"_","")) - rc = ButtonChoiceWindow(self.screen, title, text, width=60, buttons=tmpbut) - - idx = 0 - for b in tmpbut: - if string.lower(b) == rc: - return idx - idx = idx + 1 - return 0 - else: - return OkCancelWindow(self.screen, title, text) - - def partedExceptionWindow(self, exc): - # if our only option is to cancel, let us handle the exception - # in our code and avoid popping up the exception window here. - if exc.options == parted.EXCEPTION_CANCEL: - return parted.EXCEPTION_UNHANDLED - log.critical("parted exception: %s: %s" %(exc.type_string,exc.message)) - buttons = [] - buttonToAction = {} - flags = ((parted.EXCEPTION_FIX, N_("Fix")), - (parted.EXCEPTION_YES, N_("Yes")), - (parted.EXCEPTION_NO, N_("No")), - (parted.EXCEPTION_OK, N_("OK")), - (parted.EXCEPTION_RETRY, N_("Retry")), - (parted.EXCEPTION_IGNORE, N_("Ignore")), - (parted.EXCEPTION_CANCEL, N_("Cancel"))) - for flag, errorstring in flags: - if exc.options & flag: - buttons.append(_(errorstring)) - buttonToAction[string.lower(_(errorstring))] = flag - - rc = None - while not buttonToAction.has_key(rc): - rc = ButtonChoiceWindow(self.screen, exc.type_string, exc.message, - buttons=buttons) - - return buttonToAction[rc] - -def spawnShell(screen): - screen.suspend() - print "\n\nType <exit> to return to the install program.\n" - if os.path.exists("/bin/sh"): - iutil.execConsole() - else: - print "Unable to find /bin/sh to execute! Not starting shell" - time.sleep(5) - screen.resume() diff --git a/pkgs/core/pomona/src/tui_bootloader.py b/pkgs/core/pomona/src/tui_bootloader.py deleted file mode 100644 index e1c770e..0000000 --- a/pkgs/core/pomona/src/tui_bootloader.py +++ /dev/null @@ -1,453 +0,0 @@ -# -# bootloader_text.py: text mode bootloader setup -# -# Copyright 2001-2002 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -from snack import * -from constants import * -from flags import flags -import string -import iutil -import bootloader - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -class BootloaderChoiceWindow: - def __call__(self, screen, pomona): - # XXX need more text here - t = TextboxReflowed(53, _("Which boot loader would you like to use?")) - - if pomona.dispatch.stepInSkipList("instbootloader"): - useGrub = 0 - noBl = 1 - else: - useGrub = 1 - noBl = 0 - - blradio = RadioGroup() - grub = blradio.add(_("Use GRUB Boot Loader"), "grub", useGrub) - skipbl = blradio.add(_("No Boot Loader"), "nobl", noBl) - buttons = ButtonBar(screen, [TEXT_OK_BUTTON, TEXT_BACK_BUTTON]) - - grid = GridFormHelp(screen, _("Boot Loader Configuration"), - "btloadinstall", 1, 5) - grid.add(t, 0, 0, (0,0,0,1)) - grid.add(grub, 0, 1, (0,0,0,0)) - grid.add(skipbl, 0, 3, (0,0,0,1)) - grid.add(buttons, 0, 4, growx = 1) - - while 1: - result = grid.run() - - button = buttons.buttonPressed(result) - - if button == TEXT_BACK_CHECK: - screen.popWindow() - return INSTALL_BACK - - if blradio.getSelection() == "nobl": - rc = ButtonChoiceWindow(screen, _("Skip Boot Loader"), - _("You have elected not to install " - "any boot loader, which is not recommended " - "unless you have an advanced need. Booting " - "your system into Linux directly from the " - "hard drive almost always requires a boot " - "loader.\n\n" - "Are you sure you want to skip boot loader " - "installation?"), - [ (_("Yes"), "yes"), (_("No"), "no") ], width = 50) - if rc == "no": - continue - - pomona.dispatch.skipStep("instbootloader", skip = (rc == "yes")) - pomona.dispatch.skipStep("bootloaderadvanced", skip = (rc == "yes")) - - # kind of a hack... - pomona.id.bootloader.defaultDevice = None - else: - pomona.dispatch.skipStep("instbootloader", 0) - pomona.dispatch.skipStep("bootloaderadvanced", 0) - - screen.popWindow() - return INSTALL_OK - -class BootloaderAppendWindow: - def __call__(self, screen, pomona): - if pomona.dispatch.stepInSkipList("instbootloader"): - return INSTALL_NOOP - - t = TextboxReflowed(53, _("A few systems need to pass special options " - "to the kernel at boot time to function " - "properly. If you need to pass boot options to the " - "kernel, enter them now. If you don't need any or " - "aren't sure, leave this blank.")) - - entry = Entry(48, scroll = 1, returnExit = 1) - entry.set(pomona.id.bootloader.args.get()) - - cb = Checkbox(_("Force use of LBA32 (not normally required)")) - if pomona.id.bootloader.forceLBA32: - cb.setValue("*") - - buttons = ButtonBar(screen, [TEXT_OK_BUTTON, TEXT_BACK_BUTTON]) - - grid = GridFormHelp(screen, _("Boot Loader Configuration"), "kernelopts", 1, 5) - grid.add(t, 0, 0, padding = (0, 0, 0, 1)) - - grid.add(entry, 0, 2, padding = (0, 0, 0, 1)) - grid.add(cb, 0, 3, padding = (0,0,0,1)) - grid.add(buttons, 0, 4, growx = 1) - - while 1: - result = grid.run() - button = buttons.buttonPressed(result) - - if button == TEXT_BACK_CHECK: - screen.popWindow() - return INSTALL_BACK - - if cb.selected() and not pomona.id.bootloader.forceLBA32: - rc = pomona.intf.messageWindow(_("Warning"), - _("If LBA32 is not supported by your system's BIOS, " - "forcing its use can prevent your machine from " - "booting.\n\n" - "Would you like to continue and force LBA32 mode?"), - type = "yesno") - - if rc != 1: - continue - - pomona.id.bootloader.args.set(entry.value()) - pomona.id.bootloader.setForceLBA(cb.selected()) - - screen.popWindow() - return INSTALL_OK - -class BootloaderLocationWindow: - def __call__(self, screen, pomona): - if pomona.dispatch.stepInSkipList("instbootloader"): - return INSTALL_NOOP - - choices = pomona.id.fsset.bootloaderChoices(pomona.id.diskset, pomona.id.bootloader) - if len(choices.keys()) == 1: - pomona.id.bootloader.setDevice(choices[choices.keys()[0]][0]) - return INSTALL_NOOP - if len(choices.keys()) == 0: - return INSTALL_NOOP - - format = "/dev/%-11s %s" - locations = [] - devices = [] - default = 0 - - keys = choices.keys() - keys.reverse() - for key in keys: - (device, desc) = choices[key] - if device == pomona.id.bootloader.getDevice(): - default = len(locations) - locations.append (format % (device, _(desc))) - devices.append(device) - - (rc, sel) = ListboxChoiceWindow (screen, _("Boot Loader Configuration"), - _("Where do you want to install the boot loader?"), - locations, default = default, - buttons = [ TEXT_OK_BUTTON, TEXT_BACK_BUTTON ], - help = "bootloaderlocation") - - if rc == TEXT_BACK_CHECK: - return INSTALL_BACK - - pomona.id.bootloader.setDevice(devices[sel]) - return INSTALL_OK - -class BootloaderImagesWindow: - def validBootloaderLabel(self, label): - i=0 - while i < len(label): - cur = label[i] - if cur == '#' or cur == '$' or cur == '=': - return 0 - elif cur == ' ' and not self.bl.useGrub(): - return 0 - i = i + 1 - - return 1 - - - def editItem(self, screen, partition, itemLabel, allowNone=0): - devLabel = Label(_("Device") + ":") - bootLabel = Label(_("Boot label") + ":") - device = Label("/dev/" + partition) - newLabel = Entry (20, scroll = 1, returnExit = 1, text = itemLabel) - - buttons = ButtonBar(screen, [TEXT_OK_BUTTON, (_("Clear"), "clear"), - (_("Cancel"), "cancel")]) - - subgrid = Grid(2, 2) - subgrid.setField(devLabel, 0, 0, anchorLeft = 1) - subgrid.setField(device, 1, 0, padding = (1, 0, 0, 0), anchorLeft = 1) - subgrid.setField(bootLabel, 0, 1, anchorLeft = 1) - subgrid.setField(newLabel, 1, 1, padding = (1, 0, 0, 0), anchorLeft = 1) - g = GridFormHelp(screen, _("Edit Boot Label"), "bootlabel", 1, 2) - g.add(subgrid, 0, 0, padding = (0, 0, 0, 1)) - g.add(buttons, 0, 1, growx = 1) - - result = "" - while (result != TEXT_OK_CHECK and result != TEXT_F12_CHECK and result != newLabel): - result = g.run() - - if (buttons.buttonPressed(result)): - result = buttons.buttonPressed(result) - - if (result == "cancel"): - screen.popWindow () - return itemLabel - elif (result == "clear"): - newLabel.set("") - elif (result == TEXT_OK_CHECK or result == TEXT_F12_CHECK or result == newLabel): - if not allowNone and not newLabel.value(): - ButtonChoiceWindow(screen, _("Invalid Boot Label"), - _("Boot label may not be empty."), - [ TEXT_OK_BUTTON ]) - result = "" - elif not self.validBootloaderLabel(newLabel.value()): - ButtonChoiceWindow(screen, _("Invalid Boot Label"), - _("Boot label contains " - "illegal characters."), - [ TEXT_OK_BUTTON ]) - result = "" - - screen.popWindow() - - return newLabel.value() - - def formatDevice(self, label, device, default): - if default == device: - default = '*' - else: - default = "" - - if not label: - label = "" - - return " %-4s %-25s %-25s" % ( default, label, "/dev/" + device) - - def __call__(self, screen, pomona): - if pomona.dispatch.stepInSkipList("instbootloader"): - return INSTALL_NOOP - - self.bl = pomona.id.bootloader - - images = self.bl.images.getImages() - default = self.bl.images.getDefault() - - listboxLabel = Label("%-7s %-25s %-12s" % - (_("Default"), _("Boot label"), _("Device"))) - listbox = Listbox(5, scroll = 1, returnExit = 1) - - sortedKeys = images.keys() - sortedKeys.sort() - - for dev in sortedKeys: - (label, longlabel, isRoot) = images[dev] - if not self.bl.useGrub(): - listbox.append(self.formatDevice(label, dev, default), dev) - else: - listbox.append(self.formatDevice(longlabel, dev, default), dev) - - listbox.setCurrent(dev) - - buttons = ButtonBar(screen, [ TEXT_OK_BUTTON, (_("Edit"), "edit"), - TEXT_BACK_BUTTON ]) - - text = TextboxReflowed(55, _("The boot manager %s uses can boot other " - "operating systems as well. Please tell me " - "what partitions you would like to be able to boot " - "and what label you want to use for each of them.") % (name,)) - - g = GridFormHelp(screen, _("Boot Loader Configuration"), - "bootloaderlabels", 1, 4) - g.add(text, 0, 0, anchorLeft = 1) - g.add(listboxLabel, 0, 1, padding = (0, 1, 0, 0), anchorLeft = 1) - g.add(listbox, 0, 2, padding = (0, 0, 0, 1), anchorLeft = 1) - g.add(buttons, 0, 3, growx = 1) - g.addHotKey("F2") - g.addHotKey("F4") - screen.pushHelpLine(_(" <Space> select | <F2> select default | <F4> delete | <F12> next screen>")) - - rootdev = pomona.id.fsset.getEntryByMountPoint("/").device.getDevice() - - result = None - while (result != TEXT_OK_CHECK and result != TEXT_BACK_CHECK and result != TEXT_F12_CHECK): - result = g.run() - if (buttons.buttonPressed(result)): - result = buttons.buttonPressed(result) - - if (result == "edit" or result == listbox): - item = listbox.current() - (label, longlabel, type) = images[item] - if self.bl.useGrub(): - label = longlabel - if label == None: - label = "" - - label = self.editItem(screen, item, label, allowNone = (rootdev != item and item != default)) - images[item] = (label, label, type) - if (default == item and not label): - default = "" - listbox.replace(self.formatDevice(label, item, default), item) - listbox.setCurrent(item) - elif result == "F2": - item = listbox.current() - (label, longlabel, isRoot) = images[item] - if self.bl.useGrub(): - label = longlabel - - if (label): - if (default): - (oldLabel, oldLong, oldIsRoot) = images[default] - if self.bl.useGrub(): - oldLabel = oldLong - listbox.replace(self.formatDevice(oldLabel, default, ""), default) - default = item - listbox.replace(self.formatDevice(label, item, default), item) - listbox.setCurrent(item) - elif result == "F4": - item = listbox.current() - - (label, longlabel, isRoot) = images[item] - if rootdev != item: - del images[item] - listbox.delete(item) - if default == item: - default = "" - else: - pomona.intf.messageWindow(_("Cannot Delete"), - _("This boot target cannot be " - "deleted because it is for " - "the %s system you are about " - "to install.") %(name,)) - - screen.popHelpLine() - screen.popWindow() - - if (result == TEXT_BACK_CHECK): - return INSTALL_BACK - - if not default: - default = rootdev - - # copy our version over - self.bl.images.images = {} - for (dev, (label, longlabel, isRoot)) in images.items(): - self.bl.images.images[dev] = (label, longlabel, isRoot) - self.bl.images.setDefault(default) - - return INSTALL_OK - -class BootloaderPasswordWindow: - def usepasscb(self, *args): - flag = FLAGS_RESET - if not self.checkbox.selected(): - flag = FLAGS_SET - self.entry1.setFlags(FLAG_DISABLED, flag) - self.entry2.setFlags(FLAG_DISABLED, flag) - - def __call__(self, screen, pomona): - if pomona.dispatch.stepInSkipList("instbootloader"): - return INSTALL_NOOP - - intf = pomona.intf - self.bl = pomona.id.bootloader - - if not self.bl.useGrub(): - return INSTALL_NOOP - - buttons = ButtonBar(screen, [TEXT_OK_BUTTON, TEXT_BACK_BUTTON]) - - text = TextboxReflowed(55, _("A boot loader password prevents users from passing arbitrary " - "options to the kernel. For highest security, you " - "should set a password, but a password is not " - "necessary for more casual users.")) - - g = GridFormHelp(screen, _("Boot Loader Configuration"), "grubpasswd", 1, 6) - g.add(text, 0, 0, (0,0,0,1), anchorLeft = 1) - - self.checkbox = Checkbox(_("Use a GRUB Password")) - g.add(self.checkbox, 0, 1, (0,0,0,1)) - - if self.bl.password: - self.checkbox.setValue("*") - - pw = self.bl.pure - if not pw: - pw = "" - - self.entry1 = Entry (24, password = 1, text = pw) - self.entry2 = Entry (24, password = 1, text = pw) - passgrid = Grid (2, 2) - passgrid.setField (Label (_("Boot Loader Password:")), 0, 0, (0, 0, 1, 0), anchorLeft = 1) - passgrid.setField (Label (_("Confirm:")), 0, 1, (0, 0, 1, 0), anchorLeft = 1) - passgrid.setField (self.entry1, 1, 0) - passgrid.setField (self.entry2, 1, 1) - g.add (passgrid, 0, 2, (0, 0, 0, 1)) - - self.checkbox.setCallback(self.usepasscb, None) - self.usepasscb() - - g.add(buttons, 0, 3, growx=1) - - while 1: - result = g.run() - - if (buttons.buttonPressed(result)): - result = buttons.buttonPressed(result) - - if result == TEXT_BACK_CHECK: - screen.popWindow() - return INSTALL_BACK - - if not self.checkbox.selected(): - self.bl.setPassword(None) - screen.popWindow() - return INSTALL_OK - - pw = self.entry1.value() - confirm = self.entry2.value() - - if pw != confirm: - pomona.intf.messageWindow(_("Passwords Do Not Match"), - _("Passwords do not match")) - continue - - if len(pw) < 1: - pomona.intf.messageWindow(_("Password Too Short"), - _("Boot loader password is too short")) - continue - - if len(pw) < 6: - rc = pomona.intf.messageWindow(_("Warning"), - _("Your boot loader password is shorter than " - "six characters. We recommend a longer " - "boot loader password." - "\n\n" - "Would you like to continue with this " - "password?"), - type = "yesno") - if rc == 0: - continue - - self.bl.setPassword(pw, isCrypted = 0) - - screen.popWindow() - return INSTALL_OK diff --git a/pkgs/core/pomona/src/tui_complete.py b/pkgs/core/pomona/src/tui_complete.py deleted file mode 100644 index 7b10079..0000000 --- a/pkgs/core/pomona/src/tui_complete.py +++ /dev/null @@ -1,42 +0,0 @@ -# -# complete_text.py: text mode congratulations windows -# -# Copyright 2001-2006 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -from snack import * -from constants import * -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -class FinishedWindow: - def __call__ (self, screen, pomona): - bootstr = "" - - floppystr = _("Press <Enter> to end the installation process.\n\n") - bottomstr = _("<Enter> to exit") - - screen.pushHelpLine(string.center(bottomstr, screen.width)) - - txt = _("Congratulations, your %s installation is " - "complete.\n\n" - "%s%s") %(name, floppystr, bootstr) - foo = _("For information on errata (updates and bug fixes), visit " - "%s.\n\n" - "Information on using your " - "system is available in the %s wiki at " - "%s.") %(bugurl, name, wikiurl,) - - rc = ButtonChoiceWindow(screen, _("Complete"), txt, - [ _("Reboot") ], help = "finished", width=60) - - return INSTALL_OK diff --git a/pkgs/core/pomona/src/tui_confirm.py b/pkgs/core/pomona/src/tui_confirm.py deleted file mode 100644 index dc27beb..0000000 --- a/pkgs/core/pomona/src/tui_confirm.py +++ /dev/null @@ -1,45 +0,0 @@ -# -# confirm_text.py: text mode install/upgrade confirmation window -# -# Copyright 2001-2003 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -import sys - -from snack import * -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -class BeginInstallWindow: - def __call__ (self, screen, pomona): - rc = ButtonChoiceWindow(screen, _("Installation to begin"), - _("Now, we got all information we need for " - "installation. If there is something you " - "want change you can still go back. " - "If not choose OK to start."), - buttons = [ _("OK"), _("Back") ], - help = "begininstall") - if rc == string.lower(_("Back")): - return INSTALL_BACK - - if rc == 0: - rc2 = pomona.intf.messageWindow(_("Reboot?"), - _("The system will be rebooted now."), - type="custom", custom_icon="warning", - custom_buttons=[_("_Back"), _("_Reboot")]) - if rc2 == 1: - sys.exit(0) - else: - return INSTALL_BACK - elif rc == 1: # they asked to go back - return INSTALL_BACK - - return INSTALL_OK diff --git a/pkgs/core/pomona/src/tui_keyboard.py b/pkgs/core/pomona/src/tui_keyboard.py deleted file mode 100644 index 0306c84..0000000 --- a/pkgs/core/pomona/src/tui_keyboard.py +++ /dev/null @@ -1,47 +0,0 @@ -# -# keyboard_text: text mode keyboard setup dialogs -# -# Copyright 2001-2002 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -import iutil -from snack import * -from constants import * -from flags import flags - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -import logging -log = logging.getLogger("pomona") - -class KeyboardWindow: - def __call__(self, screen, pomona): - if flags.virtpconsole: - return INSTALL_NOOP - - keyboards = pomona.id.console.modelDict.keys() - keyboards.sort() - - default = pomona.id.console.getDefaultKeymap() - - (button, choice) = \ - ListboxChoiceWindow(screen, _("Keyboard Selection"), - _("Which model keyboard is attached to this computer?"), keyboards, - buttons = [TEXT_OK_BUTTON, TEXT_BACK_BUTTON], width = 30, scroll = 1, height = 8, - default = default, help = "kybd") - - if button == TEXT_BACK_CHECK: - return INSTALL_BACK - - pomona.id.console.setKeymap(keyboards[choice]) - pomona.id.console.activate() - - return INSTALL_OK diff --git a/pkgs/core/pomona/src/tui_language.py b/pkgs/core/pomona/src/tui_language.py deleted file mode 100644 index 3b6880f..0000000 --- a/pkgs/core/pomona/src/tui_language.py +++ /dev/null @@ -1,53 +0,0 @@ -# -# language_text.py: text mode language selection dialog -# -# Copyright 2001-2007 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -from snack import * -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -import logging -log = logging.getLogger("pomona") - -class LanguageWindow: - def __call__(self, screen, pomona): - id = pomona.id - languages = id.console.availableLangs() - languages.sort() - - current = id.console.lang - - height = min((8, len(languages))) - buttons = [TEXT_OK_BUTTON, TEXT_BACK_BUTTON] - - translated = [] - for lang in languages: - translated.append((_(lang), id.console.getNickByName(lang))) - - (button, choice) = \ - ListboxChoiceWindow(screen, _("Language Selection"), - _("What language would you like to use during the " - "installation process?"), translated, - buttons, width = 30, default = _(current), scroll = 1, - height = height, help = "lang") - - if button == TEXT_BACK_CHECK: - return INSTALL_BACK - - id.console.setLanguage(choice) - id.timezone.setTimezoneInfo(id.console.getDefaultTimeZone()) - - pomona.intf.drawFrame() - - return INSTALL_OK diff --git a/pkgs/core/pomona/src/tui_network.py b/pkgs/core/pomona/src/tui_network.py deleted file mode 100644 index f543e94..0000000 --- a/pkgs/core/pomona/src/tui_network.py +++ /dev/null @@ -1,81 +0,0 @@ -# -# network_text.py: text mode network configuration dialogs -# -# Copyright (C) 2000, 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): Jeremy Katz katzj@redhat.com -# Michael Fulbright msf@redhat.com -# David Cantrell dcantrell@redhat.com -# - -import string -import network -import socket -from snack import * -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -import logging -log = logging.getLogger("pomona") - -class HostnameWindow: - def __call__(self, screen, pomona): - toplevel = GridFormHelp(screen, _("Hostname"), "hostname", 1, 3) - - text = TextboxReflowed(55, - _("Please name this computer. The hostname " - "identifies the computer on a network.")) - toplevel.add(text, 0, 0, (0, 0, 0, 1)) - - hostEntry = Entry(55) - hostEntry.set(pomona.id.network.settings.get("HOSTNAME")) - toplevel.add(hostEntry, 0, 1, padding = (0, 0, 0, 1)) - - bb = ButtonBar(screen, (TEXT_OK_BUTTON, TEXT_BACK_BUTTON)) - toplevel.add(bb, 0, 2, growx = 1) - - while 1: - result = toplevel.run() - rc = bb.buttonPressed(result) - - if rc == TEXT_BACK_CHECK: - screen.popWindow() - return INSTALL_BACK - - hname = string.strip(hostEntry.value()) - if len(hname) == 0: - ButtonChoiceWindow(screen, _("Invalid Hostname"), - _("You have not specified a hostname."), - buttons = [ _("OK") ]) - continue - - neterrors = network.sanityCheckHostname(hname) - if neterrors is not None: - ButtonChoiceWindow(screen, _("Invalid Hostname"), - _("The hostname "%s" is not valid " - "for the following reason:\n\n%s") - %(hname, neterrors), - buttons = [ _("OK") ]) - continue - - pomona.id.network.hostname = hname - break - - screen.popWindow() - return INSTALL_OK diff --git a/pkgs/core/pomona/src/tui_partition.py b/pkgs/core/pomona/src/tui_partition.py deleted file mode 100644 index 606043f..0000000 --- a/pkgs/core/pomona/src/tui_partition.py +++ /dev/null @@ -1,1610 +0,0 @@ -# -# partition_text.py: allows the user to choose how to partition their disks -# in text mode -# -# Copyright (C) 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): Jeremy Katz katzj@redhat.com -# - -import os, sys -import isys -import string -import copy -import parted -import partitions -from partedUtils import * -from partIntfHelpers import * -from partRequests import * -from fsset import * -from raid import availRaidLevels -from autopart import * -from snack import * -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -import logging -log = logging.getLogger("pomona") - -# sanity checking for various numeric input boxes -def invalidInteger(str): - ints = string.digits - if str == "": - return _("Must specify a value") - for n in str: - if n not in ints: - return _("Requested value is not an integer") - if len(str) > 9: - return _("Requested value is too large") - - return None - -class PartitionWindow: - def _findFirstUnused(self, dict): - keys = dict.keys() - i = 0 - - while True: - if i in keys: - i += 1 - else: - return i - - def populate(self): - # XXX we really should separate this stuff out into interface - # independent bits... - self.lb.clear() - - # first do LVM - lvmrequests = self.partitions.getLVMRequests() - if lvmrequests: - for vgname in lvmrequests.keys(): - vgrequest = self.partitions.getRequestByVolumeGroupName(vgname) - size = vgrequest.getActualSize(self.partitions, self.diskset) - device = "VG %s" % (vgname,) - self.lb.append(["%s" % (device,), - "", "", "%dM" %(size), - "VolGroup", ""], str(vgrequest.uniqueID), - [LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT]) - - for lvrequest in lvmrequests[vgname]: - lvdevice = "LV %s" % (lvrequest.logicalVolumeName,) - if lvrequest.fstype and lvrequest.mountpoint: - mntpt = lvrequest.mountpoint - else: - mntpt = "" - lvsize = lvrequest.getActualSize(self.partitions, self.diskset) - ptype = lvrequest.fstype.getName() - self.lb.append(["%s" %(lvdevice), - "", "", "%dM" %(lvsize), - "%s" %(ptype), "%s" %(mntpt)], str(lvrequest.uniqueID), - [LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT]) - - - # next, add the raid partitions - self.raidminors = {} - raidrequests = self.partitions.getRaidRequests() - if raidrequests: - for request in raidrequests: - if request and request.mountpoint: - mount = request.mountpoint - else: - mount = "" - - if request.fstype: - ptype = request.fstype.getName() - else: - ptype = _("None") - - try: - self.raidminors[request.raidminor] = True - device = "/dev/md%d" % (request.raidminor,) - except: - minor = self._findFirstUnused(self.raidminors) - self.raidminors[minor] = True - device = _("RAID Device %s" %(str(minor))) - - size = request.size - self.lb.append(["%s" %(device), - "", "", "%dM" %(size), - "%s" %(ptype), "%s" %(mount)], str(request.uniqueID), - [LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT]) - - # next, add the drives and partitions to the list - drives = self.diskset.disks.keys() - drives.sort() - for drive in drives: - disk = self.diskset.disks[drive] - sectorsPerCyl = disk.dev.heads * disk.dev.sectors - - self.lb.append([devify(drive),"","","","",""], None) - - extendedParent = None - part = disk.next_partition() - while part: - if part.type & parted.PARTITION_METADATA: -# print("partition %s has type %d" %(get_partition_name(part), part.type)) - part = disk.next_partition(part) - continue - # ignore the tiny < 1 MB partitions (#119479) - if getPartSizeMB(part) <= 1.0: - if not part.is_active() or not part.get_flag(parted.PARTITION_BOOT): - part = disk.next_partition(part) - continue - - device = get_partition_name(part) - request = self.partitions.getRequestByDeviceName(device) - if request and request.mountpoint: - mount = request.mountpoint - else: - mount = "" - - if part.type & parted.PARTITION_FREESPACE: - ptype = _("Free space") - elif part.type & parted.PARTITION_EXTENDED: - ptype = _("Extended") - elif part.get_flag(parted.PARTITION_RAID) == 1: - ptype = _("software RAID") - elif part.fs_type: - if request and request.fstype != None: - ptype = request.fstype.getName() - if ptype == "foreign": - ptype = map_foreign_to_fsname(part.native_type) - else: - ptype = part.fs_type.name - else: - if request and request.fstype != None: - ptype = request.fstype.getName() - if ptype == "foreign": - ptype = map_foreign_to_fsname(part.native_type) - else: - ptype = _("None") - - start = (part.geom.start / sectorsPerCyl) + 1 - end = (part.geom.end / sectorsPerCyl) + 1 - size = (part.geom.length * disk.dev.sector_size / (1024.0 * 1024.0)) - - if part.type & parted.PARTITION_EXTENDED: - if extendedParent: - raise RuntimeError, ("can't handle more than" - "one extended partition per disk") - extendedParent = part.num - indent = 2 * " " - elif part.type & parted.PARTITION_LOGICAL: - if not extendedParent: - raise RuntimeError("crossed logical partition " - "before extended") - indent = 4 * " " - else: - indent = 2 * " " - - if part.type & parted.PARTITION_FREESPACE: - self.lb.append(["%s%s" %(indent, _("Free space")), - "%d" %(start), - "%d" %(end), - "%dM" %(size), - "%s" %(ptype), - ""], part, - [LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT]) - - else: - dev = devify(get_partition_name(part)) - # save some space per #90838 - if dev.startswith("/dev/iseries/"): - dev = dev[13:] - elif dev.startswith("/dev/"): - dev = dev[5:] - self.lb.append(["%s%s" %(indent, dev), - "%d" %(start), - "%d" %(end), - "%dM" %(size), - "%s" %(ptype), - "%s" %(mount)], part, - [LEFT, RIGHT, RIGHT, RIGHT, LEFT, LEFT]) - part = disk.next_partition(part) - - def refresh(self): - # XXX need some way to stay at the same place in the list after - # repopulating - - # XXXX - Backup some info which doPartitioning munges if it fails - origInfoDict = {} - for request in self.partitions.requests: - try: - origInfoDict[request.uniqueID] = (request.requestSize, request.currentDrive) - except: - pass - - try: - doPartitioning(self.diskset, self.partitions) - rc = 0 - except PartitioningError, msg: - try: - for request in self.partitions.requests: - if request.uniqueID in origInfoDict.keys(): - (request.requestSize, request.currentDrive) = origInfoDict[request.uniqueID] - except: - log.error("Failed to restore original info") - - self.intf.messageWindow(_("Error Partitioning"), - _("Could not allocate requested partitions: %s.") % (msg)) - rc = -1 - except PartitioningWarning, msg: - rc = ButtonChoiceWindow(self.screen, _("Warning"), _("Warning: %s") %(msg), - buttons = [ (_("Modify Partition"), "modify"), (_("Add anyway"), "add") ]) - - if rc == "modify": - rc = -1 - else: - rc = 0 - reqs = self.partitions.getBootableRequest() - if reqs: - for req in reqs: - req.ignoreBootConstraints = 1 - - self.populate() - return rc - - - def fstypeSet(self, obj): - (current, entry) = obj - flag = FLAGS_RESET - if not current.isMountable(): - if entry.value() != _("<Not Applicable>"): - self.oldMount = entry.value() - entry.set(_("<Not Applicable>")) - flag = FLAGS_SET - elif entry.value() == _("<Not Applicable>"): - if self.oldMount: - entry.set(self.oldMount) - else: - entry.set("") - - entry.setFlags(FLAG_DISABLED, flag) - - def fstypeSetCB(self, obj): - (listbox, entry) = obj - self.fstypeSet((listbox.current(), entry)) - - # make the entry for the mount point and its label - def makeMountEntry(self, request): - mountgrid = Grid(2, 1) - mountLbl = Label(_("Mount Point:")) - mountgrid.setField(mountLbl, 0, 0, (0,0,0,0), anchorLeft = 1) - mountpoint = request.mountpoint - if mountpoint: - mount = Entry(20, mountpoint) - else: - mount = Entry(20, "") - mountgrid.setField(mount, 1, 0, anchorRight = 1, growx = 1) - if request.fstype and not request.fstype.isMountable(): - mount.setFlags(FLAG_DISABLED, FLAGS_SET) - mount.set(_("<Not Applicable>")) - return (mount, mountgrid) - - # make the entry for the lv name and it's label - def makeLVNameEntry(self, request): - lvnamegrid = Grid(2, 1) - lvnameLbl = Label(_("Logical Volume Name:")) - lvnamegrid.setField(lvnameLbl, 0, 0, (0,0,0,0), anchorLeft = 1) - lvn = request.logicalVolumeName - if lvn: - lvname = Entry(20, lvn) - else: - lvname = Entry(20, "") - lvnamegrid.setField(lvname, 1, 0, anchorRight = 1, growx = 1) - if request.preexist: - lvname.setFlags(FLAG_DISABLED, FLAGS_SET) - return (lvname, lvnamegrid) - - # make the size entry for a logical volume - def makeLVSize(self, request): - grid = Grid(3, 1) - lbl = Label(_("Size (MB):")) - grid.setField(lbl, 0, 0, (0,0,0,0), anchorLeft = 1) - if request.size: - size = Entry(8, "%d" %(request.size,)) - else: - size = Entry(8, "") - grid.setField(size, 1, 0, anchorRight = 1, growx = 1) -# maxLbl = Label(_("(Max is %s MB") %(maxlv,)) -# grid.setField(maxLbl, 2, 0, anchorRight = 1) - if request.preexist: - size.setFlags(FLAG_DISABLED, FLAGS_SET) - return (size, grid) - - - # make the list of available filesystems and its label - def makeFsList(self, request, usecallback=1, uselabel=1, usetypes=None, - ignorefs = None): - subgrid = Grid(1, 2) - row = 0 - # filesystem type selection - if uselabel: - typeLbl = Label(_("File System type:")) - subgrid.setField(typeLbl, 0, row) - row = row + 1 - - fstype = Listbox(height=2, scroll=1) - types = fileSystemTypeGetTypes() - if usetypes: - names = usetypes - else: - names = types.keys() - names.sort() - for name in names: - if not fileSystemTypeGet(name).isSupported(): - continue - - if ignorefs and name in ignorefs: - continue - - if fileSystemTypeGet(name).isFormattable(): - fstype.append(name, types[name]) - if request.fstype and request.fstype.getName() in names and \ - request.fstype.isFormattable() and request.fstype.isSupported(): - fstype.setCurrent(request.fstype) - else: - fstype.setCurrent(fileSystemTypeGetDefault()) - subgrid.setField(fstype, 0, row) - if usecallback: - fstype.setCallback(self.fstypeSetCB, (fstype, self.mount)) - return (fstype, subgrid) - - - # make the list of drives - def makeDriveList(self, request): - subgrid = Grid(1, 2) - driveLbl = Label(_("Allowable Drives:")) - subgrid.setField(driveLbl, 0, 0) - disks = self.diskset.disks.keys() - disks.sort() - drivelist = CheckboxTree(height=2, scroll=1) - if not request.drive: - for disk in disks: - drivelist.append(disk, selected = 1) - else: - for disk in disks: - if disk in request.drive: - selected = 1 - else: - selected = 0 - drivelist.append(disk, selected = selected) - subgrid.setField(drivelist, 0, 1) - return (drivelist, subgrid) - - - def makeSizeEntry(self, request): - # requested size - sizegrid = Grid(2, 1) - sizeLbl = Label(_("Size (MB):")) - sizegrid.setField(sizeLbl, 0, 0, (0,0,2,0)) - if request.size: - origsize = "%s" %(int(request.size)) - else: - origsize = "1" - size = Entry(7, origsize) - sizegrid.setField(size, 1, 0, growx = 1, anchorLeft = 1) - return (size, sizegrid) - - - def sizeOptionsChange(self, (sizeopts, limitentry)): - flag = FLAGS_RESET - if sizeopts.getSelection() != "limit": - flag = FLAGS_SET - limitentry.setFlags(FLAG_DISABLED, flag) - - - def makeSizeOptions(self, request): - # size options - optiongrid = Grid(2, 3) - sizeopts = RadioGroup() - limitdef = 0 - maxdef = 0 - fixeddef = 0 - limitentrydef = "1" - if request.grow: - if request.maxSizeMB != None: - limitdef = 1 - limitentrydef = "%s" %(int(request.maxSizeMB)) - else: - maxdef = 1 - else: - fixeddef = 1 - fixed = sizeopts.add(_("Fixed Size:"), "fixed", fixeddef) - optiongrid.setField(fixed, 0, 0, anchorRight = 1) - limit = sizeopts.add(_("Fill maximum size of (MB):"), "limit", limitdef) - optiongrid.setField(limit, 0, 1, anchorRight = 1) - limitentry = Entry(5, limitentrydef) - optiongrid.setField(limitentry, 1, 1, (1,0,0,0), anchorRight = 1) - max = sizeopts.add(_("Fill all available space:"), "max", maxdef) - optiongrid.setField(max, 0, 2, anchorRight = 1) - fixed.setCallback(self.sizeOptionsChange, (sizeopts, limitentry)) - limit.setCallback(self.sizeOptionsChange, (sizeopts, limitentry)) - max.setCallback(self.sizeOptionsChange, (sizeopts, limitentry)) - self.sizeOptionsChange((sizeopts, limitentry)) - return (sizeopts, limitentry, optiongrid) - - - # the selected cylinder boundary type changed - def cylOptionsChange(self, (cylopts, end, size)): - if cylopts.getSelection() == "end": - end.setFlags(FLAG_DISABLED, FLAGS_RESET) - size.setFlags(FLAG_DISABLED, FLAGS_SET) - elif cylopts.getSelection() == "size": - end.setFlags(FLAG_DISABLED, FLAGS_SET) - size.setFlags(FLAG_DISABLED, FLAGS_RESET) - - - # make the list of cylinder stuff - def makeCylEntries(self, request): - subgrid = Grid(2, 4) - - startLbl = Label(_("Start Cylinder:")) - subgrid.setField(startLbl, 0, 0, (0,0,2,0), anchorRight=1) - start = "%s" %(int(request.start)) - start = Entry(7, start) - subgrid.setField(start, 1, 0, anchorLeft=1) - - cylopts = RadioGroup() - enddef = 1 - sizedef = 0 - if not request.end: - enddef = 0 - sizedef = 1 - - endrb = cylopts.add(_("End Cylinder:"), "end", enddef) - subgrid.setField(endrb, 0, 1, (0,0,2,0), anchorRight=1) - end = Entry(7) - if request.end: - end.set("%s" %(int(request.end))) - subgrid.setField(end, 1, 1, anchorLeft=1) - - sizerb = cylopts.add(_("Size (MB):"), "size", sizedef) - subgrid.setField(sizerb, 0, 2, (0,0,2,0), anchorRight=1) - size = Entry(7) - if request.size: - size.set("%s" %(int(request.size))) - subgrid.setField(size, 1, 2, anchorLeft=1) - - endrb.setCallback(self.cylOptionsChange, (cylopts, end, size)) - sizerb.setCallback(self.cylOptionsChange, (cylopts, end, size)) - self.cylOptionsChange((cylopts, end, size)) - - return (cylopts, start, end, size, subgrid) - - # make the list of VGs - def makeVGList(self, request): - subgrid = Grid(1, 2) - vgLbl = Label(_("Volume Group:")) - subgrid.setField(vgLbl, 0, 0) - vgs = self.partitions.getLVMVGRequests() - if len(vgs) > 3: - scroll = 1 - else: - scroll = 0 - vgBox = Listbox(height=3, scroll=scroll) - current = None - for vg in vgs: - vgBox.append(vg.volumeGroupName, vg) - if vg.uniqueID == request.volumeGroup: - current = vg - if request.volumeGroup is not None: - vgBox.setCurrent(current) - - subgrid.setField(vgBox, 0, 1) - return (vgBox, subgrid) - - # make the list of RAID levels - def makeRaidList(self, request): - subgrid = Grid(1, 2) - raidLbl = Label(_("RAID Level:")) - subgrid.setField(raidLbl, 0, 0) - if len(availRaidLevels) > 3: - scroll = 1 - else: - scroll = 0 - raidBox = Listbox(height=3, scroll=scroll) - for level in availRaidLevels: - raidBox.append(level, level) - if request.raidlevel: - raidBox.setCurrent(request.raidlevel) - subgrid.setField(raidBox, 0, 1) - return (raidBox, subgrid) - - - # make the list of drives for the RAID - def makeRaidDriveList(self, request): - subgrid = Grid(1, 2) - driveLbl = Label(_("RAID Members:")) - subgrid.setField(driveLbl, 0, 0) - disks = self.diskset.disks.keys() - drivelist = CheckboxTree(height=2, scroll=1) - avail = self.partitions.getAvailRaidPartitions(request, self.diskset) - - # XXX - if not request.raidmembers: - for (part, size, used) in avail: - drivelist.append(part, part, 1) - else: - for (part, size, used) in avail: - drivelist.append(part, part, used) - subgrid.setField(drivelist, 0, 1) - return (drivelist, subgrid) - - - def makeSpareEntry(self, request): - subgrid = Grid(2, 1) - label = Label(_("Number of spares?")) - subgrid.setField(label, 1, 0) - entry = Entry(3) - if request.raidspares: - entry.set(str(request.raidspares)) - else: - entry.set("0") - subgrid.setField(entry, 0, 0, (0,0,1,0)) - return (entry, subgrid) - - def fsOptionsGrid(self, origrequest, newfstype): - subgrid = Grid(2, 4) - # filesystem type selection - srow = 0 - typeLbl = Label(_("File System Type:")) - subgrid.setField(typeLbl, 0, srow, (0,0,0,1), anchorLeft = 1) - ptype = origrequest.fstype.getName() - if ptype == "foreign": - part = get_partition_by_name(self.diskset.disks, origrequest.device) - if part is not None: - ptype = map_foreign_to_fsname(part.native_type) - else: - pytype = _("Foreign") - type = Label(ptype) - subgrid.setField(type, 1, srow, (0,0,0,1), anchorRight = 1) - srow = srow +1 - if origrequest.type != REQUEST_NEW and origrequest.fslabel: - fsLbl = Label(_("File System Label:")) - subgrid.setField(fsLbl, 0, srow, (0,0,0,1), anchorLeft = 1) - label = Label(origrequest.fslabel) - subgrid.setField(label, 1, srow, (0,0,0,1), anchorRight = 1) - srow = srow + 1 - - sizeLbl = Label(_("Size (MB):")) - subgrid.setField(sizeLbl, 0, srow, (0,0,0,1), anchorLeft = 1) - size = Label("%s" %(int(origrequest.size))) - subgrid.setField(size, 1, srow, (0,0,0,1), anchorRight = 1) - srow = srow + 1 - tmpLbl = Label(_("File System Option:")) - subgrid.setField(tmpLbl, 0, srow, (0,0,0,1), anchorLeft = 1) - if origrequest.format: - fsoptLbl = Label(_("Format as %s") % (newfstype.getName())) - elif origrequest.migrate: - fsoptLbl = Label(_("Migrate to %s") %(newfstype.getName())) - else: - fsoptLbl = Label(_("Leave unchanged")) - subgrid.setField(fsoptLbl, 1, srow, (0,0,0,1), anchorLeft = 1) - - return (subgrid, fsoptLbl, type) - - - def fsOptionsDialog(self, origrequest, format, migrate, newfstype): - - def formatChanged((formatrb)): - flag = FLAGS_SET - if formatrb.selected(): - flag = FLAGS_RESET - - poplevel = GridFormHelp(self.screen, _("File System Options"), - "fsoption", 1, 6) - row = 0 - poplevel.add(TextboxReflowed(40, _("Please choose how you would " - "like to prepare the file system " - "on this partition.")), 0, 0) - row = row + 1 - subgrid = Grid(2, 5) - srow = 0 - - noformatrb = SingleRadioButton(_("Leave unchanged (preserve data)"), - None, not format and not migrate) - subgrid.setField(noformatrb, 0, srow, (0,0,0,1),anchorLeft = 1) - - srow = srow + 1 - if format: - forflag = 1 - else: - forflag = 0 - formatrb = SingleRadioButton(_("Format as:"), noformatrb, forflag) - formatrb.setCallback(formatChanged, (formatrb)) - noformatrb.setCallback(formatChanged, (formatrb)) - - subgrid.setField(formatrb, 0, srow, (0,0,0,1), anchorLeft = 1) - - (fortype, forgrid) = self.makeFsList(origrequest, usecallback = 0, - uselabel = 0) - if newfstype and newfstype.isFormattable() and \ - newfstype.getName() in fileSystemTypeGetTypes().keys() and \ - newfstype.isSupported(): - fortype.setCurrent(newfstype) - subgrid.setField(forgrid, 1, srow, (0,0,0,1)) - - if origrequest.origfstype and origrequest.origfstype.isMigratable(): - srow = srow + 1 - if migrate: - migflag = 1 - else: - migflag = 0 - migraterb = SingleRadioButton(_("Migrate to:"), formatrb, migflag) - migraterb.setCallback(formatChanged, (formatrb)) - subgrid.setField(migraterb, 0, srow, (0,0,0,1), anchorLeft = 1) - - migtypes = origrequest.origfstype.getMigratableFSTargets() - - (migtype, miggrid) = self.makeFsList(origrequest, usecallback = 0, - uselabel = 0, - usetypes = migtypes) - - if newfstype and newfstype.getName() in migtypes: - migtype.setCurrent(newfstype) - subgrid.setField(miggrid, 1, srow, (0,0,0,1)) - else: - migraterb = None - - poplevel.add(subgrid, 0, row, (0,1,0,1)) - - row = row + 1 - - formatChanged((formatrb)) - - popbb = ButtonBar(self.screen, (TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON)) - poplevel.add(popbb, 0, row, (0,0,0,0), growx = 1) - - while 1: - res = poplevel.run() - - if popbb.buttonPressed(res) == 'cancel': - self.screen.popWindow() - return (format, migrate, newfstype) - - if noformatrb.selected(): - format = 0 - migrate = 0 - newfstype = origrequest.origfstype - elif formatrb and formatrb.selected(): - format = 1 - migrate = 0 - newfstype = fortype.current() - elif migraterb and migraterb.selected(): - format = 0 - migrate = 1 - newfstype = migtype.current() - - self.screen.popWindow() - - return (format, migrate, newfstype) - - def shutdownUI(self): - # XXX remove parted object refs - # need to put in clear() method for checkboxtree in snack - if self.drivelist: - self.drivelist.key2item = {} - self.drivelist.item2key = {} - - # isNew implies that this request has never been successfully used before - def editPartitionRequest(self, origrequest, isNew = 0): - self.oldMount = None - - poplevel = GridFormHelp(self.screen,_("Add Partition"),"addpart", 1, 6) - - # mount point entry - row = 0 - (self.mount, mountgrid) = self.makeMountEntry(origrequest) - poplevel.add(mountgrid, 0, row) - - row = row + 1 - - self.drivelist = None - if origrequest.type == REQUEST_NEW: - subgrid = Grid(2, 1) - (fstype, fsgrid) = self.makeFsList(origrequest) - subgrid.setField(fsgrid, 0, 0, anchorLeft = 1, anchorTop=1) - - if origrequest.start == None: - (self.drivelist, drivegrid) = self.makeDriveList(origrequest) - subgrid.setField(drivegrid, 1, 0, (2,0,0,0), anchorRight=1, anchorTop=1) - poplevel.add(subgrid, 0, row, (0,1,0,0), growx=1) - - # size stuff - row = row + 1 - - allsize = Grid(2, 1) - (size, sizegrid) = self.makeSizeEntry(origrequest) - allsize.setField(sizegrid, 0, 0, anchorTop = 1) - - (sizeopts, limitentry, optiongrid) = self.makeSizeOptions(origrequest) - allsize.setField(optiongrid, 1, 0) - - poplevel.add(allsize, 0, row, (0,1,0,0), growx=1) - else: # explicit add via cylinder - poplevel.add(subgrid, 0, row, (0,1,0,0)) - - row = row + 1 - (cylopts, start, end, size, cylgrid) = self.makeCylEntries(origrequest) - poplevel.add(cylgrid, 0, row, (0,1,0,0)) - - # primary - # XXX need to see if cylinder range is in extended or not - row = row + 1 - primary = Checkbox(_("Force to be a primary partition")) - # only show if we have something other than primary - if not self.diskset.onlyPrimaryParts(): - poplevel.add(primary, 0, row, (0,1,0,0)) - row = row + 1 - - fsoptLbl = None - - elif origrequest.type == REQUEST_VG: - self.intf.messageWindow(_("Not Supported"), - _("You can only edit LVM Volume Groups " - "in the graphical installer.")) - return - - elif (origrequest.type == REQUEST_LV or origrequest.type == REQUEST_PREEXIST) and origrequest.fstype: - - # set some defaults - format = origrequest.format - migrate = origrequest.migrate - newfstype = origrequest.fstype - - (subgrid, fsoptLbl, fstypeLbl) = self.fsOptionsGrid(origrequest, newfstype) - poplevel.add(subgrid, 0, row, (0,1,0,0)) - - - row = row + 1 - if origrequest.type == REQUEST_NEW or origrequest.getProtected(): - popbb = ButtonBar(self.screen, (TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON)) - else: - popbb = ButtonBar(self.screen, (TEXT_OK_BUTTON, - (_("File System Options"), "fsopts"), - TEXT_CANCEL_BUTTON)) - poplevel.add(popbb, 0, row, (0,1,0,0), growx = 1) - - while 1: - - res = poplevel.run() - - # if the user hit cancel, do nothing - if popbb.buttonPressed(res) == 'cancel': - self.screen.popWindow() - return - - if popbb.buttonPressed(res) == 'fsopts': - (format, migrate, newfstype) = self.fsOptionsDialog(origrequest, format, migrate, newfstype) - self.fstypeSet((newfstype, self.mount)) - fstypeLbl.setText(newfstype.getName()) - - if fsoptLbl: - if format: - fsoptLbl.setText(_("Format as %s") % (newfstype.getName())) - elif migrate: - fsoptLbl.setText(_("Migrate to %s") %(newfstype.getName())) - else: - fsoptLbl.setText(_("Leave unchanged")) - - continue - - if origrequest.type == REQUEST_NEW: - filesystem = fstype.current() - - if primary.selected(): - primonly = True - else: - primonly = None - - request = copy.copy(origrequest) - request.fstype = filesystem - if request.fstype.isMountable(): - request.mountpoint = self.mount.value() - else: - request.mountpoint = None - request.format = True - request.primary = primonly - - if origrequest.start == None: - if invalidInteger(size.value()): - self.intf.messageWindow(_("Invalid Entry for Partition Size"), - invalidInteger(size.value())) - continue - request.size = int(size.value()) - - growtype = sizeopts.getSelection() - if growtype == "fixed": - grow = None - else: - grow = True - if growtype == "limit": - if invalidInteger(limitentry.value()): - self.intf.messageWindow(_("Invalid Entry for Maximum Size"), - invalidInteger(limitentry.value())) - continue - - maxsize = int(limitentry.value()) - else: - maxsize = None - request.grow = grow - request.maxSizeMB = maxsize - - if len(self.drivelist.getSelection()) == len(self.diskset.disks.keys()): - allowdrives = None - else: - allowdrives = [] - for i in self.drivelist.getSelection(): - allowdrives.append(i) - request.drive = allowdrives - else: - if invalidInteger(start.value()): - self.intf.messageWindow(_("Invalid Entry for Starting Cylinder"), - invalidInteger(start.value())) - continue - - request.start = int(start.value()) - - cyltype = cylopts.getSelection() - if cyltype == "end": - if invalidInteger(end.value()): - self.intf.messageWindow(_("Invalid Entry for End Cylinder"), - invalidInteger(end.value())) - continue - - request.end = int(end.value()) - request.size = None - elif cyltype == "size": - if invalidInteger(size.value()): - self.intf.messageWindow(_("Invalid Entry for Partition Size"), - invalidInteger(size.value())) - continue - request.end = None - request.size = int(size.value()) - else: # can't ever get here - raise RuntimeError, "Selected a way of partitioning by cylinder that's not supported" - - err = request.sanityCheckRequest(self.partitions) - if err: - self.intf.messageWindow(_("Error With Request"), - "%s" % (err)) - continue - else: - request = copy.copy(origrequest) - - if request.type == REQUEST_PREEXIST or request.type == REQUEST_LV: - request.fstype = newfstype - - if request.fstype.isMountable(): - request.mountpoint = self.mount.value() - else: - request.mountpoint = None - - if request.type == REQUEST_PREEXIST or request.type == REQUEST_LV: - request.format = format - request.migrate = migrate - request.fstype = newfstype - - err = request.sanityCheckRequest(self.partitions) - if err: - self.intf.messageWindow(_("Error With Request"), - "%s" % (err)) - continue - - if (not request.format and request.mountpoint - and request.formatByDefault()): - if not queryNoFormatPreExisting(self.intf): - continue - - if not isNew: - self.partitions.removeRequest(origrequest) - - self.partitions.addRequest(request) - if self.refresh(): - # the add failed; remove what we just added and put - # back what was there if we removed it - self.partitions.removeRequest(request) - if not isNew: - self.partitions.addRequest(origrequest) - if self.refresh(): - # this worked before and doesn't now... - raise RuntimeError, "Returning partitions to state prior to edit failed" - else: - break - - # clean up - self.shutdownUI() - self.screen.popWindow() - - # isNew implies that this request has never been successfully used before - def editRaidRequest(self, raidrequest, isNew = 0): - preexist = raidrequest and raidrequest.preexist - if preexist: - tmpstr = _("Edit RAID Device") - else: - tmpstr = _("Make RAID Device") - poplevel = GridFormHelp(self.screen, tmpstr, "makeraid", 1, 6) - - # mount point entry - row = 0 - (self.mount, mountgrid) = self.makeMountEntry(raidrequest) - poplevel.add(mountgrid, 0, row) - row = row + 1 - - # initialize holder for temporary mount point value - self.oldMount = None - - if preexist: - # set some defaults - format = raidrequest.format - migrate = raidrequest.migrate - newfstype = raidrequest.fstype - - (subgrid, fsoptLbl, fstypeLbl) = self.fsOptionsGrid(raidrequest, newfstype) - poplevel.add(subgrid, 0, row, (0,1,0,0)) - self.drivelist = None - else: - subgrid = Grid(2, 1) - (fstype, fsgrid) = self.makeFsList(raidrequest, ignorefs = ["software RAID", "PPC PReP Boot", "Apple Bootstrap"]) - subgrid.setField(fsgrid, 0, 0, anchorLeft = 1, anchorTop=1) - (raidtype, raidgrid) = self.makeRaidList(raidrequest) - subgrid.setField(raidgrid, 1, 0, (2,0,0,0), anchorRight=1, anchorTop=1) - poplevel.add(subgrid, 0, row, (0,1,0,0)) - - row = row + 1 - drivegrid = Grid(2, 1) - - #Let's see if we have any RAID partitions to make a RAID device with - avail = self.partitions.getAvailRaidPartitions(raidrequest, self.diskset) - - #If we don't, then tell the user that none exist - if len(avail) < 2: - ButtonChoiceWindow (self.screen, _("No RAID partitions"), - _("At least two software RAID partitions are needed."), - [ TEXT_OK_BUTTON ]) - return - - (self.drivelist, drivesubgrid) = self.makeRaidDriveList(raidrequest) - drivegrid.setField(drivesubgrid, 0, 0, (0,0,4,0), anchorLeft = 1, anchorTop = 1) - - miscgrid = Grid(1, 2) - (spares, sparegrid) = self.makeSpareEntry(raidrequest) - miscgrid.setField(sparegrid, 0, 0, anchorRight=1, anchorTop=1) - - if raidrequest.fstype and raidrequest.fstype.isFormattable(): - format = Checkbox(_("Format partition?")) - miscgrid.setField(format, 0, 1) - else: - format = None - - if raidrequest.format == 1 or raidrequest.format == None: - format.setValue("*") - - drivegrid.setField(miscgrid, 1, 0, anchorTop=1) - poplevel.add(drivegrid, 0, row, (0,1,0,0)) - - row = row + 1 - if preexist: - popbb = ButtonBar(self.screen, (TEXT_OK_BUTTON, - (_("File System Options"), "fsopts"), - TEXT_CANCEL_BUTTON)) - else: - popbb = ButtonBar(self.screen, (TEXT_OK_BUTTON,TEXT_CANCEL_BUTTON)) - poplevel.add(popbb, 0, row, (0,1,0,0), growx = 1) - - while 1: - res = poplevel.run() - - if popbb.buttonPressed(res) == 'cancel': - self.screen.popWindow() - return - - if popbb.buttonPressed(res) == 'fsopts': - (format, migrate, newfstype) = self.fsOptionsDialog(raidrequest, format, migrate, newfstype) - self.fstypeSet((newfstype, self.mount)) - fstypeLbl.setText(newfstype.getName()) - - if fsoptLbl: - if format: - fsoptLbl.setText(_("Format as %s") % (newfstype.getName())) - elif migrate: - fsoptLbl.setText(_("Migrate to %s") %(newfstype.getName())) - else: - fsoptLbl.setText(_("Leave unchanged")) - - continue - - request = copy.copy(raidrequest) - - if not preexist: - request.fstype = fstype.current() - else: - request.fstype = newfstype - - if request.fstype.isMountable(): - request.mountpoint = self.mount.value() - else: - request.mountpoint = None - - if not preexist: - raidmembers = [] - for drive in self.drivelist.getSelection(): - id = self.partitions.getRequestByDeviceName(drive).uniqueID - raidmembers.append(id) - - request.raidmembers = raidmembers - if invalidInteger(spares.value()): - self.intf.messageWindow(_("Invalid Entry for RAID Spares"), - invalidInteger(spares.value())) - continue - - request.raidspares = int(spares.value()) - request.raidlevel = raidtype.current() - request.raidminor = self._findFirstUnused(self.raidminors) - self.raidminors[request.raidminor] = True - - if format: - request.format = format.selected() - else: - request.format = 0 - - if request.raidlevel == "RAID0" and request.raidspares > 0: - self.intf.messageWindow(_("Too many spares"), - _("You may not use any spares " - "with a RAID0 array.")) - continue - else: - request.format = format - request.migrate = migrate - request.fstype = newfstype - - err = request.sanityCheckRequest(self.partitions) - if err: - self.intf.messageWindow(_("Error With Request"), - "%s" % (err)) - continue - - if not isNew: - self.partitions.removeRequest(raidrequest) - - self.partitions.addRequest(request) - - if self.refresh(): - # how can this fail? well, if it does, do the remove new, - # add old back in dance - self.partitions.removeRequest(request) - if not isNew: - self.partitions.addRequest(raidrequest) - if self.refresh(): - raise RuntimeError, "Returning partitions to state prior to RAID edit failed" - else: - break - - break - - # clean up - self.shutdownUI() - self.screen.popWindow() - - # isNew implies that this request has never been successfully used before - def editLVRequest(self, lvrequest, isNew = 0): - preexist = lvrequest and lvrequest.preexist - if preexist: - tmpstr = _("Edit Logical Volume") - else: - tmpstr = _("Make Logical Volume") - self.drivelist = None - poplevel = GridFormHelp(self.screen, tmpstr, "makelv", 1, 8) - - # mount point entry - row = 0 - (self.mount, mountgrid) = self.makeMountEntry(lvrequest) - poplevel.add(mountgrid, 0, row) - row = row + 1 - - (self.lvname, lvgrid) = self.makeLVNameEntry(lvrequest) - poplevel.add(lvgrid, 0, row) - row = row + 1 - - (lvsize, lvsizegrid) = self.makeLVSize(lvrequest) - poplevel.add(lvsizegrid, 0, row) - row = row + 1 - - # initialize holder for temporary mount point value - self.oldMount = None - - if preexist: - # set some defaults - format = lvrequest.format - migrate = lvrequest.migrate - newfstype = lvrequest.fstype - - (subgrid, fsoptLbl, fstypeLbl) = self.fsOptionsGrid(lvrequest, newfstype) - poplevel.add(subgrid, 0, row, (0,1,0,0)) - self.drivelist = None - else: - subgrid = Grid(2, 1) - (fstype, fsgrid) = self.makeFsList(lvrequest, ignorefs = ["software RAID", "efi", "PPC PReP Boot", "Apple Bootstrap"]) - subgrid.setField(fsgrid, 0, 0, anchorLeft = 1, anchorTop=1) - - vgs = self.partitions.getLVMVGRequests() - if len(vgs) < 1: - ButtonChoiceWindow (self.screen, _("No Volume Groups"), - _("No volume groups exist in which to create " - "a logical volume"),[ TEXT_OK_BUTTON ]) - return - - (vgtype, vggrid) = self.makeVGList(lvrequest) - subgrid.setField(vggrid, 1, 0, (2,0,0,0), anchorRight=1, anchorTop=1) - poplevel.add(subgrid, 0, row, (0,1,0,0)) - - row = row + 1 - - miscgrid = Grid(1, 3) - - if lvrequest.fstype and lvrequest.fstype.isFormattable(): - format = Checkbox(_("Format partition?")) - miscgrid.setField(format, 0, 1) - else: - format = None - - if lvrequest.format == 1 or lvrequest.format == None: - format.setValue("*") - - poplevel.add(miscgrid, 0, row, (0,1,0,0)) - - row = row + 1 - if preexist: - popbb = ButtonBar(self.screen, (TEXT_OK_BUTTON, - (_("File System Options"), "fsopts"), - TEXT_CANCEL_BUTTON)) - else: - popbb = ButtonBar(self.screen, (TEXT_OK_BUTTON,TEXT_CANCEL_BUTTON)) - poplevel.add(popbb, 0, row, (0,1,0,0), growx = 1) - - while 1: - res = poplevel.run() - - if popbb.buttonPressed(res) == 'cancel': - self.screen.popWindow() - return - - if popbb.buttonPressed(res) == 'fsopts': - (format, migrate, newfstype) = self.fsOptionsDialog(lvrequest, format, migrate, newfstype) - self.fstypeSet((newfstype, self.mount)) - fstypeLbl.setText(newfstype.getName()) - - if fsoptLbl: - if format: - fsoptLbl.setText(_("Format as %s") % (newfstype.getName())) - elif migrate: - fsoptLbl.setText(_("Migrate to %s") %(newfstype.getName())) - else: - fsoptLbl.setText(_("Leave unchanged")) - - continue - - request = copy.copy(lvrequest) - - if not preexist: - request.fstype = fstype.current() - else: - request.fstype = newfstype - - if request.fstype.isMountable(): - request.mountpoint = self.mount.value() - else: - request.mountpoint = None - - if not preexist: - if format: - request.format = format.selected() - else: - request.format = 0 - - # set the vg - vgreq = vgtype.current() - request.volumeGroup = vgreq.uniqueID - - if vgreq is None: - raise RuntimeError, "Somehow ended up with a None volume group!" - - # get the lv name, check for a "valid" name - lvn = self.lvname.value().strip() - err = sanityCheckLogicalVolumeName(lvn) - if err: - self.intf.messageWindow(_("Illegal Logical Volume Name"), err, custom_icon="error") - - continue - - # make sure we don't have an LV in this volume group by - # this name already - used = 0 - origlvname = lvrequest.logicalVolumeName - for lv in self.partitions.getLVMLVRequests(): - if origlvname and lvn == origlvname: - break - if ((lv.logicalVolumeName == lvn) and - (lv.volumeGroup == vgreq.uniqueID)): - used = 1 - break - - if used: - self.intf.messageWindow(_("Illegal logical volume name"), - _("The logical volume name "%s" " - "is already in use. Please " - "pick another.") % (lvn,), - custom_icon="error") - continue - - request.logicalVolumeName = lvn - - try: - size = int(lvsize.value().strip()) - except: - self.intf.messageWindow(_("Illegal size"), - _("The requested size as entered is " - "not a valid number greater " - "than 0."), custom_icon="error") - continue - - pesize = vgreq.pesize - size = lvm.clampLVSizeRequest(size, pesize, roundup=1) - - maxlv = lvm.getMaxLVSize(pesize) - if size > lvm.getMaxLVSize(pesize): - self.intf.messageWindow(_("Not enough space"), - _("The current requested size " - "(%10.2f MB) is larger than the " - "maximum logical volume " - "size (%10.2f MB). ") % (size, - maxlv), - custom_icon="error") - continue - - vgsize = vgreq.getActualSize(self.partitions, self.diskset) - avail = vgsize - for req in self.partitions.requests: - if ((req.type == REQUEST_LV) and - (req.volumeGroup == vgreq.uniqueID)): - avail -= req.size - if lvrequest.size: - avail += lvrequest.size - - if size > avail: - self.intf.messageWindow(_("Not enough space"), - _("The current requested size " - "(%10.2f MB) is larger than " - "the available size in " - "the volume group " - "(%10.2f MB).") %(size, avail), - custom_icon="error") - continue - - request.size = size - request.grow = 0 - request.dev = None - else: - request.format = format - request.migrate = migrate - request.fstype = newfstype - - err = request.sanityCheckRequest(self.partitions) - if err: - self.intf.messageWindow(_("Error With Request"), - "%s" % (err)) - continue - - if not isNew: - self.partitions.removeRequest(lvrequest) - - self.partitions.addRequest(request) - - if self.refresh(): - # how can this fail? well, if it does, do the remove new, - # add old back in dance - self.partitions.removeRequest(request) - if not isNew: - self.partitions.addRequest(lvrequest) - if self.refresh(): - raise RuntimeError, "Returning partitions to state prior to RAID edit failed" - else: - break - - break - - # clean up - self.shutdownUI() - self.screen.popWindow() - - def newCb(self): - hasvg = 1 - dolv = 0 - for request in self.partitions.requests: - if request.type == REQUEST_VG: - hasvg = 1 - break - if hasvg: - rc = ListboxChoiceWindow(self.screen, - _("New Partition or Logical Volume?"), - _("Would you like to create a new " - "partition or a new logical volume?"), - [ _("partition"), _("logical volume") ], - [ TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON ], - width = 30, scroll = 0, height = 2) - (button, choice) = rc - if button == TEXT_CANCEL_CHECK: - return - if choice == 1: - dolv = 1 - - if not dolv: - request = NewPartitionSpec(fileSystemTypeGetDefault(), 1) - self.editPartitionRequest(request, isNew = 1) - else: - request = LogicalVolumeRequestSpec(fileSystemTypeGetDefault(), - size=1) - self.editLVRequest(request, isNew = 1) - - def makeraidCb(self): - request = RaidRequestSpec(fileSystemTypeGetDefault()) - self.editRaidRequest(request, isNew = 1) - - def editCb(self): - part = self.lb.current() - (type, request) = doEditPartitionByRequest(self.intf, self.partitions, part) - if request: - if type == "RAID": - self.editRaidRequest(request) - elif type == "LVMLV": - self.editLVRequest(request) - elif type == "NEW": - self.editPartitionRequest(request, isNew = 1) - else: - self.editPartitionRequest(request) - - def deleteCb(self): - partition = self.lb.current() - - req = self.partitions.getRequestByID(partition) - if req and isinstance(req, RaidRequestSpec): - del(self.raidminors[req.raidminor]) - - if doDeletePartitionByRequest(self.intf, self.partitions, partition): - self.refresh() - - def resetCb(self): - if not confirmResetPartitionState(self.intf): - return - - self.diskset.refreshDevices() - self.partitions.setFromDisk(self.diskset) - self.populate() - - def shutdownMainUI(self): - self.lb.clear() - - def __call__(self, screen, pomona): - self.screen = screen - self.fsset = pomona.id.fsset - self.diskset = pomona.id.diskset - self.intf = pomona.intf - - self.diskset.openDevices() - self.partitions = pomona.id.partitions - - checkForSwapNoMatch(pomona) - - self.g = GridFormHelp(screen, _("Partitioning"), "partition", 1, 5) - - self.lb = CListbox(height=10, cols=6, - col_widths=[17,6,6,7,10,12], - scroll=1, returnExit = 1, - width=70, col_pad=2, - col_labels=[_('Device'), _('Start'), _('End'), _('Size'), _('Type'), _('Mount Point')], - col_label_align=[CENTER, CENTER,CENTER,CENTER,CENTER,CENTER]) - self.g.add(self.lb, 0, 1) - - self.bb = ButtonBar (screen, ((_("New"), "new", "F2"), - (_("Edit"), "edit", "F3"), - (_("Delete"), "delete", "F4"), - (_("RAID"), "raid", "F11"), - TEXT_OK_BUTTON, TEXT_BACK_BUTTON)) - - screen.pushHelpLine( _(" F1-Help F2-New F3-Edit F4-Delete F5-Reset F12-OK ")) - - self.g.add(self.bb, 0, 2, (0, 1, 0, 0)) - self.g.addHotKey("F5") - self.populate() - - while 1: - rc = self.g.run() - res = self.bb.buttonPressed(rc) - - if res == "new": - self.newCb() - elif res == "edit" or rc == self.lb.listbox: # XXX better way? - self.editCb() - elif res == "delete": - self.deleteCb() - elif res == "raid": - self.makeraidCb() - elif res == "reset" or rc == "F5": - self.resetCb() - elif res == TEXT_BACK_CHECK: - # remove refs to parted objects - self.shutdownMainUI() - - self.diskset.refreshDevices() - self.partitions.setFromDisk(self.diskset) - - screen.popHelpLine() - screen.popWindow() - return INSTALL_BACK - else: - if not self.partitions.getRequestByMountPoint("/"): - self.intf.messageWindow(_("No Root Partition"), - _("Installation requires a / partition.")) - continue - - (errors, warnings) = self.partitions.sanityCheckAllRequests(self.diskset) - rc = partitionSanityErrors(self.intf, errors) - if rc != 1: - continue - - rc = partitionSanityWarnings(self.intf, warnings) - if rc != 1: - continue - - warnings = getPreExistFormatWarnings(self.partitions, - self.diskset) - rc = partitionPreExistFormatWarnings(self.intf, warnings) - if rc != 1: - continue - - # remove refs to parted objects - self.shutdownMainUI() - - screen.popHelpLine() - screen.popWindow() - return INSTALL_OK - -class PartitionTypeWindow: - def typeboxChange(self, (typebox, drivelist)): - flag = FLAGS_RESET - if typebox.current() == CLEARPART_TYPE_NONE: - flag = FLAGS_SET - # XXX need a way to disable the checkbox tree - - def clearDrivelist(self): - # XXX remove parted object refs - # need to put in clear() method for checkboxtree in snack - self.drivelist.key2item = {} - self.drivelist.item2key = {} - - def __call__(self, screen, pomona): - self.pomona = pomona - - while 1: - g = GridFormHelp(screen, _("Partitioning Type"), "autopart", 1, 6) - - txt = TextboxReflowed(65, _("Installation requires partitioning of your hard drive. The default layout is suitable for most users. Select what space to use and which drives to use as the install target. You can also choose to create your own custom layout.")) - g.add(txt, 0, 0, (0, 0, 0, 0)) - - opts = ((_("Remove all partitions on selected drives and create default layout"), CLEARPART_TYPE_ALL), - (_("Create custom layout"), -1)) - typebox = Listbox(height = len(opts), scroll = 0) - for (txt, val) in opts: - typebox.append(txt, val) - - if pomona.dispatch.stepInSkipList("autopartitionexecute"): - typebox.setCurrent(-1) - else: - typebox.setCurrent(pomona.id.partitions.autoClearPartType) - - g.add(typebox, 0, 1, (0, 1, 0, 0)) - - # list of drives to select which to clear - subgrid = Grid(1, 2) - subgrid.setField(TextboxReflowed(55, _("Which drive(s) do you want to " - "use for this installation?")), - 0, 0) - drivelist = CheckboxTree(height=2, scroll=1) - subgrid.setField(drivelist, 0, 1) - g.add(subgrid, 0, 2, (0, 1, 0, 0)) - - bb = ButtonBar(screen, [ TEXT_OK_BUTTON, TEXT_BACK_BUTTON ]) - g.add(bb, 0, 5, (0,1,0,0)) - - - typebox.setCallback(self.typeboxChange, (typebox, drivelist)) - self.drivelist = drivelist - - screen.pushHelpLine (_("<Space>,<+>,<-> selection | <F12> next screen")) - - # restore the drive list each time - disks = pomona.id.diskset.disks.keys() - disks.sort() - cleardrives = pomona.id.partitions.autoClearPartDrives - - for disk in disks: - size = getDeviceSizeMB(pomona.id.diskset.disks[disk].dev) - model = pomona.id.diskset.disks[disk].dev.model - - if not cleardrives or len(cleardrives) < 1: - selected = 1 - else: - if disk in cleardrives: - selected = 1 - else: - selected = 0 - - sizestr = "%8.0f MB" % (size,) - diskdesc = "%6s %s (%s)" % (disk, sizestr, model[:24],) - - drivelist.append(diskdesc, selected = selected) - - rc = g.run() - - if len(self.drivelist.getSelection()) > 0: - sel = map(lambda s: s.split()[0], self.drivelist.getSelection()) - else: - sel = [] - partmethod_ans = typebox.current() - res = bb.buttonPressed(rc) - - self.clearDrivelist() - screen.popHelpLine() - screen.popWindow() - - if res == TEXT_BACK_CHECK: - return INSTALL_BACK - - if pomona.id.diskset.checkNoDisks(): - continue - - if len(sel) < 1: - mustHaveSelectedDrive(pomona.intf) - continue - - if partmethod_ans == -1: - pomona.dispatch.skipStep("autopartitionexecute", skip = 1) - break - else: - pomona.dispatch.skipStep("autopartitionexecute", skip = 0) - - pomona.id.partitions.autoClearPartType = partmethod_ans - pomona.id.partitions.autoClearPartDrives = sel - break - - # ask to review autopartition layout - but only if it's not custom partitioning - pomona.dispatch.skipStep("partition", skip = 0) - pomona.dispatch.skipStep("bootloader", skip = 1) - - if partmethod_ans != -1: - reviewLayout = pomona.intf.messageWindow(_("Review Partition Layout"), - _("Review and modify partitioning layout?"), - type = "yesno") - - if reviewLayout != 1: - pomona.dispatch.skipStep("partition", skip = 1) - - return INSTALL_OK diff --git a/pkgs/core/pomona/src/tui_progress.py b/pkgs/core/pomona/src/tui_progress.py deleted file mode 100644 index c74b909..0000000 --- a/pkgs/core/pomona/src/tui_progress.py +++ /dev/null @@ -1,115 +0,0 @@ -# -# progress_text.py: text mode install/upgrade progress dialog -# -# Copyright 2001-2007 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -from constants import * -from snack import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -import logging -log = logging.getLogger("pomona") - -def strip_markup(text): - if text.find("<") == -1: - return text - r = "" - inTag = False - for c in text: - if c == ">" and inTag: - inTag = False - continue - elif c == "<" and not inTag: - inTag = True - continue - elif not inTag: - r += c - return r - -class InstallProgressWindow: - def __init__(self, screen): - self.screen = screen - self.drawn = False - - self.pct = 0 - - def __del__ (self): - if self.drawn: - self.screen.popWindow () - - def _setupScreen(self): - screen = self.screen - - self.grid = GridForm(self.screen, _("File Installation"), 1, 6) - - self.width = 65 - self.progress = Scale(self.width, 100) - self.grid.add (self.progress, 0, 1, (0, 1, 0, 0)) - - self.label = Label("") - self.grid.add(self.label, 0, 2, (0, 1, 0, 0), anchorLeft = 1) - - self.info = Textbox(self.width, 4, "", wrap = 1) - self.grid.add(self.info, 0, 3, (0, 1, 0, 0)) - - self.grid.draw() - screen.refresh() - self.drawn = True - - def processEvents(self): - if not self.drawn: - return - self.grid.draw() - self.screen.refresh() - - def setShowPercentage(self, val): - pass - - def get_fraction(self): - return self.pct - - def set_fraction(self, pct): - if not self.drawn: - self._setupScreen() - - self.progress.set(int(pct * 100)) - self.pct = pct - self.processEvents() - - def set_label(self, txt): - if not self.drawn: - self._setupScreen() - - self.info.setText(strip_markup(txt)) - self.processEvents() - - def set_text(self, txt): - if not self.drawn: - self._setupScreen() - - if len(txt) > self.width: - txt = txt[:self.width] - else: - spaces = (self.width - len(txt)) / 2 - txt = (" " * spaces) + txt - - self.label.setText(strip_markup(txt)) - self.processEvents() - -class setupForInstall: - def __call__(self, screen, pomona): - if pomona.dir == DISPATCH_BACK: - pomona.id.setInstallProgressClass(None) - return INSTALL_BACK - - pomona.id.setInstallProgressClass(InstallProgressWindow(screen)) - return INSTALL_OK diff --git a/pkgs/core/pomona/src/tui_timezone.py b/pkgs/core/pomona/src/tui_timezone.py deleted file mode 100644 index c26253f..0000000 --- a/pkgs/core/pomona/src/tui_timezone.py +++ /dev/null @@ -1,114 +0,0 @@ -# -# timezone_text.py: text mode timezone selection dialog -# -# Copyright 2000-2006 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -import sys -import string -import iutil -import os -from time import * -from snack import * -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -class TimezoneWindow: - def getTimezoneList(self): - import zonetab - - zt = zonetab.ZoneTab() - zoneList = [ x.tz for x in zt.getEntries() ] - zoneList.sort() - return zoneList - - def updateSysClock(self): - args = ["--hctosys"] - if self.c.selected(): - args.append("--utc") - - iutil.execWithRedirect("hwclock", args, searchPath=1) - self.g.setTimer(500) - self.updateClock() - - def updateClock(self): - # disable for now - return - -# if os.access("/usr/share/zoneinfo/" + self.l.current(), os.R_OK): -# os.environ['TZ'] = self.l.current() -# self.label.setText(self.currentTime()) -# else: -# self.label.setText("") - - def currentTime(self): - return "Current time: " + strftime("%X %Z", localtime(time())) - - def __call__(self, screen, pomona): - timezones = self.getTimezoneList() - (default, asUtc, asArc) = pomona.id.timezone.getTimezoneInfo() - if not default: - default = pomona.id.instLanguage.getDefaultTimeZone() - - bb = ButtonBar(screen, [TEXT_OK_BUTTON, TEXT_BACK_BUTTON]) - t = TextboxReflowed(30, _("In which time zone are you located?")) - -# -# disabling this for now -# -# self.label = Label(self.currentTime()) - - self.l = Listbox(5, scroll = 1, returnExit = 0) - - for tz in timezones: - self.l.append(_(tz), tz) - - self.l.setCurrent(default.replace("_", " ")) -# self.l.setCallback(self.updateClock) - - self.c = Checkbox(_("System clock uses UTC"), isOn = asUtc) -# self.c.setCallback(self.updateSysClock) - - self.g = GridFormHelp(screen, _("Time Zone Selection"), "timezone", 1, 5) - self.g.add(t, 0, 0) -# self.g.add(self.label, 0, 1, padding = (0, 1, 0, 0), anchorLeft = 1) - self.g.add(self.c, 0, 2, padding = (0, 1, 0, 1), anchorLeft = 1) - self.g.add(self.l, 0, 3, padding = (0, 0, 0, 1)) - self.g.add(bb, 0, 4, growx = 1) - -# disabling for now -# self.updateClock() -# self.updateSysClock() -# -# self.g.setTimer(500) -# -# result = "TIMER" -# while result == "TIMER": -# result = self.g.run() -# if result == "TIMER": -# self.updateClock() - - result = "" - while 1: - result = self.g.run() - rc = bb.buttonPressed (result) - - if rc == TEXT_BACK_CHECK: - screen.popWindow() - return INSTALL_BACK - else: - break - - screen.popWindow() - pomona.id.timezone.setTimezoneInfo(self.l.current().replace(" ", "_"), asUtc = self.c.selected()) - - return INSTALL_OK diff --git a/pkgs/core/pomona/src/tui_userauth.py b/pkgs/core/pomona/src/tui_userauth.py deleted file mode 100644 index 772c412..0000000 --- a/pkgs/core/pomona/src/tui_userauth.py +++ /dev/null @@ -1,79 +0,0 @@ -# -# userauth_text.py: text mode authentication setup dialogs -# -# Copyright 2000-2002 Red Hat, Inc. -# -# This software may be freely redistributed under the terms of the GNU -# library public license. -# -# You should have received a copy of the GNU Library Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# - -from snack import * -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -def has_bad_chars(pw): - allowed = string.digits + string.ascii_letters + string.punctuation + " " - for letter in pw: - if letter not in allowed: - return 1 - return 0 - -class RootPasswordWindow: - def __call__ (self, screen, pomona): - toplevel = GridFormHelp(screen, _("Root Password"), "rootpw", 1, 3) - - toplevel.add(TextboxReflowed(37, _("Pick a root password. You must " - "type it twice to ensure you know " - "it and do not make a typing mistake. " - "Remember that the root password is" - "a critical part of system " - "security!")), 0, 0, (0, 0, 0, 1)) - - entry1 = Entry(24, password = 1, text = pomona.id.rootPassword["password"]) - entry2 = Entry(24, password = 1, text = pomona.id.rootPassword["password"]) - passgrid = Grid(2, 2) - passgrid.setField(Label(_("Password:")), 0, 0, (0, 0, 1, 0), anchorLeft = 1) - passgrid.setField(Label(_("Password (confirm):")), 0, 1, (0, 0, 1, 0), anchorLeft = 1) - passgrid.setField(entry1, 1, 0) - passgrid.setField(entry2, 1, 1) - toplevel.add(passgrid, 0, 1, (0, 0, 0, 1)) - - bb = ButtonBar(screen, (TEXT_OK_BUTTON, TEXT_BACK_BUTTON)) - toplevel.add(bb, 0, 2, growx = 1) - - while 1: - toplevel.setCurrent(entry1) - result = toplevel.run() - rc = bb.buttonPressed(result) - if rc == TEXT_BACK_CHECK: - screen.popWindow() - return INSTALL_BACK - - if len(entry1.value ()) < 6: - ButtonChoiceWindow(screen, _("Password Length"), - _("The root password must be at least 6 characters long."), - buttons = [ TEXT_OK_BUTTON ], width = 50) - elif entry1.value() != entry2.value(): - ButtonChoiceWindow(screen, _("Password Mismatch"), - _("The passwords you entered were different. Please try again."), - buttons = [ TEXT_OK_BUTTON ], width = 50) - elif has_bad_chars(entry1.value()): - ButtonChoiceWindow(screen, _("Error with Password"), - _("Requested password contains non-ASCII characters, " - "which are not allowed."), - buttons = [ TEXT_OK_BUTTON ], width = 50) - else: - break - - entry1.set("") - entry2.set("") - - screen.popWindow() - pomona.id.rootPassword["password"] = entry1.value() - return INSTALL_OK diff --git a/pkgs/core/pomona/src/tui_welcome.py b/pkgs/core/pomona/src/tui_welcome.py deleted file mode 100644 index 19c8b28..0000000 --- a/pkgs/core/pomona/src/tui_welcome.py +++ /dev/null @@ -1,18 +0,0 @@ - -import os -from snack import * - -from constants import * - -import gettext -_ = lambda x: gettext.ldgettext("pomona", x) - -class WelcomeWindow: - def __call__(self, screen, infire): - rc = ButtonChoiceWindow(screen, _("%s") % (name,), - _("Welcome to %s!\n\n") - % (name, ), - buttons = [TEXT_OK_BUTTON], width = 50, - help = "welcome") - - return INSTALL_OK diff --git a/pkgs/core/pomona/src/users.py b/pkgs/core/pomona/src/users.py deleted file mode 100644 index bb11788..0000000 --- a/pkgs/core/pomona/src/users.py +++ /dev/null @@ -1,157 +0,0 @@ -# -# users.py: Code for creating user accounts and setting the root password -# -# Copyright (C) 2006, 2007, 2008 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 -# - -import libuser -import string -import crypt -import random -import tempfile -import os -import os.path - -import logging -log = logging.getLogger("pomona") - -def createLuserConf(instPath, algoname='sha512'): - """Writes a libuser.conf for instPath.""" - if os.getenv("LIBUSER_CONF") and \ - os.access(os.environ["LIBUSER_CONF"], os.R_OK): - fn = os.environ["LIBUSER_CONF"] - fd = open(fn, 'w') - else: - (fp, fn) = tempfile.mkstemp(prefix="libuser.") - fd = os.fdopen(fp, 'w') - - buf = """ -[defaults] -skeleton = %(instPath)s/etc/skel -mailspooldir = %(instPath)s/var/mail -crypt_style = %(algo)s -modules = files shadow -create_modules = files shadow -[files] -directory = %(instPath)s/etc -[shadow] -directory = %(instPath)s/etc -""" % {"instPath": instPath, "algo": algoname} - - fd.write(buf) - fd.close() - os.environ["LIBUSER_CONF"] = fn - -# These are explained in crypt/crypt-entry.c in glibc's code. The prefixes -# we use for the different crypt salts: -# $1$ MD5 -# $5$ SHA256 -# $6$ SHA512 -def cryptPassword(password, algo=None): - salts = {'md5': '$1$', 'sha256': '$5$', 'sha512': '$6$', None: ''} - saltstr = salts[algo] - saltlen = 2 - - if algo == 'md5' or algo == 'sha256' or algo == 'sha512': - saltlen = 16 - - for i in range(saltlen): - saltstr = saltstr + random.choice(string.letters + - string.digits + './') - - return crypt.crypt(password, saltstr) - -class Users: - def __init__ (self): - self.admin = libuser.admin() - - def createUser(self, name=None, password=None, isCrypted=False, groups=[], - homedir=None, shell=None, uid=None, algo=None, lock=False, - root="/mnt/target"): - childpid = os.fork() - - if not childpid: - os.chroot(root) - - del(os.environ["LIBUSER_CONF"]) - self.admin = libuser.admin() - - try: - if self.admin.lookupUserByName(name): - os._exit(1) - - userEnt = self.admin.initUser(name) - groupEnt = self.admin.initGroup(name) - - grpLst = filter(lambda grp: grp, - map(lambda name: self.admin.lookupGroupByName(name), groups)) - userEnt.set(libuser.GIDNUMBER, [groupEnt.get(libuser.GIDNUMBER)[0]] + - map(lambda grp: grp.get(libuser.GIDNUMBER)[0], grpLst)) - - if not homedir: - homedir = "/home/" + name - - userEnt.set(libuser.HOMEDIRECTORY, homedir) - - if shell: - userEnt.set(libuser.LOGINSHELL, shell) - - if uid >= 0: - userEnt.set(libuser.UIDNUMBER, uid) - - self.admin.addUser(userEnt) - self.admin.addGroup(groupEnt) - - if password: - if isCrypted: - self.admin.setpassUser(userEnt, password, True) - else: - self.admin.setpassUser(userEnt, - cryptPassword(password, algo=algo), - True) - - if lock: - self.admin.lockUser(userEnt) - - # Add the user to all the groups they should be part of. - for grp in grpLst: - grp.add(libuser.MEMBERNAME, name) - self.admin.modifyGroup(grp) - - os._exit(0) - except Exception, e: - log.critical("Error when creating new user: %s" % str(e)) - os._exit(1) - - try: - (pid, status) = os.waitpid(childpid, 0) - except OSError, (num, msg): - log.critical("exception from waitpid while creating a user: %s %s" % (num, msg)) - return False - - if os.WIFEXITED(status) and (os.WEXITSTATUS(status) == 0): - return True - else: - return False - - def setRootPassword(self, password, algo=None): - rootUser = self.admin.lookupUserByName("root") - - self.admin.setpassUser(rootUser, cryptPassword(password, algo=algo), True) - - self.admin.modifyUser(rootUser) diff --git a/pkgs/core/pomona/src/util.py b/pkgs/core/pomona/src/util.py new file mode 100644 index 0000000..e9afb4d --- /dev/null +++ b/pkgs/core/pomona/src/util.py @@ -0,0 +1,45 @@ +#!/usr/bin/python + +import os +import stat + +from pyfire.executil import * + +def getArch(): + return "i386" + +def notify_kernel(path, action="change"): + """ Signal the kernel that the specified device has changed. """ + path = os.path.join(path, "uevent") + if not path.startswith("/sys/") or not os.access(path, os.W_OK): + raise ValueError("invalid sysfs path") + f = open(path, "a") + f.write("%s\n" % action) + f.close() + +def numeric_type(num): + """ Verify that a value is given as a numeric data type. + + Return the number if the type is sensible or raise ValueError + if not. + """ + if num is None: + num = 0 + elif not (isinstance(num, int) or \ + isinstance(num, long) or \ + isinstance(num, float)): + raise ValueError("value (%s) must be either a number or None" % num) + + return num + +## Create a directory path. Don't fail if the directory already exists. +# @param dir The directory path to create. +def mkdirChain(dir): + try: + os.makedirs(dir, 0755) + except OSError, (errno, msg): + try: + if errno == EEXIST and stat.S_ISDIR(os.stat(dir).st_mode): + return + except: + pass diff --git a/pkgs/core/pomona/src/windows.py b/pkgs/core/pomona/src/windows.py new file mode 100644 index 0000000..5fbc819 --- /dev/null +++ b/pkgs/core/pomona/src/windows.py @@ -0,0 +1,180 @@ +#!/usr/bin/python + +import sys + +from snack import * +from constants import * + +import gettext +_ = lambda x: gettext.ldgettext("pomona", x) + +def welcomeWindow(installer): + rc = installer.intf.messageWindow(_("%s") % PRODUCT_NAME, + _("Welcome to %s-v%s!\n\n") % (PRODUCT_NAME, PRODUCT_VERSION,)) + return DISPATCH_FORWARD + +def experimentalWindow(installer): + if installer.dispatch.dir == DISPATCH_BACK: + return DISPATCH_NOOP + + # Check if we are running a pre-release version + version = PRODUCT_VERSION + if not version.find("alpha") and \ + not version.find("beta") and \ + not version.find("rc"): + return DISPATCH_NOOP + + while 1: + rc = installer.intf.messageWindow( _("Warning! This is pre-release software!"), + _("Thank you for downloading this " + "pre-release of %s.\n\n" + "This is not a final " + "release and is not intended for use " + "on production systems. The purpose of " + "this release is to collect feedback " + "from testers, and it is not suitable " + "for day to day usage.\n\n" + "To report feedback, please visit:\n\n" + " %s\n\n" + "and file a report.\n") + % (PRODUCT_NAME, PRODUCT_URL), + type="custom", custom_buttons=[_("_Exit"), _("_Install anyway")]) + + if not rc: + rc = installer.intf.messageWindow(_("Rebooting System"), + _("Your system will now be rebooted..."), + type="custom", custom_buttons=[_("_Back"), _("_Reboot")]) + if rc: + sys.exit(0) + else: + break + +def finishedWindow(installer): + installer.intf.setHelpline(_("Press <Enter> to exit")) + + rc = installer.intf.messageWindow(_("Complete"), + _("Congratulations, your %s installation is " + "complete.\n\n" + "Press <Enter> to end the installation process.\n\n" + "For information on errata (updates and bug fixes), visit " + "%s.\n\n") % (PRODUCT_NAME, PRODUCT_URL,), + type="custom", custom_buttons=[_("Reboot")]) + + return INSTALL_OK + +def partmethodWindow(installer): + storage = installer.ds.storage + + if storage.checkNoDisks(): + sys.exit(0) + + # Resetting options + storage.doAutoPart = False +# installer.dispatch.skipStep("partition", skip=0) + + methods = [ _("Automatic partitioning"), _("Custom partitioning"),] + default = methods[0] # first should be autopartitioning + + (button, choice) = ListboxChoiceWindow(installer.intf.screen, + _("Partition Method"), + _("Installation requires partitioning of your hard drive. " + "The default option is suitable for most users. " + "You can also choose to create your own custom layout."), + methods, buttons = [TEXT_OK_BUTTON, TEXT_BACK_BUTTON], + width = 60, default=default, height = len(methods)) + + if button == TEXT_BACK_CHECK: + return INSTALL_BACK + + if choice == 0: + installer.ds.storage.doAutoPart = True + #installer.dispatch.skipStep("partition", skip=1) + + installer.log.info("User has chosen "%s"" % methods[choice]) + + return INSTALL_OK + +def autopartitionWindow(installer): + storage = installer.ds.storage + while 1: + g = GridForm(installer.intf.screen, _("Device Selection"), 1, 6) + txt = TextboxReflowed(65, _("Which drive(s) do you want to use for this installation?\n\n" + "ALL DATA stored on the devices will be destroyed.")) + g.add(txt, 0, 0, (0, 0, 0, 0)) + + drivelist = CheckboxTree(height=4, scroll=1) + g.add(drivelist, 0, 4, (0, 1, 0, 0)) + + bb = ButtonBar(installer.intf.screen, [ TEXT_OK_BUTTON, TEXT_BACK_BUTTON ]) + g.add(bb, 0, 5, (0,1,0,0)) + + for disk in storage.disks: + if not storage.clearDisks or len(storage.clearDisks) < 1: + selected = 1 + else: + if disk in storage.clearDisks: # XXX never matches... + selected = 1 + else: + selected = 0 + + diskdesc = "%6s %8.0f MB (%s)" % (disk.name, disk.size, disk.model[:24],) + + drivelist.append(diskdesc, selected = selected) + + rc = g.run() + + installer.intf.screen.popWindow() + + if bb.buttonPressed(rc) == TEXT_BACK_CHECK: + return INSTALL_BACK + + if len(drivelist.getSelection()) > 0: + storage.clearDisks = map(lambda s: s.split()[0], drivelist.getSelection()) + else: + storage.clearDisks = [] + installer.intf.messageWindow(_("No Drives Selected"), + _("An error has occurred - no valid devices were " + "selected on which to create the new file system. " + "For the installation of %s, " + "you have to select at least one drive.") % PRODUCT_NAME, + type="ok") + + continue + + installer.log.info("User selected "%s"" % storage.clearDisks) + break + + return INSTALL_OK + +def reviewlayoutWindow(installer): + if installer.dispatch.dir == DISPATCH_BACK: + return DISPATCH_NOOP + + rc = installer.intf.messageWindow(_("Review Partition Layout"), + _("Review and modify partitioning layout?"), + type = "yesno") + if rc != 1: + #installer.dispatch.skipStep("partition", skip=1) + pass + + return INSTALL_OK + +def bootloaderWindow(installer): + bootloaders = [ _("Use Grand unified bootloader"), _("Install no bootloader"),] + default = bootloaders[0] # first should a bootloader + + (button, choice) = ListboxChoiceWindow(installer.intf.screen, + _("Bootloader"), + _("Which bootloader do you want to install?\n\n" + "NOTE: If you don't choose a bootloader the system " + "might not be bootable!"), + bootloaders, buttons = [TEXT_OK_BUTTON, TEXT_BACK_BUTTON], + width = 60, default=default, height = len(bootloaders)) + + if button == TEXT_BACK_CHECK: + return INSTALL_BACK + + installer.log.info("User has chosen "%s"" % bootloaders[choice]) + # XXX skip step installbootloader here + + return INSTALL_OK diff --git a/pkgs/core/pomona/src/zonetab.py b/pkgs/core/pomona/src/zonetab.py deleted file mode 100644 index 767cc72..0000000 --- a/pkgs/core/pomona/src/zonetab.py +++ /dev/null @@ -1,119 +0,0 @@ -# -*- coding: utf-8 -*- -# -# zonetab.py: time zone classes -# -# Copyright 2001-2003,2005-2007 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, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Authors: -# Matt Wilson msw@redhat.com -# Brent Fox bfox@redhat.com -# Nils Philippsen nphilipp@redhat.com - -import string -import re -import math - -class ZoneTabEntry: - def __init__(self, code=None, lat=None, long=None, tz=None, comments=None): - self.code = code - self.lat = lat - self.long = long - self.tz = tz.replace('_', ' ') - self.comments = comments - -class ZoneTab: - def __init__ (self, fn='/usr/share/zoneinfo/zone.tab'): - self.entries = [] - self.readZoneTab(fn) - self.addNoGeoZones () - - def getEntries (self): - return self.entries - - def findEntryByTZ (self, tz): - for entry in self.entries: - if entry.tz == tz: - return entry - return None - - def findNearest(self, long, lat, longmin, latmin, longmax, latmax, currentEntry): - #print "findNearest: long:%.1f lat:%.1f longmin:%.1f longmax:%.1f latmin:%.1f latmax:%.1f currentEntry:%s" % (long, lat, longmin, longmax, longmax, latmax, currentEntry) - nearestEntry = None - if longmin <= long <= longmax and latmin <= lat <= latmax: - min = -1 - for entry in filter(lambda x: x.tz != currentEntry.tz, self.entries): - if not (entry.lat and entry.long and latmin <= entry.lat <= latmax and longmin <= entry.long <= longmax): - continue - dx = entry.long - long - dy = entry.lat - lat - dist = (dy * dy) + (dx * dx) - if dist < min or min == -1: - min = dist - nearestEntry = entry - return nearestEntry - - def convertCoord(self, coord, type="lat"): - if type != "lat" and type != "long": - raise TypeError, "invalid coord type" - if type == "lat": - deg = 3 - else: - deg = 4 - degrees = string.atoi(coord[0:deg]) - order = len (coord[deg:]) - minutes = string.atoi(coord[deg:]) - if degrees > 0: - return degrees + minutes/math.pow(10, order) - return degrees - minutes/math.pow(10, order) - - def readZoneTab(self, fn): - f = open(fn, 'r') - comment = re.compile("^#") - coordre = re.compile("[+-]") - while 1: - line = f.readline() - if not line: - break - if comment.search(line): - continue - fields = string.split(line, '\t') - if len (fields) < 3: - continue - code = fields[0] - split = coordre.search(fields[1], 1) - lat = self.convertCoord(fields[1][:split.end () - 1], "lat") - long = self.convertCoord(fields[1][split.end () - 1:], "long") - tz = string.strip(fields[2]).replace ('_', ' ') - if len(fields) > 3: - comments = string.strip(fields[3]) - else: - comments = None - entry = ZoneTabEntry(code, lat, long, tz, comments) - self.entries.append(entry) - - def addNoGeoZones(self): - nogeotzs = ['UTC'] - for offset in xrange(-14, 13): - if offset < 0: - tz = 'GMT%d' % offset - elif offset > 0: - tz = 'GMT+%d' % offset - else: - tz = 'GMT' - nogeotzs.append(tz) - for tz in nogeotzs: - self.entries.append(ZoneTabEntry (None, None, None, "Etc/" + tz, None)) diff --git a/pkgs/core/python-pyblock/python-pyblock.nm b/pkgs/core/python-pyblock/python-pyblock.nm index c44c993..a6a8912 100644 --- a/pkgs/core/python-pyblock/python-pyblock.nm +++ b/pkgs/core/python-pyblock/python-pyblock.nm @@ -25,7 +25,7 @@ include $(PKGROOT)/Include
PKG_NAME = pyblock -PKG_VER = 0.42 +PKG_VER = 0.46 PKG_REL = 0
PKG_MAINTAINER = @@ -40,15 +40,15 @@ define PKG_DESCRIPTION The pyblock contains Python modules for dealing with block devices. endef
-PKG_TARBALL = $(THISAPP).tar.gz - -DIR_APP = $(DIR_SRC)/$(PKG_NAME) +PKG_TARBALL = $(THISAPP).tar.bz2
define STAGE_PREPARE_CMDS cd $(DIR_APP) && sed -e "s/-Werror//g" -i Makefile endef
-STAGE_BUILD = # Nothing to do +define STAGE_BUILD + cd $(DIR_APP) && make USESELINUX=0 +endef
define STAGE_INSTALL cd $(DIR_APP) && make install USESELINUX=0 DESTDIR=$(BUILDROOT) diff --git a/pkgs/core/udev/udev.nm b/pkgs/core/udev/udev.nm index c0b9e9a..af19411 100644 --- a/pkgs/core/udev/udev.nm +++ b/pkgs/core/udev/udev.nm @@ -34,8 +34,7 @@ PKG_URL = ftp://ftp.kernel.org/pub/linux/utils/kernel/hotplug/ PKG_LICENSE = GPLv2+ PKG_SUMMARY = A userspace implementation of devfs.
-PKG_BUILD_DEPS+= gobject-introspection -PKG_DEPS += acl gperf libusb-compat pciutils usbutils util-linux-ng +PKG_DEPS += acl glib2 gperf kbd libusb-compat pciutils usbutils util-linux-ng
define PKG_DESCRIPTION The udev package contains an implementation of devfs in userspace using \ @@ -50,7 +49,7 @@ CONFIGURE_OPTIONS += \ --sysconfdir=/etc \ --libexecdir=/lib/udev \ --with-rootlibdir=/lib \ - --enable-introspection + --disable-introspection
define STAGE_INSTALL_CMDS # Install rules @@ -68,4 +67,15 @@ define STAGE_INSTALL_CMDS $(BUILDROOT)/usr/lib/ConsoleKit/run-seat.d/udev-acl.ck
install -m 755 $(DIR_SOURCE)/console_init $(BUILDROOT)/lib/udev/ + + # Finally, install some essential devnodes + install -dv $(BUILDROOT)/lib/{firmware,udev/devices/{pts,shm}} + -mknod -m0600 $(BUILDROOT)/lib/udev/devices/console c 5 1 + -mknod -m0600 $(BUILDROOT)/lib/udev/devices/kmsg c 1 11 + -mknod -m0666 $(BUILDROOT)/lib/udev/devices/null c 1 3 + ln -sfv /proc/self/fd $(BUILDROOT)/lib/udev/devices/fd + ln -sfv /proc/self/fd/0 $(BUILDROOT)/lib/udev/devices/stdin + ln -sfv /proc/self/fd/1 $(BUILDROOT)/lib/udev/devices/stdout + ln -sfv /proc/self/fd/2 $(BUILDROOT)/lib/udev/devices/stderr + ln -sfv /proc/kcore $(BUILDROOT)/lib/udev/devices/core endef diff --git a/pkgs/core/upstart/upstart.nm b/pkgs/core/upstart/upstart.nm index 7aaa1bd..3605d02 100644 --- a/pkgs/core/upstart/upstart.nm +++ b/pkgs/core/upstart/upstart.nm @@ -35,7 +35,7 @@ PKG_LICENSE = GPLv2+ PKG_SUMMARY = An event-driven init system.
PKG_BUILD_DEPS+= pkg-config -PKG_DEPS += dbus libnih +PKG_DEPS += dbus libnih sysvinit
define PKG_DESCRIPTION Upstart is an event-based replacement for the /sbin/init daemon \ diff --git a/src/install/etc/group b/src/install/etc/group new file mode 100644 index 0000000..ef7dd45 --- /dev/null +++ b/src/install/etc/group @@ -0,0 +1,33 @@ +root:x:0:root +bin:x:1:bin,daemon,root +daemon:x:2:bin,daemon,root +sys:x:3:bin,adm,root +adm:x:4:adm,daemon,root +tty:x:5: +disk:x:6:root +lp:x:7:daemon,lp +mem:x:8: +kmem:x:9: +wheel:x:10:root +mail:x:12:mail +news:x:13:news +uucp:x:14:uucp +man:x:15: +games:x:20: +gopher:x:30: +dip:x:40: +ftp:x:50: +lock:x:54: +nobody:x:99: +users:x:100: +dbus:x:81: +utmp:x:22: +smmsp:x:51: +nscd:x:28: +floppy:x:19: +rpc:x:32: +sshd:x:74: +pcap:x:77: +utempter:x:35: +ntp:x:38: +audio:x:63: diff --git a/src/install/etc/passwd b/src/install/etc/passwd new file mode 100644 index 0000000..eb141ce --- /dev/null +++ b/src/install/etc/passwd @@ -0,0 +1,22 @@ +root:x:0:0:root:/root:/bin/bash +bin:x:1:1:bin:/bin:/sbin/nologin +daemon:x:2:2:daemon:/sbin:/sbin/nologin +adm:x:3:4:adm:/var/adm:/sbin/nologin +lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin +sync:x:5:0:sync:/sbin:/bin/sync +shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown +halt:x:7:0:halt:/sbin:/sbin/halt +mail:x:8:12:mail:/var/spool/mail:/sbin/nologin +news:x:9:13:news:/etc/news: +uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin +operator:x:11:0:operator:/root:/sbin/nologin +games:x:12:100:games:/usr/games:/sbin/nologin +gopher:x:13:30:gopher:/var/gopher:/sbin/nologin +ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin +nobody:x:99:99:Nobody:/:/sbin/nologin +dbus:x:81:81:System message bus:/:/sbin/nologin +smmsp:x:51:51::/var/spool/mqueue:/sbin/nologin +nscd:x:28:28:NSCD Daemon:/:/sbin/nologin +rpc:x:32:32:Portmapper RPC user:/:/sbin/nologin +sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin +ntp:x:38:38::/etc/ntp:/sbin/nologin diff --git a/src/install/root/.bash_profile b/src/install/root/.bash_profile index 673c4cb..00680d6 100644 --- a/src/install/root/.bash_profile +++ b/src/install/root/.bash_profile @@ -38,7 +38,7 @@ done
if [ "$mode" = "install" ] && [[ "$(tty)" =~ "tty1" ]]; then if [ "$debug" == "on" ]; then - command="strace -ff -F -o /tmp/strace.log $command --debug" + command="$command --debug" fi exec $command fi diff --git a/tools/compressor b/tools/compressor index 659b28c..c6b9d46 100755 --- a/tools/compressor +++ b/tools/compressor @@ -33,7 +33,7 @@ function isDir() { }
function isFile() { - [ -f "${1}" ] || [ -h "${1}" ] + [ -f "${1}" ] || [ -h "${1}" ] || [ -b "${1}" ] || [ -c "${1}" ] }
function add() { diff --git a/tools/generator b/tools/generator index 14ec56c..38b72da 100755 --- a/tools/generator +++ b/tools/generator @@ -84,7 +84,12 @@ make_installer() {
rm -rf /installer/usr/include
- mksquashfs * ${dest}/installer.img -no-progress + for dir in dev proc sys; do + mkdir -p ${dir} 2>/dev/null + done + install -dv -m 1777 tmp var/tmp + + mksquashfs * ${dest}/installer.sfs -no-progress
popd } diff --git a/tools/py-compile b/tools/py-compile index 096c3d6..66c33ed 100755 --- a/tools/py-compile +++ b/tools/py-compile @@ -26,11 +26,11 @@ import sys, os, string, py_compile files = '''$files''' print 'Byte-compiling python modules...' for file in string.split(files): - if not os.path.exists(path) or not (len(path) >= 3 and path[-3:] == '.py'): + if not os.path.exists(file) or not (len(file) >= 3 and file[-3:] == '.py'): continue print file, sys.stdout.flush() - py_compile.compile(path) + py_compile.compile(file) print" || exit $?
# this will fail for python < 1.5, but that doesn't matter ... @@ -40,9 +40,9 @@ import sys, os, string, py_compile files = '''$files''' print 'Byte-compiling python modules (optimised versions) ...' for file in string.split(files): - if not os.path.exists(path) or not (len(path) >= 3 and path[-3:] == '.py'): + if not os.path.exists(file) or not (len(file) >= 3 and file[-3:] == '.py'): continue print file, sys.stdout.flush() - py_compile.compile(path) + py_compile.compile(file) print" 2>/dev/null || : diff --git a/tools/quality-agent.d/002-bad-symlinks b/tools/quality-agent.d/002-bad-symlinks index e05fc82..7c8678f 100755 --- a/tools/quality-agent.d/002-bad-symlinks +++ b/tools/quality-agent.d/002-bad-symlinks @@ -9,6 +9,10 @@ log_debug "Search for absolute symlinks"
failed=0 for link in $(find ${BUILDROOT} -type l); do + if fgrep -q "/lib/udev/devices" <<<${link}; then + continue + fi + destination=$(readlink ${link}) if [ "${destination:0:1}" = "/" ]; then log_error " absolute symlink: ${link}"
hooks/post-receive -- IPFire 3.x development tree