forked from rhinstaller/anaconda
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathanaconda.py
executable file
·1198 lines (984 loc) · 45.1 KB
/
anaconda.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/python3
#
# anaconda: The Red Hat Linux Installation program
#
# Copyright (C) 1999-2013
# 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): Brent Fox <[email protected]>
# Mike Fulbright <[email protected]>
# Jakub Jelinek <[email protected]>
# Jeremy Katz <[email protected]>
# Chris Lumens <[email protected]>
# Paul Nasrat <[email protected]>
# Erik Troan <[email protected]>
# Matt Wilson <[email protected]>
#
# This toplevel file is a little messy at the moment... (2001-06-22)
# ...still messy (2013-07-12)
import os
import site
coverage = None
proc_cmdline = open("/proc/cmdline", "r").read()
proc_cmdline = proc_cmdline.split()
if ("inst.debug=1" in proc_cmdline) or ("inst.debug" in proc_cmdline):
import coverage
pyanaconda_dir = "pyanaconda"
for sitepkg in site.getsitepackages():
possible_dir = os.path.join(sitepkg, "pyanaconda")
if os.path.isdir(possible_dir):
pyanaconda_dir = possible_dir
break
cov = coverage.coverage(data_file="/mnt/sysimage/root/anaconda.coverage",
branch=True,
source=["/usr/sbin/anaconda", pyanaconda_dir]
)
cov.start()
import atexit, sys, time, signal
import pid
def exitHandler(rebootData, storage):
# Clear the list of watched PIDs.
iutil.unwatchAllProcesses()
# stop and save coverage here b/c later the file system may be unavailable
if coverage is not None:
cov.stop()
if os.path.isdir('/mnt/sysimage/root'):
cov.save()
if flags.usevnc:
vnc.shutdownServer()
if "nokill" in flags.cmdline:
iutil.vtActivate(1)
print("anaconda halting due to nokill flag.")
print("The system will be rebooted when you press Ctrl-Alt-Delete.")
while True:
time.sleep(10000)
if image_count or flags.dirInstall:
anaconda.storage.umountFilesystems(swapoff=False)
devicetree = anaconda.storage.devicetree
devicetree.teardownAll()
for imageName in devicetree.diskImages:
dev = devicetree.getDeviceByName(imageName)
for loop in dev.parents:
loop.controllable = True
dev.deactivate(recursive=True)
if anaconda.dbus_inhibit_id:
from pyanaconda.screensaver import uninhibit_screensaver
uninhibit_screensaver(anaconda.dbus_session_connection, anaconda.dbus_inhibit_id)
anaconda.dbus_inhibit_id = None
# Unsetup the payload, which most usefully unmounts live images
if anaconda.payload:
anaconda.payload.unsetup()
# Clean up the PID file
if pidfile:
pidfile.close()
if not flags.imageInstall and not flags.livecdInstall \
and not flags.dirInstall:
from pykickstart.constants import KS_SHUTDOWN, KS_WAIT
if flags.eject or rebootData.eject:
for cdrom in storage.devicetree.getDevicesByType("cdrom"):
if iutil.get_mount_paths(cdrom.path):
iutil.dracut_eject(cdrom.path)
if flags.kexec:
iutil.execWithRedirect("systemctl", ["--no-wall", "kexec"])
while True:
time.sleep(10000)
elif rebootData.action == KS_SHUTDOWN:
iutil.execWithRedirect("systemctl", ["--no-wall", "poweroff"])
elif rebootData.action == KS_WAIT:
iutil.execWithRedirect("systemctl", ["--no-wall", "halt"])
else: # reboot action is KS_REBOOT or None
iutil.execWithRedirect("systemctl", ["--no-wall", "reboot"])
def startSpiceVDAgent():
status = iutil.execWithRedirect("spice-vdagent", [])
if status:
log.info("spice-vdagent exited with status %d", status)
else:
log.info("Started spice-vdagent.")
def startX11():
import subprocess
# Start Xorg and wait for it become ready
iutil.startX(["Xorg", "-br", "-logfile", "/tmp/X.log",
":%s" % constants.X_DISPLAY_NUMBER, "vt6", "-s", "1440", "-ac",
"-nolisten", "tcp", "-dpi", "96",
"-noreset"], output_redirect=subprocess.DEVNULL)
# function to handle X startup special issues for anaconda
def doStartupX11Actions():
"""Start window manager"""
# When metacity actually connects to the X server is unknowable, but
# fortunately it doesn't matter. metacity does not need to be the first
# connection to Xorg, and if anaconda starts up before metacity, metacity
# will just take over and maximize the window and make everything right,
# fingers crossed.
# Add XDG_DATA_DIRS to the environment to pull in our overridden schema
# files.
if 'XDG_DATA_DIRS' in os.environ:
xdg_data_dirs = '/usr/share/anaconda/window-manager:' + os.environ['XDG_DATA_DIRS']
else:
xdg_data_dirs = '/usr/share/anaconda/window-manager:/usr/share'
childproc = iutil.startProgram(["metacity", "--display", ":1", "--sm-disable"],
env_add={'XDG_DATA_DIRS': xdg_data_dirs})
iutil.watchProcess(childproc, "metacity")
def set_x_resolution(runres):
if runres and opts.display_mode == 'g' and not flags.usevnc:
try:
log.info("Setting the screen resolution to: %s.", runres)
iutil.execWithRedirect("xrandr",
["-d", ":1", "-s", runres])
except RuntimeError:
log.error("The X resolution not set")
iutil.execWithRedirect("xrandr",
["-d", ":1", "-q"])
def doExtraX11Actions(runres):
"""Perform X11 actions not related to startup"""
set_x_resolution(runres)
startSpiceVDAgent()
def setupPythonUpdates():
from distutils.sysconfig import get_python_lib
import gi.overrides
if "ANACONDA_WIDGETS_OVERRIDES" in os.environ:
for p in os.environ["ANACONDA_WIDGETS_OVERRIDES"].split(":"):
gi.overrides.__path__.insert(0, os.path.abspath(p))
# Temporary hack for F18 alpha to symlink updates and product directories
# into tmpfs. To be removed after beta in order to directly use content
# from /run/install/ -- JLK
for dirname in ("updates", "product"):
if os.path.exists("/run/install/%s" % dirname):
if os.path.islink("/tmp/%s" % dirname):
# Assume updates have already been setup
return
os.symlink("/run/install/%s" % dirname,
"/tmp/%s" % dirname)
if not os.path.exists("/tmp/updates"):
return
for pkg in os.listdir("/tmp/updates"):
d = "/tmp/updates/%s" % pkg
if not os.path.isdir(d):
continue
# See if the package exists in /usr/lib{64,}/python/?.?/site-packages.
# If it does, we can set it up as an update. If not, the pkg is
# likely a completely new directory and should not be looked at.
dest = "%s/%s" % (get_python_lib(), pkg)
if not os.access(dest, os.R_OK):
dest = "%s/%s" % (get_python_lib(1), pkg)
if not os.access(dest, os.R_OK):
continue
# Symlink over everything that's in the python libdir but not in
# the updates directory.
symlink_updates(dest, d)
gi.overrides.__path__.insert(0, "/run/install/updates")
import glob
import shutil
for rule in glob.glob("/tmp/updates/*.rules"):
target = "/etc/udev/rules.d/" + rule.split('/')[-1]
shutil.copyfile(rule, target)
def symlink_updates(dest_dir, update_dir):
contents = os.listdir(update_dir)
for f in os.listdir(dest_dir):
dest_path = os.path.join(dest_dir, f)
update_path = os.path.join(update_dir, f)
if f in contents:
# recurse into directories, there might be files missing in updates
if os.path.isdir(dest_path) and os.path.isdir(update_path):
symlink_updates(dest_path, update_path)
else:
if f.endswith(".pyc") or f.endswith(".pyo"):
continue
os.symlink(dest_path, update_path)
def getAnacondaVersionString():
# we are importing the startup module directly so that it can be replaced
# by updates image, if it was replaced before the updates image can be
# loaded, it could not be easily replaced
from pyanaconda import startup_utils
return startup_utils.get_anaconda_version_string()
def parseArguments(argv=None, boot_cmdline=None):
from pyanaconda.anaconda_argparse import getArgumentParser
ap = getArgumentParser(getAnacondaVersionString(), boot_cmdline)
namespace = ap.parse_args(argv, boot_cmdline=boot_cmdline)
return (namespace, ap.deprecated_bootargs)
def setupPythonPath():
# First add our updates path
sys.path.insert(0, '/tmp/updates/')
from pyanaconda.constants import ADDON_PATHS
# append ADDON_PATHS dirs at the end
sys.path.extend(ADDON_PATHS)
def setupEnvironment():
# This method is run before any threads are started, so this is the one
# point where it's ok to modify the environment.
# pylint: disable=environment-modify
# Silly GNOME stuff
if 'HOME' in os.environ and not "XAUTHORITY" in os.environ:
os.environ['XAUTHORITY'] = os.environ['HOME'] + '/.Xauthority'
os.environ['HOME'] = '/tmp'
os.environ['LC_NUMERIC'] = 'C'
os.environ["GCONF_GLOBAL_LOCKS"] = "1"
# In theory, this gets rid of our LVM file descriptor warnings
os.environ["LVM_SUPPRESS_FD_WARNINGS"] = "1"
# make sure we have /sbin and /usr/sbin in our path
os.environ["PATH"] += ":/sbin:/usr/sbin"
# we can't let the LD_PRELOAD hang around because it will leak into
# rpm %post and the like. ick :/
if "LD_PRELOAD" in os.environ:
del os.environ["LD_PRELOAD"]
# Go ahead and set $DISPLAY whether we're going to use X or not
if 'DISPLAY' in os.environ:
flags.preexisting_x11 = True
else:
os.environ["DISPLAY"] = ":%s" % constants.X_DISPLAY_NUMBER
def setupLoggingFromOpts(options):
if (options.debug or options.updateSrc) and not options.loglevel:
# debugging means debug logging if an explicit level hasn't been st
options.loglevel = "debug"
if options.loglevel and options.loglevel in anaconda_log.logLevelMap:
log.info("Switching logging level to %s", options.loglevel)
level = anaconda_log.logLevelMap[options.loglevel]
anaconda_log.logger.loglevel = level
anaconda_log.setHandlersLevel(log, level)
storage_log = logging.getLogger("storage")
anaconda_log.setHandlersLevel(storage_log, level)
packaging_log = logging.getLogger("packaging")
anaconda_log.setHandlersLevel(packaging_log, level)
if can_touch_runtime_system("syslog setup"):
if options.syslog:
anaconda_log.logger.updateRemote(options.syslog)
if options.remotelog:
try:
host, port = options.remotelog.split(":", 1)
port = int(port)
anaconda_log.logger.setup_remotelog(host, port)
except ValueError:
log.error("Could not setup remotelog with %s", options.remotelog)
def gtk_warning(title, reason):
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
dialog = Gtk.MessageDialog(type=Gtk.MessageType.ERROR,
buttons=Gtk.ButtonsType.CLOSE,
message_format=reason)
dialog.set_title(title)
dialog.run()
dialog.destroy()
# pylint: disable=redefined-outer-name
def check_memory(anaconda, options, display_mode=None):
from pyanaconda import isys
reason_strict = _("%(product_name)s requires %(needed_ram)s MB of memory to "
"install, but you only have %(total_ram)s MB on this machine.\n")
reason_graphical = _("The %(product_name)s graphical installer requires %(needed_ram)s "
"MB of memory, but you only have %(total_ram)s MB\n.")
reboot_extra = _('\n'
'Press <Enter> to reboot your system.\n')
livecd_title = _("Not enough RAM")
livecd_extra = _(" Try the text mode installer by running:\n\n"
"'/usr/bin/liveinst -T'\n\n from a root "
"terminal.")
nolivecd_extra = _(" Starting text mode.")
if options.rescue:
return
if not display_mode:
display_mode = anaconda.displayMode
reason = reason_strict
total_ram = int(isys.total_memory() / 1024)
needed_ram = int(isys.MIN_RAM)
graphical_ram = int(isys.MIN_GUI_RAM)
# count the squashfs.img in if it is kept in RAM
if not iutil.persistent_root_image():
needed_ram += isys.SQUASHFS_EXTRA_RAM
graphical_ram += isys.SQUASHFS_EXTRA_RAM
log.info("check_memory(): total:%s, needed:%s, graphical:%s",
total_ram, needed_ram, graphical_ram)
if not options.memcheck:
log.warning("CHECK_MEMORY DISABLED")
return
reason_args = {"product_name": product.productName,
"needed_ram": needed_ram,
"total_ram": total_ram}
if needed_ram > total_ram:
if options.liveinst:
# pylint: disable=logging-not-lazy
stdoutLog.warning(reason % reason_args)
gtk_warning(livecd_title, reason % reason_args)
else:
reason += reboot_extra
print(reason % reason_args)
print(_("The installation cannot continue and the system will be rebooted"))
print(_("Press ENTER to continue"))
input()
iutil.ipmi_report(constants.IPMI_ABORTED)
sys.exit(1)
# override display mode if machine cannot nicely run X
if display_mode not in ('t', 'c', 's') and not flags.usevnc:
needed_ram = graphical_ram
reason_args["needed_ram"] = graphical_ram
reason = reason_graphical
if needed_ram > total_ram:
if options.liveinst:
reason += livecd_extra
# pylint: disable=logging-not-lazy
stdoutLog.warning(reason % reason_args)
title = livecd_title
gtk_warning(title, reason % reason_args)
iutil.ipmi_report(constants.IPMI_ABORTED)
sys.exit(1)
else:
reason += nolivecd_extra
# pylint: disable=logging-not-lazy
stdoutLog.warning(reason % reason_args)
anaconda.displayMode = 't'
time.sleep(2)
def startDebugger(signum, frame):
# pylint: disable=import-error
import epdb
epdb.serve(skip=1)
# pylint: disable=redefined-outer-name
def setupDisplay(anaconda, options, addons=None):
from pyanaconda.ui.tui.simpleline import App
from pyanaconda.ui.tui.spokes.askvnc import AskVNCSpoke
from pykickstart.constants import DISPLAY_MODE_TEXT
from pyanaconda.nm import nm_is_connected, nm_is_connecting
from blivet import arch
graphical_failed = 0
vncS = vnc.VncServer() # The vnc Server object.
vncS.anaconda = anaconda
anaconda.displayMode = options.display_mode
anaconda.isHeadless = arch.isS390()
if options.vnc:
flags.usevnc = True
anaconda.displayMode = 'g'
vncS.password = options.vncpassword
# Only consider vncconnect when vnc is a param
if options.vncconnect:
cargs = options.vncconnect.split(":")
vncS.vncconnecthost = cargs[0]
if len(cargs) > 1 and len(cargs[1]) > 0:
if len(cargs[1]) > 0:
vncS.vncconnectport = cargs[1]
if options.xdriver:
anaconda.xdriver = options.xdriver
anaconda.writeXdriver(root="/")
if flags.rescue_mode:
return
if anaconda.ksdata.vnc.enabled:
flags.usevnc = True
anaconda.displayMode = 'g'
if vncS.password == "":
vncS.password = anaconda.ksdata.vnc.password
if vncS.vncconnecthost == "":
vncS.vncconnecthost = anaconda.ksdata.vnc.host
if vncS.vncconnectport == "":
vncS.vncconnectport = anaconda.ksdata.vnc.port
if anaconda.displayMode == "g":
import pkgutil
import pyanaconda.ui
mods = (tup[1] for tup in pkgutil.iter_modules(pyanaconda.ui.__path__, "pyanaconda.ui."))
if "pyanaconda.ui.gui" not in mods:
stdoutLog.warning("Graphical user interface not available, falling back to text mode")
anaconda.displayMode = "t"
flags.usevnc = False
flags.vncquestion = False
# disable VNC over text question when not enough memory is available
if blivet.util.total_memory() < isys.MIN_GUI_RAM:
stdoutLog.warning("Not asking for VNC because current memory (%d) < MIN_GUI_RAM (%d)", blivet.util.total_memory(), isys.MIN_GUI_RAM)
flags.vncquestion = False
# disable VNC question if text mode is requested and this is a ks install
if anaconda.displayMode == 't' and flags.automatedInstall:
stdoutLog.warning("Not asking for VNC because of an automated install")
flags.vncquestion = False
# disable VNC question if we were explicitly asked for text in kickstart
if anaconda.ksdata.displaymode.displayMode == DISPLAY_MODE_TEXT:
stdoutLog.warning("Not asking for VNC because text mode was explicitly asked for in kickstart")
flags.vncquestion = False
# disable VNC question if we don't have network
if not nm_is_connecting() and not nm_is_connected():
stdoutLog.warning("Not asking for VNC because we don't have a network")
flags.vncquestion = False
# disable VNC question if we don't have Xvnc
if not os.access('/usr/bin/Xvnc', os.X_OK):
stdoutLog.warning("Not asking for VNC because we don't have Xvnc")
flags.vncquestion = False
# Should we try to start Xorg?
want_x = anaconda.displayMode == 'g' and \
not (flags.preexisting_x11 or flags.usevnc)
# X on a headless (e.g. s390) system? Nonsense!
if want_x and anaconda.isHeadless:
stdoutLog.warning(_("DISPLAY variable not set. Starting text mode."))
anaconda.displayMode = 't'
graphical_failed = 1
time.sleep(2)
want_x = False
# Is Xorg is actually available?
if want_x and not os.access("/usr/bin/Xorg", os.X_OK):
stdoutLog.warning(_("Graphical installation is not available. "
"Starting text mode."))
time.sleep(2)
anaconda.displayMode = 't'
want_x = False
if anaconda.displayMode == 't' and flags.vncquestion:
#we prefer vnc over text mode, so ask about that
message = _("Text mode provides a limited set of installation "
"options. It does not offer custom partitioning for "
"full control over the disk layout. Would you like "
"to use VNC mode instead?")
app = App("VNC Question")
spoke = AskVNCSpoke(app, anaconda.ksdata, message=message)
app.schedule_screen(spoke)
app.run()
if anaconda.ksdata.vnc.enabled:
anaconda.displayMode = 'g'
flags.usevnc = True
vncS.password = anaconda.ksdata.vnc.password
else:
# user has explicitly specified text mode
flags.vncquestion = False
log.info("Display mode = %s", anaconda.displayMode)
check_memory(anaconda, options)
# check_memory may have changed the display mode
want_x = want_x and (anaconda.displayMode == "g")
if want_x:
try:
startX11()
doStartupX11Actions()
except (OSError, RuntimeError) as e:
log.warning("X startup failed: %s", e)
stdoutLog.warning("X startup failed, falling back to text mode")
anaconda.displayMode = 't'
graphical_failed = 1
time.sleep(2)
if not graphical_failed:
doExtraX11Actions(options.runres)
if anaconda.displayMode == 't' and graphical_failed and \
flags.vncquestion and not anaconda.ksdata.vnc.enabled:
app = App("VNC Question")
spoke = AskVNCSpoke(app, anaconda.ksdata)
app.schedule_screen(spoke)
app.run()
if anaconda.ksdata.vnc.enabled:
anaconda.displayMode = 'g'
flags.usevnc = True
vncS.password = anaconda.ksdata.vnc.password
# if they want us to use VNC do that now
if anaconda.displayMode == 'g' and flags.usevnc:
vncS.startServer()
doStartupX11Actions()
# with X running we can initialize the UI interface
anaconda.initInterface(addons)
anaconda.instClass.configure(anaconda)
# report if starting the GUI failed
anaconda.gui_startup_failed = bool(graphical_failed)
def prompt_for_ssh():
# Do some work here to get the ip addr / hostname to pass
# to the user.
import socket
ip = network.getFirstRealIP()
if not ip:
stdoutLog.error("No IP addresses found, cannot continue installation.")
iutil.ipmi_report(constants.IPMI_ABORTED)
sys.exit(1)
ipstr = ip
try:
hinfo = socket.gethostbyaddr(ipstr)
except socket.herror as e:
stdoutLog.debug("Exception caught trying to get host name of %s: %s", ipstr, e)
name = network.getHostname()
else:
if len(hinfo) == 3:
name = hinfo[0]
if ip.find(':') != -1:
ipstr = "[%s]" % (ip,)
if (name is not None) and (not name.startswith('localhost')) and (ipstr is not None):
connxinfo = "%s (%s)" % (socket.getfqdn(name=name), ipstr,)
elif ipstr is not None:
connxinfo = "%s" % (ipstr,)
else:
connxinfo = None
if connxinfo:
stdoutLog.info(_("Please ssh install@%s to begin the install."), connxinfo)
else:
stdoutLog.info(_("Please ssh install@<host> to continue installation."))
def cleanPStore():
"""remove files stored in nonvolatile ram created by the pstore subsystem"""
# files in pstore are linux (not distribution) specific, but we want to
# make sure the entirity of them are removed so as to ensure that there
# is sufficient free space on the flash part. On some machines this will
# take effect immediately, which is the best case. Unfortunately on some,
# an intervening reboot is needed."""
iutil.dir_tree_map("/sys/fs/pstore", os.unlink, files=True, dirs=False)
if __name__ == "__main__":
# check if the CLI help is requested and return it at once,
# without importing random stuff and spamming stdout
if ("--help" in sys.argv) or ("-h" in sys.argv) or ("--version" in sys.argv):
# we skip the full logging initialisation, but we need to do at least
# this much (redirect any log messages to stdout) to get rid of the
# harmless but annoying "no handlers found" message on stdout
import logging
log = logging.getLogger("anaconda")
log.addHandler(logging.StreamHandler(stream=sys.stdout))
parseArguments()
print("Starting installer, one moment...")
# Allow a file to be loaded as early as possible
try:
# pylint: disable=import-error,unused-import
import updates_disk_hook
except ImportError:
pass
# this handles setting up updates for pypackages to minimize the set needed
setupPythonUpdates()
setupPythonPath()
# init threading before Gtk can do anything and before we start using threads
# initThreading initializes the threadMgr instance, import it afterwards
from pyanaconda.threads import initThreading, AnacondaThread
initThreading()
from pyanaconda.threads import threadMgr
from pyanaconda.i18n import _
from pyanaconda import constants
from pyanaconda.addons import collect_addon_paths
from pyanaconda import geoloc
from pyanaconda import iutil
# do this early so we can set flags before initializing logging
from pyanaconda.flags import flags, can_touch_runtime_system
(opts, depr) = parseArguments(boot_cmdline=flags.cmdline)
if opts.images:
flags.imageInstall = True
elif opts.dirinstall:
flags.dirInstall = True
# Set up logging as early as possible.
import logging
from pyanaconda import anaconda_log
anaconda_log.init()
anaconda_log.logger.setupVirtio()
from pyanaconda import network
network.setup_ifcfg_log()
log = logging.getLogger("anaconda")
stdoutLog = logging.getLogger("anaconda.stdout")
if os.geteuid() != 0:
stdoutLog.error("anaconda must be run as root.")
sys.exit(1)
# see if we're on s390x and if we've got an ssh connection
uname = os.uname()
if uname[4] == 's390x':
if 'TMUX' not in os.environ and 'ks' not in flags.cmdline and not flags.imageInstall:
prompt_for_ssh()
sys.exit(0)
log.info("%s %s", sys.argv[0], getAnacondaVersionString())
if os.path.exists("/tmp/updates"):
log.info("Using updates in /tmp/updates/ from %s", opts.updateSrc)
# TODO: uncomment this when we're sure that we're doing the right thing
# with flags.cmdline *everywhere* it appears...
#for arg in depr:
# stdoutLog.warn("Boot argument '%s' is deprecated. "
# "In the future, use 'inst.%s'.", arg, arg)
# pull this in to get product name and versioning
from pyanaconda import product
from pyanaconda import isys
iutil.ipmi_report(constants.IPMI_STARTED)
if opts.images and opts.dirinstall:
stdoutLog.error("--images and --dirinstall cannot be used at the same time")
iutil.ipmi_report(constants.IPMI_ABORTED)
sys.exit(1)
elif opts.dirinstall:
root_path = opts.dirinstall
iutil.setTargetPhysicalRoot(root_path)
iutil.setSysroot(root_path)
from pyanaconda import vnc
from pyanaconda import kickstart
from pyanaconda import ntp
from pyanaconda import keyboard
from pyanaconda.iutil import ProxyString, ProxyStringError
verdesc = "%s for %s %s" % (getAnacondaVersionString(),
product.productName, product.productVersion)
logs_note = " * installation log files are stored in /tmp during the installation"
shell_and_tmux_note = " * shell is available on TTY2"
shell_only_note = " * shell is available on TTY2 and in second TMUX pane (ctrl+b, then press 2)"
tmux_only_note = " * shell is available in second TMUX pane (ctrl+b, then press 2)"
text_mode_note = " * if the graphical installation interface fails to start, try again with the\n"\
" inst.text bootoption to start text installation"
separate_attachements_note = " * when reporting a bug add logs from /tmp as separate text/plain attachments"
if product.isFinal:
print("anaconda %s started." % verdesc)
else:
print("anaconda %s (pre-release) started." % verdesc)
# we are past the --version and --help shortcut so we can import Blivet
# now without slowing down anything critical
# pylint: disable=import-error
from blivet import arch
if not opts.images and not opts.dirinstall:
print(logs_note)
# no fancy stuff like TTYs on a s390...
if not arch.isS390():
if "TMUX" in os.environ and os.environ.get("TERM") == "screen":
print(shell_and_tmux_note)
else:
print(shell_only_note) # TMUX is not running
# ...but there is apparently TMUX during the manual installation on s390!
elif not opts.ksfile:
print(tmux_only_note) # but not during kickstart installation
# no need to tell users how to switch to text mode
# if already in text mode
if opts.display_mode == 'g':
print(text_mode_note)
print(separate_attachements_note)
from pyanaconda.anaconda import Anaconda
anaconda = Anaconda()
iutil.setup_translations()
# reset python's default SIGINT handler
signal.signal(signal.SIGINT, signal.SIG_IGN)
signal.signal(signal.SIGTERM, lambda num, frame: sys.exit(1))
# synchronously-delivered signals such as SIGSEGV and SIGILL cannot be
# handled properly from python, so install signal handlers from the C
# function in isys.
isys.installSyncSignalHandlers()
setupEnvironment()
# make sure we have /var/log soon, some programs fail to start without it
iutil.mkdirChain("/var/log")
# Create a PID file. The exit handler, installed later, will clean it up.
pidfile = pid.PidFile(pidname='anaconda', register_term_signal_handler=False)
try:
pidfile.create()
except pid.PidFileError as e:
log.error("Unable to create %s, exiting", pidfile.filename)
# If we had a $DISPLAY at start 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 flags.preexisting_x11 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 %s because the file" +
" already exists. Anaconda is already running, or a previous instance" +
" of anaconda has crashed.") % pidfile.filename])
else:
print("%s already exists, exiting" % pidfile.filename)
iutil.ipmi_report(constants.IPMI_FAILED)
sys.exit(1)
# add our own additional signal handlers
signal.signal(signal.SIGHUP, startDebugger)
anaconda.opts = opts
# check memory, just the text mode for now:
check_memory(anaconda, opts, 't')
# Now that we've got arguments, do some extra processing.
setupLoggingFromOpts(opts)
# Default is to prompt to mount the installed system.
anaconda.rescue_mount = not opts.rescue_nomount
# assign the other anaconda variables from options
anaconda.proxy = opts.proxy
anaconda.updateSrc = opts.updateSrc
anaconda.methodstr = opts.method
anaconda.stage2 = opts.stage2
flags.rescue_mode = opts.rescue
if opts.liveinst:
from pyanaconda.screensaver import inhibit_screensaver
from pyanaconda import safe_dbus
flags.livecdInstall = True
try:
anaconda.dbus_session_connection = safe_dbus.get_new_session_connection()
except safe_dbus.DBusCallError as e:
log.info("Unable to connect to DBus session bus: %s", e)
else:
anaconda.dbus_inhibit_id = inhibit_screensaver(anaconda.dbus_session_connection)
elif "LIVECMD" in os.environ:
log.warning("Running via liveinst, but not setting flags.livecdInstall - this is for testing only")
# set flags
flags.noverifyssl = opts.noverifyssl
flags.armPlatform = opts.armPlatform
flags.extlinux = opts.extlinux
flags.nombr = opts.nombr
flags.mpathFriendlyNames = opts.mpathfriendlynames
flags.debug = opts.debug
flags.askmethod = opts.askmethod
flags.dmraid = opts.dmraid
flags.mpath = opts.mpath
flags.ibft = opts.ibft
flags.selinux = opts.selinux
flags.eject = opts.eject
flags.kexec = opts.kexec
# Switch to tty1 on exception in case something goes wrong during X start.
# This way if, for example, metacity doesn't start, we switch back to a
# text console with a traceback instead of being left looking at a blank
# screen. python-meh will replace this excepthook with its own handler
# once it gets going.
if can_touch_runtime_system("early exception handler"):
def _earlyExceptionHandler(ty, value, traceback):
iutil.ipmi_report(constants.IPMI_FAILED)
iutil.vtActivate(1)
return sys.__excepthook__(ty, value, traceback)
sys.excepthook = _earlyExceptionHandler
if can_touch_runtime_system("start audit daemon"):
# auditd will turn into a daemon and exit. Ignore startup errors
try:
iutil.execWithRedirect("/sbin/auditd", [])
except OSError:
pass
# setup links required for all install types
for i in ("services", "protocols", "nsswitch.conf", "joe", "selinux",
"mke2fs.conf"):
try:
if os.path.exists("/mnt/runtime/etc/" + i):
os.symlink("../mnt/runtime/etc/" + i, "/etc/" + i)
except OSError:
pass
log.info("anaconda called with cmdline = %s", sys.argv)
log.info("Default encoding = %s ", sys.getdefaultencoding())
iutil.execWithRedirect("udevadm", ["control", "--env=ANACONDA=1"])
# Collect all addon paths
addon_paths = collect_addon_paths(constants.ADDON_PATHS)
# If we were given a kickstart file on the command line, parse (but do not
# execute) that now. Otherwise, load in defaults from kickstart files
# shipped with the installation media.
ksdata = None
if opts.ksfile and not opts.liveinst:
if not os.path.exists(opts.ksfile):
stdoutLog.error("Kickstart file %s is missing.", opts.ksfile)
iutil.ipmi_report(constants.IPMI_ABORTED)
sys.exit(1)
flags.automatedInstall = True
flags.eject = False
ksFiles = [opts.ksfile]
elif os.path.exists("/run/install/ks.cfg") and not opts.liveinst:
# this is to handle such cases where a user has pre-loaded a
# ks.cfg onto an OEMDRV labeled device
flags.automatedInstall = True
flags.eject = False
ksFiles = ["/run/install/ks.cfg"]
else:
ksFiles = ["/tmp/updates/interactive-defaults.ks",
"/usr/share/anaconda/interactive-defaults.ks"]
for ks in ksFiles:
if not os.path.exists(ks):
continue
kickstart.preScriptPass(ks)
log.info("Parsing kickstart: " + ks)
ksdata = kickstart.parseKickstart(ks)
# Only load the first defaults file we find.
break
if not ksdata:
ksdata = kickstart.AnacondaKSHandler(addon_paths["ks"])
# Pick up any changes from interactive-defaults.ks that would
# otherwise be covered by the dracut KS parser.
if ksdata.bootloader.extlinux:
flags.extlinux = True
if ksdata.rescue.rescue:
flags.rescue_mode = True
# reboot with kexec
if ksdata.reboot.kexec:
flags.kexec = True
# Some kickstart commands must be executed immediately, as they affect
# how anaconda operates.
ksdata.logging.execute()
anaconda.ksdata = ksdata
# setup keyboard layout from the command line option and let
# it override from kickstart if/when X is initialized
if opts.keymap:
if not ksdata.keyboard.keyboard:
ksdata.keyboard.keyboard = opts.keymap
if ksdata.keyboard.keyboard:
if can_touch_runtime_system("activate keyboard"):
keyboard.activate_keyboard(ksdata.keyboard)
else:
# at least make sure we have all the values
keyboard.populate_missing_items(ksdata.keyboard)
# Some post-install parts of anaconda are implemented as kickstart
# scripts. Add those to the ksdata now.
kickstart.appendPostScripts(ksdata)
# cmdline flags override kickstart settings
if anaconda.proxy:
ksdata.method.proxy = anaconda.proxy
# Setup proxy environmental variables so that pre/post scripts use it
# as well as libreport
try:
proxy = ProxyString(anaconda.proxy)
except ProxyStringError as e:
log.info("Failed to parse proxy \"%s\": %s", anaconda.proxy, e)
else:
# Set environmental variables to be used by pre/post scripts
iutil.setenv("PROXY", proxy.noauth_url)
iutil.setenv("PROXY_USER", proxy.username or "")
iutil.setenv("PROXY_PASSWORD", proxy.password or "")
# Variables used by curl, libreport, etc.
iutil.setenv("http_proxy", proxy.url)
iutil.setenv("ftp_proxy", proxy.url)
iutil.setenv("HTTPS_PROXY", proxy.url)
if flags.noverifyssl:
ksdata.method.noverifyssl = flags.noverifyssl
if opts.multiLib:
# sets dnf's multilib_policy to "all" (as opposed to "best")