SlideShare ist ein Scribd-Unternehmen logo
1 von 32
Asianux 安装光盘分析

中科院软件所基础软件中心 程光瑶
架构
⇨ 以Asianux 3 sp2 一张dvd的发行版为例:
⇨ 安装光盘的框架:
   -Asianux <-安装向导镜像及rpm包
   -Documents <-License协议及相关说明文档
   -dosutils <-为Dos下特殊安装准备的工具
   -images <-其他引导img镜像及额外驱动
   -isolinux <-光盘引导程序及msg提示信息
   -repodata <-精确描述一个 rpm 包的详细信息,如依赖关
  系,包含文件,校验码信息
   --TRANS.TBL <-当前目录的列表,用mkisofs的-T参数重新
  生成
  --.discinfo <-安装程序anaconda用于检验光盘正确性的文件
  --.treeinfo <-不同安装方式安装程序所在目录结构,如:内
  核kernel = images/pxeboot/vmlinuz;根文件系统initrd =
  images/pxeboot/initrd.img
/Asianux
/base包含了在安装过程中要用到的描述组织结构和安装行为的所
有文件,其中comps,hdlist和hdlist2是描述RPM包组织结构的文件


--comps.xml 把各个RPM包按一定的原则组织成若干组,即
components,这样在安装过程中就不必对每一个包做出取舍,而以组
为单位。如:kde-desktop,development 等。
--hdlist,hdlist2 这两个文件维护从RPM包名到真实包文件名
的映射过程。这两个文件是用genhdlist生成的,无法用简单的方法察
看其中的内容和结构。


/RPMS包含了Asianux发布的主要部分,即以RPM包的形式将
Asianux系统中的二进制可执行文件,配置文件,文档等等组织在一
起,形成能完成一定功能的比较独立的软件包。这个目录就是把这些
软件包都集合在一起,形成了Asianux发布。
comps.xml格式
/images
包含了制作启动盘的映像文件,以及从一些非常规硬件上
 加载安装程序所需的驱动程序盘映像
⇨ boot.iso 当安装介质光盘时,负责引导系统的映像文件
⇨ bootefi.img 用于Intel EFI引导方式的机器
⇨ diskboot.img 安装引导盘,可以写入U盘或其他大容量
 可引导存储介质中,用来引导从本地光盘、网络、硬盘或
 PCMCIA设备的安装

⇨ stage2.img,minstg2.img 光盘引导的镜像文件,
 在定制Live CD的时候,需要修改它

⇨ /pxeboot 用于PXE安装方式
boot.img结构
boot.img
    |----vmlinuz Linux内核
    |----ldlinux.sys 引导Linux的系统文件
    |----syslinux.cfg Linux内核引导参数配置文件
    |----initrd.img 内存虚拟文件系统映像文件
    |----*.msg文件 引导时的各种提示信息文件

其中,initrd.img为Linux ext2文件系统,构成如下:
    initrd.img
    |----/bin
    |----/dev
    |----/etc
    |----/module
    |----/sbin ------ loader安装程序装载器
    |----/tmp
    |----/var
   可执行文件/sbin/loader的任务是判断安装介质的有效性,并从中执行安装
程序。其实正是boot.img,在系统启动时被执行,经解析之后在内存建立起
了Linux内核,并根据配置文件syslinux.cfg装载虚拟文件系统,形成了完整的
LinuxSystem,为后续的工作提供了必要的操作系统环境。
stage2.img结构
  stage2.img
|----/etc
|----/modules
|----/proc
|----/usr----/bin----anaconda 安装程序主执行文件
|-------------/lib-----/anaconda安装程序脚本文件目录
                      | |----/installclasses 安装类型分类目录
                      | |----/iw 安装各步骤响应目录
                      | |----/texttw 字符界面各步骤响应目录
                      | |----*.py
|-------------/share---/anaconda安装程序资源文件目录
                            | |----/help 安装过程帮助系统目录
                            | |----/pixmaps 安装时图片存储的位置


如上所示,stage2.img映像文件中的主要部分是安装程序
anaconda,它的主执行体是/usr/bin下的anaconda,由其调用的
大量例程分布在/usr/lib/anaconda下,而安装过程中要用到的资源
文件分布在/usr/share/anaconda下。
initrd(boot loader initialized
             RAM disk)
⇨ 定义:
由 boot loader 初始化的内存盘。在 linux内核启动前, boot loader 会将存储介
   质中的 initrd文件加载到内存,内核启动时会在访问真正的根文件系统前
   先访问该内存中的 initrd 文件系统。在 boot loader 配置了 initrd的情况
   下,内核启动被分成了两个阶段,第一阶段先执行 initrd文件系统中的文
   件,完成加载驱动模块等任务,第二阶段才会执行真正的根文件系统中
   的 /sbin/init 进程。

⇨ cpio-initrd 的处理流程:
1. boot loader 把内核以及 initrd 文件加载到内存的特定位置。
2. 内核判断initrd的文件格式,如果是cpio格式。
3. 将initrd的内容释放到rootfs中。
4. 执行initrd中的/init文件,执行到这一点,内核的工作全部结束,完全交给
    /init文件处理。
initrd处理流程
initrd相关代码的调用层次关系图
(内核的初始化代码位于 init/main.c 中的 static int init(void * unused)函数中。同initrd的处理相关
  部分函数调用层次如下图 )
相关概念
• rootfs: 一个基于内存的文件系统,是linux在初
  始化时加载的第一个文件系统。
• initramfs: initramfs同本文的主题关系不是很
  大,Initramfs是在 kernel 2.5中引入的技术。在
  内核镜像中附加一个cpio包,这个cpio包中包含
  了一个小型的文件系统,当内核启动时,内核
  将这个 cpio包解开,并且将其中包含的文件系
  统释放到rootfs中,内核中的一部分初始化代码
  会放到这个文件系统中,作为用户层进程来执
  行。
• cpio-initrd: 指linux内核使用的cpio格式的initrd。
• image-initrd: 指传统的文件镜像格式的initrd。
• realfs: 用户最终使用的真正的文件系统。
代码分析( unused函数 )
static int init(void * unused){
[1]            populate_rootfs();

[2]          if (sys_access((const char __user *) "/init", 0) == 0)
                         execute_command = "/init";
             else
                         prepare_namespace();

[3]         if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
                        printk(KERN_WARNING "Warning: unable to open an initial
console.n");

             (void) sys_dup(0);
             (void) sys_dup(0);

[4]          if (execute_command)
                         run_init_process(execute_command);

             run_init_process("/sbin/init");
             run_init_process("/etc/init");
             run_init_process("/bin/init");
             run_init_process("/bin/sh");
             panic("No init found. Try passing init= option to kernel.");
}
代码分析( unused函数 )
• 代码[1]:populate_rootfs函数负责加载initramfs
  和cpio-initrd。
• 代码[2]:如果rootfs的根目录下中包含/init进程,
  则赋予execute_command,在init函数的末尾会
  被执行。否则执行prepare_namespace函数,
  initrd是在该函数中被加载的。
• 代码[3]:将控制台设置为标准输入,后续的两
  个sys_dup(0),则复制标准输入为标准输出
  和标准错误输出。
• 代码[4]:如果rootfs中存在init进程,就将后续
  的处理工作交给该init进程。其实这段代码的含
  义是如果加载了cpio-initrd则交给cpio-initrd中的
  /init处理,否则会执行realfs中的init.
代码分析( populate_rootfs )
对cpio-initrd的处理位于populate_rootfs函数中
void __init populate_rootfs(void){
[1] char *err = unpack_to_rootfs(__initramfs_start,
                                           __initramfs_end - __initramfs_start, 0);
[2]          if (initrd_start) {
[3]                        err = unpack_to_rootfs((char *)initrd_start,
                                          initrd_end - initrd_start, 1);
[4]                        if (!err) {
                                          printk(" it isn");
                                          unpack_to_rootfs((char *)initrd_start,
                                                         initrd_end - initrd_start, 0);
                                          free_initrd_mem(initrd_start, initrd_end);
                                          return;
                           }
[5]                        fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 700);
                           if (fd >= 0) {
                                          sys_write(fd, (char *)initrd_start,
                                                                      initrd_end - initrd_start);
                                          sys_close(fd);
                                          free_initrd_mem(initrd_start, initrd_end);
                           }
}
代码分析( populate_rootfs )
• 代码[1]:加载initramfs,initramfs位于地址
  __initramfs_start处,是内核在编译过程中生成的,
  initramfs的是作为内核的一部分而存在的,不是boot
  loader加载的。
• 代码[2]:判断是否加载了initrd.无论哪种格式的initrd,
  都会被boot loader加载到地址initrd_start处。
• 代码[3]:判断加载的是不是cpio-initrd.实际上
  unpack_to_rootfs有两个功能一个是释放cpio包,另一个
  就是判断是不是cpio包, 这是通过最后一个参数来区分
  的,0-释放 1-查看。
• 代码[4]:如果是cpio-initrd则将其内容释放出来到rootfs
  中。
• 代码[5]:如果不是cpio-initrd,则认为是一个image-
  initrd,将其内容保存到/initrd.image中。在后面的
  image-initrd的处理代码中会读取/initrd.image.
代码分析(prepare_namespace)
对image-initrd的处理在prepare_namespace函数里,包含了对image-
initrd进行处理的代码

void _init prepare_namespace(void){
[1]       if (initrd_load())
                      goto out;

out:
                 umount_devfs("/dev");
[2]              sys_mount(".", "/", NULL, MS_MOVE, NULL);
                 sys_chroot(".");
                 security_sb_post_mountroot();
                 mount_devfs_fs ();

代码[1]:执行initrd_load函数,将initrd载入,如果载入成功的话
initrd_load函数会将realfs的根设置为当前目录。

代码[2]:将当前目录即realfs的根mount为Linux VFS的根。initrd_load函
数执行完后,将真正的文件系统的根设置为当前目录。
代码分析( initrd_load函数 )
initrd_load函数负责载入image-initrd

int __init initrd_load(void)
{
[1]            if (mount_initrd) {
                           create_dev("/dev/ram", Root_RAM0, NULL);
[2]                        if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) {
                                        sys_unlink("/initrd.image");
                                        handle_initrd();
                                        return 1;
                           }
               }
               sys_unlink("/initrd.image");
               return 0;
}

代码[1]:如果加载initrd则建立一个ram0设备 /dev/ram。
代码[2]:/initrd.image文件保存的就是image-initrd,rd_load_image函数
执行具体的加载操作,将 image-nitrd的文件内容释放到ram0里。判断
ROOT_DEV!=Root_RAM0的含义是,如果你在grub或者lilo里配置了
root=/dev/ram0 ,则实际上真正的根设备就是initrd了,所以就不把它作为
initrd处理,而是作为realfs处理。
代码分析(handle_initrd)
handle_initrd()函数负责对initrd进行具体的处理
            static void __init handle_initrd(void){
[1]         real_root_dev = new_encode_dev(ROOT_DEV);
[2]         create_dev("/dev/root.old", Root_RAM0, NULL);
            mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);
[3]         sys_mkdir("/old", 0700);
            root_fd = sys_open("/", 0, 0);
            old_fd = sys_open("/old", 0, 0);
            /* move initrd over / and chdir/chroot in initrd root */
[4]         sys_chdir("/root");
            sys_mount(".", "/", NULL, MS_MOVE, NULL);
            sys_chroot(".");
            mount_devfs_fs ();
[5]         pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
            if (pid > 0) {
                           while (pid != sys_wait4(-1, &i, 0, NULL))
                                        yield();
            }
            /* move initrd to rootfs' /old */
            sys_fchdir(old_fd);
            sys_mount("/", ".", NULL, MS_MOVE, NULL);
            /* switch root and cwd back to / of rootfs */
[6]         sys_fchdir(root_fd);
            sys_chroot(".");
            sys_close(old_fd);
            sys_close(root_fd);
            umount_devfs("/old/dev");
代码分析(handle_initrd)
[7]   if (new_decode_dev(real_root_dev) == Root_RAM0) {
                  sys_chdir("/old");
                  return;
      }
[8]   ROOT_DEV = new_decode_dev(real_root_dev);
      mount_root();
[9]   printk(KERN_NOTICE "Trying to move old root to /initrd ... ");
      error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL);
      if (!error)
                  printk("okayn");
      else {
                  int fd = sys_open("/dev/root.old", O_RDWR, 0);
                  printk("failedn");
                  printk(KERN_NOTICE "Unmounting old rootn");
                  sys_umount("/old", MNT_DETACH);
                  printk(KERN_NOTICE "Trying to free ramdisk memory ... ");
                  if (fd < 0) {
                                error = fd;
                  } else {
                                error = sys_ioctl(fd, BLKFLSBUF, 0);
                                sys_close(fd);
                  }
                  printk(!error ? "okayn" : "failedn");
      }
代码分析(handle_initrd)
• handle_initrd函数的主要功能是执行initrd的linuxrc文
  件,并且将realfs的根目录设置为当前目录
•   代码[1]:real_root_dev,是一个全局变量保存的是realfs的设备号。
•   代码[2]:调用mount_block_root函数将initrd文件系统挂载到了VFS
    的/root下。
•   代码[3]:提取rootfs的根的文件描述符并将其保存到root_fd.它的作
    用就是为了在chroot到initrd的文件系统,处理完initrd之后要,还
    能够返回rootfs.返回的代码参考代码[7].
•   代码[4]:chroot进入initrd的文件系统。前面initrd已挂载到了rootfs
    的/root目录。
•   代码[5]:执行initrd的linuxrc文件,等待其结束。
•   代码[6]:initrd处理完之后,重新chroot进入rootfs.
•   代码[7]:如果real_root_dev在 linuxrc中重新设成Root_RAM0,则
    initrd就是最终的realfs了,改变当前目录到initrd中,不作后续处理
    直接返回。
•   代码[8]:在linuxrc执行完后,realfs设备已经确定,调用
    mount_root函数将realfs挂载到root_fs的 /root目录下,并将当前目
    录设置为/root.
•   代码[9]:收尾并释放内存盘。
anaconda目录结构
installclasses子目录中的各个模块定义了在安装过程中用户可选择
的安装类型。 例如:workstation.py,server.py,custom.py和
personal_desktop.py。其中,workstation.py描述了工作站安装类
型,server.py描述了服务器安装类型,custom.py描述了用户自定
义安装类型,personal_desktop.py描述了个人桌面安装类型。每个
安装类型描述文件根据相应安装类型的特点,分别对安装步骤、
分区策略以及安装包的取舍给出了不同的方案。
iw子目录下包含所有安装图形界面类所在的模块,每个图形界面
对应一个类,负责相应安装步骤图形界面的具体外观显示及与用
户的交互,调用anaconda主目录下的相关安装行为模块完成具体的
安装操作。
textw子目录和iw子目录含义是一致的,只是包含的是字符安装模
式的前端字符用户界面类所在的模块,每个字符用户界面对应一
个类,负责与用户的交互。
如果说用户界面类是处理安装程序外观的话,则anaconda主目录下
的各python模块则执行每个安装界面背后具体的安装行为,包括那
些无用户界面安装步骤的安装操作。
各模块间逻辑关系
Dispatcher类
作用:
该类在anaconda主目录下的dispatch.py模
块中。无论是图形模式安装还是字符模
式安装,都由该类来控制安装流程。
installSteps
• dispatch.py模块中有一个序列(sequence)数据
  结构:installSteps。installSteps中记录了有序排
  列的整个安装过程中所有可能的安装步骤,在
  生成具体的Dispatcher实例时,会根据安装类型
  制定对此进行相应裁减。
• installSteps中的条目(item)有如下两种格式
  – 第一种格式:( name, tuple):这种格式表示有用户界
    面的安装步骤。其中,name代表安装步骤的名称,
    tuple(元组,python的一种内置数据类型)存放创建相
    应安装步骤的用户界面的参数。
  – 第二种格式:( name, Function, tuple):这种格式表示
    没有用户界面的安装步骤,其中,name代表安装步
    骤的名称,Function指安装操作的具体执行函数,
    tuple存放的是传递给Function的参数。该安装步骤直
    接由Dispatcher调度进行。
Dispatcher的主要接口
• gotoNext & gotoPrev:这两个接口分别从当前安装步骤
  前进(后退)到下一个(上一个)具有用户界面的安
  装步骤,在图形界面安装模式下,由
  installcontrolwindow调用,在字符模式下,由
  InstallInterface调用。这两个函数只是简单的设置安装
  方向,然后调用 movestep函数,其核心操作是movestep。
• currentStep:Dispatcher类的另一个主要接口,取得当前
  的安装步骤及其相关信息返回给调用者。在图形安装
  模式下,该函数主要由 InstallControlWindow调度图形
  用户界面类时调用,在字符模式下,主要由
  InstallInterface调度字符用户界面时调用,这两个类通
  过该接口取得当前安装步骤的用户界面对应的类及创
  建该用户界面类的实例所需的信息。
• skipStep(self, stepToSkip, skip = 1, permanent = 0)是裁减
  安装步骤函数。setStepList(self, *steps)是安装步骤设置
  函数,主要由安装类型实例调用,每个安装类型会根
  据自身的特点设置安装步骤。
movestep
def moveStep(self):
……
if self.step == None:
            self.step = self.firstStep
else:
self.step = self.step + self.dir
            while ((self.step >= self.firstStep and self.step < len(installSteps))
           and (self.skipSteps.has_key(installSteps[self.step][0])
              or (type(installSteps[self.step][1]) == FunctionType))):
info = installSteps[self.step]
              if ((type(info[1]) == FunctionType) and (not
self.skipSteps.has_key(info[0]))):
(func, args) = info[1:]
                                   rc = apply(func, self.bindArgs(args))
                                   if rc == DISPATCH_BACK:
                                   self.dir = -1
                                   elif rc == DISPATCH_FORWARD:
                                   self.dir = 1
                       self.step = self.step + self.dir
if self.step == len(installSteps):
                                               return None
movestep
• 首先看一下循环条件:当下一个安装步骤是合法的,
  即在第一个安装步骤和最后一个安装步骤之间,且该
  步骤被裁减了或者该步骤是一个无用户界面的安装步
  骤,即installSteps的条目的第二个元素是一个function,
  则进入循环体。
• 进入循环后,Dispatcher直接调用该函数执行安装操
  作,其中bindArgs是Dispatcher类的一个函数,负责参
  数解析,这里的apply是python的的一个内置方法,用
  来执行函数,apply接口的第一个参数是要运行的函数
  名称,第二个参数是传给该函数的参数。
• 如果下一个安装步骤依然无用户界面,则继续循环,
  直到下一个没有被裁减的具有用户界面的安装步骤,
  对于图形安装模式,Dispatcher将控制权交给
  InstallControlWindow,对于字符安装模式,Dispatcher
  将控制权交给InstallInterface。如果安装过程完成则退
  出循环。
InstallControlWindow
• 控制安装过程中前端图形界面的显示,
  该类在anaconda主目录下的gui.py模块中。
• 启动图形安装界面的入口函数run,该函
  数调用了setup_window接口,该接口调用
  gtk"绘制"图形安装界面的主窗体,然后
  控制权交给了gtk。
   def run (self, runres, configFileData):
             self.configFileData = configFileData
             self.setup_window(runres)
             gtk.main()
数据结构stepToClass
gui.py模块中的一个数据结构:stepToClass记录了安装过
  程中所有的具有图形用户界面的安装步骤。

stepToClass = {
   "language" : ("language_gui", "LanguageWindow"),
"keyboard" : ("keyboard_gui", "KeyboardWindow"),
……
}


每一个条目从左到右依次是安装步骤名称、图形界面对应的类所在的
模块,图形界面类的名称。如language为安装步骤名称,
language_gui为该步骤对应的图形界面类所在的模块
language_gui.py,LanguageWindow为图形界面对应的类名。
nextClicked & prevClicked
作用:
这两个接口分别执行从当前图形安装界
面向前(向后)到下一个图形安装界面
的操作。这两个函数首先调用主流程控
制Dispatcher实例向前(向后)前进到下
一个图形安装界面,然后调用setScreen函
数,setScreen是设置图形界面的。
setScreen
def setScreen (self):
           (step, args) = self.dispatch.currentStep()
           if not stepToClass[step]:
               if self.dir == 1:
                                 return self.nextClicked()
               else:
                                 return self.prevClicked()
           (file, className) = stepToClass[step]
newScreenClass = None
           s = "from %s import %s; newScreenClass = %s" % (file,
className, className)
   while 1:
           exec s
     break
           self.destroyCurrentWindow()
   self.currentWindow = newScreenClass(ics)
           new_screen = apply(self.currentWindow.getScreen, args)
   self.installFrame.add(new_screen)
   self.installFrame.show_all()
           ……
InstallControlWindow 流程
• 前面的nextClicked和 prevClicked函数已经通过
  Dispatcher将要进行的安装步骤标记为当前安装步骤,
  所以该函数首先通过Dispatcher的 currentStep从
  Dispatcher的数据结构installSteps中取得当前安装步骤名
  称及相关信息
• 做了一下判断,如果 Dispatcher的当前安装步骤不在字
  典stepToClass中,则忽略该步骤,调用nextClicked或
  prevClicked继续下一个图形界面安装步骤,直到下一个
  步骤在字典stepToClass中
• 从字典stepToClass中取得当前图形安装界面对应的类及
  该类所在模块,然后导入该模块并创建图形安装界面
  的实例,销毁前一个图形安装界面,并将新创建的图
  形界面实例置为当前安装界面,调用图形安装界面实
  例的 getScreen函数生成该安装步骤的图形用户界面并
  显示。
Q&A



The end
谢谢

Weitere ähnliche Inhalte

Was ist angesagt?

康盛创想项目部Linux 服务器部署标准(最新版)
康盛创想项目部Linux 服务器部署标准(最新版)康盛创想项目部Linux 服务器部署标准(最新版)
康盛创想项目部Linux 服务器部署标准(最新版)Yiwei Ma
 
Mongo db架构之优先方案
Mongo db架构之优先方案Mongo db架构之优先方案
Mongo db架构之优先方案Lucien Li
 
ch13-pv1-system-calls
ch13-pv1-system-callsch13-pv1-system-calls
ch13-pv1-system-callsyushiang fu
 
Ceph中国社区9.19 Ceph IO 路径 和性能分析-王豪迈05
Ceph中国社区9.19 Ceph IO 路径 和性能分析-王豪迈05Ceph中国社区9.19 Ceph IO 路径 和性能分析-王豪迈05
Ceph中国社区9.19 Ceph IO 路径 和性能分析-王豪迈05Hang Geng
 
Unixtoolbox zh cn
Unixtoolbox zh cnUnixtoolbox zh cn
Unixtoolbox zh cnxdboy2006
 
Talking about exploit writing
Talking about exploit writingTalking about exploit writing
Talking about exploit writingsbha0909
 
Installation and configuration 11g r2 asm using job role separation(grid & or...
Installation and configuration 11g r2 asm using job role separation(grid & or...Installation and configuration 11g r2 asm using job role separation(grid & or...
Installation and configuration 11g r2 asm using job role separation(grid & or...Zhaoyang Wang
 
Hadoop+spark實作
Hadoop+spark實作Hadoop+spark實作
Hadoop+spark實作FEG
 
The New Process No. 1 of Linux -- SystemD
The New Process No. 1 of Linux -- SystemDThe New Process No. 1 of Linux -- SystemD
The New Process No. 1 of Linux -- SystemDfreedman6022e20
 
Handler socket测试报告 - 20110422
Handler socket测试报告 - 20110422Handler socket测试报告 - 20110422
Handler socket测试报告 - 20110422Jinrong Ye
 
Python 于 webgame 的应用
Python 于 webgame 的应用Python 于 webgame 的应用
Python 于 webgame 的应用勇浩 赖
 
iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门Lucien Li
 
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)Simen Li
 
Linux必学的60个命令
Linux必学的60个命令Linux必学的60个命令
Linux必学的60个命令yiditushe
 

Was ist angesagt? (19)

Java Thread
Java ThreadJava Thread
Java Thread
 
unixtoolbox_zh_CN
unixtoolbox_zh_CNunixtoolbox_zh_CN
unixtoolbox_zh_CN
 
康盛创想项目部Linux 服务器部署标准(最新版)
康盛创想项目部Linux 服务器部署标准(最新版)康盛创想项目部Linux 服务器部署标准(最新版)
康盛创想项目部Linux 服务器部署标准(最新版)
 
MySQL aio
MySQL aioMySQL aio
MySQL aio
 
Mongo db架构之优先方案
Mongo db架构之优先方案Mongo db架构之优先方案
Mongo db架构之优先方案
 
ch13-pv1-system-calls
ch13-pv1-system-callsch13-pv1-system-calls
ch13-pv1-system-calls
 
Ceph中国社区9.19 Ceph IO 路径 和性能分析-王豪迈05
Ceph中国社区9.19 Ceph IO 路径 和性能分析-王豪迈05Ceph中国社区9.19 Ceph IO 路径 和性能分析-王豪迈05
Ceph中国社区9.19 Ceph IO 路径 和性能分析-王豪迈05
 
Unixtoolbox zh cn
Unixtoolbox zh cnUnixtoolbox zh cn
Unixtoolbox zh cn
 
Talking about exploit writing
Talking about exploit writingTalking about exploit writing
Talking about exploit writing
 
Installation and configuration 11g r2 asm using job role separation(grid & or...
Installation and configuration 11g r2 asm using job role separation(grid & or...Installation and configuration 11g r2 asm using job role separation(grid & or...
Installation and configuration 11g r2 asm using job role separation(grid & or...
 
Hadoop+spark實作
Hadoop+spark實作Hadoop+spark實作
Hadoop+spark實作
 
ch7-pv1-modules
ch7-pv1-modulesch7-pv1-modules
ch7-pv1-modules
 
The New Process No. 1 of Linux -- SystemD
The New Process No. 1 of Linux -- SystemDThe New Process No. 1 of Linux -- SystemD
The New Process No. 1 of Linux -- SystemD
 
Handler socket测试报告 - 20110422
Handler socket测试报告 - 20110422Handler socket测试报告 - 20110422
Handler socket测试报告 - 20110422
 
Python 于 webgame 的应用
Python 于 webgame 的应用Python 于 webgame 的应用
Python 于 webgame 的应用
 
ios分享
ios分享ios分享
ios分享
 
iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门
 
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
 
Linux必学的60个命令
Linux必学的60个命令Linux必学的60个命令
Linux必学的60个命令
 

Ähnlich wie Aisanux安装光盘分析

unix toolbox 中文版
unix toolbox 中文版unix toolbox 中文版
unix toolbox 中文版Jie Bao
 
5, system admin
5, system admin5, system admin
5, system adminted-xu
 
Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)
Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)
Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)rvillegasg
 
利用Cent Os快速构建自己的发行版
利用Cent Os快速构建自己的发行版利用Cent Os快速构建自己的发行版
利用Cent Os快速构建自己的发行版xingsu1021
 
Device Driver - Chapter 3字元驅動程式
Device Driver - Chapter 3字元驅動程式Device Driver - Chapter 3字元驅動程式
Device Driver - Chapter 3字元驅動程式ZongYing Lyu
 
Oraliux+mysql5单机多实例安装文档
Oraliux+mysql5单机多实例安装文档Oraliux+mysql5单机多实例安装文档
Oraliux+mysql5单机多实例安装文档xuebao_zx
 
CentOS5 apache2 mysql5 php5 Zend
CentOS5 apache2 mysql5 php5 ZendCentOS5 apache2 mysql5 php5 Zend
CentOS5 apache2 mysql5 php5 Zendwensheng wei
 
文件系统简述.pptx
文件系统简述.pptx文件系统简述.pptx
文件系统简述.pptxGuoliangDing3
 
Install Oracle11g For Aix 5 L
Install Oracle11g For Aix 5 LInstall Oracle11g For Aix 5 L
Install Oracle11g For Aix 5 Lheima911
 
MySQL源码分析.01.代码结构与基本流程
MySQL源码分析.01.代码结构与基本流程MySQL源码分析.01.代码结构与基本流程
MySQL源码分析.01.代码结构与基本流程Lixun Peng
 
Aix操作系统培训文档
Aix操作系统培训文档Aix操作系统培训文档
Aix操作系统培训文档lwj2012
 
Bypat博客出品-利用cent os快速构建自己的发行版
Bypat博客出品-利用cent os快速构建自己的发行版Bypat博客出品-利用cent os快速构建自己的发行版
Bypat博客出品-利用cent os快速构建自己的发行版redhat9
 
Erlang Practice
Erlang PracticeErlang Practice
Erlang Practicelitaocheng
 
Android系统移植技术详解
Android系统移植技术详解Android系统移植技术详解
Android系统移植技术详解zzc89522
 
Nagios的安装部署和与cacti的整合(linuxtone)
Nagios的安装部署和与cacti的整合(linuxtone)Nagios的安装部署和与cacti的整合(linuxtone)
Nagios的安装部署和与cacti的整合(linuxtone)Yiwei Ma
 
Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出wang hongjiang
 
Kick start无人值守批量安装linux
Kick start无人值守批量安装linuxKick start无人值守批量安装linux
Kick start无人值守批量安装linuxYiwei Ma
 

Ähnlich wie Aisanux安装光盘分析 (20)

unix toolbox 中文版
unix toolbox 中文版unix toolbox 中文版
unix toolbox 中文版
 
5, system admin
5, system admin5, system admin
5, system admin
 
Asm+aix
Asm+aixAsm+aix
Asm+aix
 
Overlayfs and VFS
Overlayfs and VFSOverlayfs and VFS
Overlayfs and VFS
 
Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)
Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)
Windowsîä¼þïµí³¹ýâëçý¶¯¿ª·¢½ì³ì(µú¶þ°æ)
 
Rootkit 101
Rootkit 101Rootkit 101
Rootkit 101
 
利用Cent Os快速构建自己的发行版
利用Cent Os快速构建自己的发行版利用Cent Os快速构建自己的发行版
利用Cent Os快速构建自己的发行版
 
Device Driver - Chapter 3字元驅動程式
Device Driver - Chapter 3字元驅動程式Device Driver - Chapter 3字元驅動程式
Device Driver - Chapter 3字元驅動程式
 
Oraliux+mysql5单机多实例安装文档
Oraliux+mysql5单机多实例安装文档Oraliux+mysql5单机多实例安装文档
Oraliux+mysql5单机多实例安装文档
 
CentOS5 apache2 mysql5 php5 Zend
CentOS5 apache2 mysql5 php5 ZendCentOS5 apache2 mysql5 php5 Zend
CentOS5 apache2 mysql5 php5 Zend
 
文件系统简述.pptx
文件系统简述.pptx文件系统简述.pptx
文件系统简述.pptx
 
Install Oracle11g For Aix 5 L
Install Oracle11g For Aix 5 LInstall Oracle11g For Aix 5 L
Install Oracle11g For Aix 5 L
 
MySQL源码分析.01.代码结构与基本流程
MySQL源码分析.01.代码结构与基本流程MySQL源码分析.01.代码结构与基本流程
MySQL源码分析.01.代码结构与基本流程
 
Aix操作系统培训文档
Aix操作系统培训文档Aix操作系统培训文档
Aix操作系统培训文档
 
Bypat博客出品-利用cent os快速构建自己的发行版
Bypat博客出品-利用cent os快速构建自己的发行版Bypat博客出品-利用cent os快速构建自己的发行版
Bypat博客出品-利用cent os快速构建自己的发行版
 
Erlang Practice
Erlang PracticeErlang Practice
Erlang Practice
 
Android系统移植技术详解
Android系统移植技术详解Android系统移植技术详解
Android系统移植技术详解
 
Nagios的安装部署和与cacti的整合(linuxtone)
Nagios的安装部署和与cacti的整合(linuxtone)Nagios的安装部署和与cacti的整合(linuxtone)
Nagios的安装部署和与cacti的整合(linuxtone)
 
Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出
 
Kick start无人值守批量安装linux
Kick start无人值守批量安装linuxKick start无人值守批量安装linux
Kick start无人值守批量安装linux
 

Aisanux安装光盘分析

  • 2. 架构 ⇨ 以Asianux 3 sp2 一张dvd的发行版为例: ⇨ 安装光盘的框架: -Asianux <-安装向导镜像及rpm包 -Documents <-License协议及相关说明文档 -dosutils <-为Dos下特殊安装准备的工具 -images <-其他引导img镜像及额外驱动 -isolinux <-光盘引导程序及msg提示信息 -repodata <-精确描述一个 rpm 包的详细信息,如依赖关 系,包含文件,校验码信息 --TRANS.TBL <-当前目录的列表,用mkisofs的-T参数重新 生成 --.discinfo <-安装程序anaconda用于检验光盘正确性的文件 --.treeinfo <-不同安装方式安装程序所在目录结构,如:内 核kernel = images/pxeboot/vmlinuz;根文件系统initrd = images/pxeboot/initrd.img
  • 3. /Asianux /base包含了在安装过程中要用到的描述组织结构和安装行为的所 有文件,其中comps,hdlist和hdlist2是描述RPM包组织结构的文件 --comps.xml 把各个RPM包按一定的原则组织成若干组,即 components,这样在安装过程中就不必对每一个包做出取舍,而以组 为单位。如:kde-desktop,development 等。 --hdlist,hdlist2 这两个文件维护从RPM包名到真实包文件名 的映射过程。这两个文件是用genhdlist生成的,无法用简单的方法察 看其中的内容和结构。 /RPMS包含了Asianux发布的主要部分,即以RPM包的形式将 Asianux系统中的二进制可执行文件,配置文件,文档等等组织在一 起,形成能完成一定功能的比较独立的软件包。这个目录就是把这些 软件包都集合在一起,形成了Asianux发布。
  • 5. /images 包含了制作启动盘的映像文件,以及从一些非常规硬件上 加载安装程序所需的驱动程序盘映像 ⇨ boot.iso 当安装介质光盘时,负责引导系统的映像文件 ⇨ bootefi.img 用于Intel EFI引导方式的机器 ⇨ diskboot.img 安装引导盘,可以写入U盘或其他大容量 可引导存储介质中,用来引导从本地光盘、网络、硬盘或 PCMCIA设备的安装 ⇨ stage2.img,minstg2.img 光盘引导的镜像文件, 在定制Live CD的时候,需要修改它 ⇨ /pxeboot 用于PXE安装方式
  • 6. boot.img结构 boot.img |----vmlinuz Linux内核 |----ldlinux.sys 引导Linux的系统文件 |----syslinux.cfg Linux内核引导参数配置文件 |----initrd.img 内存虚拟文件系统映像文件 |----*.msg文件 引导时的各种提示信息文件 其中,initrd.img为Linux ext2文件系统,构成如下: initrd.img |----/bin |----/dev |----/etc |----/module |----/sbin ------ loader安装程序装载器 |----/tmp |----/var 可执行文件/sbin/loader的任务是判断安装介质的有效性,并从中执行安装 程序。其实正是boot.img,在系统启动时被执行,经解析之后在内存建立起 了Linux内核,并根据配置文件syslinux.cfg装载虚拟文件系统,形成了完整的 LinuxSystem,为后续的工作提供了必要的操作系统环境。
  • 7. stage2.img结构 stage2.img |----/etc |----/modules |----/proc |----/usr----/bin----anaconda 安装程序主执行文件 |-------------/lib-----/anaconda安装程序脚本文件目录 | |----/installclasses 安装类型分类目录 | |----/iw 安装各步骤响应目录 | |----/texttw 字符界面各步骤响应目录 | |----*.py |-------------/share---/anaconda安装程序资源文件目录 | |----/help 安装过程帮助系统目录 | |----/pixmaps 安装时图片存储的位置 如上所示,stage2.img映像文件中的主要部分是安装程序 anaconda,它的主执行体是/usr/bin下的anaconda,由其调用的 大量例程分布在/usr/lib/anaconda下,而安装过程中要用到的资源 文件分布在/usr/share/anaconda下。
  • 8. initrd(boot loader initialized RAM disk) ⇨ 定义: 由 boot loader 初始化的内存盘。在 linux内核启动前, boot loader 会将存储介 质中的 initrd文件加载到内存,内核启动时会在访问真正的根文件系统前 先访问该内存中的 initrd 文件系统。在 boot loader 配置了 initrd的情况 下,内核启动被分成了两个阶段,第一阶段先执行 initrd文件系统中的文 件,完成加载驱动模块等任务,第二阶段才会执行真正的根文件系统中 的 /sbin/init 进程。 ⇨ cpio-initrd 的处理流程: 1. boot loader 把内核以及 initrd 文件加载到内存的特定位置。 2. 内核判断initrd的文件格式,如果是cpio格式。 3. 将initrd的内容释放到rootfs中。 4. 执行initrd中的/init文件,执行到这一点,内核的工作全部结束,完全交给 /init文件处理。
  • 9. initrd处理流程 initrd相关代码的调用层次关系图 (内核的初始化代码位于 init/main.c 中的 static int init(void * unused)函数中。同initrd的处理相关 部分函数调用层次如下图 )
  • 10. 相关概念 • rootfs: 一个基于内存的文件系统,是linux在初 始化时加载的第一个文件系统。 • initramfs: initramfs同本文的主题关系不是很 大,Initramfs是在 kernel 2.5中引入的技术。在 内核镜像中附加一个cpio包,这个cpio包中包含 了一个小型的文件系统,当内核启动时,内核 将这个 cpio包解开,并且将其中包含的文件系 统释放到rootfs中,内核中的一部分初始化代码 会放到这个文件系统中,作为用户层进程来执 行。 • cpio-initrd: 指linux内核使用的cpio格式的initrd。 • image-initrd: 指传统的文件镜像格式的initrd。 • realfs: 用户最终使用的真正的文件系统。
  • 11. 代码分析( unused函数 ) static int init(void * unused){ [1] populate_rootfs(); [2] if (sys_access((const char __user *) "/init", 0) == 0) execute_command = "/init"; else prepare_namespace(); [3] if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) printk(KERN_WARNING "Warning: unable to open an initial console.n"); (void) sys_dup(0); (void) sys_dup(0); [4] if (execute_command) run_init_process(execute_command); run_init_process("/sbin/init"); run_init_process("/etc/init"); run_init_process("/bin/init"); run_init_process("/bin/sh"); panic("No init found. Try passing init= option to kernel."); }
  • 12. 代码分析( unused函数 ) • 代码[1]:populate_rootfs函数负责加载initramfs 和cpio-initrd。 • 代码[2]:如果rootfs的根目录下中包含/init进程, 则赋予execute_command,在init函数的末尾会 被执行。否则执行prepare_namespace函数, initrd是在该函数中被加载的。 • 代码[3]:将控制台设置为标准输入,后续的两 个sys_dup(0),则复制标准输入为标准输出 和标准错误输出。 • 代码[4]:如果rootfs中存在init进程,就将后续 的处理工作交给该init进程。其实这段代码的含 义是如果加载了cpio-initrd则交给cpio-initrd中的 /init处理,否则会执行realfs中的init.
  • 13. 代码分析( populate_rootfs ) 对cpio-initrd的处理位于populate_rootfs函数中 void __init populate_rootfs(void){ [1] char *err = unpack_to_rootfs(__initramfs_start, __initramfs_end - __initramfs_start, 0); [2] if (initrd_start) { [3] err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start, 1); [4] if (!err) { printk(" it isn"); unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start, 0); free_initrd_mem(initrd_start, initrd_end); return; } [5] fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 700); if (fd >= 0) { sys_write(fd, (char *)initrd_start, initrd_end - initrd_start); sys_close(fd); free_initrd_mem(initrd_start, initrd_end); } }
  • 14. 代码分析( populate_rootfs ) • 代码[1]:加载initramfs,initramfs位于地址 __initramfs_start处,是内核在编译过程中生成的, initramfs的是作为内核的一部分而存在的,不是boot loader加载的。 • 代码[2]:判断是否加载了initrd.无论哪种格式的initrd, 都会被boot loader加载到地址initrd_start处。 • 代码[3]:判断加载的是不是cpio-initrd.实际上 unpack_to_rootfs有两个功能一个是释放cpio包,另一个 就是判断是不是cpio包, 这是通过最后一个参数来区分 的,0-释放 1-查看。 • 代码[4]:如果是cpio-initrd则将其内容释放出来到rootfs 中。 • 代码[5]:如果不是cpio-initrd,则认为是一个image- initrd,将其内容保存到/initrd.image中。在后面的 image-initrd的处理代码中会读取/initrd.image.
  • 15. 代码分析(prepare_namespace) 对image-initrd的处理在prepare_namespace函数里,包含了对image- initrd进行处理的代码 void _init prepare_namespace(void){ [1] if (initrd_load()) goto out; out: umount_devfs("/dev"); [2] sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); security_sb_post_mountroot(); mount_devfs_fs (); 代码[1]:执行initrd_load函数,将initrd载入,如果载入成功的话 initrd_load函数会将realfs的根设置为当前目录。 代码[2]:将当前目录即realfs的根mount为Linux VFS的根。initrd_load函 数执行完后,将真正的文件系统的根设置为当前目录。
  • 16. 代码分析( initrd_load函数 ) initrd_load函数负责载入image-initrd int __init initrd_load(void) { [1] if (mount_initrd) { create_dev("/dev/ram", Root_RAM0, NULL); [2] if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) { sys_unlink("/initrd.image"); handle_initrd(); return 1; } } sys_unlink("/initrd.image"); return 0; } 代码[1]:如果加载initrd则建立一个ram0设备 /dev/ram。 代码[2]:/initrd.image文件保存的就是image-initrd,rd_load_image函数 执行具体的加载操作,将 image-nitrd的文件内容释放到ram0里。判断 ROOT_DEV!=Root_RAM0的含义是,如果你在grub或者lilo里配置了 root=/dev/ram0 ,则实际上真正的根设备就是initrd了,所以就不把它作为 initrd处理,而是作为realfs处理。
  • 17. 代码分析(handle_initrd) handle_initrd()函数负责对initrd进行具体的处理 static void __init handle_initrd(void){ [1] real_root_dev = new_encode_dev(ROOT_DEV); [2] create_dev("/dev/root.old", Root_RAM0, NULL); mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); [3] sys_mkdir("/old", 0700); root_fd = sys_open("/", 0, 0); old_fd = sys_open("/old", 0, 0); /* move initrd over / and chdir/chroot in initrd root */ [4] sys_chdir("/root"); sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); mount_devfs_fs (); [5] pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); if (pid > 0) { while (pid != sys_wait4(-1, &i, 0, NULL)) yield(); } /* move initrd to rootfs' /old */ sys_fchdir(old_fd); sys_mount("/", ".", NULL, MS_MOVE, NULL); /* switch root and cwd back to / of rootfs */ [6] sys_fchdir(root_fd); sys_chroot("."); sys_close(old_fd); sys_close(root_fd); umount_devfs("/old/dev");
  • 18. 代码分析(handle_initrd) [7] if (new_decode_dev(real_root_dev) == Root_RAM0) { sys_chdir("/old"); return; } [8] ROOT_DEV = new_decode_dev(real_root_dev); mount_root(); [9] printk(KERN_NOTICE "Trying to move old root to /initrd ... "); error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL); if (!error) printk("okayn"); else { int fd = sys_open("/dev/root.old", O_RDWR, 0); printk("failedn"); printk(KERN_NOTICE "Unmounting old rootn"); sys_umount("/old", MNT_DETACH); printk(KERN_NOTICE "Trying to free ramdisk memory ... "); if (fd < 0) { error = fd; } else { error = sys_ioctl(fd, BLKFLSBUF, 0); sys_close(fd); } printk(!error ? "okayn" : "failedn"); }
  • 19. 代码分析(handle_initrd) • handle_initrd函数的主要功能是执行initrd的linuxrc文 件,并且将realfs的根目录设置为当前目录 • 代码[1]:real_root_dev,是一个全局变量保存的是realfs的设备号。 • 代码[2]:调用mount_block_root函数将initrd文件系统挂载到了VFS 的/root下。 • 代码[3]:提取rootfs的根的文件描述符并将其保存到root_fd.它的作 用就是为了在chroot到initrd的文件系统,处理完initrd之后要,还 能够返回rootfs.返回的代码参考代码[7]. • 代码[4]:chroot进入initrd的文件系统。前面initrd已挂载到了rootfs 的/root目录。 • 代码[5]:执行initrd的linuxrc文件,等待其结束。 • 代码[6]:initrd处理完之后,重新chroot进入rootfs. • 代码[7]:如果real_root_dev在 linuxrc中重新设成Root_RAM0,则 initrd就是最终的realfs了,改变当前目录到initrd中,不作后续处理 直接返回。 • 代码[8]:在linuxrc执行完后,realfs设备已经确定,调用 mount_root函数将realfs挂载到root_fs的 /root目录下,并将当前目 录设置为/root. • 代码[9]:收尾并释放内存盘。
  • 20. anaconda目录结构 installclasses子目录中的各个模块定义了在安装过程中用户可选择 的安装类型。 例如:workstation.py,server.py,custom.py和 personal_desktop.py。其中,workstation.py描述了工作站安装类 型,server.py描述了服务器安装类型,custom.py描述了用户自定 义安装类型,personal_desktop.py描述了个人桌面安装类型。每个 安装类型描述文件根据相应安装类型的特点,分别对安装步骤、 分区策略以及安装包的取舍给出了不同的方案。 iw子目录下包含所有安装图形界面类所在的模块,每个图形界面 对应一个类,负责相应安装步骤图形界面的具体外观显示及与用 户的交互,调用anaconda主目录下的相关安装行为模块完成具体的 安装操作。 textw子目录和iw子目录含义是一致的,只是包含的是字符安装模 式的前端字符用户界面类所在的模块,每个字符用户界面对应一 个类,负责与用户的交互。 如果说用户界面类是处理安装程序外观的话,则anaconda主目录下 的各python模块则执行每个安装界面背后具体的安装行为,包括那 些无用户界面安装步骤的安装操作。
  • 23. installSteps • dispatch.py模块中有一个序列(sequence)数据 结构:installSteps。installSteps中记录了有序排 列的整个安装过程中所有可能的安装步骤,在 生成具体的Dispatcher实例时,会根据安装类型 制定对此进行相应裁减。 • installSteps中的条目(item)有如下两种格式 – 第一种格式:( name, tuple):这种格式表示有用户界 面的安装步骤。其中,name代表安装步骤的名称, tuple(元组,python的一种内置数据类型)存放创建相 应安装步骤的用户界面的参数。 – 第二种格式:( name, Function, tuple):这种格式表示 没有用户界面的安装步骤,其中,name代表安装步 骤的名称,Function指安装操作的具体执行函数, tuple存放的是传递给Function的参数。该安装步骤直 接由Dispatcher调度进行。
  • 24. Dispatcher的主要接口 • gotoNext & gotoPrev:这两个接口分别从当前安装步骤 前进(后退)到下一个(上一个)具有用户界面的安 装步骤,在图形界面安装模式下,由 installcontrolwindow调用,在字符模式下,由 InstallInterface调用。这两个函数只是简单的设置安装 方向,然后调用 movestep函数,其核心操作是movestep。 • currentStep:Dispatcher类的另一个主要接口,取得当前 的安装步骤及其相关信息返回给调用者。在图形安装 模式下,该函数主要由 InstallControlWindow调度图形 用户界面类时调用,在字符模式下,主要由 InstallInterface调度字符用户界面时调用,这两个类通 过该接口取得当前安装步骤的用户界面对应的类及创 建该用户界面类的实例所需的信息。 • skipStep(self, stepToSkip, skip = 1, permanent = 0)是裁减 安装步骤函数。setStepList(self, *steps)是安装步骤设置 函数,主要由安装类型实例调用,每个安装类型会根 据自身的特点设置安装步骤。
  • 25. movestep def moveStep(self): …… if self.step == None: self.step = self.firstStep else: self.step = self.step + self.dir while ((self.step >= self.firstStep and self.step < len(installSteps)) and (self.skipSteps.has_key(installSteps[self.step][0]) or (type(installSteps[self.step][1]) == FunctionType))): info = installSteps[self.step] if ((type(info[1]) == FunctionType) and (not self.skipSteps.has_key(info[0]))): (func, args) = info[1:] rc = apply(func, self.bindArgs(args)) if rc == DISPATCH_BACK: self.dir = -1 elif rc == DISPATCH_FORWARD: self.dir = 1 self.step = self.step + self.dir if self.step == len(installSteps): return None
  • 26. movestep • 首先看一下循环条件:当下一个安装步骤是合法的, 即在第一个安装步骤和最后一个安装步骤之间,且该 步骤被裁减了或者该步骤是一个无用户界面的安装步 骤,即installSteps的条目的第二个元素是一个function, 则进入循环体。 • 进入循环后,Dispatcher直接调用该函数执行安装操 作,其中bindArgs是Dispatcher类的一个函数,负责参 数解析,这里的apply是python的的一个内置方法,用 来执行函数,apply接口的第一个参数是要运行的函数 名称,第二个参数是传给该函数的参数。 • 如果下一个安装步骤依然无用户界面,则继续循环, 直到下一个没有被裁减的具有用户界面的安装步骤, 对于图形安装模式,Dispatcher将控制权交给 InstallControlWindow,对于字符安装模式,Dispatcher 将控制权交给InstallInterface。如果安装过程完成则退 出循环。
  • 27. InstallControlWindow • 控制安装过程中前端图形界面的显示, 该类在anaconda主目录下的gui.py模块中。 • 启动图形安装界面的入口函数run,该函 数调用了setup_window接口,该接口调用 gtk"绘制"图形安装界面的主窗体,然后 控制权交给了gtk。 def run (self, runres, configFileData): self.configFileData = configFileData self.setup_window(runres) gtk.main()
  • 28. 数据结构stepToClass gui.py模块中的一个数据结构:stepToClass记录了安装过 程中所有的具有图形用户界面的安装步骤。 stepToClass = { "language" : ("language_gui", "LanguageWindow"), "keyboard" : ("keyboard_gui", "KeyboardWindow"), …… } 每一个条目从左到右依次是安装步骤名称、图形界面对应的类所在的 模块,图形界面类的名称。如language为安装步骤名称, language_gui为该步骤对应的图形界面类所在的模块 language_gui.py,LanguageWindow为图形界面对应的类名。
  • 30. setScreen def setScreen (self): (step, args) = self.dispatch.currentStep() if not stepToClass[step]: if self.dir == 1: return self.nextClicked() else: return self.prevClicked() (file, className) = stepToClass[step] newScreenClass = None s = "from %s import %s; newScreenClass = %s" % (file, className, className) while 1: exec s break self.destroyCurrentWindow() self.currentWindow = newScreenClass(ics) new_screen = apply(self.currentWindow.getScreen, args) self.installFrame.add(new_screen) self.installFrame.show_all() ……
  • 31. InstallControlWindow 流程 • 前面的nextClicked和 prevClicked函数已经通过 Dispatcher将要进行的安装步骤标记为当前安装步骤, 所以该函数首先通过Dispatcher的 currentStep从 Dispatcher的数据结构installSteps中取得当前安装步骤名 称及相关信息 • 做了一下判断,如果 Dispatcher的当前安装步骤不在字 典stepToClass中,则忽略该步骤,调用nextClicked或 prevClicked继续下一个图形界面安装步骤,直到下一个 步骤在字典stepToClass中 • 从字典stepToClass中取得当前图形安装界面对应的类及 该类所在模块,然后导入该模块并创建图形安装界面 的实例,销毁前一个图形安装界面,并将新创建的图 形界面实例置为当前安装界面,调用图形安装界面实 例的 getScreen函数生成该安装步骤的图形用户界面并 显示。