1 |
charliebrady |
1.1 |
# |
2 |
|
|
# text.py - text mode frontend to anaconda |
3 |
|
|
# |
4 |
|
|
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. |
5 |
|
|
# All rights reserved. |
6 |
|
|
# |
7 |
|
|
# This program is free software; you can redistribute it and/or modify |
8 |
|
|
# it under the terms of the GNU General Public License as published by |
9 |
|
|
# the Free Software Foundation; either version 2 of the License, or |
10 |
|
|
# (at your option) any later version. |
11 |
|
|
# |
12 |
|
|
# This program is distributed in the hope that it will be useful, |
13 |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
|
|
# GNU General Public License for more details. |
16 |
|
|
# |
17 |
|
|
# You should have received a copy of the GNU General Public License |
18 |
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 |
|
|
# |
20 |
|
|
# Author(s): Erik Troan <ewt@redhat.com> |
21 |
|
|
# Matt Wilson <msw@redhat.com> |
22 |
|
|
# |
23 |
|
|
|
24 |
|
|
from snack import * |
25 |
|
|
import sys |
26 |
|
|
import os |
27 |
|
|
import isys |
28 |
|
|
import iutil |
29 |
|
|
import time |
30 |
|
|
import signal |
31 |
|
|
import parted |
32 |
|
|
import product |
33 |
|
|
import string |
34 |
|
|
from language import expandLangs |
35 |
|
|
from flags import flags |
36 |
|
|
from constants_text import * |
37 |
|
|
from constants import * |
38 |
|
|
import network |
39 |
|
|
from installinterfacebase import InstallInterfaceBase |
40 |
|
|
import imputil |
41 |
|
|
|
42 |
|
|
import gettext |
43 |
|
|
_ = lambda x: gettext.ldgettext("anaconda", x) |
44 |
|
|
P_ = lambda x, y, z: gettext.ldngettext("anaconda", x, y, z) |
45 |
|
|
|
46 |
|
|
import logging |
47 |
|
|
log = logging.getLogger("anaconda") |
48 |
|
|
|
49 |
|
|
stepToClasses = { |
50 |
|
|
"language" : ("language_text", "LanguageWindow"), |
51 |
|
|
"keyboard" : ("keyboard_text", "KeyboardWindow"), |
52 |
|
|
"welcome" : ("welcome_text", "WelcomeWindow"), |
53 |
|
|
"parttype" : ("partition_text", "PartitionTypeWindow"), |
54 |
|
|
"addswap" : ("upgrade_text", "UpgradeSwapWindow"), |
55 |
|
|
"upgrademigratefs" : ("upgrade_text", "UpgradeMigrateFSWindow"), |
56 |
|
|
"zfcpconfig": ("zfcp_text", ("ZFCPWindow")), |
57 |
|
|
"findinstall" : ("upgrade_text", ("UpgradeExamineWindow")), |
58 |
|
|
"upgbootloader": ("upgrade_bootloader_text", "UpgradeBootloaderWindow"), |
59 |
|
|
"network" : ("network_text", ("HostnameWindow")), |
60 |
|
|
"timezone" : ("timezone_text", "TimezoneWindow"), |
61 |
|
|
"accounts" : ("userauth_text", "RootPasswordWindow"), |
62 |
|
|
"tasksel": ("task_text", "TaskWindow"), |
63 |
|
|
"install" : ("progress_text", "setupForInstall"), |
64 |
|
|
"complete" : ("complete_text", "FinishedWindow"), |
65 |
|
|
} |
66 |
|
|
|
67 |
|
|
if iutil.isS390(): |
68 |
|
|
stepToClasses["bootloader"] = ("zipl_text", ( "ZiplWindow")) |
69 |
|
|
|
70 |
|
|
class InstallWindow: |
71 |
|
|
def __call__ (self, screen): |
72 |
|
|
raise RuntimeError, "Unimplemented screen" |
73 |
|
|
|
74 |
|
|
class WaitWindow: |
75 |
|
|
def pop(self): |
76 |
|
|
self.screen.popWindow() |
77 |
|
|
self.screen.refresh() |
78 |
|
|
|
79 |
|
|
def refresh(self): |
80 |
|
|
pass |
81 |
|
|
|
82 |
|
|
def __init__(self, screen, title, text): |
83 |
|
|
self.screen = screen |
84 |
|
|
width = 40 |
85 |
|
|
if (len(text) < width): width = len(text) |
86 |
|
|
|
87 |
|
|
t = TextboxReflowed(width, text) |
88 |
|
|
|
89 |
|
|
g = GridForm(self.screen, title, 1, 1) |
90 |
|
|
g.add(t, 0, 0) |
91 |
|
|
g.draw() |
92 |
|
|
self.screen.refresh() |
93 |
|
|
|
94 |
|
|
class OkCancelWindow: |
95 |
|
|
def getrc(self): |
96 |
|
|
return self.rc |
97 |
|
|
|
98 |
|
|
def __init__(self, screen, title, text): |
99 |
|
|
rc = ButtonChoiceWindow(screen, title, text, |
100 |
|
|
buttons=[TEXT_OK_BUTTON, _("Cancel")]) |
101 |
|
|
if rc == string.lower(_("Cancel")): |
102 |
|
|
self.rc = 1 |
103 |
|
|
else: |
104 |
|
|
self.rc = 0 |
105 |
|
|
|
106 |
|
|
class ProgressWindow: |
107 |
|
|
def pop(self): |
108 |
|
|
self.screen.popWindow() |
109 |
|
|
self.screen.refresh() |
110 |
|
|
del self.scale |
111 |
|
|
self.scale = None |
112 |
|
|
|
113 |
|
|
def pulse(self): |
114 |
|
|
pass |
115 |
|
|
|
116 |
|
|
def set(self, amount): |
117 |
|
|
self.scale.set(int(float(amount) * self.multiplier)) |
118 |
|
|
self.screen.refresh() |
119 |
|
|
|
120 |
|
|
def refresh(self): |
121 |
|
|
pass |
122 |
|
|
|
123 |
|
|
def __init__(self, screen, title, text, total, updpct = 0.05, pulse = False): |
124 |
|
|
self.multiplier = 1 |
125 |
|
|
if total == 1.0: |
126 |
|
|
self.multiplier = 100 |
127 |
|
|
self.screen = screen |
128 |
|
|
width = 55 |
129 |
|
|
if (len(text) > width): width = len(text) |
130 |
|
|
|
131 |
|
|
t = TextboxReflowed(width, text) |
132 |
|
|
|
133 |
|
|
g = GridForm(self.screen, title, 1, 2) |
134 |
|
|
g.add(t, 0, 0, (0, 0, 0, 1), anchorLeft=1) |
135 |
|
|
|
136 |
|
|
self.scale = Scale(int(width), int(float(total) * self.multiplier)) |
137 |
|
|
if not pulse: |
138 |
|
|
g.add(self.scale, 0, 1) |
139 |
|
|
|
140 |
|
|
g.draw() |
141 |
|
|
self.screen.refresh() |
142 |
|
|
|
143 |
|
|
class LuksPassphraseWindow: |
144 |
|
|
def __init__(self, screen, passphrase = "", preexist = False): |
145 |
|
|
self.screen = screen |
146 |
|
|
self.passphrase = passphrase |
147 |
|
|
self.minLength = 8 |
148 |
|
|
self.preexist = preexist |
149 |
|
|
self.txt = _("Choose a passphrase for the encrypted devices. You " |
150 |
|
|
"will be prompted for this passphrase during system boot.") |
151 |
|
|
self.rc = None |
152 |
|
|
|
153 |
|
|
def run(self): |
154 |
|
|
toplevel = GridForm(self.screen, _("Passphrase for encrypted device"), |
155 |
|
|
1, 5) |
156 |
|
|
|
157 |
|
|
txt = TextboxReflowed(65, self.txt) |
158 |
|
|
toplevel.add(txt, 0, 0) |
159 |
|
|
|
160 |
|
|
passphraseentry = Entry(60, password = 1) |
161 |
|
|
toplevel.add(passphraseentry, 0, 1, (0,0,0,1)) |
162 |
|
|
|
163 |
|
|
confirmentry = Entry(60, password = 1) |
164 |
|
|
toplevel.add(confirmentry, 0, 2, (0,0,0,1)) |
165 |
|
|
|
166 |
|
|
if self.preexist: |
167 |
|
|
globalcheckbox = Checkbox(_("Also add this passphrase to all existing encrypted devices"), isOn = True) |
168 |
|
|
toplevel.add(globalcheckbox, 0, 3) |
169 |
|
|
|
170 |
|
|
buttons = ButtonBar(self.screen, [TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON]) |
171 |
|
|
toplevel.add(buttons, 0, 4, growx=1) |
172 |
|
|
|
173 |
|
|
passphraseentry.set(self.passphrase) |
174 |
|
|
confirmentry.set(self.passphrase) |
175 |
|
|
|
176 |
|
|
while True: |
177 |
|
|
rc = toplevel.run() |
178 |
|
|
res = buttons.buttonPressed(rc) |
179 |
|
|
|
180 |
|
|
passphrase = None |
181 |
|
|
if res == TEXT_OK_CHECK or rc == "F12": |
182 |
|
|
passphrase = passphraseentry.value() |
183 |
|
|
confirm = confirmentry.value() |
184 |
|
|
|
185 |
|
|
if passphrase != confirm: |
186 |
|
|
ButtonChoiceWindow(self.screen, |
187 |
|
|
_("Error with passphrase"), |
188 |
|
|
_("The passphrases you entered were " |
189 |
|
|
"different. Please try again."), |
190 |
|
|
buttons=[TEXT_OK_BUTTON]) |
191 |
|
|
passphraseentry.set("") |
192 |
|
|
confirmentry.set("") |
193 |
|
|
continue |
194 |
|
|
|
195 |
|
|
if len(passphrase) < self.minLength: |
196 |
|
|
ButtonChoiceWindow(self.screen, |
197 |
|
|
_("Error with passphrase"), |
198 |
|
|
P_("The passphrase must be at least " |
199 |
|
|
"%d character long.", |
200 |
|
|
"The passphrase must be at least " |
201 |
|
|
"%d characters long.", |
202 |
|
|
self.minLength) |
203 |
|
|
% (self.minLength,), |
204 |
|
|
buttons=[TEXT_OK_BUTTON]) |
205 |
|
|
passphraseentry.set("") |
206 |
|
|
confirmentry.set("") |
207 |
|
|
continue |
208 |
|
|
else: |
209 |
|
|
passphrase = self.passphrase |
210 |
|
|
passphraseentry.set(self.passphrase) |
211 |
|
|
confirmentry.set(self.passphrase) |
212 |
|
|
|
213 |
|
|
retrofit = False |
214 |
|
|
if self.preexist: |
215 |
|
|
retrofit = globalcheckbox.selected() |
216 |
|
|
self.rc = passphrase |
217 |
|
|
return (self.rc, retrofit) |
218 |
|
|
|
219 |
|
|
def pop(self): |
220 |
|
|
self.screen.popWindow() |
221 |
|
|
|
222 |
|
|
class PassphraseEntryWindow: |
223 |
|
|
def __init__(self, screen, device): |
224 |
|
|
self.screen = screen |
225 |
|
|
self.txt = _("Device %s is encrypted. In order to " |
226 |
|
|
"access the device's contents during " |
227 |
|
|
"installation you must enter the device's " |
228 |
|
|
"passphrase below.") % (device,) |
229 |
|
|
self.rc = None |
230 |
|
|
|
231 |
|
|
def run(self): |
232 |
|
|
toplevel = GridForm(self.screen, _("Passphrase"), 1, 4) |
233 |
|
|
|
234 |
|
|
txt = TextboxReflowed(65, self.txt) |
235 |
|
|
toplevel.add(txt, 0, 0) |
236 |
|
|
|
237 |
|
|
passphraseentry = Entry(60, password = 1) |
238 |
|
|
toplevel.add(passphraseentry, 0, 1, (0,0,0,1)) |
239 |
|
|
|
240 |
|
|
globalcheckbox = Checkbox(_("This is a global passphrase")) |
241 |
|
|
toplevel.add(globalcheckbox, 0, 2) |
242 |
|
|
|
243 |
|
|
buttons = ButtonBar(self.screen, [TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON]) |
244 |
|
|
toplevel.add(buttons, 0, 3, growx=1) |
245 |
|
|
|
246 |
|
|
rc = toplevel.run() |
247 |
|
|
res = buttons.buttonPressed(rc) |
248 |
|
|
|
249 |
|
|
passphrase = None |
250 |
|
|
isglobal = False |
251 |
|
|
if res == TEXT_OK_CHECK or rc == "F12": |
252 |
|
|
passphrase = passphraseentry.value().strip() |
253 |
|
|
isglobal = globalcheckbox.selected() |
254 |
|
|
|
255 |
|
|
self.rc = (passphrase, isglobal) |
256 |
|
|
return self.rc |
257 |
|
|
|
258 |
|
|
def pop(self): |
259 |
|
|
self.screen.popWindow() |
260 |
|
|
|
261 |
|
|
class InstallInterface(InstallInterfaceBase): |
262 |
|
|
def progressWindow(self, title, text, total, updpct = 0.05, pulse = False): |
263 |
|
|
return ProgressWindow(self.screen, title, text, total, updpct, pulse) |
264 |
|
|
|
265 |
|
|
def exitWindow(self, title, text): |
266 |
|
|
return self.messageWindow(title, text, type="custom", |
267 |
|
|
custom_buttons=[_("Exit installer")]) |
268 |
|
|
|
269 |
|
|
def messageWindow(self, title, text, type="ok", default = None, |
270 |
|
|
custom_icon=None, custom_buttons=[]): |
271 |
|
|
text = str(text) |
272 |
|
|
if type == "ok": |
273 |
|
|
ButtonChoiceWindow(self.screen, title, text, |
274 |
|
|
buttons=[TEXT_OK_BUTTON]) |
275 |
|
|
elif type == "yesno": |
276 |
|
|
if default and default == "no": |
277 |
|
|
btnlist = [TEXT_NO_BUTTON, TEXT_YES_BUTTON] |
278 |
|
|
else: |
279 |
|
|
btnlist = [TEXT_YES_BUTTON, TEXT_NO_BUTTON] |
280 |
|
|
rc = ButtonChoiceWindow(self.screen, title, text, |
281 |
|
|
buttons=btnlist) |
282 |
|
|
if rc == "yes": |
283 |
|
|
return 1 |
284 |
|
|
else: |
285 |
|
|
return 0 |
286 |
|
|
elif type == "custom": |
287 |
|
|
tmpbut = [] |
288 |
|
|
for but in custom_buttons: |
289 |
|
|
tmpbut.append(string.replace(but,"_","")) |
290 |
|
|
|
291 |
|
|
rc = ButtonChoiceWindow(self.screen, title, text, width=60, |
292 |
|
|
buttons=tmpbut) |
293 |
|
|
|
294 |
|
|
idx = 0 |
295 |
|
|
for b in tmpbut: |
296 |
|
|
if string.lower(b) == rc: |
297 |
|
|
return idx |
298 |
|
|
idx = idx + 1 |
299 |
|
|
return 0 |
300 |
|
|
else: |
301 |
|
|
return OkCancelWindow(self.screen, title, text) |
302 |
|
|
|
303 |
|
|
def detailedMessageWindow(self, title, text, longText=None, type="ok", |
304 |
|
|
default=None, custom_icon=None, |
305 |
|
|
custom_buttons=[], expanded=False): |
306 |
|
|
t = TextboxReflowed(60, text, maxHeight=8) |
307 |
|
|
|
308 |
|
|
# if it is a string, just print it as it is (#674322) |
309 |
|
|
if isinstance(longText, basestring): |
310 |
|
|
lt = Textbox(60, 6, longText, scroll=1, wrap=1) |
311 |
|
|
# if the argument is anything else we have to join it together (#654074) |
312 |
|
|
else: |
313 |
|
|
lt = Textbox(60, 6, "\n".join(longText), scroll=1, wrap=1) |
314 |
|
|
|
315 |
|
|
g = GridFormHelp(self.screen, title, help, 1, 3) |
316 |
|
|
g.add(t, 0, 0) |
317 |
|
|
g.add(lt, 0, 1, padding = (0, 1, 0, 1)) |
318 |
|
|
|
319 |
|
|
if type == "ok": |
320 |
|
|
bb = ButtonBar(self.screen, [TEXT_OK_BUTTON]) |
321 |
|
|
g.add(bb, 0, 2, growx = 1) |
322 |
|
|
return bb.buttonPressed(g.runOnce(None, None)) |
323 |
|
|
elif type == "yesno": |
324 |
|
|
if default and default == "no": |
325 |
|
|
buttons = [TEXT_NO_BUTTON, TEXT_YES_BUTTON] |
326 |
|
|
else: |
327 |
|
|
buttons = [TEXT_YES_BUTTON, TEXT_NO_BUTTON] |
328 |
|
|
|
329 |
|
|
bb = ButtonBar(self.screen, buttons) |
330 |
|
|
g.add(bb, 0, 2, growx = 1) |
331 |
|
|
rc = bb.buttonPressed(g.runOnce(None, None)) |
332 |
|
|
|
333 |
|
|
if rc == "yes": |
334 |
|
|
return 1 |
335 |
|
|
else: |
336 |
|
|
return 0 |
337 |
|
|
elif type == "custom": |
338 |
|
|
buttons = [] |
339 |
|
|
idx = 0 |
340 |
|
|
|
341 |
|
|
for button in custom_buttons: |
342 |
|
|
buttons.append(string.replace(button, "_", "")) |
343 |
|
|
|
344 |
|
|
bb = ButtonBar(self.screen, buttons) |
345 |
|
|
g.add(bb, 0, 2, growx = 1) |
346 |
|
|
rc = bb.buttonPressed(g.runOnce(None, None)) |
347 |
|
|
|
348 |
|
|
for b in buttons: |
349 |
|
|
if string.lower(b) == rc: |
350 |
|
|
return idx |
351 |
|
|
idx += 1 |
352 |
|
|
|
353 |
|
|
return 0 |
354 |
|
|
else: |
355 |
|
|
return self.messageWindow(title, text, type, default, custom_icon, |
356 |
|
|
custom_buttons) |
357 |
|
|
|
358 |
|
|
def createRepoWindow(self): |
359 |
|
|
self.messageWindow(_("Error"), |
360 |
|
|
_("Repository editing is not available in text mode.")) |
361 |
|
|
|
362 |
|
|
def editRepoWindow(self, repoObj): |
363 |
|
|
self.messageWindow(_("Error"), |
364 |
|
|
_("Repository editing is not available in text mode.")) |
365 |
|
|
|
366 |
|
|
def entryWindow(self, title, text, prompt, entrylength = None): |
367 |
|
|
(res, value) = EntryWindow(self.screen, title, text, [prompt]) |
368 |
|
|
if res == "cancel": |
369 |
|
|
return None |
370 |
|
|
r = value[0] |
371 |
|
|
r.strip() |
372 |
|
|
return r |
373 |
|
|
|
374 |
|
|
def getLuksPassphrase(self, passphrase = "", preexist = False): |
375 |
|
|
w = LuksPassphraseWindow(self.screen, passphrase = passphrase, |
376 |
|
|
preexist = preexist) |
377 |
|
|
rc = w.run() |
378 |
|
|
w.pop() |
379 |
|
|
return rc |
380 |
|
|
|
381 |
|
|
def passphraseEntryWindow(self, device): |
382 |
|
|
w = PassphraseEntryWindow(self.screen, device) |
383 |
|
|
(passphrase, isglobal) = w.run() |
384 |
|
|
w.pop() |
385 |
|
|
return (passphrase, isglobal) |
386 |
|
|
|
387 |
|
|
def enableNetwork(self): |
388 |
|
|
if len(self.anaconda.id.network.netdevices) == 0: |
389 |
|
|
return False |
390 |
|
|
from netconfig_text import NetworkConfiguratorText |
391 |
|
|
w = NetworkConfiguratorText(self.screen, self.anaconda) |
392 |
|
|
ret = w.run() |
393 |
|
|
return ret != INSTALL_BACK |
394 |
|
|
|
395 |
|
|
def kickstartErrorWindow(self, text): |
396 |
|
|
s = _("The following error was found while parsing the " |
397 |
|
|
"kickstart configuration file:\n\n%s") %(text,) |
398 |
|
|
self.messageWindow(_("Error Parsing Kickstart Config"), |
399 |
|
|
s, |
400 |
|
|
type = "custom", |
401 |
|
|
custom_buttons = [("_Reboot")], |
402 |
|
|
custom_icon="error") |
403 |
|
|
|
404 |
|
|
def mainExceptionWindow(self, shortText, longTextFile): |
405 |
|
|
from meh.ui.text import MainExceptionWindow |
406 |
|
|
log.critical(shortText) |
407 |
|
|
exnWin = MainExceptionWindow(shortText, longTextFile, screen=self.screen) |
408 |
|
|
return exnWin |
409 |
|
|
|
410 |
|
|
def saveExceptionWindow(self, accountManager, signature, *args, **kwargs): |
411 |
|
|
from meh.ui.text import SaveExceptionWindow |
412 |
|
|
network.saveExceptionEnableNetwork(self) |
413 |
|
|
win = SaveExceptionWindow (accountManager, signature, screen=self.screen, |
414 |
|
|
*args, **kwargs) |
415 |
|
|
win.run() |
416 |
|
|
|
417 |
|
|
def waitWindow(self, title, text): |
418 |
|
|
return WaitWindow(self.screen, title, text) |
419 |
|
|
|
420 |
|
|
def beep(self): |
421 |
|
|
# no-op. could call newtBell() if it was bound |
422 |
|
|
pass |
423 |
|
|
|
424 |
|
|
def drawFrame(self): |
425 |
|
|
self.screen.drawRootText (0, 0, self.screen.width * " ") |
426 |
|
|
if productArch: |
427 |
|
|
self.screen.drawRootText (0, 0, _("Welcome to %(productName)s for %(productArch)s") % {'productName': productName, 'productArch': productArch}) |
428 |
|
|
else: |
429 |
|
|
self.screen.drawRootText (0, 0, _("Welcome to %s") % productName) |
430 |
|
|
|
431 |
|
|
self.screen.pushHelpLine(_(" <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen")) |
432 |
|
|
|
433 |
|
|
def setScreen(self, screen): |
434 |
|
|
self.screen = screen |
435 |
|
|
|
436 |
|
|
def shutdown(self): |
437 |
|
|
self.screen.finish() |
438 |
|
|
self.screen = None |
439 |
|
|
|
440 |
|
|
def suspend(self): |
441 |
|
|
self.screen.suspend() |
442 |
|
|
|
443 |
|
|
def resume(self): |
444 |
|
|
self.screen.resume() |
445 |
|
|
|
446 |
|
|
def __init__(self): |
447 |
|
|
InstallInterfaceBase.__init__(self) |
448 |
|
|
signal.signal(signal.SIGINT, signal.SIG_IGN) |
449 |
|
|
signal.signal(signal.SIGTSTP, signal.SIG_IGN) |
450 |
|
|
self.screen = SnackScreen() |
451 |
|
|
self._inconsistentLVMAnswers = {} |
452 |
|
|
|
453 |
|
|
def __del__(self): |
454 |
|
|
if self.screen: |
455 |
|
|
self.screen.finish() |
456 |
|
|
|
457 |
|
|
def isRealConsole(self): |
458 |
|
|
"""Returns True if this is a _real_ console that can do things, False |
459 |
|
|
for non-real consoles such as serial, i/p virtual consoles or xen.""" |
460 |
|
|
if flags.serial or flags.virtpconsole: |
461 |
|
|
return False |
462 |
|
|
if isys.isPseudoTTY(0): |
463 |
|
|
return False |
464 |
|
|
if isys.isVioConsole(): |
465 |
|
|
return False |
466 |
|
|
return True |
467 |
|
|
|
468 |
|
|
def resetInitializeDiskQuestion(self): |
469 |
|
|
pass |
470 |
|
|
|
471 |
|
|
def questionInitializeDisk(self, path, description, size, details=""): |
472 |
|
|
if not path: |
473 |
|
|
return False |
474 |
|
|
return True |
475 |
|
|
|
476 |
|
|
def resetReinitInconsistentLVMQuestion(self): |
477 |
|
|
self._inconsistentLVMAnswers = {} |
478 |
|
|
|
479 |
|
|
def questionReinitInconsistentLVM(self, pv_names=None, lv_name=None, vg_name=None): |
480 |
|
|
|
481 |
|
|
retVal = False # The less destructive default |
482 |
|
|
allSet = frozenset(["all"]) |
483 |
|
|
|
484 |
|
|
if not pv_names or (lv_name is None and vg_name is None): |
485 |
|
|
return retVal |
486 |
|
|
|
487 |
|
|
# We are caching answers so that we don't ask for ignoring |
488 |
|
|
# in each storage.reset() again (note that reinitialization is |
489 |
|
|
# done right after confirmation in dialog, not as a planned |
490 |
|
|
# action). |
491 |
|
|
key = frozenset(pv_names) |
492 |
|
|
if key in self._inconsistentLVMAnswers: |
493 |
|
|
log.info("UI not asking about disk initialization, " |
494 |
|
|
"using cached answer: %s" % self._inconsistentLVMAnswers[key]) |
495 |
|
|
return self._inconsistentLVMAnswers[key] |
496 |
|
|
elif allSet in self._inconsistentLVMAnswers: |
497 |
|
|
log.info("UI not asking about disk initialization, " |
498 |
|
|
"using cached answer: %s" % self._inconsistentLVMAnswers[allSet]) |
499 |
|
|
return self._inconsistentLVMAnswers[allSet] |
500 |
|
|
|
501 |
|
|
if vg_name is not None: |
502 |
|
|
message = "Volume Group %s" % vg_name |
503 |
|
|
elif lv_name is not None: |
504 |
|
|
message = "Logical Volume %s" % lv_name |
505 |
|
|
|
506 |
|
|
na = {'msg': message, 'pvs': ", ".join(pv_names)} |
507 |
|
|
rc = self.messageWindow(_("Warning"), |
508 |
|
|
_("Error processing LVM.\n" |
509 |
|
|
"There is inconsistent LVM data on %(msg)s. You can " |
510 |
|
|
"reinitialize all related PVs (%(pvs)s) which will erase " |
511 |
|
|
"the LVM metadata, or ignore which will preserve the " |
512 |
|
|
"contents. This action may also be applied to all other " |
513 |
|
|
"PVs with inconsistent metadata.") % na, |
514 |
|
|
type="custom", |
515 |
|
|
custom_buttons = [ _("_Ignore"), |
516 |
|
|
_("Ignore _all"), |
517 |
|
|
_("_Re-initialize"), |
518 |
|
|
_("Re-ini_tialize all") ], |
519 |
|
|
custom_icon="question") |
520 |
|
|
if rc == 0: |
521 |
|
|
retVal = False |
522 |
|
|
elif rc == 1: |
523 |
|
|
key = allSet |
524 |
|
|
retVal = False |
525 |
|
|
elif rc == 2: |
526 |
|
|
retVal = True |
527 |
|
|
elif rc == 3: |
528 |
|
|
key = allSet |
529 |
|
|
retVal = True |
530 |
|
|
|
531 |
|
|
self._inconsistentLVMAnswers[key] = retVal |
532 |
|
|
return retVal |
533 |
|
|
|
534 |
|
|
def run(self, anaconda): |
535 |
|
|
self.anaconda = anaconda |
536 |
|
|
instLang = anaconda.id.instLanguage |
537 |
|
|
|
538 |
|
|
if instLang.getFontFile(instLang.instLang) == "none": |
539 |
|
|
if not anaconda.isKickstart: |
540 |
|
|
ButtonChoiceWindow(self.screen, "Language Unavailable", |
541 |
|
|
"%s display is unavailable in text mode. " |
542 |
|
|
"The installation will continue in " |
543 |
|
|
"English." % (instLang.instLang,), |
544 |
|
|
buttons=[TEXT_OK_BUTTON]) |
545 |
|
|
|
546 |
|
|
if not self.isRealConsole(): |
547 |
|
|
self.screen.suspendCallback(spawnShell, self.screen) |
548 |
|
|
|
549 |
|
|
# drop into the python debugger on ctrl-z if we're running in test mode |
550 |
|
|
if flags.debug: |
551 |
|
|
self.screen.suspendCallback(debugSelf, self.screen) |
552 |
|
|
|
553 |
|
|
self.instLanguage = anaconda.id.instLanguage |
554 |
|
|
|
555 |
|
|
# draw the frame after setting up the fallback |
556 |
|
|
self.drawFrame() |
557 |
|
|
|
558 |
|
|
lastrc = INSTALL_OK |
559 |
|
|
(step, instance) = anaconda.dispatch.currentStep() |
560 |
|
|
while step: |
561 |
|
|
(file, classNames) = stepToClasses[step] |
562 |
|
|
|
563 |
|
|
if type(classNames) != type(()): |
564 |
|
|
classNames = (classNames,) |
565 |
|
|
|
566 |
|
|
if lastrc == INSTALL_OK: |
567 |
|
|
step = 0 |
568 |
|
|
else: |
569 |
|
|
step = len(classNames) - 1 |
570 |
|
|
|
571 |
|
|
while step >= 0 and step < len(classNames): |
572 |
|
|
# reget the args. they could change (especially direction) |
573 |
|
|
(foo, args) = anaconda.dispatch.currentStep() |
574 |
|
|
nextWindow = None |
575 |
|
|
|
576 |
|
|
while 1: |
577 |
|
|
try: |
578 |
|
|
found = imputil.imp.find_module(file) |
579 |
|
|
loaded = imputil.imp.load_module(classNames[step], |
580 |
|
|
found[0], found[1], |
581 |
|
|
found[2]) |
582 |
|
|
nextWindow = loaded.__dict__[classNames[step]] |
583 |
|
|
break |
584 |
|
|
except ImportError, e: |
585 |
|
|
rc = ButtonChoiceWindow(self.screen, _("Error!"), |
586 |
|
|
_("An error occurred when attempting " |
587 |
|
|
"to load an installer interface " |
588 |
|
|
"component.\n\nclassName = %s") |
589 |
|
|
% (classNames[step],), |
590 |
|
|
buttons=[_("Exit"), _("Retry")]) |
591 |
|
|
|
592 |
|
|
if rc == string.lower(_("Exit")): |
593 |
|
|
sys.exit(0) |
594 |
|
|
|
595 |
|
|
win = nextWindow() |
596 |
|
|
|
597 |
|
|
#log.info("TUI running step %s (class %s, file %s)" % |
598 |
|
|
#(step, file, classNames)) |
599 |
|
|
|
600 |
|
|
rc = win(self.screen, instance) |
601 |
|
|
|
602 |
|
|
if rc == INSTALL_NOOP: |
603 |
|
|
rc = lastrc |
604 |
|
|
|
605 |
|
|
if rc == INSTALL_BACK: |
606 |
|
|
step = step - 1 |
607 |
|
|
anaconda.dispatch.dir = DISPATCH_BACK |
608 |
|
|
elif rc == INSTALL_OK: |
609 |
|
|
step = step + 1 |
610 |
|
|
anaconda.dispatch.dir = DISPATCH_FORWARD |
611 |
|
|
|
612 |
|
|
lastrc = rc |
613 |
|
|
|
614 |
|
|
if step == -1: |
615 |
|
|
if not anaconda.dispatch.canGoBack(): |
616 |
|
|
ButtonChoiceWindow(self.screen, _("Cancelled"), |
617 |
|
|
_("I can't go to the previous step " |
618 |
|
|
"from here. You will have to try " |
619 |
|
|
"again."), |
620 |
|
|
buttons=[_("OK")]) |
621 |
|
|
anaconda.dispatch.gotoPrev() |
622 |
|
|
else: |
623 |
|
|
anaconda.dispatch.gotoNext() |
624 |
|
|
|
625 |
|
|
(step, args) = anaconda.dispatch.currentStep() |
626 |
|
|
|
627 |
|
|
self.screen.finish() |
628 |
|
|
|
629 |
|
|
def setSteps(self, anaconda): |
630 |
|
|
anaconda.dispatch.skipStep("filtertype", permanent=1) |
631 |
|
|
anaconda.dispatch.skipStep("filter", permanent=1) |
632 |
|
|
anaconda.dispatch.skipStep("cleardiskssel", permanent=1) |
633 |
|
|
anaconda.dispatch.skipStep("group-selection", permanent=1) |
634 |
|
|
|
635 |
|
|
def killSelf(screen): |
636 |
|
|
screen.finish() |
637 |
|
|
os._exit(0) |
638 |
|
|
|
639 |
|
|
def debugSelf(screen): |
640 |
|
|
screen.suspend() |
641 |
|
|
import pdb |
642 |
|
|
try: |
643 |
|
|
pdb.set_trace() |
644 |
|
|
except: |
645 |
|
|
sys.exit(-1) |
646 |
|
|
screen.resume() |
647 |
|
|
|
648 |
|
|
def spawnShell(screen): |
649 |
|
|
screen.suspend() |
650 |
|
|
print("\n\nType <exit> to return to the install program.\n") |
651 |
|
|
if os.path.exists("/bin/sh"): |
652 |
|
|
iutil.execConsole() |
653 |
|
|
else: |
654 |
|
|
print("Unable to find /bin/sh to execute! Not starting shell") |
655 |
|
|
time.sleep(5) |
656 |
|
|
screen.resume() |