def _doFilesystemMangling(self, anaconda): log.info("doing post-install fs mangling") wait = anaconda.intf.waitWindow( _("Post-Installation"), _("Performing post-installation filesystem changes. This may take several minutes." )) # resize rootfs first, since it is 100% full due to genMinInstDelta self._resizeRootfs(anaconda, wait) # remount filesystems anaconda.id.storage.mountFilesystems() # restore the label of / to what we think it is rootDevice = anaconda.id.storage.rootDevice rootDevice.setup() # ensure we have a random UUID on the rootfs # FIXME: this should be abstracted per filesystem type iutil.execWithRedirect("tune2fs", ["-U", "random", rootDevice.path], stdout="/dev/tty5", stderr="/dev/tty5") # and now set the uuid in the storage layer rootDevice.updateSysfsPath() iutil.notify_kernel("/sys%s" % rootDevice.sysfsPath) storage.udev.udev_settle() rootDevice.updateSysfsPath() info = storage.udev.udev_get_block_device(rootDevice.sysfsPath) rootDevice.format.uuid = storage.udev.udev_device_get_uuid(info) log.info("reset the rootdev (%s) to have a uuid of %s" % (rootDevice.sysfsPath, rootDevice.format.uuid)) # for any filesystem that's _not_ on the root, we need to handle # moving the bits from the livecd -> the real filesystems. # this is pretty distasteful, but should work with things like # having a separate /usr/local def _setupFilesystems(mounts, chroot="", teardown=False): """ Setup or teardown all filesystems except for "/" """ mountpoints = sorted(mounts.keys(), reverse=teardown is True) if teardown: method = "teardown" kwargs = {} else: method = "setup" kwargs = {"chroot": chroot} mountpoints.remove("/") for mountpoint in mountpoints: device = mounts[mountpoint] getattr(device.format, method)(**kwargs) # Start by sorting the mountpoints in decreasing-depth order. mountpoints = sorted(anaconda.id.storage.mountpoints.keys(), reverse=True) # We don't want to copy the root filesystem. mountpoints.remove("/") stats = {} # mountpoint: posix.stat_result # unmount the filesystems, except for / _setupFilesystems(anaconda.id.storage.mountpoints, teardown=True) # mount all of the filesystems under /mnt so we can copy in content _setupFilesystems(anaconda.id.storage.mountpoints, chroot=anaconda.rootPath + "/mnt") # And now let's do the real copies for tocopy in mountpoints: device = anaconda.id.storage.mountpoints[tocopy] # FIXME: all calls to wait.refresh() are kind of a hack... we # should do better about not doing blocking things in the # main thread. but threading anaconda is a job for another # time. wait.refresh() if not os.path.exists("%s/%s" % (anaconda.rootPath, tocopy)): # the directory does not exist in the live image, so there's # nothing to move continue iutil.copytree("%s/%s" % (anaconda.rootPath, tocopy), "%s/mnt/%s" % (anaconda.rootPath, tocopy), True, True, flags.selinux) wait.refresh() shutil.rmtree("%s/%s" % (anaconda.rootPath, tocopy)) wait.refresh() # now unmount each fs, collect stat info for the mountpoint, then # remove the entire tree containing the mountpoint for tocopy in mountpoints: device = anaconda.id.storage.mountpoints[tocopy] device.format.teardown() if not os.path.exists("%s/%s" % (anaconda.rootPath, tocopy)): continue try: stats[tocopy] = os.stat("%s/mnt/%s" % (anaconda.rootPath, tocopy)) except Exception as e: log.info("failed to get stat info for mountpoint %s: %s" % (tocopy, e)) shutil.rmtree("%s/mnt/%s" % (anaconda.rootPath, tocopy.split("/")[1])) wait.refresh() # now mount all of the filesystems so that post-install writes end # up where they're supposed to end up _setupFilesystems(anaconda.id.storage.mountpoints, chroot=anaconda.rootPath) # restore stat info for each mountpoint for mountpoint in reversed(mountpoints): if mountpoint not in stats: # there's no info to restore since the mountpoint did not # exist in the live image continue dest = "%s/%s" % (anaconda.rootPath, mountpoint) st = stats[mountpoint] # restore the correct stat info for this mountpoint os.utime(dest, (st.st_atime, st.st_mtime)) os.chown(dest, st.st_uid, st.st_gid) os.chmod(dest, stat.S_IMODE(st.st_mode)) # ensure that non-fstab filesystems are mounted in the chroot if flags.selinux: try: isys.mount("/selinux", anaconda.rootPath + "/selinux", "selinuxfs") except Exception, e: log.error("error mounting selinuxfs: %s" % (e, ))
def _doFilesystemMangling(self, anaconda): log.info("doing post-install fs mangling") wait = anaconda.intf.waitWindow(_("Post-Installation"), _("Performing post-installation filesystem changes. This may take several minutes.")) # resize rootfs first, since it is 100% full due to genMinInstDelta rootDevice = anaconda.storage.rootDevice rootDevice.setup() # This is a workaround to make sure the m_time it set to current time so that # the e2fsck before resizing doesn't get confused by times in the future rootDevice.format.testMount() rootDevice.format.targetSize = rootDevice.size rootDevice.format.doResize(intf=anaconda.intf) # ensure we have a random UUID on the rootfs rootDevice.format.writeRandomUUID() # remount filesystems anaconda.storage.mountFilesystems() # and now set the uuid in the storage layer rootDevice.updateSysfsPath() iutil.notify_kernel("/sys%s" %rootDevice.sysfsPath) storage.udev.udev_settle() rootDevice.updateSysfsPath() info = storage.udev.udev_get_block_device(rootDevice.sysfsPath) rootDevice.format.uuid = storage.udev.udev_device_get_uuid(info) log.info("reset the rootdev (%s) to have a uuid of %s" %(rootDevice.sysfsPath, rootDevice.format.uuid)) # for any filesystem that's _not_ on the root, we need to handle # moving the bits from the livecd -> the real filesystems. # this is pretty distasteful, but should work with things like # having a separate /usr/local def _setupFilesystems(mounts, chroot="", teardown=False): """ Setup or teardown all filesystems except for "/" """ mountpoints = sorted(mounts.keys(), reverse=teardown is True) if teardown: method = "teardown" kwargs = {} else: method = "setup" kwargs = {"chroot": chroot} mountpoints.remove("/") for mountpoint in mountpoints: device = mounts[mountpoint] getattr(device.format, method)(**kwargs) # Start by sorting the mountpoints in decreasing-depth order. # Only include ones that exist on the original livecd filesystem mountpoints = filter(os.path.exists, sorted(anaconda.storage.mountpoints.keys(), reverse=True)) # We don't want to copy the root filesystem. mountpoints.remove("/") stats = {} # mountpoint: posix.stat_result # unmount the filesystems, except for / _setupFilesystems(anaconda.storage.mountpoints, teardown=True) # mount all of the filesystems under /mnt so we can copy in content _setupFilesystems(anaconda.storage.mountpoints, chroot="/mnt") # And now let's do the real copies for tocopy in mountpoints: device = anaconda.storage.mountpoints[tocopy] source = "%s/%s" % (ROOT_PATH, tocopy) dest = "/mnt/%s" % (tocopy,) # FIXME: all calls to wait.refresh() are kind of a hack... we # should do better about not doing blocking things in the # main thread. but threading anaconda is a job for another # time. wait.refresh() try: log.info("Gathering stats on %s" % (source,)) stats[tocopy]= os.stat(source) except Exception as e: log.info("failed to get stat info for mountpoint %s: %s" % (source, e)) log.info("Copying %s to %s" % (source, dest)) copytree(source, dest, True, True, flags.selinux) wait.refresh() log.info("Removing %s" % (source,)) shutil.rmtree(source) wait.refresh() # unmount the target filesystems and remount in their final locations # so that post-install writes end up where they're supposed to end up _setupFilesystems(anaconda.storage.mountpoints, teardown=True) _setupFilesystems(anaconda.storage.mountpoints, chroot=ROOT_PATH) # restore stat info for each mountpoint for mountpoint in reversed(mountpoints): dest = "%s/%s" % (ROOT_PATH, mountpoint) log.info("Restoring stats on %s" % (dest,)) st = stats[mountpoint] # restore the correct stat info for this mountpoint os.utime(dest, (st.st_atime, st.st_mtime)) os.chown(dest, st.st_uid, st.st_gid) os.chmod(dest, stat.S_IMODE(st.st_mode)) wait.pop()
def _doFilesystemMangling(self, anaconda): log.info("doing post-install fs mangling") wait = anaconda.intf.waitWindow(_("Post-Installation"), _("Performing post-installation filesystem changes. This may take several minutes.")) # resize rootfs first, since it is 100% full due to genMinInstDelta rootDevice = anaconda.storage.rootDevice rootDevice.setup() rootDevice.format.targetSize = rootDevice.size rootDevice.format.doResize(intf=anaconda.intf) # ensure we have a random UUID on the rootfs rootDevice.format.writeRandomUUID() # remount filesystems anaconda.storage.mountFilesystems() # and now set the uuid in the storage layer rootDevice.updateSysfsPath() iutil.notify_kernel("/sys%s" %rootDevice.sysfsPath) storage.udev.udev_settle() rootDevice.updateSysfsPath() info = storage.udev.udev_get_block_device(rootDevice.sysfsPath) rootDevice.format.uuid = storage.udev.udev_device_get_uuid(info) log.info("reset the rootdev (%s) to have a uuid of %s" %(rootDevice.sysfsPath, rootDevice.format.uuid)) # for any filesystem that's _not_ on the root, we need to handle # moving the bits from the livecd -> the real filesystems. # this is pretty distasteful, but should work with things like # having a separate /usr/local def _setupFilesystems(mounts, chroot="", teardown=False): """ Setup or teardown all filesystems except for "/" """ mountpoints = sorted(mounts.keys(), reverse=teardown is True) if teardown: method = "teardown" kwargs = {} else: method = "setup" kwargs = {"chroot": chroot} mountpoints.remove("/") for mountpoint in mountpoints: device = mounts[mountpoint] getattr(device.format, method)(**kwargs) # Start by sorting the mountpoints in decreasing-depth order. mountpoints = sorted(anaconda.storage.mountpoints.keys(), reverse=True) # We don't want to copy the root filesystem. mountpoints.remove("/") stats = {} # mountpoint: posix.stat_result # unmount the filesystems, except for / _setupFilesystems(anaconda.storage.mountpoints, teardown=True) # mount all of the filesystems under /mnt so we can copy in content _setupFilesystems(anaconda.storage.mountpoints, chroot=anaconda.rootPath + "/mnt") # And now let's do the real copies for tocopy in mountpoints: device = anaconda.storage.mountpoints[tocopy] # FIXME: all calls to wait.refresh() are kind of a hack... we # should do better about not doing blocking things in the # main thread. but threading anaconda is a job for another # time. wait.refresh() if not os.path.exists("%s/%s" % (anaconda.rootPath, tocopy)): # the directory does not exist in the live image, so there's # nothing to move continue copytree("%s/%s" % (anaconda.rootPath, tocopy), "%s/mnt/%s" % (anaconda.rootPath, tocopy), True, True, flags.selinux) wait.refresh() shutil.rmtree("%s/%s" % (anaconda.rootPath, tocopy)) wait.refresh() # now unmount each fs, collect stat info for the mountpoint, then # remove the entire tree containing the mountpoint for tocopy in mountpoints: device = anaconda.storage.mountpoints[tocopy] device.format.teardown() if not os.path.exists("%s/%s" % (anaconda.rootPath, tocopy)): continue try: stats[tocopy]= os.stat("%s/mnt/%s" % (anaconda.rootPath, tocopy)) except Exception as e: log.info("failed to get stat info for mountpoint %s: %s" % (tocopy, e)) shutil.rmtree("%s/mnt/%s" % (anaconda.rootPath, tocopy.split("/")[1])) wait.refresh() # now mount all of the filesystems so that post-install writes end # up where they're supposed to end up _setupFilesystems(anaconda.storage.mountpoints, chroot=anaconda.rootPath) # restore stat info for each mountpoint for mountpoint in reversed(mountpoints): if mountpoint not in stats: # there's no info to restore since the mountpoint did not # exist in the live image continue dest = "%s/%s" % (anaconda.rootPath, mountpoint) st = stats[mountpoint] # restore the correct stat info for this mountpoint os.utime(dest, (st.st_atime, st.st_mtime)) os.chown(dest, st.st_uid, st.st_gid) os.chmod(dest, stat.S_IMODE(st.st_mode)) wait.pop()
log_method_call(self, device=self.device, type=self.type) 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: log.warning("failed to get dm node for %s" % self.device) return else: name = self.device path = get_sysfs_path_by_name(name) try: notify_kernel(path, action="change") except Exception, e: log.warning("failed to notify kernel of change: %s" % e) def create(self, *args, **kwargs): log_method_call(self, device=self.device, type=self.type, status=self.status) # 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",
type=self.type) 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: log.warning("failed to get dm node for %s" % self.device) return else: name = self.device path = get_sysfs_path_by_name(name) try: notify_kernel(path, action="change") except Exception, e: log.warning("failed to notify kernel of change: %s" % e) def cacheMajorminor(self): """ Cache the value of self.majorminor. Once a device node of this format's device disappears (for instance after a teardown), it is no longer possible to figure out the value of self.majorminor pseudo-unique string. Call this method before that happens for caching this. """ self._majorminor = None try: self.majorminor # this does the caching except StorageError:
def _doFilesystemMangling(self, anaconda): # FIXME: this whole method is a big f*****g mess log.info("doing post-install fs mangling") wait = anaconda.intf.waitWindow(_("Post-Installation"), _("Performing post-installation filesystem changes. This may take several minutes.")) # resize rootfs first, since it is 100% full due to genMinInstDelta self._resizeRootfs(anaconda, wait) # remount filesystems anaconda.storage.mountFilesystems() # restore the label of / to what we think it is rootDevice = anaconda.storage.rootDevice rootDevice.setup() # ensure we have a random UUID on the rootfs # FIXME: this should be abstracted per filesystem type iutil.execWithRedirect("tune2fs", ["-U", "random", rootDevice.path], stdout="/dev/tty5", stderr="/dev/tty5") # and now set the uuid in the storage layer rootDevice.updateSysfsPath() iutil.notify_kernel("/sys%s" %rootDevice.sysfsPath) storage.udev.udev_settle() rootDevice.updateSysfsPath() info = storage.udev.udev_get_block_device(rootDevice.sysfsPath) rootDevice.format.uuid = storage.udev.udev_device_get_uuid(info) log.info("reset the rootdev (%s) to have a uuid of %s" %(rootDevice.sysfsPath, rootDevice.format.uuid)) # for any filesystem that's _not_ on the root, we need to handle # moving the bits from the livecd -> the real filesystems. # this is pretty distasteful, but should work with things like # having a separate /usr/local # now create a tree so that we know what's mounted under where fsdict = {"/": []} for mount in sorted(anaconda.storage.mountpoints.keys()): entry = anaconda.storage.mountpoints[mount] tocopy = entry.format.mountpoint if tocopy.startswith("/mnt") or tocopy == "swap": continue keys = sorted(fsdict.keys(), reverse = True) for key in keys: if tocopy.startswith(key): fsdict[key].append(entry) break fsdict[tocopy] = [] log.debug("mangling dict looks like %s" %(fsdict,)) # and now let's do the real copies; and we don't want to copy /! copied = ["/"] for tocopy in sorted(fsdict.keys()): if tocopy in copied: continue copied.append(tocopy) copied.extend(map(lambda x: x.format.mountpoint, fsdict[tocopy])) entry = anaconda.storage.mountpoints[tocopy] # FIXME: all calls to wait.refresh() are kind of a hack... we # should do better about not doing blocking things in the # main thread. but threading anaconda is a job for another # time. wait.refresh() # unmount subdirs + this one and then remount under /mnt for e in fsdict[tocopy] + [entry]: e.format.teardown() for e in [entry] + fsdict[tocopy]: e.format.setup(chroot=anaconda.rootPath + "/mnt") copytree("%s/%s" %(anaconda.rootPath, tocopy), "%s/mnt/%s" %(anaconda.rootPath, tocopy), True, True, flags.selinux) shutil.rmtree("%s/%s" %(anaconda.rootPath, tocopy)) wait.refresh() # mount it back in the correct place for e in fsdict[tocopy] + [entry]: e.format.teardown() try: os.rmdir("%s/mnt/%s" %(anaconda.rootPath, e.format.mountpoint)) except OSError as e: log.debug("error removing %s" %(tocopy,)) for e in [entry] + fsdict[tocopy]: e.format.setup(chroot=anaconda.rootPath) wait.refresh() # ensure that non-fstab filesystems are mounted in the chroot if flags.selinux: try: isys.mount("/selinux", anaconda.rootPath + "/selinux", "selinuxfs") except Exception, e: log.error("error mounting selinuxfs: %s" %(e,))