diff options
Diffstat (limited to 'pyanaconda/isys/__init__.py')
-rwxr-xr-x | pyanaconda/isys/__init__.py | 552 |
1 files changed, 552 insertions, 0 deletions
diff --git a/pyanaconda/isys/__init__.py b/pyanaconda/isys/__init__.py new file mode 100755 index 000000000..470c52d04 --- /dev/null +++ b/pyanaconda/isys/__init__.py @@ -0,0 +1,552 @@ +# +# 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> +# + +try: + from pyanaconda import _isys +except ImportError: + # We're running in some sort of testing mode, in which case we can fix + # up PYTHONPATH and just do this basic import. + import _isys + +import string +import os +import os.path +import socket +import stat +import posix +import sys +from pyanaconda import iutil +import warnings +import resource +import re +import struct +import dbus +import selinux + +import logging +log = logging.getLogger("anaconda") + +NM_SERVICE = "org.freedesktop.NetworkManager" +NM_MANAGER_PATH = "/org/freedesktop/NetworkManager" +NM_MANAGER_IFACE = "org.freedesktop.NetworkManager" +NM_ACTIVE_CONNECTION_IFACE = "org.freedesktop.NetworkManager.Connection.Active" +NM_CONNECTION_IFACE = "org.freedesktop.NetworkManagerSettings.Connection" +NM_DEVICE_IFACE = "org.freedesktop.NetworkManager.Device" +NM_IP4CONFIG_IFACE = "org.freedesktop.NetworkManager.IP4Config" +NM_ACCESS_POINT_IFACE = "org.freedesktop.NetworkManager.AccessPoint" + +NM_STATE_UNKNOWN = 0 +NM_STATE_ASLEEP = 1 +NM_STATE_CONNECTING = 2 +NM_STATE_CONNECTED = 3 +NM_STATE_DISCONNECTED = 4 +NM_DEVICE_STATE_ACTIVATED = 8 + +DBUS_PROPS_IFACE = "org.freedesktop.DBus.Properties" + +mountCount = {} + +MIN_RAM = _isys.MIN_RAM +MIN_GUI_RAM = _isys.MIN_GUI_RAM +GUI_INSTALL_EXTRA_RAM = _isys.GUI_INSTALL_EXTRA_RAM +URL_INSTALL_EXTRA_RAM = _isys.URL_INSTALL_EXTRA_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) + +## 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): + # FIXME: implement this as a storage.devices.Device subclass + 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): + # FIXME: implement this as a storage.devices.Device subclass + 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): + # FIXME: implement this as a storage.devices.Device subclass + loop = os.open(device, os.O_RDONLY) + try: + _isys.unlosetup(loop) + finally: + os.close(loop) + +## Mount a filesystem, similar to the mount system call. +# @param device The device to mount. If bindMount is True, this should be an +# already mounted directory. Otherwise, it should be a device +# name. +# @param location The path to mount device on. +# @param fstype The filesystem type on device. This can be disk filesystems +# such as vfat or ext3, or pseudo filesystems such as proc or +# selinuxfs. +# @param readOnly Should this filesystem be mounted readonly? +# @param bindMount Is this a bind mount? (see the mount(8) man page) +# @param remount Are we mounting an already mounted filesystem? +# @return The return value from the mount system call. +def mount(device, location, fstype = "ext2", readOnly = False, + bindMount = False, remount = False, options = None): + flags = None + location = os.path.normpath(location) + if not options: + opts = ["defaults"] + else: + opts = options.split(",") + + # We don't need to create device nodes for devices that start with '/' + # (like '/usbdevfs') and also some special fake devices like 'proc'. + # First try to make a device node and if that fails, assume we can + # mount without making a device node. If that still fails, the caller + # will have to deal with the exception. + # We note whether or not we created a node so we can clean up later. + + if mountCount.has_key(location) and mountCount[location] > 0: + mountCount[location] = mountCount[location] + 1 + return + + if readOnly or bindMount or remount: + if readOnly: + opts.append("ro") + if bindMount: + opts.append("bind") + if remount: + opts.append("remount") + + flags = ",".join(opts) + + log.debug("isys.py:mount()- going to mount %s on %s as %s with options %s" %(device, location, fstype, flags)) + rc = _isys.mount(fstype, device, location, flags) + + if not rc: + mountCount[location] = 1 + + return rc + +## Unmount a filesystem, similar to the umount system call. +# @param what The directory to be unmounted. This does not need to be the +# absolute path. +# @param removeDir Should the mount point be removed after being unmounted? +# @return The return value from the umount system call. +def umount(what, removeDir = True): + what = os.path.normpath(what) + + if not os.path.isdir(what): + raise ValueError, "isys.umount() can only umount by mount point" + + if mountCount.has_key(what) and mountCount[what] > 1: + mountCount[what] = mountCount[what] - 1 + return + + log.debug("isys.py:umount()- going to unmount %s, removeDir = %s" % (what, removeDir)) + rc = _isys.umount(what) + + if removeDir and os.path.isdir(what): + try: + os.rmdir(what) + except: + pass + + if not rc and mountCount.has_key(what): + del mountCount[what] + + return rc + +## 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) + +def resetResolv(): + return _isys.resetresolv() + +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 buf.startswith("HM"): + return "physical volume (LVM)" + for sec in range(0, 4): + off = (sec * 512) + 24 + if len(buf) < off: + continue + if buf[off:].startswith("LVM2"): + return "physical volume (LVM)" + elif fstype == "lvm2pv": + return "physical volume (LVM)" + return fstype + +def ext2IsDirty(device): + label = _isys.e2dirty(device) + return label + +def ext2HasJournal(device): + hasjournal = _isys.e2hasjournal(device) + return hasjournal + +def modulesWithPaths(): + mods = [] + for modline in open("/proc/modules", "r"): + modName = modline.split(" ", 1)[0] + modInfo = iutil.execWithCapture("modinfo", + ["-F", "filename", modName]).splitlines() + modPaths = [ line.strip() for line in modInfo if line!="" ] + mods.extend(modPaths) + return mods + +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 + +def vtActivate (num): + if iutil.isS390(): + return + _isys.vtActivate (num) + +def isPseudoTTY (fd): + return _isys.isPseudoTTY (fd) + +## Flush filesystem buffers. +def sync (): + return _isys.sync () + +## Determine if a file is an ISO image or not. +# @param file The full path to a file to check. +# @return True if ISO image, False otherwise. +def isIsoImage(file): + return _isys.isisoimage(file) + +# Return number of network devices +def getNetworkDeviceCount(): + bus = dbus.SystemBus() + nm = bus.get_object(NM_SERVICE, NM_MANAGER_PATH) + devlist = nm.get_dbus_method("GetDevices")() + return len(devlist) + +# Get a D-Bus interface for the specified device's (e.g., eth0) properties. +# If dev=None, return a hash of the form 'hash[dev] = props_iface' that +# contains all device properties for all interfaces that NetworkManager knows +# about. +def getDeviceProperties(dev=None): + bus = dbus.SystemBus() + nm = bus.get_object(NM_SERVICE, NM_MANAGER_PATH) + devlist = nm.get_dbus_method("GetDevices")() + all = {} + + for path in devlist: + device = bus.get_object(NM_SERVICE, path) + device_props_iface = dbus.Interface(device, DBUS_PROPS_IFACE) + + device_interface = str(device_props_iface.Get(NM_DEVICE_IFACE, "Interface")) + + if dev is None: + all[device_interface] = device_props_iface + elif device_interface == dev: + return device_props_iface + + if dev is None: + return all + else: + return None + +# Return true if method is currently 'dhcp' for the specified device. +def isDeviceDHCP(dev=None): + if dev is None: + return False + + bus = dbus.SystemBus() + nm = bus.get_object(NM_SERVICE, NM_MANAGER_PATH) + nm_props_iface = dbus.Interface(nm, DBUS_PROPS_IFACE) + active_connections = nm_props_iface.Get(NM_MANAGER_IFACE, "ActiveConnections") + + for path in active_connections: + active = bus.get_object(NM_SERVICE, path) + active_props_iface = dbus.Interface(active, DBUS_PROPS_IFACE) + + active_service_name = active_props_iface.Get(NM_ACTIVE_CONNECTION_IFACE, "ServiceName") + active_path = active_props_iface.Get(NM_ACTIVE_CONNECTION_IFACE, "Connection") + active_devices = active_props_iface.Get(NM_ACTIVE_CONNECTION_IFACE, "Devices") + + device = bus.get_object(NM_SERVICE, active_devices[0]) + device_props_iface = dbus.Interface(device, DBUS_PROPS_IFACE) + iface = device_props_iface.Get(NM_DEVICE_IFACE, "Interface") + + if iface != dev: + continue + + connection = bus.get_object(active_service_name, active_path) + connection_iface = dbus.Interface(connection, NM_CONNECTION_IFACE) + settings = connection_iface.GetSettings() + + ip4_setting = settings.get('ipv4') + if not ip4_setting or not ip4_setting['method'] or ip4_setting['method'] == 'auto': + return True + + return False + +# Get the MAC address for a network device. +def getMacAddress(dev): + if dev == '' or dev is None: + return False + + device_props_iface = getDeviceProperties(dev=dev) + if device_props_iface is None: + return None + + device_macaddr = None + try: + device_macaddr = device_props_iface.Get(NM_DEVICE_IFACE, "HwAddress").upper() + except dbus.exceptions.DBusException as e: + if e.get_dbus_name() != 'org.freedesktop.DBus.Error.InvalidArgs': + raise + return device_macaddr + +# Get a description string for a network device (e.g., eth0) +def getNetDevDesc(dev): + from pyanaconda.baseudev import udev_get_device + desc = "Network Interface" + + if dev == '' or dev is None: + return desc + + bus = dbus.SystemBus() + nm = bus.get_object(NM_SERVICE, NM_MANAGER_PATH) + devlist = nm.get_dbus_method("GetDevices")() + + for path in devlist: + device = bus.get_object(NM_SERVICE, path) + device_iface = dbus.Interface(device, DBUS_PROPS_IFACE) + device_props = device_iface.get_dbus_method("GetAll")(NM_DEVICE_IFACE) + + if dev == device_props['Interface']: + # This is the sysfs path (for now). + udev_path = device_props['Udi'] + dev = udev_get_device(udev_path[4:]) + + if dev is None: + log.debug("weird, we have a None dev with path %s" % path) + elif dev.has_key("ID_VENDOR_ENC") and dev.has_key("ID_MODEL_ENC"): + desc = "%s %s" % (dev["ID_VENDOR_ENC"], dev["ID_MODEL_ENC"]) + elif dev.has_key("ID_VENDOR_FROM_DATABASE") and dev.has_key("ID_MODEL_FROM_DATABASE"): + desc = "%s %s" % (dev["ID_VENDOR_FROM_DATABASE"], dev["ID_MODEL_FROM_DATABASE"]) + + return desc + + return desc + +# Determine if a network device is a wireless device. +def isWirelessDevice(dev): + return _isys.isWirelessDevice(dev) + +# Get the IP address for a network device. +def getIPAddress(dev): + if dev == '' or dev is None: + return None + + device_props_iface = getDeviceProperties(dev=dev) + if device_props_iface is None: + return None + + # XXX: add support for IPv6 addresses when NM can do that + device_ip4addr = device_props_iface.Get(NM_DEVICE_IFACE, "Ip4Address") + + try: + tmp = struct.pack('I', device_ip4addr) + address = socket.inet_ntop(socket.AF_INET, tmp) + except ValueError, e: + return None + + return address + +## Get the correct context for a file from loaded policy. +# @param fn The filename to query. +def matchPathContext(fn): + con = None + try: + con = selinux.matchpathcon(os.path.normpath(fn), 0)[1] + except OSError as e: + log.info("failed to get default SELinux context for %s: %s" % (fn, e)) + return con + +## Set the SELinux file context of a file +# @param fn The filename to fix. +# @param con The context to use. +# @param instroot An optional root filesystem to look under for fn. +def setFileContext(fn, con, instroot = '/'): + full_path = os.path.normpath("%s/%s" % (instroot, fn)) + rc = False + if con is not None and os.access(full_path, os.F_OK): + try: + rc = (selinux.lsetfilecon(full_path, con) == 0) + except OSError as e: + log.info("failed to set SELinux context for %s: %s" % (full_path, e)) + return rc + +## Restore the SELinux file context of a file to its default. +# @param fn The filename to fix. +# @param instroot An optional root filesystem to look under for fn. +def resetFileContext(fn, instroot = '/'): + con = matchPathContext(fn) + if con: + if setFileContext(fn, con, instroot): + return con + return None + +def prefix2netmask(prefix): + return _isys.prefix2netmask(prefix) + +def netmask2prefix (netmask): + prefix = 0 + + while prefix < 33: + if (prefix2netmask(prefix) == netmask): + return prefix + + prefix += 1 + + return prefix + +isPAE = None +def isPaeAvailable(): + global isPAE + if isPAE is not None: + return isPAE + + isPAE = False + if not iutil.isX86(): + return isPAE + + f = open("/proc/cpuinfo", "r") + lines = f.readlines() + f.close() + + for line in lines: + if line.startswith("flags") and line.find("pae") != -1: + isPAE = True + break + + return isPAE + +def getLinkStatus(dev): + return _isys.getLinkStatus(dev) + +def getAnacondaVersion(): + return _isys.getAnacondaVersion() + +auditDaemon = _isys.auditdaemon + +handleSegv = _isys.handleSegv + +printObject = _isys.printObject +bind_textdomain_codeset = _isys.bind_textdomain_codeset +isVioConsole = _isys.isVioConsole +initLog = _isys.initLog +total_memory = _isys.total_memory |