neil / rpms / anaconda

Forked from rpms/anaconda a year ago
Clone
fbcaed
From 74d70fcd113ca0622959e272cb78cedc6509fbef Mon Sep 17 00:00:00 2001
fbcaed
From: Colin Walters <walters@verbum.org>
fbcaed
Date: Tue, 22 Apr 2014 14:39:26 -0400
fbcaed
Subject: [PATCH 04/20] iutil: Introduce getSysroot()/getTargetPhysicalRoot(),
fbcaed
 use instead of ROOT_PATH
fbcaed
fbcaed
For OSTree, the OS lives in a chroot, thus creating a distinction
fbcaed
between the "physical" root and the "deployment" root.  The physical
fbcaed
root as mounted by anaconda remains as /mnt/sysimage of course, but
fbcaed
*nearly* everything needs to reference the deployment, as that's where
fbcaed
the binaries, config files, etc live.
fbcaed
fbcaed
The deployment root is dynamic - we only know it after we do an
fbcaed
initial installation what the path will be.  This dynamic nature means
fbcaed
that the API is best as a function call.
fbcaed
fbcaed
Resolves: rhbz#1113535
fbcaed
Port of rpmostreepayload patches from master
fbcaed
commit 1b260c0c3ca70b53d44b543babe1a5ab06fb5fb5
fbcaed
---
fbcaed
 pyanaconda/__init__.py              |  6 +--
fbcaed
 pyanaconda/bootloader.py            | 96 +++++++++++++++++--------------------
fbcaed
 pyanaconda/constants.py             |  2 +
fbcaed
 pyanaconda/desktop.py               | 10 ++--
fbcaed
 pyanaconda/exception.py             | 10 ++--
fbcaed
 pyanaconda/install.py               |  6 +--
fbcaed
 pyanaconda/installclasses/fedora.py |  8 ++--
fbcaed
 pyanaconda/installclasses/rhel.py   |  3 +-
fbcaed
 pyanaconda/iutil.py                 | 48 ++++++++++++++++++-
fbcaed
 pyanaconda/kickstart.py             | 51 ++++++++++----------
fbcaed
 pyanaconda/packaging/__init__.py    | 40 ++++++++--------
fbcaed
 pyanaconda/packaging/livepayload.py | 25 +++++-----
fbcaed
 pyanaconda/packaging/tarpayload.py  |  2 +-
fbcaed
 pyanaconda/packaging/yumpayload.py  | 12 ++---
fbcaed
 pyanaconda/rescue.py                | 16 +++----
fbcaed
 pyanaconda/users.py                 |  7 ++-
fbcaed
 16 files changed, 187 insertions(+), 155 deletions(-)
fbcaed
fbcaed
diff --git a/pyanaconda/__init__.py b/pyanaconda/__init__.py
fbcaed
index 9b58f92..fad7a90 100644
fbcaed
--- a/pyanaconda/__init__.py
fbcaed
+++ b/pyanaconda/__init__.py
fbcaed
@@ -30,11 +30,11 @@
fbcaed
 
fbcaed
 import os, time, string
fbcaed
 import sys
fbcaed
-from constants import ROOT_PATH
fbcaed
 from tempfile import mkstemp
fbcaed
 
fbcaed
 from pyanaconda.bootloader import get_bootloader
fbcaed
 from pyanaconda import constants
fbcaed
+from pyanaconda import iutil
fbcaed
 from pyanaconda import addons
fbcaed
 from pyanaconda.i18n import _
fbcaed
 
fbcaed
@@ -228,7 +228,7 @@ class Anaconda(object):
fbcaed
         if self.xdriver is None:
fbcaed
             return
fbcaed
         if root is None:
fbcaed
-            root = ROOT_PATH
fbcaed
+            root = iutil.getSysroot()
fbcaed
         if not os.path.isdir("%s/etc/X11" %(root,)):
fbcaed
             os.makedirs("%s/etc/X11" %(root,), mode=0755)
fbcaed
         f = open("%s/etc/X11/xorg.conf" %(root,), 'w')
fbcaed
@@ -241,7 +241,7 @@ class Anaconda(object):
fbcaed
 
fbcaed
         network.write_sysconfig_network()
fbcaed
         network.disableIPV6()
fbcaed
-        network.copyConfigToPath(ROOT_PATH)
fbcaed
+        network.copyConfigToPath(iutil.getSysroot())
fbcaed
         if not self.ksdata:
fbcaed
             self.instClass.setNetworkOnbootDefault()
fbcaed
         self.desktop.write()
fbcaed
diff --git a/pyanaconda/bootloader.py b/pyanaconda/bootloader.py
fbcaed
index 2fc1d49..90aec61 100644
fbcaed
--- a/pyanaconda/bootloader.py
fbcaed
+++ b/pyanaconda/bootloader.py
fbcaed
@@ -34,7 +34,6 @@ from blivet.devicelibs import mdraid
fbcaed
 from pyanaconda.isys import sync
fbcaed
 from pyanaconda.product import productName
fbcaed
 from pyanaconda.flags import flags
fbcaed
-from pyanaconda.constants import *
fbcaed
 from blivet.errors import StorageError
fbcaed
 from blivet.fcoe import fcoe
fbcaed
 import pyanaconda.network
fbcaed
@@ -929,19 +928,19 @@ class BootLoader(object):
fbcaed
 
fbcaed
     def write_config_post(self):
fbcaed
         try:
fbcaed
-            os.chmod(ROOT_PATH + self.config_file, self.config_file_mode)
fbcaed
+            os.chmod(iutil.getSysroot() + self.config_file, self.config_file_mode)
fbcaed
         except OSError as e:
fbcaed
             log.error("failed to set config file permissions: %s" % e)
fbcaed
 
fbcaed
     def add_crash_args(self):
fbcaed
         buf = ""
fbcaed
-        if os.access("%s%s" % (ROOT_PATH, "/usr/sbin/rhcrashkernel-param"), \
fbcaed
+        if os.access("%s%s" % (iutil.getSysroot(), "/usr/sbin/rhcrashkernel-param"), \
fbcaed
                      os.X_OK):
fbcaed
             (pread, pwrite) = os.pipe()
fbcaed
             os.close(pwrite)
fbcaed
             buf = iutil.execWithCapture("/usr/sbin/rhcrashkernel-param", [],
fbcaed
                                         stdin=pread,
fbcaed
-                                        root=ROOT_PATH)
fbcaed
+                                        root=iutil.getSysroot())
fbcaed
             os.close(pread)
fbcaed
         self.boot_args.add(buf.replace('\n', ' '))
fbcaed
 
fbcaed
@@ -952,7 +951,7 @@ class BootLoader(object):
fbcaed
 
fbcaed
         self.add_crash_args()
fbcaed
 
fbcaed
-        config_path = os.path.normpath(ROOT_PATH + self.config_file)
fbcaed
+        config_path = os.path.normpath(iutil.getSysroot() + self.config_file)
fbcaed
         if os.access(config_path, os.R_OK):
fbcaed
             os.rename(config_path, config_path + ".anacbak")
fbcaed
 
fbcaed
@@ -988,7 +987,7 @@ class BootLoader(object):
fbcaed
 
fbcaed
         self.write_config()
fbcaed
         sync()
fbcaed
-        self.stage2_device.format.sync(root=ROOT_PATH)
fbcaed
+        self.stage2_device.format.sync(root=iutil.getTargetPhysicalRoot())
fbcaed
         self.install()
fbcaed
 
fbcaed
     def install(self):
fbcaed
@@ -1180,7 +1179,7 @@ class GRUB(BootLoader):
fbcaed
 
fbcaed
         if iutil.isConsoleOnVirtualTerminal(self.console):
fbcaed
             splash = "splash.xpm.gz"
fbcaed
-            splash_path = os.path.normpath("%s/boot/%s/%s" % (ROOT_PATH,
fbcaed
+            splash_path = os.path.normpath("%s/boot/%s/%s" % (iutil.getSysroot(),
fbcaed
                                                         self.splash_dir,
fbcaed
                                                         splash))
fbcaed
             if os.access(splash_path, os.R_OK):
fbcaed
@@ -1233,7 +1232,7 @@ class GRUB(BootLoader):
fbcaed
 
fbcaed
     def write_device_map(self):
fbcaed
         """ Write out a device map containing all supported devices. """
fbcaed
-        map_path = os.path.normpath(ROOT_PATH + self.device_map_file)
fbcaed
+        map_path = os.path.normpath(iutil.getSysroot() + self.device_map_file)
fbcaed
         if os.access(map_path, os.R_OK):
fbcaed
             os.rename(map_path, map_path + ".anacbak")
fbcaed
 
fbcaed
@@ -1249,7 +1248,7 @@ class GRUB(BootLoader):
fbcaed
         super(GRUB, self).write_config_post()
fbcaed
 
fbcaed
         # make symlink for menu.lst (grub's default config file name)
fbcaed
-        menu_lst = "%s%s/menu.lst" % (ROOT_PATH, self.config_dir)
fbcaed
+        menu_lst = "%s%s/menu.lst" % (iutil.getSysroot(), self.config_dir)
fbcaed
         if os.access(menu_lst, os.R_OK):
fbcaed
             try:
fbcaed
                 os.rename(menu_lst, menu_lst + '.anacbak')
fbcaed
@@ -1262,7 +1261,7 @@ class GRUB(BootLoader):
fbcaed
             log.error("failed to create grub menu.lst symlink: %s" % e)
fbcaed
 
fbcaed
         # make symlink to grub.conf in /etc since that's where configs belong
fbcaed
-        etc_grub = "%s/etc/%s" % (ROOT_PATH, self._config_file)
fbcaed
+        etc_grub = "%s/etc/%s" % (iutil.getSysroot(), self._config_file)
fbcaed
         if os.access(etc_grub, os.R_OK):
fbcaed
             try:
fbcaed
                 os.unlink(etc_grub)
fbcaed
@@ -1320,9 +1319,8 @@ class GRUB(BootLoader):
fbcaed
 
fbcaed
         return targets
fbcaed
 
fbcaed
-    def install(self):
fbcaed
-        rc = iutil.execWithRedirect("grub-install", ["--just-copy"],
fbcaed
-                                    root=ROOT_PATH)
fbcaed
+    def install(self, args=None):
fbcaed
+        rc = iutil.execInSysroot("grub-install", ["--just-copy"])
fbcaed
         if rc:
fbcaed
             raise BootLoaderError("bootloader install failed")
fbcaed
 
fbcaed
@@ -1342,8 +1340,7 @@ class GRUB(BootLoader):
fbcaed
             os.close(pwrite)
fbcaed
             args = ["--batch", "--no-floppy",
fbcaed
                     "--device-map=%s" % self.device_map_file]
fbcaed
-            rc = iutil.execWithRedirect("grub", args,
fbcaed
-                                        stdin=pread, root=ROOT_PATH)
fbcaed
+            rc = iutil.execInSysroot("grub", args, stdin=pread)
fbcaed
             os.close(pread)
fbcaed
             if rc:
fbcaed
                 raise BootLoaderError("bootloader install failed")
fbcaed
@@ -1452,7 +1449,7 @@ class GRUB2(GRUB):
fbcaed
 
fbcaed
     def write_device_map(self):
fbcaed
         """ Write out a device map containing all supported devices. """
fbcaed
-        map_path = os.path.normpath(ROOT_PATH + self.device_map_file)
fbcaed
+        map_path = os.path.normpath(iutil.getSysroot() + self.device_map_file)
fbcaed
         if os.access(map_path, os.R_OK):
fbcaed
             os.rename(map_path, map_path + ".anacbak")
fbcaed
 
fbcaed
@@ -1477,7 +1474,7 @@ class GRUB2(GRUB):
fbcaed
         dev_map.close()
fbcaed
 
fbcaed
     def write_defaults(self):
fbcaed
-        defaults_file = "%s%s" % (ROOT_PATH, self.defaults_file)
fbcaed
+        defaults_file = "%s%s" % (iutil.getSysroot(), self.defaults_file)
fbcaed
         defaults = open(defaults_file, "w+")
fbcaed
         defaults.write("GRUB_TIMEOUT=%d\n" % self.timeout)
fbcaed
         defaults.write("GRUB_DISTRIBUTOR=\"$(sed 's, release .*$,,g' /etc/system-release)\"\n")
fbcaed
@@ -1511,7 +1508,7 @@ class GRUB2(GRUB):
fbcaed
         os.close(pwrite)
fbcaed
         buf = iutil.execWithCapture("grub2-mkpasswd-pbkdf2", [],
fbcaed
                                     stdin=pread,
fbcaed
-                                    root=ROOT_PATH)
fbcaed
+                                    root=iutil.getSysroot())
fbcaed
         os.close(pread)
fbcaed
         self.encrypted_password = buf.split()[-1].strip()
fbcaed
         if not self.encrypted_password.startswith("grub.pbkdf2."):
fbcaed
@@ -1521,7 +1518,7 @@ class GRUB2(GRUB):
fbcaed
         if not self.password and not self.encrypted_password:
fbcaed
             return
fbcaed
 
fbcaed
-        users_file = ROOT_PATH + "/etc/grub.d/01_users"
fbcaed
+        users_file = iutil.getSysroot() + "/etc/grub.d/01_users"
fbcaed
         header = open(users_file, "w")
fbcaed
         header.write("#!/bin/sh -e\n\n")
fbcaed
         header.write("cat << \"EOF\"\n")
fbcaed
@@ -1555,16 +1552,13 @@ class GRUB2(GRUB):
fbcaed
         # make sure the default entry is the OS we are installing
fbcaed
         entry_title = "%s Linux, with Linux %s" % (productName,
fbcaed
                                                    self.default.version)
fbcaed
-        rc = iutil.execWithRedirect("grub2-set-default",
fbcaed
-                                    [entry_title],
fbcaed
-                                    root=ROOT_PATH)
fbcaed
+        rc = iutil.execInSysroot("grub2-set-default", [entry_title])
fbcaed
         if rc:
fbcaed
             log.error("failed to set default menu entry to %s" % productName)
fbcaed
 
fbcaed
         # now tell grub2 to generate the main configuration file
fbcaed
-        rc = iutil.execWithRedirect("grub2-mkconfig",
fbcaed
-                                    ["-o", self.config_file],
fbcaed
-                                    root=ROOT_PATH)
fbcaed
+        rc = iutil.execInSysroot("grub2-mkconfig",
fbcaed
+                                 ["-o", self.config_file])
fbcaed
         if rc:
fbcaed
             raise BootLoaderError("failed to write bootloader configuration")
fbcaed
 
fbcaed
@@ -1585,7 +1579,7 @@ class GRUB2(GRUB):
fbcaed
                 grub_args.insert(0, '--force')
fbcaed
 
fbcaed
             rc = iutil.execWithRedirect("grub2-install", grub_args,
fbcaed
-                                        root=ROOT_PATH,
fbcaed
+                                        root=iutil.getSysroot(),
fbcaed
                                         env_prune=['MALLOC_PERTURB_'])
fbcaed
             if rc:
fbcaed
                 raise BootLoaderError("bootloader install failed")
fbcaed
@@ -1600,14 +1594,14 @@ class GRUB2(GRUB):
fbcaed
             return
fbcaed
 
fbcaed
         self.write_device_map()
fbcaed
-        self.stage2_device.format.sync(root=ROOT_PATH)
fbcaed
+        self.stage2_device.format.sync(root=iutil.getTargetPhysicalRoot())
fbcaed
         sync()
fbcaed
         self.install()
fbcaed
         sync()
fbcaed
-        self.stage2_device.format.sync(root=ROOT_PATH)
fbcaed
+        self.stage2_device.format.sync(root=iutil.getTargetPhysicalRoot())
fbcaed
         self.write_config()
fbcaed
         sync()
fbcaed
-        self.stage2_device.format.sync(root=ROOT_PATH)
fbcaed
+        self.stage2_device.format.sync(root=iutil.getTargetPhysicalRoot())
fbcaed
 
fbcaed
     def check(self):
fbcaed
         """ When installing to the mbr of a disk grub2 needs enough space
fbcaed
@@ -1676,7 +1670,7 @@ class EFIGRUB(GRUB2):
fbcaed
         else:
fbcaed
             exec_func = iutil.execWithRedirect
fbcaed
         if "root" not in kwargs:
fbcaed
-            kwargs["root"] = ROOT_PATH
fbcaed
+            kwargs["root"] = iutil.getSysroot()
fbcaed
 
fbcaed
         return exec_func("efibootmgr", list(args), **kwargs)
fbcaed
 
fbcaed
@@ -1722,7 +1716,8 @@ class EFIGRUB(GRUB2):
fbcaed
         rc = self.efibootmgr("-c", "-w", "-L", productName,
fbcaed
                              "-d", boot_disk.path, "-p", boot_part_num,
fbcaed
                              "-l",
fbcaed
-                             self.efi_dir_as_efifs_dir + self._efi_binary)
fbcaed
+                             self.efi_dir_as_efifs_dir + self._efi_binary,
fbcaed
+                             root=iutil.getSysroot())
fbcaed
         if rc:
fbcaed
             raise BootLoaderError("failed to set new efi boot target")
fbcaed
 
fbcaed
@@ -1747,7 +1742,7 @@ class EFIGRUB(GRUB2):
fbcaed
             return
fbcaed
 
fbcaed
         sync()
fbcaed
-        self.stage2_device.format.sync(root=ROOT_PATH)
fbcaed
+        self.stage2_device.format.sync(root=iutil.getTargetPhysicalRoot())
fbcaed
         self.install()
fbcaed
         self.write_config()
fbcaed
 
fbcaed
@@ -1765,9 +1760,8 @@ class Aarch64EFIGRUB(EFIGRUB):
fbcaed
 
fbcaed
 class MacEFIGRUB(EFIGRUB):
fbcaed
     def mactel_config(self):
fbcaed
-        if os.path.exists(ROOT_PATH + "/usr/libexec/mactel-boot-setup"):
fbcaed
-            rc = iutil.execWithRedirect("/usr/libexec/mactel-boot-setup", [],
fbcaed
-                                        root=ROOT_PATH)
fbcaed
+        if os.path.exists(iutil.getSysroot() + "/usr/libexec/mactel-boot-setup"):
fbcaed
+            rc = iutil.execInSysroot("/usr/libexec/mactel-boot-setup", [])
fbcaed
             if rc:
fbcaed
                 log.error("failed to configure Mac bootloader")
fbcaed
 
fbcaed
@@ -1881,7 +1875,7 @@ class Yaboot(YabootBase):
fbcaed
         super(Yaboot, self).write_config_post()
fbcaed
 
fbcaed
         # make symlink in /etc to yaboot.conf if config is in /boot/etc
fbcaed
-        etc_yaboot_conf = ROOT_PATH + "/etc/yaboot.conf"
fbcaed
+        etc_yaboot_conf = iutil.getSysroot() + "/etc/yaboot.conf"
fbcaed
         if not os.access(etc_yaboot_conf, os.R_OK):
fbcaed
             try:
fbcaed
                 os.symlink("../boot/etc/yaboot.conf", etc_yaboot_conf)
fbcaed
@@ -1889,8 +1883,8 @@ class Yaboot(YabootBase):
fbcaed
                 log.error("failed to create /etc/yaboot.conf symlink: %s" % e)
fbcaed
 
fbcaed
     def write_config(self):
fbcaed
-        if not os.path.isdir(ROOT_PATH + self.config_dir):
fbcaed
-            os.mkdir(ROOT_PATH + self.config_dir)
fbcaed
+        if not os.path.isdir(iutil.getSysroot() + self.config_dir):
fbcaed
+            os.mkdir(iutil.getSysroot() + self.config_dir)
fbcaed
 
fbcaed
         # this writes the config
fbcaed
         super(Yaboot, self).write_config()
fbcaed
@@ -1901,8 +1895,7 @@ class Yaboot(YabootBase):
fbcaed
 
fbcaed
     def install(self):
fbcaed
         args = ["-f", "-C", self.config_file]
fbcaed
-        rc = iutil.execWithRedirect(self.prog, args,
fbcaed
-                                    root=ROOT_PATH)
fbcaed
+        rc = iutil.execInSysroot(self.prog, args)
fbcaed
         if rc:
fbcaed
             raise BootLoaderError("bootloader installation failed")
fbcaed
 
fbcaed
@@ -2027,7 +2020,7 @@ class IPSeriesGRUB2(GRUB2):
fbcaed
     def write_defaults(self):
fbcaed
         super(IPSeriesGRUB2, self).write_defaults()
fbcaed
 
fbcaed
-        defaults_file = "%s%s" % (ROOT_PATH, self.defaults_file)
fbcaed
+        defaults_file = "%s%s" % (iutil.getSysroot(), self.defaults_file)
fbcaed
         defaults = open(defaults_file, "a+")
fbcaed
         # The terminfo's X and Y size, and output location could change in the future
fbcaed
         defaults.write("GRUB_TERMINFO=\"terminfo -g 80x24 console\"\n")
fbcaed
@@ -2142,10 +2135,8 @@ class ZIPL(BootLoader):
fbcaed
     # installation
fbcaed
     #
fbcaed
 
fbcaed
-    def install(self):
fbcaed
-        buf = iutil.execWithCapture("zipl", [],
fbcaed
-                                    root=ROOT_PATH,
fbcaed
-                                    fatal=True)
fbcaed
+    def install(self, args=None):
fbcaed
+        buf = iutil.execWithCapture("zipl", [], root=iutil.getSysroot(), fatal=True)
fbcaed
         for line in buf.splitlines():
fbcaed
             if line.startswith("Preparing boot device: "):
fbcaed
                 # Output here may look like:
fbcaed
@@ -2192,7 +2183,7 @@ class UBOOT(BootLoader):
fbcaed
     def install(self):
fbcaed
         # a-b-c is a tool that generates a generic boor.scr that works in most situations.
fbcaed
         # not perfect but is better than doing nothing
fbcaed
-        rc = iutil.execWithRedirect("a-b-c", [], root=ROOT_PATH)
fbcaed
+        rc = iutil.execWithRedirect("a-b-c", [], root=iutil.getSysroot())
fbcaed
 
fbcaed
         if rc:
fbcaed
             raise BootLoaderError("bootloader install failed")
fbcaed
@@ -2274,7 +2265,7 @@ class EXTLINUX(BootLoader):
fbcaed
             config.write("menu notabmsg Press [Tab] and enter the password to edit options")
fbcaed
 
fbcaed
     def write_config_post(self):
fbcaed
-        etc_extlinux = os.path.normpath(ROOT_PATH + "/etc/" + self._config_file)
fbcaed
+        etc_extlinux = os.path.normpath(iutil.getSysroot() + "/etc/" + self._config_file)
fbcaed
         if not os.access(etc_extlinux, os.R_OK):
fbcaed
             try:
fbcaed
                 os.symlink("../boot/%s" % self._config_file, etc_extlinux)
fbcaed
@@ -2291,8 +2282,7 @@ class EXTLINUX(BootLoader):
fbcaed
     def install(self):
fbcaed
         backup = "%s/backup.b" % self._config_dir
fbcaed
         args = ["--install", self._config_dir]
fbcaed
-        rc = iutil.execWithRedirect("extlinux", args,
fbcaed
-                                    root=ROOT_PATH)
fbcaed
+        rc = iutil.execInSysroot("extlinux", args)
fbcaed
 
fbcaed
         if rc:
fbcaed
             raise BootLoaderError("bootloader install failed")
fbcaed
@@ -2326,9 +2316,9 @@ def writeSysconfigKernel(storage, version):
fbcaed
     # get the name of the default kernel package based on the version
fbcaed
     kernel_basename = "vmlinuz-" + version
fbcaed
     kernel_file = "/boot/%s" % kernel_basename
fbcaed
-    if not os.path.isfile(ROOT_PATH + kernel_file):
fbcaed
+    if not os.path.isfile(iutil.getSysroot() + kernel_file):
fbcaed
         kernel_file = "/boot/efi/EFI/redhat/%s" % kernel_basename
fbcaed
-        if not os.path.isfile(ROOT_PATH + kernel_file):
fbcaed
+        if not os.path.isfile(iutil.getSysroot() + kernel_file):
fbcaed
             log.error("failed to recreate path to default kernel image")
fbcaed
             return
fbcaed
 
fbcaed
@@ -2338,7 +2328,7 @@ def writeSysconfigKernel(storage, version):
fbcaed
         log.error("failed to import rpm python module")
fbcaed
         return
fbcaed
 
fbcaed
-    ts = rpm.TransactionSet(ROOT_PATH)
fbcaed
+    ts = rpm.TransactionSet(iutil.getSysroot())
fbcaed
     mi = ts.dbMatch('basenames', kernel_file)
fbcaed
     try:
fbcaed
         h = mi.next()
fbcaed
@@ -2348,7 +2338,7 @@ def writeSysconfigKernel(storage, version):
fbcaed
 
fbcaed
     kernel = h.name
fbcaed
 
fbcaed
-    f = open(ROOT_PATH + "/etc/sysconfig/kernel", "w+")
fbcaed
+    f = open(iutil.getSysroot() + "/etc/sysconfig/kernel", "w+")
fbcaed
     f.write("# UPDATEDEFAULT specifies if new-kernel-pkg should make\n"
fbcaed
             "# new kernels the default\n")
fbcaed
     # only update the default if we're setting the default to linux (#156678)
fbcaed
diff --git a/pyanaconda/constants.py b/pyanaconda/constants.py
fbcaed
index e864630..1d523c0 100644
fbcaed
--- a/pyanaconda/constants.py
fbcaed
+++ b/pyanaconda/constants.py
fbcaed
@@ -80,6 +80,8 @@ DD_RPMS = "/tmp/DD-*"
fbcaed
 TRANSLATIONS_UPDATE_DIR="/tmp/updates/po"
fbcaed
 
fbcaed
 ANACONDA_CLEANUP = "anaconda-cleanup"
fbcaed
+# This is a legacy variable; new code should use iutil.getSysroot()
fbcaed
+# or iutil.getTargetPhysicalRoot().
fbcaed
 ROOT_PATH = os.environ.get("ANACONDA_ROOT_PATH", "/mnt/sysimage")
fbcaed
 MOUNT_DIR = "/mnt/install"
fbcaed
 DRACUT_REPODIR = "/run/install/repo"
fbcaed
diff --git a/pyanaconda/desktop.py b/pyanaconda/desktop.py
fbcaed
index fde1dc7..c4edf2f 100644
fbcaed
--- a/pyanaconda/desktop.py
fbcaed
+++ b/pyanaconda/desktop.py
fbcaed
@@ -21,7 +21,8 @@
fbcaed
 
fbcaed
 import os
fbcaed
 from simpleconfig import SimpleConfigFile
fbcaed
-from pyanaconda.constants import ROOT_PATH, RUNLEVELS
fbcaed
+from pyanaconda.constants import RUNLEVELS
fbcaed
+from pyanaconda import iutil
fbcaed
 
fbcaed
 import logging
fbcaed
 log = logging.getLogger("anaconda")
fbcaed
@@ -51,14 +52,15 @@ class Desktop(SimpleConfigFile):
fbcaed
 
fbcaed
     def write(self):
fbcaed
         if self.getDefaultDesktop():
fbcaed
-            f = open(ROOT_PATH + "/etc/sysconfig/desktop", "w")
fbcaed
+            f = open(iutil.getSysroot() + "/etc/sysconfig/desktop", "w")
fbcaed
             f.write(str(self))
fbcaed
             f.close()
fbcaed
 
fbcaed
-        if not os.path.isdir(ROOT_PATH + '/etc/systemd/system'):
fbcaed
+        if not os.path.isdir(iutil.getSysroot() + '/etc/systemd/system'):
fbcaed
             log.warning("there is no /etc/systemd/system directory, cannot update default.target!")
fbcaed
             return
fbcaed
-        default_target = ROOT_PATH + '/etc/systemd/system/default.target'
fbcaed
+
fbcaed
+        default_target = iutil.getSysroot() + '/etc/systemd/system/default.target'
fbcaed
         if os.path.islink(default_target):
fbcaed
             os.unlink(default_target)
fbcaed
         os.symlink('/lib/systemd/system/%s' % RUNLEVELS[self.runlevel],
fbcaed
diff --git a/pyanaconda/exception.py b/pyanaconda/exception.py
fbcaed
index 861425f..fe2bb8d 100644
fbcaed
--- a/pyanaconda/exception.py
fbcaed
+++ b/pyanaconda/exception.py
fbcaed
@@ -34,7 +34,7 @@ import kickstart
fbcaed
 import blivet.errors
fbcaed
 from pyanaconda.errors import CmdlineError
fbcaed
 from pyanaconda.ui.communication import hubQ
fbcaed
-from pyanaconda.constants import ROOT_PATH, THREAD_EXCEPTION_HANDLING_TEST
fbcaed
+from pyanaconda.constants import THREAD_EXCEPTION_HANDLING_TEST
fbcaed
 from pyanaconda.threads import threadMgr
fbcaed
 from pyanaconda.i18n import _
fbcaed
 from pyanaconda import flags
fbcaed
@@ -159,12 +159,12 @@ class AnacondaExceptionHandler(ExceptionHandler):
fbcaed
         anaconda = dump_info.object
fbcaed
 
fbcaed
         # See if there is a /root present in the root path and put exception there as well
fbcaed
-        if os.access(ROOT_PATH + "/root", os.X_OK):
fbcaed
+        if os.access(iutil.getSysroot() + "/root", os.X_OK):
fbcaed
             try:
fbcaed
-                dest = ROOT_PATH + "/root/%s" % os.path.basename(self.exnFile)
fbcaed
+                dest = iutil.getSysroot() + "/root/%s" % os.path.basename(self.exnFile)
fbcaed
                 shutil.copyfile(self.exnFile, dest)
fbcaed
             except:
fbcaed
-                log.error("Failed to copy %s to %s/root" % (self.exnFile, ROOT_PATH))
fbcaed
+                log.error("Failed to copy %s to %s/root" % (self.exnFile, iutil.getSysroot()))
fbcaed
                 pass
fbcaed
 
fbcaed
         # run kickstart traceback scripts (if necessary)
fbcaed
@@ -213,7 +213,7 @@ class AnacondaExceptionHandler(ExceptionHandler):
fbcaed
 def initExceptionHandling(anaconda):
fbcaed
     fileList = [ "/tmp/anaconda.log", "/tmp/packaging.log",
fbcaed
                  "/tmp/program.log", "/tmp/storage.log", "/tmp/ifcfg.log",
fbcaed
-                 "/tmp/yum.log", ROOT_PATH + "/root/install.log",
fbcaed
+                 "/tmp/yum.log", iutil.getSysroot() + "/root/install.log",
fbcaed
                  "/proc/cmdline" ]
fbcaed
     if flags.flags.livecdInstall:
fbcaed
         fileList.extend(["/var/log/messages"])
fbcaed
diff --git a/pyanaconda/install.py b/pyanaconda/install.py
fbcaed
index 5796086..db66e78 100644
fbcaed
--- a/pyanaconda/install.py
fbcaed
+++ b/pyanaconda/install.py
fbcaed
@@ -20,12 +20,12 @@
fbcaed
 # Red Hat Author(s): Chris Lumens <clumens@redhat.com>
fbcaed
 #
fbcaed
 
fbcaed
-from pyanaconda.constants import ROOT_PATH, THREAD_PAYLOAD
fbcaed
 from blivet import turnOnFilesystems
fbcaed
 from pyanaconda.bootloader import writeBootLoader
fbcaed
 from pyanaconda.progress import progress_report, progressQ
fbcaed
 from pyanaconda.users import createLuserConf, getPassAlgo, Users
fbcaed
 from pyanaconda import flags
fbcaed
+from pyanaconda import iutil
fbcaed
 from pyanaconda import timezone
fbcaed
 from pyanaconda.i18n import _
fbcaed
 from pyanaconda.threads import threadMgr
fbcaed
@@ -35,7 +35,7 @@ log = logging.getLogger("anaconda")
fbcaed
 def _writeKS(ksdata):
fbcaed
     import os
fbcaed
 
fbcaed
-    path = ROOT_PATH + "/root/anaconda-ks.cfg"
fbcaed
+    path = iutil.getSysroot() + "/root/anaconda-ks.cfg"
fbcaed
 
fbcaed
     # Clear out certain sensitive information that kickstart doesn't have a
fbcaed
     # way of representing encrypted.
fbcaed
@@ -80,7 +80,7 @@ def doConfiguration(storage, payload, ksdata, instClass):
fbcaed
 
fbcaed
     # Creating users and groups requires some pre-configuration.
fbcaed
     with progress_report(_("Creating users")):
fbcaed
-        createLuserConf(ROOT_PATH, algoname=getPassAlgo(ksdata.authconfig.authconfig))
fbcaed
+        createLuserConf(iutil.getSysroot(), algoname=getPassAlgo(ksdata.authconfig.authconfig))
fbcaed
         u = Users()
fbcaed
         ksdata.rootpw.execute(storage, ksdata, instClass, u)
fbcaed
         ksdata.group.execute(storage, ksdata, instClass, u)
fbcaed
diff --git a/pyanaconda/installclasses/fedora.py b/pyanaconda/installclasses/fedora.py
fbcaed
index 98e922f..3e0a5f2 100644
fbcaed
--- a/pyanaconda/installclasses/fedora.py
fbcaed
+++ b/pyanaconda/installclasses/fedora.py
fbcaed
@@ -18,11 +18,11 @@
fbcaed
 #
fbcaed
 
fbcaed
 from pyanaconda.installclass import BaseInstallClass
fbcaed
-from pyanaconda.constants import *
fbcaed
-from pyanaconda.product import *
fbcaed
+from pyanaconda.product import productName
fbcaed
 from pyanaconda import network
fbcaed
+from pyanaconda import iutil
fbcaed
 from pyanaconda import nm
fbcaed
-from pyanaconda.i18n import _
fbcaed
+from pyanaconda.i18n import _, N_
fbcaed
 
fbcaed
 import os, types
fbcaed
 
fbcaed
@@ -68,7 +68,7 @@ class InstallClass(BaseInstallClass):
fbcaed
             except ValueError as e:
fbcaed
                 continue
fbcaed
             if link_up:
fbcaed
-                ifcfg_path = network.find_ifcfg_file_of_device(devName, root_path=ROOT_PATH)
fbcaed
+                ifcfg_path = network.find_ifcfg_file_of_device(devName, root_path=iutil.getSysroot())
fbcaed
                 if not ifcfg_path:
fbcaed
                     continue
fbcaed
                 ifcfg = network.IfcfgFile(ifcfg_path)
fbcaed
diff --git a/pyanaconda/installclasses/rhel.py b/pyanaconda/installclasses/rhel.py
fbcaed
index f3e5a99..74052fd 100644
fbcaed
--- a/pyanaconda/installclasses/rhel.py
fbcaed
+++ b/pyanaconda/installclasses/rhel.py
fbcaed
@@ -22,6 +22,7 @@ from pyanaconda.constants import *
fbcaed
 from pyanaconda.product import *
fbcaed
 from pyanaconda import network
fbcaed
 from pyanaconda import nm
fbcaed
+from pyanaconda import iutil
fbcaed
 import types
fbcaed
 
fbcaed
 class InstallClass(BaseInstallClass):
fbcaed
@@ -71,7 +72,7 @@ class InstallClass(BaseInstallClass):
fbcaed
             return
fbcaed
         if nm.nm_device_type_is_wifi(devName):
fbcaed
             return
fbcaed
-        ifcfg_path = network.find_ifcfg_file_of_device(devName, root_path=ROOT_PATH)
fbcaed
+        ifcfg_path = network.find_ifcfg_file_of_device(devName, root_path=iutil.getSysroot())
fbcaed
         if not ifcfg_path:
fbcaed
             return
fbcaed
         ifcfg = network.IfcfgFile(ifcfg_path)
fbcaed
diff --git a/pyanaconda/iutil.py b/pyanaconda/iutil.py
fbcaed
index 8d6b31b..46f8079 100644
fbcaed
--- a/pyanaconda/iutil.py
fbcaed
+++ b/pyanaconda/iutil.py
fbcaed
@@ -44,10 +44,44 @@ from anaconda_log import program_log_lock
fbcaed
 def augmentEnv():
fbcaed
     env = os.environ.copy()
fbcaed
     env.update({"LC_ALL": "C",
fbcaed
-                "ANA_INSTALL_PATH": ROOT_PATH
fbcaed
+                "ANA_INSTALL_PATH": getSysroot()
fbcaed
                })
fbcaed
     return env
fbcaed
 
fbcaed
+def getTargetPhysicalRoot():
fbcaed
+    """Returns the path to the "physical" storage root, traditionally /mnt/sysimage.
fbcaed
+
fbcaed
+    This may be distinct from the sysroot, which could be a
fbcaed
+    chroot-type subdirectory of the physical root.  This is used for
fbcaed
+    example by all OSTree-based installations.
fbcaed
+    """
fbcaed
+
fbcaed
+    # We always use the traditional /mnt/sysimage - the physical OS
fbcaed
+    # target is never mounted anywhere else.  This API call just
fbcaed
+    # allows us to have a clean "git grep ROOT_PATH" in other parts of
fbcaed
+    # the code.
fbcaed
+    return ROOT_PATH
fbcaed
+
fbcaed
+_sysroot = ROOT_PATH
fbcaed
+
fbcaed
+def getSysroot():
fbcaed
+    """Returns the path to the target OS installation.
fbcaed
+
fbcaed
+    For ordinary package-based installations, this is the same as the
fbcaed
+    target root.
fbcaed
+    """
fbcaed
+    return _sysroot
fbcaed
+
fbcaed
+def setSysroot(path):
fbcaed
+    """Change the OS root path.
fbcaed
+       :param path: The new OS root path
fbcaed
+
fbcaed
+    This should only be used by Payload subclasses which install operating
fbcaed
+    systems to non-default roots.
fbcaed
+    """
fbcaed
+    global _sysroot
fbcaed
+    _sysroot = path
fbcaed
+
fbcaed
 def _run_program(argv, root='/', stdin=None, stdout=None, env_prune=None, log_output=True, binary_output=False):
fbcaed
     """ Run an external program, log the output and return it to the caller
fbcaed
         @param argv The command to run and argument
fbcaed
@@ -105,6 +139,16 @@ def _run_program(argv, root='/', stdin=None, stdout=None, env_prune=None, log_ou
fbcaed
 
fbcaed
     return (proc.returncode, output_string)
fbcaed
 
fbcaed
+def execInSysroot(command, argv, stdin=None):
fbcaed
+    """ Run an external program in the target root.
fbcaed
+        :param command: The command to run
fbcaed
+        :param argv: The argument list
fbcaed
+        :param stdin: The file object to read stdin from.
fbcaed
+        :return: The return code of the command
fbcaed
+    """
fbcaed
+
fbcaed
+    return execWithRedirect(command, argv, stdin=stdin, root=getSysroot())
fbcaed
+
fbcaed
 def execWithRedirect(command, argv, stdin=None, stdout=None,
fbcaed
                      stderr=None, root='/', env_prune=[], log_output=True, binary_output=False):
fbcaed
     """ Run an external program and redirect the output to a file.
fbcaed
@@ -323,7 +367,7 @@ def reIPL(ipldev):
fbcaed
         log.info("reIPL configuration successful")
fbcaed
 
fbcaed
 def resetRpmDb():
fbcaed
-    for rpmfile in glob.glob("%s/var/lib/rpm/__db.*" % ROOT_PATH):
fbcaed
+    for rpmfile in glob.glob("%s/var/lib/rpm/__db.*" % getSysroot()):
fbcaed
         try:
fbcaed
             os.unlink(rpmfile)
fbcaed
         except OSError as e:
fbcaed
diff --git a/pyanaconda/kickstart.py b/pyanaconda/kickstart.py
fbcaed
index df7b5e6..92a406a 100644
fbcaed
--- a/pyanaconda/kickstart.py
fbcaed
+++ b/pyanaconda/kickstart.py
fbcaed
@@ -40,7 +40,7 @@ import tempfile
fbcaed
 import subprocess
fbcaed
 import flags as flags_module
fbcaed
 from flags import flags
fbcaed
-from constants import *
fbcaed
+from constants import ADDON_PATHS
fbcaed
 import shlex
fbcaed
 import sys
fbcaed
 import urlgrabber
fbcaed
@@ -227,14 +227,14 @@ class Authconfig(commands.authconfig.FC3_Authconfig):
fbcaed
         args = ["--update", "--nostart"] + shlex.split(self.authconfig)
fbcaed
 
fbcaed
         if not flags.automatedInstall and \
fbcaed
-           (os.path.exists(ROOT_PATH + "/lib64/security/pam_fprintd.so") or \
fbcaed
-            os.path.exists(ROOT_PATH + "/lib/security/pam_fprintd.so")):
fbcaed
+           (os.path.exists(iutil.getSysroot() + "/lib64/security/pam_fprintd.so") or \
fbcaed
+            os.path.exists(iutil.getSysroot() + "/lib/security/pam_fprintd.so")):
fbcaed
             args += ["--enablefingerprint"]
fbcaed
 
fbcaed
         try:
fbcaed
-            iutil.execWithRedirect("/usr/sbin/authconfig", args, root=ROOT_PATH)
fbcaed
+            iutil.execInSysroot("/usr/sbin/authconfig", args)
fbcaed
         except OSError as msg:
fbcaed
-            log.error("Error running /usr/sbin/authconfig %s: %s", args, msg)
fbcaed
+            log.error("Error running /usr/sbin/authconfig %s: %s" %  (args, msg))
fbcaed
 
fbcaed
 class AutoPart(commands.autopart.F20_AutoPart):
fbcaed
     def execute(self, storage, ksdata, instClass):
fbcaed
@@ -470,7 +470,7 @@ class Realm(commands.realm.F19_Realm):
fbcaed
             # no explicit password arg using implicit --no-password
fbcaed
             pw_args = ["--no-password"]
fbcaed
 
fbcaed
-        argv = ["realm", "join", "--install", ROOT_PATH, "--verbose"] + \
fbcaed
+        argv = ["realm", "join", "--install", iutil.getSysroot(), "--verbose"] + \
fbcaed
                pw_args + self.join_args
fbcaed
         rc = -1
fbcaed
         try:
fbcaed
@@ -581,11 +581,11 @@ class Firewall(commands.firewall.F20_Firewall):
fbcaed
             args += [ "--service=%s" % (service,) ]
fbcaed
 
fbcaed
         cmd = "/usr/bin/firewall-offline-cmd"
fbcaed
-        if not os.path.exists(ROOT_PATH+cmd):
fbcaed
+        if not os.path.exists(iutil.getSysroot()+cmd):
fbcaed
             msg = _("%s is missing. Cannot setup firewall.") % (cmd,)
fbcaed
             raise KickstartError(msg)
fbcaed
         else:
fbcaed
-            iutil.execWithRedirect(cmd, args, root=ROOT_PATH)
fbcaed
+            iutil.execInSysroot(cmd, args)
fbcaed
 
fbcaed
 class Firstboot(commands.firstboot.FC3_Firstboot):
fbcaed
     def setup(self, *args):
fbcaed
@@ -598,7 +598,7 @@ class Firstboot(commands.firstboot.FC3_Firstboot):
fbcaed
                          "/lib/systemd/system/initial-setup-graphical.service",
fbcaed
                          "/lib/systemd/system/initial-setup-text.service")
fbcaed
 
fbcaed
-        if not any(os.path.exists(ROOT_PATH + path) for path in service_paths):
fbcaed
+        if not any(os.path.exists(iutil.getSysroot() + path) for path in service_paths):
fbcaed
             # none of the first boot utilities installed, nothing to do here
fbcaed
             return
fbcaed
 
fbcaed
@@ -607,13 +607,12 @@ class Firstboot(commands.firstboot.FC3_Firstboot):
fbcaed
         if self.firstboot == FIRSTBOOT_SKIP:
fbcaed
             action = "disable"
fbcaed
         elif self.firstboot == FIRSTBOOT_RECONFIG:
fbcaed
-            f = open(ROOT_PATH + "/etc/reconfigSys", "w+")
fbcaed
+            f = open(iutil.getSysroot() + "/etc/reconfigSys", "w+")
fbcaed
             f.close()
fbcaed
 
fbcaed
-        iutil.execWithRedirect("systemctl", [action, "firstboot-graphical.service",
fbcaed
+        iutil.execInSysroot("systemctl", [action, "firstboot-graphical.service",
fbcaed
                                                      "initial-setup-graphical.service",
fbcaed
-                                                     "initial-setup-text.service"],
fbcaed
-                               root=ROOT_PATH)
fbcaed
+                                                     "initial-setup-text.service"])
fbcaed
 
fbcaed
 class Group(commands.group.F12_Group):
fbcaed
     def execute(self, storage, ksdata, instClass, users):
fbcaed
@@ -621,7 +620,7 @@ class Group(commands.group.F12_Group):
fbcaed
 
fbcaed
         for grp in self.groupList:
fbcaed
             kwargs = grp.__dict__
fbcaed
-            kwargs.update({"root": ROOT_PATH})
fbcaed
+            kwargs.update({"root": iutil.getSysroot()})
fbcaed
             if not users.createGroup(grp.name, **kwargs):
fbcaed
                 log.error("Group %s already exists, not creating." % grp.name)
fbcaed
 
fbcaed
@@ -692,7 +691,7 @@ class IscsiName(commands.iscsiname.FC6_IscsiName):
fbcaed
 
fbcaed
 class Lang(commands.lang.F19_Lang):
fbcaed
     def execute(self, *args, **kwargs):
fbcaed
-        localization.write_language_configuration(self, ROOT_PATH)
fbcaed
+        localization.write_language_configuration(self, iutil.getSysroot())
fbcaed
 
fbcaed
 # no overrides needed here
fbcaed
 Eula = commands.eula.F20_Eula
fbcaed
@@ -902,7 +901,7 @@ class Logging(commands.logging.FC6_Logging):
fbcaed
 
fbcaed
 class Network(commands.network.RHEL7_Network):
fbcaed
     def execute(self, storage, ksdata, instClass):
fbcaed
-        network.write_network_config(storage, ksdata, instClass, ROOT_PATH)
fbcaed
+        network.write_network_config(storage, ksdata, instClass, iutil.getSysroot())
fbcaed
 
fbcaed
 class MultiPath(commands.multipath.FC6_MultiPath):
fbcaed
     def parse(self, args):
fbcaed
@@ -1326,7 +1325,7 @@ class SELinux(commands.selinux.FC3_SELinux):
fbcaed
             return
fbcaed
 
fbcaed
         try:
fbcaed
-            selinux_cfg = SimpleConfigFile(ROOT_PATH+"/etc/selinux/config")
fbcaed
+            selinux_cfg = SimpleConfigFile(iutil.getSysroot()+"/etc/selinux/config")
fbcaed
             selinux_cfg.read()
fbcaed
             selinux_cfg.set(("SELINUX", selinux_states[self.selinux]))
fbcaed
             selinux_cfg.write()
fbcaed
@@ -1339,12 +1338,10 @@ class Services(commands.services.FC6_Services):
fbcaed
         enabled = map(lambda s: s + ".service", self.enabled)
fbcaed
 
fbcaed
         if disabled:
fbcaed
-            iutil.execWithRedirect("systemctl", ["disable"] + disabled,
fbcaed
-                                   root=ROOT_PATH)
fbcaed
+            iutil.execInSysroot("systemctl", ["disable"] + disabled)
fbcaed
 
fbcaed
         if enabled:
fbcaed
-            iutil.execWithRedirect("systemctl", ["enable"] + enabled,
fbcaed
-                                   root=ROOT_PATH)
fbcaed
+            iutil.execInSysroot("systemctl", ["enable"] + enabled)
fbcaed
 
fbcaed
 class Timezone(commands.timezone.F18_Timezone):
fbcaed
     def __init__(self, *args):
fbcaed
@@ -1393,11 +1390,11 @@ class Timezone(commands.timezone.F18_Timezone):
fbcaed
                         "back to default (America/New_York)." % (self.timezone,))
fbcaed
             self.timezone = "America/New_York"
fbcaed
 
fbcaed
-        timezone.write_timezone_config(self, ROOT_PATH)
fbcaed
+        timezone.write_timezone_config(self, iutil.getSysroot())
fbcaed
 
fbcaed
         # write out NTP configuration (if set)
fbcaed
         if not self.nontp and self.ntpservers:
fbcaed
-            chronyd_conf_path = os.path.normpath(ROOT_PATH + ntp.NTP_CONFIG_FILE)
fbcaed
+            chronyd_conf_path = os.path.normpath(iutil.getSysroot() + ntp.NTP_CONFIG_FILE)
fbcaed
             try:
fbcaed
                 ntp.save_servers_to_config(self.ntpservers,
fbcaed
                                            conf_file_path=chronyd_conf_path)
fbcaed
@@ -1410,7 +1407,7 @@ class User(commands.user.F12_User):
fbcaed
 
fbcaed
         for usr in self.userList:
fbcaed
             kwargs = usr.__dict__
fbcaed
-            kwargs.update({"algo": algo, "root": ROOT_PATH})
fbcaed
+            kwargs.update({"algo": algo, "root": iutil.getSysroot()})
fbcaed
 
fbcaed
             # If the user password came from a kickstart and it is blank we
fbcaed
             # need to make sure the account is locked, not created with an
fbcaed
@@ -1515,7 +1512,7 @@ class ZFCP(commands.zfcp.F14_ZFCP):
fbcaed
 
fbcaed
 class Keyboard(commands.keyboard.F18_Keyboard):
fbcaed
     def execute(self, *args):
fbcaed
-        keyboard.write_keyboard_config(self, ROOT_PATH)
fbcaed
+        keyboard.write_keyboard_config(self, iutil.getSysroot())
fbcaed
 
fbcaed
     def dracutSetupArgs(self, *args):
fbcaed
         return keyboard.dracut_setup_args(self)
fbcaed
@@ -1542,7 +1539,7 @@ class SpokeRegistry(dict):
fbcaed
 
fbcaed
     # pylint: disable-msg=C0103
fbcaed
     def execute(self, storage, ksdata, instClass, users):
fbcaed
-        path = os.path.join(ROOT_PATH, "var", "lib", "inital-setup")
fbcaed
+        path = os.path.join(iutil.getSysroot(), "var", "lib", "inital-setup")
fbcaed
         try:
fbcaed
             os.makedirs(path, 0755)
fbcaed
         except OSError:
fbcaed
@@ -1748,7 +1745,7 @@ def runPostScripts(scripts):
fbcaed
             del(os.environ[var])
fbcaed
 
fbcaed
     log.info("Running kickstart %%post script(s)")
fbcaed
-    map (lambda s: s.run(ROOT_PATH), postScripts)
fbcaed
+    map (lambda s: s.run(iutil.getSysroot()), postScripts)
fbcaed
     log.info("All kickstart %%post script(s) have been run")
fbcaed
 
fbcaed
 def runPreScripts(scripts):
fbcaed
diff --git a/pyanaconda/packaging/__init__.py b/pyanaconda/packaging/__init__.py
fbcaed
index 47bb895..9b97149 100644
fbcaed
--- a/pyanaconda/packaging/__init__.py
fbcaed
+++ b/pyanaconda/packaging/__init__.py
fbcaed
@@ -377,8 +377,8 @@ class Payload(object):
fbcaed
             else:
fbcaed
                 cmpfunc = yum.rpmUtils.miscutils.compareVerOnly
fbcaed
 
fbcaed
-            files = glob.glob(ROOT_PATH + "/boot/vmlinuz-*")
fbcaed
-            files.extend(glob.glob(ROOT_PATH + "/boot/efi/EFI/redhat/vmlinuz-*"))
fbcaed
+            files = glob.glob(iutil.getSysroot() + "/boot/vmlinuz-*")
fbcaed
+            files.extend(glob.glob(iutil.getSysroot() + "/boot/efi/EFI/redhat/vmlinuz-*"))
fbcaed
             # strip off everything up to and including vmlinuz- to get versions
fbcaed
             # Ignore rescue kernels
fbcaed
             versions = [f.split("/")[-1][8:] for f in files if os.path.isfile(f) \
fbcaed
@@ -536,7 +536,7 @@ class Payload(object):
fbcaed
     ###
fbcaed
     def preInstall(self, packages=None, groups=None):
fbcaed
         """ Perform pre-installation tasks. """
fbcaed
-        iutil.mkdirChain(ROOT_PATH + "/root")
fbcaed
+        iutil.mkdirChain(iutil.getSysroot() + "/root")
fbcaed
 
fbcaed
         self._writeModuleBlacklist()
fbcaed
 
fbcaed
@@ -552,8 +552,8 @@ class Payload(object):
fbcaed
         if "modprobe.blacklist" not in flags.cmdline:
fbcaed
             return
fbcaed
 
fbcaed
-        iutil.mkdirChain(ROOT_PATH + "/etc/modprobe.d")
fbcaed
-        with open(ROOT_PATH + "/etc/modprobe.d/anaconda-blacklist.conf", "w") as f:
fbcaed
+        iutil.mkdirChain(iutil.getSysroot() + "/etc/modprobe.d")
fbcaed
+        with open(iutil.getSysroot() + "/etc/modprobe.d/anaconda-blacklist.conf", "w") as f:
fbcaed
             f.write("# Module blacklists written by anaconda\n")
fbcaed
             for module in flags.cmdline["modprobe.blacklist"].split():
fbcaed
                 f.write("blacklist %s\n" % module)
fbcaed
@@ -568,7 +568,7 @@ class Payload(object):
fbcaed
         # the firmware files in the common DD firmware directory
fbcaed
         for f in glob.glob(DD_FIRMWARE+"/*"):
fbcaed
             try:
fbcaed
-                shutil.copyfile(f, "%s/lib/firmware/" % ROOT_PATH)
fbcaed
+                shutil.copyfile(f, "%s/lib/firmware/" % iutil.getSysroot())
fbcaed
             except IOError as e:
fbcaed
                 log.error("Could not copy firmware file %s: %s" % (f, e.strerror))
fbcaed
             else:
fbcaed
@@ -576,12 +576,12 @@ class Payload(object):
fbcaed
 
fbcaed
         #copy RPMS
fbcaed
         for d in glob.glob(DD_RPMS):
fbcaed
-            shutil.copytree(d, ROOT_PATH + "/root/" + os.path.basename(d))
fbcaed
+            shutil.copytree(d, iutil.getSysroot() + "/root/" + os.path.basename(d))
fbcaed
 
fbcaed
         #copy modules and firmware into root's home directory
fbcaed
         if os.path.exists(DD_ALL):
fbcaed
             try:
fbcaed
-                shutil.copytree(DD_ALL, ROOT_PATH + "/root/DD")
fbcaed
+                shutil.copytree(DD_ALL, iutil.getSysroot() + "/root/DD")
fbcaed
             except IOError as e:
fbcaed
                 log.error("failed to copy driver disk files: %s" % e.strerror)
fbcaed
                 # XXX TODO: real error handling, as this is probably going to
fbcaed
@@ -603,26 +603,24 @@ class Payload(object):
fbcaed
         for kernel in self.kernelVersionList:
fbcaed
             log.info("recreating initrd for %s" % kernel)
fbcaed
             if not flags.imageInstall:
fbcaed
-                iutil.execWithRedirect("new-kernel-pkg",
fbcaed
-                                       ["--mkinitrd", "--dracut",
fbcaed
-                                        "--depmod", "--update", kernel],
fbcaed
-                                       root=ROOT_PATH)
fbcaed
+                iutil.execInSysroot("new-kernel-pkg",
fbcaed
+                                    ["--mkinitrd", "--dracut",
fbcaed
+                                    "--depmod", "--update", kernel])
fbcaed
             else:
fbcaed
                 # hostonly is not sensible for disk image installations
fbcaed
                 # using /dev/disk/by-uuid/ is necessary due to disk image naming
fbcaed
-                iutil.execWithRedirect("dracut",
fbcaed
-                                       ["-N",
fbcaed
-                                        "--persistent-policy", "by-uuid",
fbcaed
-                                        "-f", "/boot/initramfs-%s.img" % kernel,
fbcaed
-                                        kernel],
fbcaed
-                                        root=ROOT_PATH)
fbcaed
+                iutil.execInSysroot("dracut",
fbcaed
+                                    ["-N",
fbcaed
+                                     "--persistent-policy", "by-uuid",
fbcaed
+                                     "-f", "/boot/initramfs-%s.img" % kernel,
fbcaed
+                                    kernel])
fbcaed
 
fbcaed
         self._createdInitrds = True
fbcaed
 
fbcaed
 
fbcaed
     def _setDefaultBootTarget(self):
fbcaed
         """ Set the default systemd target for the system. """
fbcaed
-        if not os.path.exists(ROOT_PATH + "/etc/systemd/system"):
fbcaed
+        if not os.path.exists(iutil.getSysroot() + "/etc/systemd/system"):
fbcaed
             log.error("systemd is not installed -- can't set default target")
fbcaed
             return
fbcaed
 
fbcaed
@@ -635,7 +633,7 @@ class Payload(object):
fbcaed
         except ImportError:
fbcaed
             log.info("failed to import rpm -- not adjusting default runlevel")
fbcaed
         else:
fbcaed
-            ts = rpm.TransactionSet(ROOT_PATH)
fbcaed
+            ts = rpm.TransactionSet(iutil.getSysroot())
fbcaed
 
fbcaed
             # XXX one day this might need to account for anaconda's display mode
fbcaed
             if ts.dbMatch("provides", 'service(graphical-login)').count() and \
fbcaed
@@ -653,7 +651,7 @@ class Payload(object):
fbcaed
             pass
fbcaed
         else:
fbcaed
             iutil.resetRpmDb()
fbcaed
-            ts = rpm.TransactionSet(ROOT_PATH)
fbcaed
+            ts = rpm.TransactionSet(iutil.getSysroot())
fbcaed
 
fbcaed
             # Only add "rhgb quiet" on non-s390, non-serial installs
fbcaed
             if iutil.isConsoleOnVirtualTerminal() and \
fbcaed
diff --git a/pyanaconda/packaging/livepayload.py b/pyanaconda/packaging/livepayload.py
fbcaed
index 48c154f..09485e1 100644
fbcaed
--- a/pyanaconda/packaging/livepayload.py
fbcaed
+++ b/pyanaconda/packaging/livepayload.py
fbcaed
@@ -42,7 +42,7 @@ import glob
fbcaed
 
fbcaed
 from . import ImagePayload, PayloadSetupError, PayloadInstallError
fbcaed
 
fbcaed
-from pyanaconda.constants import INSTALL_TREE, ROOT_PATH, THREAD_LIVE_PROGRESS
fbcaed
+from pyanaconda.constants import INSTALL_TREE, THREAD_LIVE_PROGRESS
fbcaed
 from pyanaconda.constants import IMAGE_DIR
fbcaed
 
fbcaed
 from pyanaconda import iutil
fbcaed
@@ -61,7 +61,7 @@ class LiveImagePayload(ImagePayload):
fbcaed
     """ A LivePayload copies the source image onto the target system. """
fbcaed
     def __init__(self, *args, **kwargs):
fbcaed
         super(LiveImagePayload, self).__init__(*args, **kwargs)
fbcaed
-        # Used to adjust size of ROOT_PATH when files are already present
fbcaed
+        # Used to adjust size of sysroot when files are already present
fbcaed
         self._adj_size = 0
fbcaed
 
fbcaed
     def setup(self, storage):
fbcaed
@@ -91,7 +91,7 @@ class LiveImagePayload(ImagePayload):
fbcaed
         while self.pct < 100:
fbcaed
             dest_size = 0
fbcaed
             for mnt in mountpoints:
fbcaed
-                mnt_stat = os.statvfs(ROOT_PATH+mnt)
fbcaed
+                mnt_stat = os.statvfs(iutil.getSysroot()+mnt)
fbcaed
                 dest_size += mnt_stat.f_frsize * (mnt_stat.f_blocks - mnt_stat.f_bfree)
fbcaed
             if dest_size >= self._adj_size:
fbcaed
                 dest_size -= self._adj_size
fbcaed
@@ -118,7 +118,7 @@ class LiveImagePayload(ImagePayload):
fbcaed
         # file system boundaries
fbcaed
         args = ["-pogAXtlHrDx", "--exclude", "/dev/", "--exclude", "/proc/",
fbcaed
                 "--exclude", "/sys/", "--exclude", "/run/", "--exclude", "/boot/*rescue*",
fbcaed
-                "--exclude", "/etc/machine-id", INSTALL_TREE+"/", ROOT_PATH]
fbcaed
+                "--exclude", "/etc/machine-id", INSTALL_TREE+"/", iutil.getSysroot()]
fbcaed
         try:
fbcaed
             rc = iutil.execWithRedirect(cmd, args)
fbcaed
         except (OSError, RuntimeError) as e:
fbcaed
@@ -149,14 +149,13 @@ class LiveImagePayload(ImagePayload):
fbcaed
 
fbcaed
         # Live needs to create the rescue image before bootloader is written
fbcaed
         for kernel in self.kernelVersionList:
fbcaed
-            log.info("Generating rescue image for %s", kernel)
fbcaed
-            iutil.execWithRedirect("new-kernel-pkg",
fbcaed
-                                   ["--rpmposttrans", kernel],
fbcaed
-                                   root=ROOT_PATH)
fbcaed
+            log.info("Generating rescue image for %s" % kernel)
fbcaed
+            iutil.execInSysroot("new-kernel-pkg",
fbcaed
+                                ["--rpmposttrans", kernel])
fbcaed
 
fbcaed
         # Make sure the new system has a machine-id, it won't boot without it
fbcaed
-        if not os.path.exists(ROOT_PATH+"/etc/machine-id"):
fbcaed
-            iutil.execWithRedirect("systemd-machine-id-setup", [], root=ROOT_PATH)
fbcaed
+        if not os.path.exists(iutil.getSysroot()+"/etc/machine-id"):
fbcaed
+            iutil.execInSysroot("systemd-machine-id-setup", [])
fbcaed
 
fbcaed
     @property
fbcaed
     def spaceRequired(self):
fbcaed
@@ -216,7 +215,7 @@ class LiveImageKSPayload(LiveImagePayload):
fbcaed
     def __init__(self, *args, **kwargs):
fbcaed
         super(LiveImageKSPayload, self).__init__(*args, **kwargs)
fbcaed
         self._min_size = 0
fbcaed
-        self.image_path = ROOT_PATH+"/disk.img"
fbcaed
+        self.image_path = iutil.getSysroot()+"/disk.img"
fbcaed
 
fbcaed
     def setup(self, storage):
fbcaed
         """ Check the availability and size of the image.
fbcaed
@@ -263,10 +262,10 @@ class LiveImageKSPayload(LiveImagePayload):
fbcaed
         """ Download image and loopback mount it.
fbcaed
 
fbcaed
             This is called after partitioning is setup, we now have space
fbcaed
-            to grab the image. Download it to ROOT_PATH and provide feedback
fbcaed
+            to grab the image. Download it to sysroot and provide feedback
fbcaed
             during the download (using urlgrabber callback).
fbcaed
         """
fbcaed
-        # Setup urlgrabber and call back to download image to ROOT_PATH
fbcaed
+        # Setup urlgrabber and call back to download image to sysroot
fbcaed
         progress = URLGrabberProgress()
fbcaed
         ugopts = {"ssl_verify_peer": not self.data.method.noverifyssl,
fbcaed
                   "ssl_verify_host": not self.data.method.noverifyssl,
fbcaed
diff --git a/pyanaconda/packaging/tarpayload.py b/pyanaconda/packaging/tarpayload.py
fbcaed
index 26922af..fe78478 100644
fbcaed
--- a/pyanaconda/packaging/tarpayload.py
fbcaed
+++ b/pyanaconda/packaging/tarpayload.py
fbcaed
@@ -79,7 +79,7 @@ class TarPayload(ArchivePayload):
fbcaed
 
fbcaed
     def install(self):
fbcaed
         try:
fbcaed
-            self.archive.extractall(path=ROOT_PATH)
fbcaed
+            self.archive.extractall(path=iutil.getSysroot())
fbcaed
         except (tarfile.ExtractError, tarfile.CompressionError) as e:
fbcaed
             log.error("extracting tar archive %s: %s" % (self.image_file, e))
fbcaed
 
fbcaed
diff --git a/pyanaconda/packaging/yumpayload.py b/pyanaconda/packaging/yumpayload.py
fbcaed
index 211e5e9..a81b5bc 100644
fbcaed
--- a/pyanaconda/packaging/yumpayload.py
fbcaed
+++ b/pyanaconda/packaging/yumpayload.py
fbcaed
@@ -288,7 +288,7 @@ reposdir=%s
fbcaed
     def _yumCacheDirHack(self):
fbcaed
         # This is what it takes to get yum to use a cache dir outside the
fbcaed
         # install root. We do this so we don't have to re-gather repo meta-
fbcaed
-        # data after we change the install root to ROOT_PATH, which can only
fbcaed
+        # data after we change the install root to sysroot, which can only
fbcaed
         # happen after we've enabled the new storage configuration.
fbcaed
         with _yum_lock:
fbcaed
             if not self._yum.conf.cachedir.startswith(self._yum.conf.installroot):
fbcaed
@@ -363,7 +363,7 @@ reposdir=%s
fbcaed
         self._writeYumConfig()
fbcaed
         self._writeLangpacksConfig()
fbcaed
         log.debug("setting releasever to previous value of %s" % releasever)
fbcaed
-        self._resetYum(root=ROOT_PATH, keep_cache=True, releasever=releasever)
fbcaed
+        self._resetYum(root=iutil.getSysroot(), keep_cache=True, releasever=releasever)
fbcaed
         self._yumCacheDirHack()
fbcaed
         self.gatherRepoMetadata()
fbcaed
 
fbcaed
@@ -1629,7 +1629,7 @@ reposdir=%s
fbcaed
             "PROGRESS_POST"    : _("Performing post-installation setup tasks")
fbcaed
         }
fbcaed
 
fbcaed
-        ts_file = ROOT_PATH+"/anaconda-yum.yumtx"
fbcaed
+        ts_file = iutil.getSysroot()+"/anaconda-yum.yumtx"
fbcaed
         with _yum_lock:
fbcaed
             # Save the transaction, this will be loaded and executed by the new
fbcaed
             # process.
fbcaed
@@ -1646,7 +1646,7 @@ reposdir=%s
fbcaed
         args = ["--config", "/tmp/anaconda-yum.conf",
fbcaed
                 "--tsfile", ts_file,
fbcaed
                 "--rpmlog", script_log,
fbcaed
-                "--installroot", ROOT_PATH,
fbcaed
+                "--installroot", iutil.getSysroot(),
fbcaed
                 "--release", release,
fbcaed
                 "--arch", blivet.arch.getArch()]
fbcaed
 
fbcaed
@@ -1702,7 +1702,7 @@ reposdir=%s
fbcaed
         #        all yumvars and writing out the expanded pairs to the conf
fbcaed
         yb = yum.YumBase()
fbcaed
         yum_conf_path = "/etc/yum.conf"
fbcaed
-        yb.preconf.fn = ROOT_PATH + yum_conf_path
fbcaed
+        yb.preconf.fn = iutil.getSysroot() + yum_conf_path
fbcaed
         yb.conf.multilib_policy = "all"
fbcaed
 
fbcaed
         # this will appear in yum.conf, which is silly
fbcaed
@@ -1712,7 +1712,7 @@ reposdir=%s
fbcaed
         cachedir = yb.conf.cachedir.replace("/%s/" % yb.arch.basearch,
fbcaed
                                             "/$basearch/")
fbcaed
         yb.conf.cachedir = cachedir
fbcaed
-        yum_conf = ROOT_PATH + yum_conf_path
fbcaed
+        yum_conf = iutil.getSysroot() + yum_conf_path
fbcaed
         if os.path.exists(yum_conf):
fbcaed
             try:
fbcaed
                 os.rename(yum_conf, yum_conf + ".anacbak")
fbcaed
diff --git a/pyanaconda/rescue.py b/pyanaconda/rescue.py
fbcaed
index ff74f6b..e0c4e13 100644
fbcaed
--- a/pyanaconda/rescue.py
fbcaed
+++ b/pyanaconda/rescue.py
fbcaed
@@ -40,7 +40,7 @@ import subprocess
fbcaed
 
fbcaed
 from snack import ButtonChoiceWindow, ListboxChoiceWindow,SnackScreen
fbcaed
 
fbcaed
-from constants import ANACONDA_CLEANUP, ROOT_PATH
fbcaed
+from constants import ANACONDA_CLEANUP
fbcaed
 from constants_text import TEXT_OK_BUTTON, TEXT_NO_BUTTON, TEXT_YES_BUTTON
fbcaed
 from text import WaitWindow, OkCancelWindow, ProgressWindow, PassphraseEntryWindow
fbcaed
 from flags import flags
fbcaed
@@ -308,7 +308,7 @@ def doRescue(intf, rescue_mount, ksdata):
fbcaed
                   "\n\n"
fbcaed
                   "If for some reason this process fails you can choose 'Skip' "
fbcaed
                   "and this step will be skipped and you will go directly to a "
fbcaed
-                  "command shell.\n\n") % (ROOT_PATH,),
fbcaed
+                  "command shell.\n\n") % (iutil.getSysroot(),),
fbcaed
                   [_("Continue"), _("Read-Only"), _("Skip")] )
fbcaed
 
fbcaed
             if rc == _("Skip").lower():
fbcaed
@@ -380,14 +380,14 @@ def doRescue(intf, rescue_mount, ksdata):
fbcaed
                 rootmounted = False
fbcaed
             else:
fbcaed
                 if flags.automatedInstall:
fbcaed
-                    log.info("System has been mounted under: %s" % ROOT_PATH)
fbcaed
+                    log.info("System has been mounted under: %s" % iutil.getSysroot())
fbcaed
                 else:
fbcaed
                     ButtonChoiceWindow(intf.screen, _("Rescue"),
fbcaed
                        _("Your system has been mounted under %(rootPath)s.\n\n"
fbcaed
                          "Press <return> to get a shell. If you would like to "
fbcaed
                          "make your system the root environment, run the command:\n\n"
fbcaed
                          "\tchroot %(rootPath)s\n\n%(msg)s") %
fbcaed
-                                       {'rootPath': ROOT_PATH,
fbcaed
+                                       {'rootPath': iutil.getSysroot(),
fbcaed
                                         'msg': msg},
fbcaed
                                        [_("OK")] )
fbcaed
                 rootmounted = True
fbcaed
@@ -404,7 +404,7 @@ def doRescue(intf, rescue_mount, ksdata):
fbcaed
                     # we have to catch the possible exception
fbcaed
                     # because we support read-only mounting
fbcaed
                     try:
fbcaed
-                        fd = open("%s/.autorelabel" % ROOT_PATH, "w+")
fbcaed
+                        fd = open("%s/.autorelabel" % iutil.getSysroot(), "w+")
fbcaed
                         fd.close()
fbcaed
                     except IOError:
fbcaed
                         log.warning("cannot touch /.autorelabel")
fbcaed
@@ -456,7 +456,7 @@ def doRescue(intf, rescue_mount, ksdata):
fbcaed
                 ButtonChoiceWindow(intf.screen, _("Rescue"),
fbcaed
                     _("An error occurred trying to mount some or all of your "
fbcaed
                       "system. Some of it may be mounted under %s.\n\n"
fbcaed
-                      "Press <return> to get a shell.") % ROOT_PATH + msg,
fbcaed
+                      "Press <return> to get a shell.") % iutil.getSysroot() + msg,
fbcaed
                       [_("OK")] )
fbcaed
     else:
fbcaed
         if flags.automatedInstall and ksdata.reboot.action in [KS_REBOOT, KS_SHUTDOWN]:
fbcaed
@@ -480,10 +480,10 @@ def doRescue(intf, rescue_mount, ksdata):
fbcaed
     if rootmounted and not readOnly:
fbcaed
         sto.makeMtab()
fbcaed
         try:
fbcaed
-            makeResolvConf(ROOT_PATH)
fbcaed
+            makeResolvConf(iutil.getSysroot())
fbcaed
         except (OSError, IOError) as e:
fbcaed
             log.error("error making a resolv.conf: %s" %(e,))
fbcaed
-        msgStr = _("Your system is mounted under the %s directory.") % (ROOT_PATH,)
fbcaed
+        msgStr = _("Your system is mounted under the %s directory.") % (iutil.getSysroot(),)
fbcaed
         ButtonChoiceWindow(intf.screen, _("Rescue"), msgStr, [_("OK")] )
fbcaed
 
fbcaed
     # we do not need ncurses anymore, shut them down
fbcaed
diff --git a/pyanaconda/users.py b/pyanaconda/users.py
fbcaed
index 9e09be0..2e40465 100644
fbcaed
--- a/pyanaconda/users.py
fbcaed
+++ b/pyanaconda/users.py
fbcaed
@@ -29,7 +29,6 @@ import os.path
fbcaed
 import iutil
fbcaed
 import pwquality
fbcaed
 import re
fbcaed
-from pyanaconda.constants import ROOT_PATH
fbcaed
 from pyanaconda.iutil import strip_accents
fbcaed
 from pyanaconda.i18n import _
fbcaed
 
fbcaed
@@ -192,7 +191,7 @@ class Users:
fbcaed
         """
fbcaed
 
fbcaed
         childpid = os.fork()
fbcaed
-        root = kwargs.get("root", ROOT_PATH)
fbcaed
+        root = kwargs.get("root", iutil.getSysroot())
fbcaed
 
fbcaed
         if not childpid:
fbcaed
             if not root in ["","/"]:
fbcaed
@@ -258,7 +257,7 @@ class Users:
fbcaed
                         available one is used.
fbcaed
         """
fbcaed
         childpid = os.fork()
fbcaed
-        root = kwargs.get("root", ROOT_PATH)
fbcaed
+        root = kwargs.get("root", iutil.getSysroot())
fbcaed
 
fbcaed
         if not childpid:
fbcaed
             if not root in ["","/"]:
fbcaed
@@ -358,7 +357,7 @@ class Users:
fbcaed
         else:
fbcaed
             return False
fbcaed
 
fbcaed
-    def checkUserExists(self, username, root=ROOT_PATH):
fbcaed
+    def checkUserExists(self, username, root=iutil.getSysroot()):
fbcaed
         childpid = os.fork()
fbcaed
 
fbcaed
         if not childpid:
fbcaed
-- 
fbcaed
1.9.3
fbcaed