[master] Skip running efibootmgr for noefi mode (#1047904)
by Brian C. Lane
noefi on the cmdline tells the kernel not to make runtime EFI calls so
Anaconda should skip trying to run efibootmgr.
Note that noefi does NOT mean do a BIOS install. To do that the system
needs to be booted in CSM mode.
---
pyanaconda/bootloader.py | 4 ++++
pyanaconda/flags.py | 3 ++-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/pyanaconda/bootloader.py b/pyanaconda/bootloader.py
index 1bc10c9..3178027 100644
--- a/pyanaconda/bootloader.py
+++ b/pyanaconda/bootloader.py
@@ -1670,6 +1670,10 @@ class EFIGRUB(GRUB2):
log.info("Skipping efibootmgr for image/directory install.")
return ""
+ if "noefi" in flags.cmdline:
+ log.info("Skipping efibootmgr for noefi")
+ return ""
+
if kwargs.pop("capture", False):
exec_func = iutil.execWithCapture
else:
diff --git a/pyanaconda/flags.py b/pyanaconda/flags.py
index 5403f75..5636b44 100644
--- a/pyanaconda/flags.py
+++ b/pyanaconda/flags.py
@@ -69,6 +69,7 @@ class Flags(object):
# ksprompt is whether or not to prompt for missing ksdata
self.ksprompt = True
self.rescue_mode = False
+ self.noefi = False
# parse the boot commandline
self.cmdline = BootArgs()
# Lock it down: no more creating new flags!
@@ -78,7 +79,7 @@ class Flags(object):
def read_cmdline(self):
for f in ("selinux", "debug", "leavebootorder", "testing", "extlinux",
- "gpt", "dnf"):
+ "gpt", "dnf", "noefi"):
self.set_cmdline_bool(f)
if not selinux.is_selinux_enabled():
--
1.9.3
9 years, 7 months
[f21/master] Fix a race between checking for Gtk.main_level and running Gtk.main
by David Shea
Ensure that if an exception occurs before the GUI has started, causing
meh to start its own Gtk main loop, that the GUI really doesn't start
another Gtk main loop.
---
pyanaconda/anaconda.py | 10 ++++++++--
pyanaconda/exception.py | 13 ++++++++-----
pyanaconda/ui/__init__.py | 5 ++++-
pyanaconda/ui/gui/__init__.py | 13 +++++++------
pyanaconda/ui/tui/__init__.py | 4 ++--
5 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/pyanaconda/anaconda.py b/pyanaconda/anaconda.py
index 88c2e02..c207640 100644
--- a/pyanaconda/anaconda.py
+++ b/pyanaconda/anaconda.py
@@ -31,6 +31,7 @@ import sys
import stat
from glob import glob
from tempfile import mkstemp
+import threading
from pyanaconda.bootloader import get_bootloader
from pyanaconda import constants
@@ -78,6 +79,11 @@ class Anaconda(object):
self.dbus_session_connection = None
self.dbus_inhibit_id = None
+ # This is used to synchronize Gtk.main calls between the graphical
+ # interface and error dialogs. Whoever gets to their initialization code
+ # first will lock gui_initializing
+ self.gui_initialized = threading.Lock()
+
@property
def bootloader(self):
if not self._bootloader:
@@ -206,7 +212,7 @@ class Anaconda(object):
if self.displayMode == 'g':
from pyanaconda.ui.gui import GraphicalUserInterface
self._intf = GraphicalUserInterface(self.storage, self.payload,
- self.instClass)
+ self.instClass, self.gui_initialized)
# needs to be refreshed now we know if gui or tui will take place
addon_paths = addons.collect_addon_paths(constants.ADDON_PATHS,
@@ -214,7 +220,7 @@ class Anaconda(object):
elif self.displayMode in ['t', 'c']: # text and command line are the same
from pyanaconda.ui.tui import TextUserInterface
self._intf = TextUserInterface(self.storage, self.payload,
- self.instClass)
+ self.instClass, self.gui_initialized)
# needs to be refreshed now we know if gui or tui will take place
addon_paths = addons.collect_addon_paths(constants.ADDON_PATHS,
diff --git a/pyanaconda/exception.py b/pyanaconda/exception.py
index 0c5fe91..b60ac0f 100644
--- a/pyanaconda/exception.py
+++ b/pyanaconda/exception.py
@@ -50,7 +50,7 @@ log = logging.getLogger("anaconda")
class AnacondaExceptionHandler(ExceptionHandler):
- def __init__(self, confObj, intfClass, exnClass, tty_num):
+ def __init__(self, confObj, intfClass, exnClass, tty_num, gui_lock):
"""
:see: python-meh's ExceptionHandler
:param tty_num: the number of tty the interface is running on
@@ -58,6 +58,7 @@ class AnacondaExceptionHandler(ExceptionHandler):
"""
ExceptionHandler.__init__(self, confObj, intfClass, exnClass)
+ self._gui_lock = gui_lock
self._intf_tty_num = tty_num
def run_handleException(self, dump_info):
@@ -110,9 +111,10 @@ class AnacondaExceptionHandler(ExceptionHandler):
if not initialized:
raise RuntimeError()
- if Gtk.main_level() > 0:
- # main loop is running, don't crash it by running another one
- # potentially from a different thread
+ # Attempt to grab the GUI initializing lock, do not block
+ if not self._gui_lock.acquire(False):
+ # the graphical interface is running, don't crash it by
+ # running another one potentially from a different thread
log.debug("Gtk running, queuing exception handler to the "
"main loop")
GLib.idle_add(self.run_handleException, dump_info)
@@ -267,7 +269,8 @@ def initExceptionHandling(anaconda):
conf.register_callback("journalctl", journalctl_callback, attchmnt_only=False)
handler = AnacondaExceptionHandler(conf, anaconda.intf.meh_interface,
- ReverseExceptionDump, anaconda.intf.tty_num)
+ ReverseExceptionDump, anaconda.intf.tty_num,
+ anaconda.gui_initialized)
handler.install(anaconda)
return conf
diff --git a/pyanaconda/ui/__init__.py b/pyanaconda/ui/__init__.py
index b1eb060..28b24bb 100644
--- a/pyanaconda/ui/__init__.py
+++ b/pyanaconda/ui/__init__.py
@@ -42,7 +42,7 @@ class UserInterface(object):
defines what kinds of dialogs and entry widgets every interface must
provide that the rest of anaconda may rely upon.
"""
- def __init__(self, storage, payload, instclass):
+ def __init__(self, storage, payload, instclass, gui_lock):
"""Create a new UserInterface instance.
The arguments this base class accepts defines the API that interfaces
@@ -60,6 +60,8 @@ class UserInterface(object):
is useful for determining distribution-specific
installation information like default package
selections and default partitioning.
+ gui_lock -- A lock object acquired by the first thread to initialize
+ a GUI.
"""
if self.__class__ is UserInterface:
raise TypeError("UserInterface is an abstract class.")
@@ -67,6 +69,7 @@ class UserInterface(object):
self.storage = storage
self.payload = payload
self.instclass = instclass
+ self.gui_lock = gui_lock
# Register this interface with the top-level ErrorHandler.
from pyanaconda.errors import errorHandler
diff --git a/pyanaconda/ui/gui/__init__.py b/pyanaconda/ui/gui/__init__.py
index 3582718..7c3df99 100644
--- a/pyanaconda/ui/gui/__init__.py
+++ b/pyanaconda/ui/gui/__init__.py
@@ -429,11 +429,11 @@ class GraphicalUserInterface(UserInterface):
"""This is the standard GTK+ interface we try to steer everything to using.
It is suitable for use both directly and via VNC.
"""
- def __init__(self, storage, payload, instclass,
+ def __init__(self, storage, payload, instclass, gui_lock,
distributionText = product.distributionText, isFinal = product.isFinal,
quitDialog = QuitDialog):
- UserInterface.__init__(self, storage, payload, instclass)
+ UserInterface.__init__(self, storage, payload, instclass, gui_lock)
self._actions = []
self._currentAction = None
@@ -563,7 +563,8 @@ class GraphicalUserInterface(UserInterface):
if not success:
raise RuntimeError("Failed to initialize Gtk")
- if Gtk.main_level() > 0:
+ # Check if the GUI lock has already been taken
+ if not self.gui_lock.acquire(False):
# Gtk main loop running. That means python-meh caught exception
# and runs its main loop. Do not crash Gtk by running another one
# from a different thread and just wait until python-meh is
@@ -571,10 +572,10 @@ class GraphicalUserInterface(UserInterface):
unbusyCursor()
log.error("Unhandled exception caught, waiting for python-meh to "\
"exit")
- while Gtk.main_level() > 0:
- time.sleep(2)
- sys.exit(0)
+ # Loop forever, meh will call sys.exit() when it's done
+ while True:
+ time.sleep(10000)
while not self._currentAction:
self._currentAction = self._instantiateAction(self._actions[0])
diff --git a/pyanaconda/ui/tui/__init__.py b/pyanaconda/ui/tui/__init__.py
index 0fb1ca7..731437a 100644
--- a/pyanaconda/ui/tui/__init__.py
+++ b/pyanaconda/ui/tui/__init__.py
@@ -58,7 +58,7 @@ class TextUserInterface(ui.UserInterface):
ENVIRONMENT = "anaconda"
- def __init__(self, storage, payload, instclass,
+ def __init__(self, storage, payload, instclass, gui_lock,
productTitle = u"Anaconda", isFinal = True,
quitMessage = None):
"""
@@ -91,7 +91,7 @@ class TextUserInterface(ui.UserInterface):
"""
- ui.UserInterface.__init__(self, storage, payload, instclass)
+ ui.UserInterface.__init__(self, storage, payload, instclass, gui_lock)
self._app = None
self._meh_interface = meh.ui.text.TextIntf()
--
2.1.0
9 years, 7 months
[f21/master] Allow recursive lightbox calls (#1147337)
by David Shea
This way a lightbox on top of a lightbox (such as an error window on top
of a dialog, or multiple dialogs accidentally being opened on top of one
another) only adds one overlay image, and turning the lightbox off on
the way back out doesn't crash.
---
pyanaconda/ui/gui/__init__.py | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/pyanaconda/ui/gui/__init__.py b/pyanaconda/ui/gui/__init__.py
index a8269fb..5b809d4 100644
--- a/pyanaconda/ui/gui/__init__.py
+++ b/pyanaconda/ui/gui/__init__.py
@@ -280,6 +280,8 @@ class MainWindow(Gtk.Window):
self._overlay_img = None
self._overlay.connect("get-child-position", self._on_overlay_get_child_position)
+ self._overlay_depth = 0
+
# Create a stack and a list of what's been added to the stack
self._stack = Gtk.Stack()
self._stack_contents = set()
@@ -398,15 +400,19 @@ class MainWindow(Gtk.Window):
self._setVisibleChild(self._current_action)
def lightbox_on(self):
- # Add an overlay image that will be filled and scaled in get-child-position
- self._overlay_img = Gtk.Image()
- self._overlay_img.show_all()
- self._overlay.add_overlay(self._overlay_img)
+ self._overlay_depth += 1
+ if not self._overlay_img:
+ # Add an overlay image that will be filled and scaled in get-child-position
+ self._overlay_img = Gtk.Image()
+ self._overlay_img.show_all()
+ self._overlay.add_overlay(self._overlay_img)
def lightbox_off(self):
- # Remove the overlay image
- self._overlay_img.destroy()
- self._overlay_img = None
+ self._overlay_depth -= 1
+ if self._overlay_depth == 0 and self._overlay_img:
+ # Remove the overlay image
+ self._overlay_img.destroy()
+ self._overlay_img = None
@contextmanager
def enlightbox(self, dialog):
--
2.1.0
9 years, 7 months
[blivet][master/f21/rhel7] fix container member set management
by David Lehman
These are fixes for two bugs I introduced with ContainerDevice and
ParentList, together with the change that enforces raid level constraints
on member set removals in BTRFSVolumeDevice.
The DeviceFactory classes must be able to manage a container's member set.
It is important to retain the basic accounting done in _addParent and
_removeParent methods, but also to bypass any checks that enforce raid-
level requirements on the container's member set.
David Lehman (2):
Allow toggling encryption of raid container members. (#1148373)
Avoid unneccesarily tripping raid-level member count checks.
blivet/devicefactory.py | 51 ++++++++++++++++++++++++-------------------------
blivet/devices/lib.py | 15 +++++++++++++++
2 files changed, 40 insertions(+), 26 deletions(-)
--
1.9.3
9 years, 7 months
[f21/master] Disable the ntp service with --nontp (#1135768)
by David Shea
Both un-enable and disable the ntp service when ntp is turned off. We
can't always assume that ntp will be turned off by default on the
installed system, because of live images.
---
pyanaconda/kickstart.py | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/pyanaconda/kickstart.py b/pyanaconda/kickstart.py
index 1cc07ab..4843e20 100644
--- a/pyanaconda/kickstart.py
+++ b/pyanaconda/kickstart.py
@@ -1503,6 +1503,7 @@ class Timezone(commands.timezone.F18_Timezone):
self._added_chrony = False
self._enabled_chrony = False
+ self._disabled_chrony = False
def setup(self, ksdata):
if self.nontp:
@@ -1516,10 +1517,16 @@ class Timezone(commands.timezone.F18_Timezone):
ksdata.packages.packageList.remove(NTP_PACKAGE)
self._added_chrony = False
+ # Both un-enable and disable chrony, because sometimes it's installed
+ # off by default (packages) and sometimes not (liveimg).
if self._enabled_chrony and NTP_SERVICE in ksdata.services.enabled:
ksdata.services.enabled.remove(NTP_SERVICE)
self._enabled_chrony = False
+ if NTP_SERVICE not in ksdata.services.disabled:
+ ksdata.services.disabled.append(NTP_SERVICE)
+ self._disabled_chrony = True
+
else:
if not iutil.service_running(NTP_SERVICE) and \
can_touch_runtime_system("start NTP service"):
@@ -1531,6 +1538,10 @@ class Timezone(commands.timezone.F18_Timezone):
ksdata.packages.packageList.append(NTP_PACKAGE)
self._added_chrony = True
+ if self._disabled_chrony and NTP_SERVICE in ksdata.service.disabled:
+ ksdata.services.disabled.remove(NTP_SERVICE)
+ self._disabled_chrony = False
+
if not NTP_SERVICE in ksdata.services.enabled and \
not NTP_SERVICE in ksdata.services.disabled:
ksdata.services.enabled.append(NTP_SERVICE)
--
2.1.0
9 years, 7 months
[f21/master] Only allow one anaconda instance (#1146735)
by David Shea
Display a graphical error dialog if we're in the sort of environment
that can display graphical dialogs early on, otherwise just print a
message and bomb out.
---
anaconda | 42 ++++++++++++++++++++++++++++++++++++++----
1 file changed, 38 insertions(+), 4 deletions(-)
diff --git a/anaconda b/anaconda
index beeaabd..1507bbf 100755
--- a/anaconda
+++ b/anaconda
@@ -44,7 +44,7 @@ if ("debug=1" in proc_cmdline) or ("debug" in proc_cmdline):
cov.start()
-import atexit, sys, os, time, signal
+import atexit, sys, os, time, signal, stat, errno
def exitHandler(rebootData, storage):
# Clear the list of watched PIDs.
@@ -81,6 +81,9 @@ def exitHandler(rebootData, storage):
uninhibit_screensaver(anaconda.dbus_session_connection, anaconda.dbus_inhibit_id)
anaconda.dbus_inhibit_id = None
+ # Clean up the PID file
+ os.unlink("/var/run/anaconda.pid")
+
if not flags.imageInstall and not flags.livecdInstall \
and not flags.dirInstall:
from pykickstart.constants import KS_SHUTDOWN, KS_WAIT
@@ -841,9 +844,40 @@ if __name__ == "__main__":
# make sure we have /var/log soon, some programs fail to start without it
iutil.mkdirChain("/var/log")
- pidfile = open("/var/run/anaconda.pid", "w")
- pidfile.write("%s\n" % (os.getpid(),))
- del pidfile
+ # Attempt to create the pidfile
+ # Set all of the read/write bits and let umask make it make sense
+ try:
+ pidfile = os.open("/var/run/anaconda.pid", os.O_WRONLY|os.O_CREAT|os.O_EXCL,
+ stat.S_IRUSR|stat.S_IWUSR|stat.S_IRGRP|stat.S_IWGRP|stat.S_IROTH|stat.S_IWOTH)
+ os.write(pidfile, "%s\n" % os.getpid())
+ os.close(pidfile)
+ except OSError as e:
+ # If the failure was anything other than EEXIST during the open call,
+ # just re-raise the exception
+ if e.errno != errno.EEXIST:
+ raise
+
+ log.error("/var/run/anaconda.pid already exists, exiting")
+
+ # If we have a $DISPLAY and zenity is available, we may be running in
+ # a live environment and we can display an error dialog. Otherwise
+ # just print an error.
+ if "DISPLAY" in os.environ and os.access("/usr/bin/zenity", os.X_OK):
+ # The module-level _() calls are ok here because the language may
+ # be set from the live environment in this case, and anaconda's
+ # language setup hasn't happened yet.
+ # pylint: disable=found-_-in-module-class
+ iutil.execWithRedirect("zenity",
+ ["--error", "--title", _("Unable to create PID file"), "--text",
+ _("Anaconda is unable to create /var/run/anaconda.pid because the file" +
+ " already exists. Anaconda is already running, or a previous instance" +
+ " of anaconda has crashed.")])
+ else:
+ print("/var/run/anaconda.pid already exists, exiting")
+
+ iutil.ipmi_report(constants.IPMI_FAILED)
+ sys.exit(1)
+
# add our own additional signal handlers
signal.signal(signal.SIGHUP, startDebugger)
--
1.9.3
9 years, 7 months
[PATCH] We now need to specify an epoch for the python-blivet version requires.
by Chris Lumens
Currently it's not defined, which means it's 0, which means any python-blivet
build with an epoch of 1 is new enough. Of course, that's not what we want.
---
anaconda.spec.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/anaconda.spec.in b/anaconda.spec.in
index 90c39a4..714399a 100644
--- a/anaconda.spec.in
+++ b/anaconda.spec.in
@@ -91,7 +91,7 @@ The anaconda package is a metapackage for the Anaconda installer.
%package core
Summary: Core of the Anaconda installer
Requires: dnf >= %{dnfver}
-Requires: python-blivet >= 0.66
+Requires: python-blivet >= 1:0.66
Requires: python-meh >= %{mehver}
Requires: libreport-anaconda >= 2.0.21-1
Requires: libselinux-python
--
1.9.3
9 years, 7 months
[master/f21] Ignore partition start if there is a biosboot partition (#1044849)
by Brian C. Lane
A biosboot partition can be anywhere on the disk, it doesn't need to be
the first. When there is one the first partition can start lower than
without one.
---
pyanaconda/bootloader.py | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/pyanaconda/bootloader.py b/pyanaconda/bootloader.py
index b3492ee..1bc10c9 100644
--- a/pyanaconda/bootloader.py
+++ b/pyanaconda/bootloader.py
@@ -1626,20 +1626,27 @@ class GRUB2(GRUB):
if not self.stage1_disk:
return False
- # If the first partition starts too low show an error.
+ # If the first partition starts too low and there is no biosboot partition show an error.
+ error_msg = None
+ biosboot = False
parts = self.stage1_disk.format.partedDisk.partitions
for p in parts:
- start = p.geometry.start * p.disk.device.sectorSize
- if not p.getFlag(PARTITION_BIOS_GRUB) and start < min_start:
- msg = _("%(deviceName)s may not have enough space for grub2 to embed "
- "core.img when using the %(fsType)s file system on %(deviceType)s") \
- % {"deviceName": self.stage1_device.name, "fsType": self.stage2_device.format.type,
- "deviceType": self.stage2_device.type}
- log.error(msg)
- self.errors.append(msg)
- ret = False
+ if p.getFlag(PARTITION_BIOS_GRUB):
+ biosboot = True
break
+ start = p.geometry.start * p.disk.device.sectorSize
+ if start < min_start:
+ error_msg = _("%(deviceName)s may not have enough space for grub2 to embed "
+ "core.img when using the %(fsType)s file system on %(deviceType)s") \
+ % {"deviceName": self.stage1_device.name, "fsType": self.stage2_device.format.type,
+ "deviceType": self.stage2_device.type}
+
+ if error_msg and not biosboot:
+ log.error(error_msg)
+ self.errors.append(error_msg)
+ ret = False
+
return ret
class EFIGRUB(GRUB2):
--
1.9.3
9 years, 8 months
[master/f21] Remove duplicates when adding new devices (#887526)
by Brian C. Lane
bootLoaderDevices is added automatically so if the device that was just
added is one of them we were ending up with two of them. This makes sure
there aren't any duplicates.
---
pyanaconda/ui/gui/spokes/custom.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pyanaconda/ui/gui/spokes/custom.py b/pyanaconda/ui/gui/spokes/custom.py
index 9178c25..d926aca 100644
--- a/pyanaconda/ui/gui/spokes/custom.py
+++ b/pyanaconda/ui/gui/spokes/custom.py
@@ -560,6 +560,7 @@ class CustomPartitioningSpoke(NormalSpoke, StorageChecker):
# also pull in biosboot and prepboot that are on our boot disk
devices.extend(self.bootLoaderDevices)
+ devices = list(set(devices))
for _device in devices:
page.addSelector(_device, self.on_selector_clicked)
--
1.9.3
9 years, 8 months