Linux安装程序Anaconda分析(续)
本来想写篇关于Anaconda的文章,但看到这里写的这么详细,转,原文在这里:Linux安装程序Anaconda分析(续)
(1) disptach.py: 下面我们看一下Dispatcher类的主要接口。
1)gotoNext & gotoPrev:这两个接口分别从当前安装步骤前进(后退)到下一个(上一个)具有用户界面的安装步骤,在图形界面安装模式下,由InstallControlWindow类调用,在字符模式下,由InstallInterface类(在text.py和cmdline.py中)调用。这两个函数只是简单的设置安装方向,然后调用moveStep函数,其核心操作是moveStep。
2)moveStep:我们来重点分析movestep函数,代码如下:
def moveStep(self):
if self.step == None:
self.step = self.firstStep
else:
if self.step >= len(installSteps):
return None log.info("leaving (%d) step %s" %(self._getDir(), installSteps[self.step][0]))
self.step = self.step + self._getDir() if self.step >= len(installSteps):
return None while self.step >= self.firstStep and self.step < len(installSteps) \
and (self.stepInSkipList(self.step) or self.stepIsDirect(self.step)): if self.stepIsDirect(self.step) and not self.stepInSkipList(self.step):
(stepName, stepFunc) = installSteps[self.step]
log.info("moving (%d) to step %s" %(self._getDir(), stepName))
log.debug("%s is a direct step" %(stepName,))
rc = stepFunc(self.anaconda)
if rc in [DISPATCH_BACK, DISPATCH_FORWARD]:
self._setDir(rc)
log.info("leaving (%d) step %s" %(self._getDir(), stepName))
# if anything else, leave self.dir alone self.step = self.step + self._getDir()
if self.step == len(installSteps): # 安装过程完成,退出循环
return None if (self.step < 0):
# pick the first step not in the skip list
self.step = 0
while self.skipSteps.has_key(installSteps[self.step][0]):
self.step = self.step + 1 # 步数加一,向前
elif self.step >= len(installSteps):
self.step = len(installSteps) - 1
while self.skipSteps.has_key(installSteps[self.step][0]):
self.step = self.step - 1
log.info("moving (%d) to step %s" %(self._getDir(), installSteps[self.step][0]))
我们重点看一下程序while循环体,首先看一下循环条件:当下一个安装步骤是合法的,即在第一个安装步骤和最后一个安装步骤之间,并且(and)该步骤被跳过或者该步骤是一个无用户界面的安装步骤,即installSteps的条目的第二个元素是一个function,则进入循环体。进入循环后,Dispatcher直接调用该函数stepFunc执行安装操作。如果下一个安装步骤依然无用户界面,则步数加一向前,继续循环,直到下一个没有被跳过的具有用户界面的安装步骤,对于图形安装模式,Dispatcher将控制权交给guid.py中的InstallControlWindow,对于字符安装模式,Dispatcher将控制权交给InstallInterface。如果安装过程完成则退出循环。
3)currentStep:Dispatcher类的另一个主要接口,取得当前的安装步骤及其相关信息返回给调用者。在图形安装模式下,该函数主要在InstallControlWindow调度图形用户界面类时调用,在字符模式下,主要在InstallInterface调度字符用户界面时调用,这两个类通过该接口取得当前安装步骤的用户界面对应类及创建该用户界面类的实例所需的信息。
def currentStep(self):
if self.step == None:
self.gotoNext()
elif self.step >= len(installSteps):
return (None, None) stepInfo = installSteps[self.step]
step = stepInfo[0] return (step, self.anaconda)
另外,Dispatcher类的主要接口还有skipStep(self, stepToSkip, skip = 1, permanent = 0)是跳过安装步骤的函数。setStepList(self, *steps)是安装步骤设置函数,主要由安装类型实例调用,每个安装类型会根据自身的特点设置安装步骤。这些接口的实现逻辑都比较简单,这里不一一给出分析了。
(2)gui.py: 核心是字符安装模式的InstallInterface类和图形安装模式InstallControlWindow类的实现。看InstallControlWindow中的接口。
1)数据结构stepTopClass: 该字典中记录了安装过程中所有的具有图形用户界面的安装步骤。
stepToClass = {
"language" : ("language_gui", "LanguageWindow"),
"keyboard" : ("kbd_gui", "KeyboardWindow"),
"filtertype" : ("filter_type", "FilterTypeWindow"),
"filter" : ("filter_gui", "FilterWindow"),
"zfcpconfig" : ("zfcp_gui", "ZFCPWindow"),
"partition" : ("partition_gui", "PartitionWindow"),
"parttype" : ("autopart_type", "PartitionTypeWindow"),
"cleardiskssel": ("cleardisks_gui", "ClearDisksWindow"),
"findinstall" : ("examine_gui", "UpgradeExamineWindow"),
"addswap" : ("upgrade_swap_gui", "UpgradeSwapWindow"),
"upgrademigratefs" : ("upgrade_migratefs_gui", "UpgradeMigrateFSWindow"),
"bootloader": ("bootloader_main_gui", "MainBootloaderWindow"),
"upgbootloader": ("upgrade_bootloader_gui", "UpgradeBootloaderWindow"),
"network" : ("network_gui", "NetworkWindow"),
"timezone" : ("timezone_gui", "TimezoneWindow"),
"accounts" : ("account_gui", "AccountWindow"),
"tasksel": ("task_gui", "TaskWindow"),
"group-selection": ("package_gui", "GroupSelectionWindow"),
"install" : ("progress_gui", "InstallProgressWindow"),
"complete" : ("congrats_gui", "CongratulationWindow"),
}
每一个条目从左到右依次是安装步骤名称、图形界面类所在模块,图形界面类的名称。如language为安装步骤名称,language_gui为该步骤对应的图形界面类所在模块language_gui.py,LanguageWindow为图形界面对应的类名。
2)run: 启动图形安装界面的入口函数。该函数调用了setup_window接口,该接口调用gtk"绘制"图形安装界面的主窗体,然后控制权交给了gtk
def run (self):
self.setup_theme()
self.setup_window(False)
gtk.main()
3)nextClicked & prevClicked:这两个接口分别执行从当前图形安装界面向前(向后)到下一个图形安装界面的操作,我们可以想象安装过程中当用户点击"下一步" 或"上一步"按钮时,这两个函数被调用。这两个函数首先调用主流程控制Dispatcher实例向前(向后)前进到下一个图形安装界面,然后调用setScreen函数设置图形界面。
def prevClicked (self, *args):
try:
self.currentWindow.getPrev ()
except StayOnScreen:
return self.anaconda.dispatch.gotoPrev()
self.setScreen () def nextClicked (self, *args):
try:
rc = self.currentWindow.getNext ()
except StayOnScreen:
return self.anaconda.dispatch.gotoNext()
self.setScreen ()
4)setScreen: 用于设置图形界面。代码如下:
def setScreen (self):
# 取得当前安装步骤信息
(step, anaconda) = self.anaconda.dispatch.currentStep()
if step is None:
gtk.main_quit()
return if not stepToClass[step]: # 不在其中,则直接跳到下一步
if self.anaconda.dispatch.dir == DISPATCH_FORWARD:
return self.nextClicked()
else:
return self.prevClicked() (file, className) = stepToClass[step] # 获得图形界面类所在模块及其类名
newScreenClass = None while True:
try:
found = imp.find_module(file, iw.__path__)
moduleName = 'pyanaconda.iw.%s' % file
loaded = imp.load_module(moduleName, *found) # 载入该图形界面模块
newScreenClass = loaded.__dict__[className]
break
except ImportError, e:
stdout_log.error("loading interface component %s" % className)
stdout_log.error(traceback.format_exc())
win = MessageWindow(_("Error!"),
_("An error occurred when attempting "
"to load an installer interface "
"component.\n\nclassName = %s")
% (className,),
type="custom", custom_icon="warning",
custom_buttons=[_("_Exit"),
_("_Retry")])
if not win.getrc():
msg = _("The system will now reboot.")
buttons = [_("_Reboot")] MessageWindow(_("Exiting"),
msg,
type="custom",
custom_icon="warning",
custom_buttons=buttons)
sys.exit(0) ics = InstallControlState (self)
# 设置是否是可以返回上一步
ics.setPrevEnabled(self.anaconda.dispatch.canGoBack())
self.destroyCurrentWindow() # 销毁原来的图形安装界面
self.currentWindow = newScreenClass(ics) # 创建新的图形安装界面并设为当前界面 new_screen = self.currentWindow.getScreen(anaconda) # 生成安装步骤的界面 # If the getScreen method returned None, that means the screen did not
# want to be displayed for some reason and we should skip to the next
# step. However, we do not want to remove the current step from the
# list as later events may cause the screen to be displayed.
if not new_screen:
if self.anaconda.dispatch.dir == DISPATCH_FORWARD:
self.anaconda.dispatch.gotoNext()
else:
self.anaconda.dispatch.gotoPrev() return self.setScreen() self.update (ics) self.installFrame.add(new_screen)
self.installFrame.show_all() self.currentWindow.focus() self.handle = gobject.idle_add(self.handleRenderCallback) if self.reloadRcQueued:
self.window.reset_rc_styles()
self.reloadRcQueued = 0
前面的nextClicked和prevClicked函数已经通过Dispatcher将要进行的安装步骤标记为当前安装步骤,所以该函数首先通过Dispatcher的currentStep从Dispatcher的数据结构installSteps中取得当前安装步骤名称及相关信息,接下来,做了一下判断,如果Dispatcher的当前安装步骤不在字典stepToClass中,则忽略该步骤,调用nextClicked或prevClicked继续下一个图形界面安装步骤,直到下一个步骤在字典stepToClass中。验证通过后,从字典stepToClass中取得当前图形安装界面对应的类及该类所在模块,然后导入该模块并创建图形安装界面的实例,销毁前一个图形安装界面,并将新创建的图形界面实例置为当前安装界面,调用图形安装界面实例的getScreen函数生成该安装步骤的图形用户界面,然后显示。
至此,InstallControlWindow的主要逻辑已经分析完了,接下来涉及每个具体安装界面及其安装操作读者可以到iw目录下逐个深入分析。
(3)anaconda主程序: 图形环境运行是建立在X Server基础上的,对于图形模式,anaconda需要先运行X服务器,然后启动图形模式安装过程。而对于字符模式,anaconda的主执行体就作了一件事,启动字符模式安装过程。
if __name__ == "__main__":
setupPythonPath() # ...... # 解析启动本脚本时传入的参数
(opts, args) = parseOptions()
from pyanaconda.flags import flags
if opts.images:
flags.imageInstall = True # 设置log
import logging
from pyanaconda import anaconda_log
anaconda_log.init() log = logging.getLogger("anaconda")
stdoutLog = logging.getLogger("anaconda.stdout") # ...... from pyanaconda import Anaconda
anaconda = Anaconda() # 创建主执行体实例
warnings.showwarning = AnacondaShowWarning
iutil.setup_translations(gettext) # ...... # 检测内存,现在只用在文本模式下
check_memory(anaconda, opts, 't') if opts.unsupportedMode:
stdoutLog.error("Running anaconda in %s mode is no longer supported." % opts.unsupportedMode)
sys.exit(0) # ...... # kickstart文件解析
if opts.ksfile:
kickstart.preScriptPass(anaconda, opts.ksfile)
anaconda.ksdata = kickstart.parseKickstart(anaconda, opts.ksfile)
opts.rescue = opts.rescue or anaconda.ksdata.rescue.rescue # ......
# 如果没有X server,使用文本模式
if not flags.livecdInstall and not iutil.isS390() 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' # ......
# 启动本地的X server
if anaconda.displayMode == 'g' and not flags.preexisting_x11 and not flags.usevnc:
try:
# start X with its USR1 handler set to ignore. this will make it send
# us SIGUSR1 if it succeeds. if it fails, catch SIGCHLD and bomb out. def sigchld_handler(num, frame):
raise OSError(0, "SIGCHLD caught when trying to start the X server.") def sigusr1_handler(num, frame):
log.debug("X server has signalled a successful start.") def preexec_fn():
signal.signal(signal.SIGUSR1, signal.SIG_IGN) old_sigusr1 = signal.signal(signal.SIGUSR1, sigusr1_handler)
old_sigchld = signal.signal(signal.SIGCHLD, sigchld_handler)
xout = open("/dev/tty5", "w") # 启动X server
proc = subprocess.Popen(["Xorg", "-br", "-logfile", "/tmp/X.log",
":1", "vt6", "-s", "1440", "-ac",
"-nolisten", "tcp", "-dpi", "96",
"-noreset"],
close_fds=True, stdout=xout, stderr=xout,
preexec_fn=preexec_fn) signal.pause() os.environ["DISPLAY"] = ":1"
doStartupX11Actions()
except (OSError, RuntimeError) as e:
stdoutLog.warning(" X startup failed, falling back to text mode")
anaconda.displayMode = 't'
graphical_failed = 1
time.sleep(2)
finally:
signal.signal(signal.SIGUSR1, old_sigusr1)
signal.signal(signal.SIGCHLD, old_sigchld) set_x_resolution(opts.runres) # ...... # 初始化UI界面
anaconda.initInterface()
anaconda.instClass.configure(anaconda) # ...... # 启动安装过程
try:
anaconda.intf.run(anaconda)
except SystemExit, code:
anaconda.intf.shutdown() if anaconda.ksdata and anaconda.ksdata.reboot.eject:
for drive in anaconda.storage.devicetree.devices:
if drive.type != "cdrom":
continue log.info("attempting to eject %s" % drive.path)
drive.eject() del anaconda.intf
主要工作包括引用模块路径设置、参数解析、设置log、内存检测、安装类型设置,然后调用pyanaconda/__init__.py::Anaconda类创建主执行体实例anaconda,接着解析kickstart文件,调用/usr/bin/Xorg(位于解开后的install.img中)程序启动X server,调用Anaconda类的initInterface()初始化界面,调用intf(是InstallInterface类的实例)的run()启动安装过程。对于字符安装模式,是直接调用InstallInterface实例的run接口。而对于图形安装模式,则是由InstallInterface实例的run接口间接的调用installcontrolwindow实例的run接口,从而启动图形界面。
(4)pyanaconda/__init__.py: 里面有Anaconda类,负责具体的启动安装过程。前面说过,安装的流程由Dispatcher控制,对于图形模式,图形模式的前端显示及与用户的交互由InstallControlWindow调度,而字符模式的前端显示层由InstallInterface调度。因此,启动安装过程,实际就是创建主要控制类的实例,调用实例的接口,启动安装过程,然后再由这几个主要的控制类的实例创建具体安装界面,创建安装行为类的实例,调用具体的函数完成具体的安装过程。
class Anaconda(object):
def __init__(self):
import desktop, dispatch, firewall, security
import system_config_keyboard.keyboard as keyboard
from flags import flags # ......
# 创建dispatch实例
self.dispatch = dispatch.Dispatcher(self)
# ...... # ...... intf = property(_getInterface, _setInterface, _delInterface) # ...... def initInterface(self):
if self._intf:
raise RuntimeError, "Second attempt to initialize the InstallInterface" # 设置图形模式需要的链接
if self.displayMode == 'g':
stdoutLog.info (_("Starting graphical installation.")) try:
from gui import InstallInterface
except Exception, e:
from flags import flags
stdoutLog.error("Exception starting GUI installer: %s" %(e,))
# if we're not going to really go into GUI mode, we need to get
# back to vc1 where the text install is going to pop up.
if not flags.livecdInstall:
isys.vtActivate (1)
stdoutLog.warning("GUI installer startup failed, falling back to text mode.")
self.displayMode = 't'
if 'DISPLAY' in os.environ.keys():
del os.environ['DISPLAY']
time.sleep(2) if self.displayMode == 't':
from text import InstallInterface
if not os.environ.has_key("LANG"):
os.environ["LANG"] = "en_US.UTF-8" if self.displayMode == 'c':
from cmdline import InstallInterface self._intf = InstallInterface() # 创建InstallInterface实例
return self._intf
主要的工作包括创建dispatch实例,初始化界面,创建InstallInterface实例,它最后会创建InstallControlWindow实例,生成图形界面。
整个Anaconda的运行流程如下图:
图2 Anaconda运行流程
Linux安装程序Anaconda分析(续)的更多相关文章
- Linux安装程序Anaconda分析
1.概述 Anaconda是RedHat.CentOS.Fedora等Linux的安装管理程序.它能够提供文本.图形等安装管理方式,并支持Kickstart等脚本提供自己主动安装的功能.此外, ...
- linux 安装程序的方式
linux 安装程序的方式 通用二进制格式(绿色软件,打开即用) 软件包管理器(rpm) 软件包管理器的前端工具(yum) 源代码编译
- [linux笔记]理清linux安装程序用到的(configure, make, make install)
我作为一名经常和linux打交道的程序员,每次在linux安装软件都祈求可以用——apt-get,yum,brew等应用程序管理器安装,有的时候事与愿违,你只能自己编译安装-wtf,说好的美丽世界呢? ...
- linux驱动基础系列--linux spi驱动框架分析(续)
前言 这篇文章是对linux驱动基础系列--linux spi驱动框架分析的补充,主要是添加了最新的linux内核里设备树相关内容. spi设备树相关信息 如之前的文章里所述,控制器的device和s ...
- Linux挖矿程序kworkerds分析
0×00 背景概述 近日,同伴的一台Linux服务器中了kworkerds挖矿程序,随即对挖矿程序进行了处理与分析. 0×01服务器现状 进入服务器之后通过top命令,没有发现有占用CPU资源过高的进 ...
- ubuntu中的Linux安装程序的方法
Ubuntu: 1.下载.deb文件,下载后,cd到.deb文件目录,然后使用sudo dpkg -i xxx.deb dpkg=debian packager的缩写 -i=install ...
- linux 安装程序
tar文件打开 tar -xvf myfile.tar bz2文件打开
- Linux安装-kickstart无人值守安装
Linux安装-kickstart无人值守安装 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 大家做运维估计都避免不了时不时会去机房安装一台linux服务器,但是服务器启动的特别慢 ...
- RHEL64 缺少ISO 9660图像 安装程序试图挂载映像#1,在硬盘上无法找到该映像
用光盘安装Linux,很容易,按照提示一步一步就好.如果没有光驱,只好想办法用硬盘或者U盘安装了. 首先说说怎样用U盘启动Linux的安装程序:1.将ISO镜像文件拷贝到U盘中,并解压到U盘根目录.将 ...
随机推荐
- [android 代码search地址]
http://www.androidcodesearch.com/source/packages/apps/Settings/src/com/android/settings/SecuritySett ...
- SPOJ-New Distinct Substrings,注意会爆int
SUBST1 - New Distinct Substrings 和上一题题意一样,只是数据范围有所改动,50000. 思路还是和上一题一样,所有字串数(len+1)*len/2.注意这里可能爆int ...
- POJ-2002 Squares,哈希模板+数学公式!
Squares 题意:二维坐标轴给出n个点求有多少个正方形. 要是平时做比赛的话毫无疑问会 ...
- 【bzoj3231】[Sdoi2008]递归数列 矩阵乘法+快速幂
题目描述 一个由自然数组成的数列按下式定义: 对于i <= k:ai = bi 对于i > k: ai = c1ai-1 + c2ai-2 + ... + ckai-k 其中bj和 cj ...
- 算法复习——平面分治(hud1007)
题目: 问题描述 : Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitch ...
- HDU 4433 locker(12年天津,DP)
4576 njczy2010 C Accepted 860 KB 140 ms G++ 2063 B 2014-10-16 09:51:19 哎,为啥1000*100*100的复杂度的dp就不敢敲了呢 ...
- 解决U3D4.1.5或以上无法启动MONODEV的方法
通常会报这样的错误 System.EntryPointNotFoundException: Unable to find an entry point named 'gtksharp_list_get ...
- android中自定义下拉框(转)
android自带的下拉框好用不?我觉得有时候好用,有时候难有,项目规定这样的效果,自带的控件实现不了,那么只有我们自己来老老实实滴写一个新的了,其实最基本的下拉框就像一些资料填写时,点击的时候出现在 ...
- springboot主要注解及其作用
1.注解(annotations)列表 @SpringBootApplication:包含了@ComponentScan.@Configuration和@EnableAutoConfiguration ...
- Ubuntu 16.04安装JAD反编译工具(Java)
JAD反编译工具有个好处,就是字节码和源代码一起输出. 官网:https://varaneckas.com/jad/ 安装步骤: 1.下载: 离线版本:(链接: https://pan.baidu.c ...