2013-01-23 17:28:19 +00:00
|
|
|
#
|
|
|
|
# flags.py: global anaconda flags
|
|
|
|
#
|
|
|
|
# Copyright (C) 2001 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/>.
|
|
|
|
#
|
|
|
|
|
|
|
|
import selinux
|
|
|
|
import shlex
|
|
|
|
import glob
|
2015-03-23 11:36:12 +00:00
|
|
|
from pyanaconda.constants import SELINUX_DEFAULT, CMDLINE_APPEND
|
2013-01-23 17:28:19 +00:00
|
|
|
from collections import OrderedDict
|
|
|
|
|
|
|
|
import logging
|
|
|
|
log = logging.getLogger("anaconda")
|
|
|
|
|
2016-04-10 04:00:00 +00:00
|
|
|
# Importing iutil in this module would cause an import loop, so just
|
|
|
|
# reimplement the open override
|
|
|
|
import functools
|
|
|
|
def eintr_retry_call(func, *args, **kwargs):
|
|
|
|
"""Retry an interruptible system call if interrupted."""
|
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
return func(*args, **kwargs)
|
|
|
|
except InterruptedError:
|
|
|
|
continue
|
|
|
|
open = functools.partial(eintr_retry_call, open) # pylint: disable=redefined-builtin
|
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
# A lot of effort, but it only allows a limited set of flags to be referenced
|
|
|
|
class Flags(object):
|
|
|
|
def __setattr__(self, attr, val):
|
2015-03-23 11:36:12 +00:00
|
|
|
# pylint: disable=no-member
|
2013-01-23 17:28:19 +00:00
|
|
|
if attr not in self.__dict__ and not self._in_init:
|
2014-04-07 12:38:09 +00:00
|
|
|
raise AttributeError(attr)
|
2013-01-23 17:28:19 +00:00
|
|
|
else:
|
|
|
|
self.__dict__[attr] = val
|
|
|
|
|
|
|
|
def get(self, attr, val=None):
|
|
|
|
return getattr(self, attr, val)
|
|
|
|
|
|
|
|
def set_cmdline_bool(self, flag):
|
|
|
|
if flag in self.cmdline:
|
|
|
|
setattr(self, flag, self.cmdline.getbool(flag))
|
|
|
|
|
|
|
|
def __init__(self, read_cmdline=True):
|
|
|
|
self.__dict__['_in_init'] = True
|
2015-03-23 11:36:12 +00:00
|
|
|
self.livecdInstall = False
|
|
|
|
self.ibft = True
|
|
|
|
self.usevnc = False
|
2013-01-23 17:28:19 +00:00
|
|
|
self.vncquestion = True
|
2015-03-23 11:36:12 +00:00
|
|
|
self.mpath = True
|
|
|
|
self.dmraid = True
|
2013-01-23 17:28:19 +00:00
|
|
|
self.selinux = SELINUX_DEFAULT
|
2015-03-23 11:36:12 +00:00
|
|
|
self.debug = False
|
2013-01-23 17:28:19 +00:00
|
|
|
self.armPlatform = None
|
|
|
|
self.preexisting_x11 = False
|
|
|
|
self.noverifyssl = False
|
|
|
|
self.imageInstall = False
|
|
|
|
self.automatedInstall = False
|
2014-04-07 12:38:09 +00:00
|
|
|
self.dirInstall = False
|
|
|
|
self.askmethod = False
|
|
|
|
self.eject = True
|
|
|
|
self.extlinux = False
|
2015-03-23 11:36:12 +00:00
|
|
|
self.nombr = False
|
2013-01-23 17:28:19 +00:00
|
|
|
self.gpt = False
|
|
|
|
self.leavebootorder = False
|
|
|
|
self.testing = False
|
2015-03-23 11:36:12 +00:00
|
|
|
self.mpathFriendlyNames = True
|
2013-01-23 17:28:19 +00:00
|
|
|
# ksprompt is whether or not to prompt for missing ksdata
|
|
|
|
self.ksprompt = True
|
2015-03-23 11:36:12 +00:00
|
|
|
self.rescue_mode = False
|
2015-05-30 11:20:59 +00:00
|
|
|
self.noefi = False
|
2016-04-10 04:00:00 +00:00
|
|
|
self.kexec = False
|
2013-01-23 17:28:19 +00:00
|
|
|
# parse the boot commandline
|
|
|
|
self.cmdline = BootArgs()
|
|
|
|
# Lock it down: no more creating new flags!
|
|
|
|
self.__dict__['_in_init'] = False
|
|
|
|
if read_cmdline:
|
|
|
|
self.read_cmdline()
|
|
|
|
|
|
|
|
def read_cmdline(self):
|
2015-03-23 11:36:12 +00:00
|
|
|
for f in ("selinux", "debug", "leavebootorder", "testing", "extlinux",
|
2016-04-10 04:00:00 +00:00
|
|
|
"nombr", "gpt", "noefi"):
|
2013-01-23 17:28:19 +00:00
|
|
|
self.set_cmdline_bool(f)
|
|
|
|
|
|
|
|
if not selinux.is_selinux_enabled():
|
|
|
|
self.selinux = 0
|
|
|
|
|
|
|
|
cmdline_files = ['/proc/cmdline', '/run/install/cmdline',
|
|
|
|
'/run/install/cmdline.d/*.conf', '/etc/cmdline']
|
|
|
|
class BootArgs(OrderedDict):
|
|
|
|
"""
|
|
|
|
Hold boot arguments as an OrderedDict.
|
|
|
|
"""
|
2014-04-07 12:38:09 +00:00
|
|
|
def __init__(self, cmdline=None, files=None):
|
2013-01-23 17:28:19 +00:00
|
|
|
"""
|
|
|
|
Create a BootArgs object.
|
|
|
|
Reads each of the "files", then parses "cmdline" if it was provided.
|
|
|
|
"""
|
|
|
|
OrderedDict.__init__(self)
|
2014-04-07 12:38:09 +00:00
|
|
|
if files is None:
|
|
|
|
self.read(cmdline_files)
|
|
|
|
elif files:
|
2013-01-23 17:28:19 +00:00
|
|
|
self.read(files)
|
|
|
|
if cmdline:
|
|
|
|
self.readstr(cmdline)
|
|
|
|
|
|
|
|
def read(self, filenames):
|
|
|
|
"""
|
|
|
|
Read and parse a filename (or a list of filenames).
|
|
|
|
Files that can't be read are silently ignored.
|
|
|
|
Returns a list of successfully read files.
|
2016-04-10 04:00:00 +00:00
|
|
|
filenames can contain \\*, ?, and character ranges expressed with []
|
2013-01-23 17:28:19 +00:00
|
|
|
"""
|
2016-04-10 04:00:00 +00:00
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
readfiles = []
|
2016-04-10 04:00:00 +00:00
|
|
|
if isinstance(filenames, str):
|
2013-01-23 17:28:19 +00:00
|
|
|
filenames = [filenames]
|
|
|
|
|
|
|
|
# Expand any filename globs
|
|
|
|
filenames = [f for g in filenames for f in glob.glob(g)]
|
|
|
|
|
|
|
|
for f in filenames:
|
|
|
|
try:
|
|
|
|
self.readstr(open(f).read())
|
|
|
|
readfiles.append(f)
|
|
|
|
except IOError:
|
|
|
|
continue
|
|
|
|
return readfiles
|
|
|
|
|
|
|
|
def readstr(self, cmdline):
|
|
|
|
cmdline = cmdline.strip()
|
|
|
|
# if the BOOT_IMAGE contains a space, pxelinux will strip one of the
|
|
|
|
# quotes leaving one at the end that shlex doesn't know what to do
|
|
|
|
# with
|
|
|
|
(left, middle, right) = cmdline.rpartition("BOOT_IMAGE=")
|
|
|
|
if right.count('"') % 2:
|
|
|
|
cmdline = left + middle + '"' + right
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
# shlex doesn't properly handle \\ (it removes them)
|
|
|
|
# which scrambles the spaces used in labels so use underscores
|
|
|
|
cmdline = cmdline.replace("\\x20", "_")
|
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
lst = shlex.split(cmdline)
|
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
# options might have the inst. prefix (used to differentiate
|
|
|
|
# boot options for the installer from other boot options)
|
|
|
|
inst_prefix = "inst."
|
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
for i in lst:
|
2015-03-23 11:36:12 +00:00
|
|
|
# drop the inst. prefix (if found), so that getbool() works
|
|
|
|
# consistently for both "foo=0" and "inst.foo=0"
|
|
|
|
if i.startswith(inst_prefix):
|
|
|
|
i = i[len(inst_prefix):]
|
|
|
|
|
2013-01-23 17:28:19 +00:00
|
|
|
if "=" in i:
|
|
|
|
(key, val) = i.split("=", 1)
|
|
|
|
else:
|
|
|
|
key = i
|
|
|
|
val = None
|
|
|
|
|
2015-03-23 11:36:12 +00:00
|
|
|
# Some duplicate args create a space separated string
|
|
|
|
if key in CMDLINE_APPEND and self.get(key, None):
|
|
|
|
if val:
|
|
|
|
self[key] = self[key] + " " + val
|
|
|
|
else:
|
|
|
|
self[key] = val
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
def getbool(self, arg, default=False):
|
|
|
|
"""
|
|
|
|
Return the value of the given arg, as a boolean. The rules are:
|
|
|
|
- "arg", "arg=val": True
|
|
|
|
- "noarg", "noarg=val", "arg=[0|off|no]": False
|
|
|
|
"""
|
|
|
|
result = default
|
|
|
|
for a in self:
|
|
|
|
if a == arg:
|
|
|
|
if self[arg] in ("0", "off", "no"):
|
|
|
|
result = False
|
|
|
|
else:
|
|
|
|
result = True
|
|
|
|
elif a == 'no'+arg:
|
|
|
|
result = False # XXX: should noarg=off -> True?
|
|
|
|
return result
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
def can_touch_runtime_system(msg, touch_live=False):
|
2013-01-23 17:28:19 +00:00
|
|
|
"""
|
|
|
|
Guard that should be used before doing actions that modify runtime system.
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
:param msg: message to be logged in case that runtime system cannot be touched
|
|
|
|
:type msg: str
|
|
|
|
:param touch_live: whether to allow touching liveCD installation system
|
|
|
|
:type touch_live: bool
|
|
|
|
:rtype: bool
|
2013-01-23 17:28:19 +00:00
|
|
|
|
|
|
|
"""
|
|
|
|
|
2014-04-07 12:38:09 +00:00
|
|
|
if flags.livecdInstall and not touch_live:
|
|
|
|
log.info("Not doing '%s' in live installation", msg)
|
2013-01-23 17:28:19 +00:00
|
|
|
return False
|
|
|
|
|
|
|
|
if flags.imageInstall:
|
2014-04-07 12:38:09 +00:00
|
|
|
log.info("Not doing '%s' in image installation", msg)
|
|
|
|
return False
|
|
|
|
|
|
|
|
if flags.dirInstall:
|
|
|
|
log.info("Not doing '%s' in directory installation", msg)
|
2013-01-23 17:28:19 +00:00
|
|
|
return False
|
|
|
|
|
|
|
|
if flags.testing:
|
2014-04-07 12:38:09 +00:00
|
|
|
log.info("Not doing '%s', because we are just testing", msg)
|
2013-01-23 17:28:19 +00:00
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
flags = Flags()
|
|
|
|
|