2013-01-23 17:28:19 +00:00
|
|
|
#
|
|
|
|
# image.py: Support methods for CD/DVD and ISO image installations.
|
|
|
|
#
|
|
|
|
# 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/>.
|
|
|
|
#
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
from pyanaconda import isys
|
|
|
|
import os, os.path, stat, tempfile
|
2013-01-23 17:28:19 +00:00
|
|
|
|
2016-04-10 04:00:00 +00:00
|
|
|
from pyanaconda.errors import errorHandler, ERROR_RAISE, InvalidImageSizeError, MissingImageError
|
2013-01-23 17:28:19 +00:00
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
import blivet.util
|
|
|
|
import blivet.arch
|
2016-04-10 04:00:00 +00:00
|
|
|
from blivet.errors import FSError
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
import logging
|
|
|
|
log = logging.getLogger("anaconda")
|
|
|
|
|
2017-01-09 02:09:07 +00:00
|
|
|
_arch = blivet.arch.get_arch()
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
def findFirstIsoImage(path):
|
|
|
|
"""
|
|
|
|
Find the first iso image in path
|
|
|
|
This also supports specifying a specific .iso image
|
|
|
|
|
|
|
|
Returns the basename of the image
|
|
|
|
"""
|
|
|
|
try:
|
2014-04-07 12:38:09 +00:00
|
|
|
os.stat(path)
|
2013-01-23 17:28:19 +00:00
|
|
|
except OSError:
|
|
|
|
return None
|
|
|
|
|
|
|
|
arch = _arch
|
|
|
|
|
|
|
|
if os.path.isfile(path) and path.endswith(".iso"):
|
|
|
|
files = [os.path.basename(path)]
|
|
|
|
path = os.path.dirname(path)
|
|
|
|
else:
|
|
|
|
files = os.listdir(path)
|
|
|
|
|
|
|
|
for fn in files:
|
|
|
|
what = path + '/' + fn
|
2014-04-07 12:38:09 +00:00
|
|
|
log.debug("Checking %s", what)
|
2013-01-23 17:28:19 +00:00
|
|
|
if not isys.isIsoImage(what):
|
|
|
|
continue
|
|
|
|
|
|
|
|
log.debug("mounting %s on /mnt/install/cdimage", what)
|
|
|
|
try:
|
2014-04-07 12:38:09 +00:00
|
|
|
blivet.util.mount(what, "/mnt/install/cdimage", fstype="iso9660", options="ro")
|
|
|
|
except OSError:
|
2013-01-23 17:28:19 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
if not os.access("/mnt/install/cdimage/.discinfo", os.R_OK):
|
2014-04-07 12:38:09 +00:00
|
|
|
blivet.util.umount("/mnt/install/cdimage")
|
2013-01-23 17:28:19 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
log.debug("Reading .discinfo")
|
|
|
|
f = open("/mnt/install/cdimage/.discinfo")
|
|
|
|
f.readline() # skip timestamp
|
|
|
|
f.readline() # skip release description
|
|
|
|
discArch = f.readline().strip() # read architecture
|
|
|
|
f.close()
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
log.debug("discArch = %s", discArch)
|
2013-01-23 17:28:19 +00:00
|
|
|
if discArch != arch:
|
2014-04-07 12:38:09 +00:00
|
|
|
log.warning("findFirstIsoImage: architectures mismatch: %s, %s",
|
|
|
|
discArch, arch)
|
|
|
|
blivet.util.umount("/mnt/install/cdimage")
|
2013-01-23 17:28:19 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
# If there's no repodata, there's no point in trying to
|
|
|
|
# install from it.
|
|
|
|
if not os.access("/mnt/install/cdimage/repodata", os.R_OK):
|
2014-04-07 12:38:09 +00:00
|
|
|
log.warning("%s doesn't have repodata, skipping", what)
|
|
|
|
blivet.util.umount("/mnt/install/cdimage")
|
2013-01-23 17:28:19 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
# warn user if images appears to be wrong size
|
|
|
|
if os.stat(what)[stat.ST_SIZE] % 2048:
|
2014-04-07 12:38:09 +00:00
|
|
|
log.warning("%s appears to be corrupted", what)
|
2015-03-23 11:36:12 +00:00
|
|
|
exn = InvalidImageSizeError("size is not a multiple of 2048 bytes", what)
|
2013-01-23 17:28:19 +00:00
|
|
|
if errorHandler.cb(exn) == ERROR_RAISE:
|
|
|
|
raise exn
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
log.info("Found disc at %s", fn)
|
|
|
|
blivet.util.umount("/mnt/install/cdimage")
|
2013-01-23 17:28:19 +00:00
|
|
|
return fn
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
def mountImage(isodir, tree):
|
|
|
|
while True:
|
|
|
|
if os.path.isfile(isodir):
|
|
|
|
image = isodir
|
|
|
|
else:
|
|
|
|
image = findFirstIsoImage(isodir)
|
|
|
|
if image is None:
|
|
|
|
exn = MissingImageError()
|
|
|
|
if errorHandler.cb(exn) == ERROR_RAISE:
|
|
|
|
raise exn
|
|
|
|
else:
|
|
|
|
continue
|
|
|
|
|
|
|
|
image = os.path.normpath("%s/%s" % (isodir, image))
|
|
|
|
|
|
|
|
try:
|
2016-04-10 04:00:00 +00:00
|
|
|
blivet.util.mount(image, tree, fstype='iso9660', options="ro")
|
2014-04-07 12:38:09 +00:00
|
|
|
except OSError:
|
2013-01-23 17:28:19 +00:00
|
|
|
exn = MissingImageError()
|
|
|
|
if errorHandler.cb(exn) == ERROR_RAISE:
|
|
|
|
raise exn
|
|
|
|
else:
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
break
|
|
|
|
|
|
|
|
# Return the first Device instance containing valid optical install media
|
|
|
|
# for this product.
|
2014-04-07 12:38:09 +00:00
|
|
|
def opticalInstallMedia(devicetree):
|
2013-01-23 17:28:19 +00:00
|
|
|
retval = None
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
# Search for devices identified as cdrom along with any other
|
|
|
|
# device that has an iso9660 filesystem. This will catch USB media
|
|
|
|
# created from ISO images.
|
2017-01-09 02:09:07 +00:00
|
|
|
for dev in set([d for d in devicetree.devices if d.type == "cdrom"] + \
|
2014-04-07 12:38:09 +00:00
|
|
|
[d for d in devicetree.devices if d.format.type == "iso9660"]):
|
|
|
|
if not dev.controllable:
|
|
|
|
continue
|
|
|
|
|
2017-01-09 02:09:07 +00:00
|
|
|
devicetree.handle_format(None, dev)
|
2014-04-07 12:38:09 +00:00
|
|
|
if not hasattr(dev.format, "mount"):
|
|
|
|
# no mountable media
|
2013-01-23 17:28:19 +00:00
|
|
|
continue
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
mountpoint = tempfile.mkdtemp()
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
dev.format.mount(mountpoint=mountpoint)
|
|
|
|
except FSError:
|
|
|
|
continue
|
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
try:
|
|
|
|
if not verifyMedia(mountpoint):
|
|
|
|
continue
|
|
|
|
finally:
|
2016-04-10 04:00:00 +00:00
|
|
|
dev.format.unmount(mountpoint=mountpoint)
|
2014-04-07 12:38:09 +00:00
|
|
|
finally:
|
|
|
|
os.rmdir(mountpoint)
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
retval = dev
|
|
|
|
break
|
|
|
|
|
|
|
|
return retval
|
|
|
|
|
2017-01-09 02:09:07 +00:00
|
|
|
# Return a generator yielding Device instances that may have HDISO install
|
|
|
|
# media somewhere. Candidate devices are simply any that we can mount.
|
2013-01-23 17:28:19 +00:00
|
|
|
def potentialHdisoSources(devicetree):
|
2017-01-09 02:09:07 +00:00
|
|
|
return (d for d in devicetree.devices
|
|
|
|
if d.type == "partition" and d.format.exists and d.format.mountable)
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
def verifyMedia(tree, timestamp=None):
|
|
|
|
if os.access("%s/.discinfo" % tree, os.R_OK):
|
|
|
|
f = open("%s/.discinfo" % tree)
|
|
|
|
|
|
|
|
newStamp = f.readline().strip()
|
2014-04-07 12:38:09 +00:00
|
|
|
# Next is the description, which we just want to throw away.
|
|
|
|
f.readline()
|
2013-01-23 17:28:19 +00:00
|
|
|
arch = f.readline().strip()
|
|
|
|
f.close()
|
|
|
|
|
|
|
|
if timestamp is not None:
|
|
|
|
if newStamp == timestamp and arch == _arch:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
if arch == _arch:
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|