Linux發行版製作指南

火星人 @ 2014-03-12 , reply:0


  摘要
  此文檔著重介紹了Linux發行版製作過程中的各個步驟。(2002-10-08 13:20:09)
By Coolee


1.項目整體分析

  製作Linux發布的目的是為了在系統中能夠快速,正確地建立Linux系統環境。製作Linux發布的主要工作是決定各種軟體的去留,因為有了RPM(RedHat Package Manager)包對其提供優良的管理能力,所以以目前比較成熟的RedHat 7.1(Linux Kernel Version 2.4.2-12)Linux發布程序作為藍本,以RPM包作為基本的制定單元,以需求為原則對其進行取捨,得到適合實際需要的Linux系統。

  由此,項目自然而然的以分析RedHat Linux的光碟安裝系統為起點,在掌握了其結構和行為的基礎上,在包一級(結構部分)和代碼一級(行為部分)進行修改,同時建立相應的測試環境,以便對修改進行及時的規範。

2.項目分步驟實施細節

  2.1對Linux光碟安裝系統的分析

  ●結構部分

  在安裝光碟中,主要的目錄結構和文件大致如下:

  images/ 此目錄下包含了製作啟動盤的映像文件(文件後綴img),

  其中boot.img是當安裝介質為CD-ROM時負責引導系統的映像文件

  bootnet.img是當安裝介質為FTP,NFS等時負責引導系統的映像文件

  driver.img是由一些特殊設備驅動程序模塊組成的映像文件,在當前內核不支持這些設備的情況下,提供了對它們進行訪問的一種方法

  其中,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裝載虛擬文件系統,形成了完整的Linux System,為後續的工作提供了必要的操作系統環境。Boot.img映像的文件系統類型為msdos,而其中的initrd.img映像的文件系統類型必為Linux系統自己的ext2,所以對於它們的解析操作是不同的,具體請參考附錄A 。

  RedHat/ 此目錄是RedHat Linux發布的核心目錄,主要的目錄結構都在這裡,其中

  RPMS/ 包含了RedHat Linux發布的主要部分,即以RPM包的形式將Linux系統中的二進位可執行文件,配置文件,文檔等等組織在一起,形成能完成一定功能的比較獨立的軟體包(文件後綴rpm)。這個目錄就是把這些軟體包都集合在一起,形成了RedHat Linux發布。

  base/ 包含了在安裝過程中要用到的描述組織結構和安裝行為的所有文件,其中comps,hdlist和hdlist2是描述RPM包組織結構的文件。

  comps 此文件把各個RPM包按一定的原則組織成若干組,即components,這樣在安裝過程中就不必對每一個包做出取捨,而以組為單位。comps文件為簡單文本格式,它的結構如下所示:


  4 表示RPM包的版本號,當前為4
  1 base { }
   base是此component名,{…}中是此component中所包含的RPM包
    的名稱列表,1表示在安裝中默認為選中,即默認安裝。

0 ?hide IDS sensor{
        snort
   libpcap
}
    表示IDS sensor組中包含有snort和lipcap這兩個RPM包。0表示
    這個組在安裝中默認為不選中即默認不安裝,並且由—hide指出
    不在用戶界面上顯示此組。



  hdlist和hdlist2 這兩個文件維護從RPM包名到真實包文件名的映射過程,例如從snort這個RPM包名到真實包文件名snort-1.8.1-1.1.2.i386.rpm的映射。這兩個文件是用特殊的程序生成的,無法用簡單的方法察看其中的內容和結構。具體的生成方法請參考附錄D。

  stage2.img , hdstg1.img , hdstg2.img , netstg1.img 和netstg2.img 是描述安裝行為的映像文件,其中

  stage2.img 是當安裝介質為CD-ROM時的安裝程序映像文件

  hdstg1.img 是當安裝介質為HardDisk時的安裝程序映像文件

  hdstg2.img 是當安裝介質為HardDisk時的安裝程序映像文件

  netstg1.img 是當安裝介質為FTP,NFS時的安裝程序映像文件

  netstg2.img 是當安裝介質為FTP,NFS時的安裝程序映像文件

這裡主要討論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下。stage2.img 的解析方法請參考附錄B。

  ●行為部分

  RedHat 7.1的安裝程序被命名為anaconda。如前所述,當boot.img所代表的啟動介質被系統引導之後,在內存中就建立了一個完整的Linux系統(包括Linux內核和一個內存虛擬文件系統),之後便執行文件系統中存在的loader命令,從適當的介質中執行安裝程序(例:安裝介質是CD-ROM,就解析CD-ROM上的stage2.img,並從中執行安裝程序),即執行anaconda,完成Linux系統的安裝任務。

  此次利用RedHat 7.1的安裝程序源代碼的SRPM包形式:anaconda-7.1-5.src.rpm來獲得anaconda的源程序,經解包后在/usr/src/redhat/SOURCES/anaconda-7.1形成了源代碼樹。


  anaconda-7.1
  |-------------------/bootdisk
啟動盤目錄
  |-------------------/docs
文檔目錄
  |-------------------/help
安裝過程幫助系統目錄
  |-------------------/installclasses
安裝類型分類目錄
  |-------------------/iw
安裝各步驟響應目錄
  |-------------------/loader
安裝程序裝載器目錄
  |-------------------/pixmap
圖形資源目錄
  |-------------------/utils
工具目錄
  |-------------------*.py
各Python腳本文件



  分析如下:

  anaconda安裝程序主要用Python語言寫成,它是一種解釋性的,面向對象的腳本語言。源文件後綴為.py,也可生成可執行的位元組碼,後綴為.pyc或.pyo。其中:

  installclasses/ 子目錄中各文件定義了在安裝過程中用戶可選擇的安裝類型,通常由四個文件workstation.py , server.py , laptop.py和custom.py來描述workstation(工作站)安裝類型,server(伺服器)安裝類型,laptop(膝上型電腦)安裝類型和custom(自定義)安裝類型。每個腳本文件的內部,則是根據自己安裝類型的特點對安裝步驟,分區策略以及包的取捨做出了不同的方案。

  iw/ 子目錄中各文件定義了在圖形界面安裝狀態時各步驟對Next(下一步)和Prev(上一步)的響應函數。

  loader/ 安裝程序裝載器的源代碼目錄,用C語言寫成。

  pixmap/ 圖形資源目錄,包括安裝過程中使用到的所有點陣圖,圖標。

  utils/ 安裝程序實用工具目錄。

  anaconda 是安裝程序的主執行文件,它建立了Python語言的運行環境,提供了程序的入口點並以模塊的方式將各個子系統結合在一起。

  gui.py 定義了安裝程序圖形界面使用的各種窗口類,包括MessageWindow,ProgressWindow,WaitWindow,ExeceptWindow等,和控制這些窗口及圖形界面行為的InstallInterface, InstallControlWindow, InstallControlState類。總之,控制gui。

  todo.py 定義了安裝程序的各種行為函數,它是圖形界面背後真正進行各項操作的函數集合。

  harddrive.py 定義了當安裝介質為硬碟時,系統該如何找到安裝程序的光碟映像,並從中執行程序。

  安裝程序源代碼的編譯由make和make install組成,完成後在/usr/src/RedHat目錄下形成了如下目錄結構:


  instimage
|------/etc
|------/usr
|------/bin
|------/sbin
|------/lib
| |------/anaconda
| | |------installclasses
| | |------iw
| | |------texttw
| | |------*.py
| |
| |------/anaconda-runtime
| |------/boot/loader
|
|------/share------/anaconda
|------/help
|------/pixmaps



  此目錄結構基本與stage2.img的文件結構相同。

  2.2調試環境的建立:

  ●對源程序的修改

  在分析完安裝程序的基本構成之後,就要建立相應的調試環境。建立此環境的目的是為了可以方便地對修改過的安裝程序及裁減后的RPM包進行隨時的確認。顯然,可以選用CD-ROM或本地硬碟作為調試介質,下表比較了兩者的差別:

CDROM 硬碟
對應的安裝界面 圖形界面 菜單界面
對應的映像文件 stage2.img *.iso中的hdstg1.img , hdstg2.img
優點 圖形界面,直接使用映像文件stage2.img 隨改隨調,調試周期短,效率高
缺點 每次改動都要求刻盤,調試效率低 菜單界面,每次調試都要求提供光碟映像文件*.iso,效率上打折扣

  在兩者各有優缺點的情況下,考慮折衷的方案,即為了首先保證調試的效率,採用硬碟作為調試介質,但對應的映像文件選取stage2.img,這樣能達到效率最大化,同時調試界面採取圖形方式。採用此方案時,須修改源代碼,以達到預期的效果。

  從前面對安裝系統的分析,可以看出在initrd.img中的/sbin/loader程序負責判斷安裝介質的有效性,並從中執行安裝程序。所以要首先修改它的源代碼文件loader.c,從中找出硬碟安裝時默認讀出光碟映像文件*.iso的函數setupIsoImages,並註釋掉其中在硬碟目錄中尋找映像文件*.iso的相關操作,具體對應Line 582 至 Line590行中包含sprintf和if(){}循環的語句,以避免打開子目錄,並在其後加入mountLoopback("/tmp/hdimage/RedHat/base/stage2.img","/mnt/runtime", "loop0");一句以便實現直接使用stage2.img的目的,並註釋掉其後從errno=0開始的代碼,經過整個while循環到closedir(dir),但保留umount(「/tmp/hdimage」);註釋掉if(!net) return NULL;一句。以上操作目的是防止程序讀出光碟映像文件*.iso。在loader.c的主函數main()中的結尾部分,註釋掉if (!FL_TESTING(flags)) { 和 }的條件判斷的兩條語句,讓程序毫無疑問地執行硬碟上的安裝程序。至此,對loader.c修改完畢。

  同時還要對Python腳本的一些相關文件進行修改以保證對stage2.img文件的支持。具體的,在harddrive.py的類class HardDriveInstallMethod中,註釋掉函數 mountMedia(self, cdNum)中的所有內容並加Pass語句的方法使此函數失效,同樣方法處理umountMedia函數,mountDirectory函數和umountDirectory函數,為了保險起見,在其他函數中註釋掉有關上面函數的調用。並在類的構造函數(初始化)中的# Go ahead…語句之前加self.tree=」/tmp/hdimage/」語句,並註釋掉後面的所有語句。這樣做仍然是要保證廢棄iso映像轉而對stage2.img實現控制。不僅如此,最好還註釋掉todo.py中的Line1781至Line1783調用self.method.systemMounted一段,以確保不出差錯。接著進行make和make install,重新編譯程序,使修改生效,並把新的loader程序從編譯的目標目錄中copy到boot.img中initrd.img中的相應目錄並覆蓋舊的loader文件。為了啟動時的快速,修改boot.img中的syslinux.cfg文件,去掉啟動提示,延時和其他Linux啟動選項,修改後的syslinux.cfg文件,請參考附錄F

  最後,把boot.img做成啟動盤,方法請參考附錄G。

  ●建立硬碟介質中的調試目錄

  在硬碟的Linux分區中建立形如RedHat安裝光碟目錄結構的調試目錄及相關文件,如下所示:
  |----/images
  | |------boot.img
  |
  |----/RedHat
|----/base
  |     |------comps , hdlist , hdlist2,stage2.img
  |
|----/RPMS
  |   |----*.rpm




  建立這種目錄結構和相關文件的原因是在安裝程序中已經以代碼的形式確定了它們的命名及結構。其中,對boot.img和stage2.img的相關修改如前所述,而涉及到對comps,hdlist,hdlist2的修改,則需在後續的裁剪過程中確定。

  至此,調試環境建立完畢。現在可以用做好的啟動盤來引導系統,並且可以從指定的硬碟上測試安裝程序和RPM包的正確性。

2.3對安裝步驟的簡化

  在對RPM 包的剪裁進行之前,還要對原有的安裝步驟做出簡化,去掉一些與系統需求大致無關的項目,使安裝者可以集中精力地配置Sensor的主要參數,忽略諸如對鍵盤,滑鼠,和多國語言的配置。具體的如下所示:

  原有的安裝步驟有:

  1.安裝語言選擇

  2.鍵盤配置

  3.滑鼠配置

  4.歡迎信息

  5.安裝類型選擇(包括安裝或升級,安裝部分又包括workstation,server,laptop,custom四種類型)

  6.選擇分區方式(自動分區,手動分區,專業分區)

  7.選擇以上部分或全部分區格式化

  8.Lilo操作系統引導器配置

  9.網卡及網路配置

  10.防火牆配置

  11.語言配置

  12.時區配置

  13.賬戶配置

  14.認證配置

  15.包組及單RPM包選擇

  16.包獨立性檢查

  17.X-Window配置

  18.安裝前確認

  19.安裝過程

  20.製作啟動盤

  21.安裝完畢確認

  在這些安裝步驟中很多都是在確定了RPM包組及調試完成後不必要存在的,所以去掉第1,2,3,4,7,8,10,11,14,16,17和第20項安裝步驟,所有去掉步驟的相關設置都採取默認的設置值,如第7步 採取分區全部格式化的方案,第8步,採取Lilo放置在MBR上,default boot 為Linux的設置等等,並修改第5步,去掉升級類型和安裝類型中的所有4種既定類型,添加IDS sensor類型。修改完成以後的安裝步驟如下所示:

  1.安裝類型選擇(現有的為IDS sensor一種)

  2.選擇分區方式(自動分區,手動分區,專業分區)

  3.網卡及網路配置

  4.時區配置

  5.賬戶配置

  6.包組及單RPM包選擇

  7.安裝過程

  8.安裝完畢確認

  為此,需要修改Python腳本語言

  ● 在安裝程序運行之初,需要先禁止掉安裝語言選擇,鍵盤配置,滑鼠配置和歡迎信息,在anaconda中在判斷語言是否有效之前即Line491 if lang:之前加上以下四句:

[aidcode]   instClass.addToSkipList("language");   instClass.addToSkipList("keyboard");   instClass.addToSkipList("mouse");   instClass.addToSkipList("welcome"); [/aidcode]
  並在gui.py中的類class InstallInterface的run函數中註釋掉Line371至Line371,即在commonSteps結構中除保留( InstallPathWindow, "installtype" )外,註釋掉( LanguageWindow, "language" ),( KeyboardWindow, "keyboard" ),( MouseWindow, "mouse" )和( WelcomeWindow, "welcome" )

  ●對安裝類型進行精簡。在installclasses目錄下去掉upgrateonly.py , workstation.py , server.py , laptop.py和custom.py即去掉升級類型和安裝類型中的所有4種既定類型, 添加IDS sensor類型,即在目錄中添加sensor.py文件,文件的具體內容請參考附錄E。

  除此之外,還要修改iw/installpath_gui.py腳本文件,以便在圖形界面上不顯示Install和Upgrate圖標和選項,只顯示IDS Sensor項目。具體的,註釋掉Line223,Line 227,Line 233和Line 234代碼,即在類class InstallPathWindow中的getScreen函數的最後部分不執行顯示。

  ● 去掉其他多餘步驟,主要修改iw/installpath_gui.py腳本文件。註釋掉類class InstallPathWindow初始化函數__init__里結構self.installSteps中的( FormatWindow, "format" ) , ( FirewallWindow, "firewall" ) , ( LanguageSupportWindow, "languagesupport" ) , ( AuthWindow, "authentication" ) , ( UnresolvedDependenciesWindow, "dependencies" ) , ( XConfigWindow, "xconfig" ) , ( BootdiskWindow, "bootdisk" ),即對應著去掉的第7,10,11,14,16,17和第20步驟。

  當這三步完成後,進行make和make install,重新編譯程序,使修改生效,並把這些文件Copy至stage2.img中的相關位置,替換掉舊文件。這樣就完成了對安裝步驟的簡化。

  2.4對RPM 包的剪裁

  對RPM包的裁剪依這次的需求進行。項目整體分析時已做出說明,製作目的是為了在系統前端Sensor 中能夠快速,正確地建立運行Snort的Linux系統環境。所以只需保留Linux基本系統和運行snort所需的環境即可。

  Linux基本系統的RPM包組成在comps文件中的base部分中有詳細的描述,所以就以它為藍本,去掉除base以外的所有component,並去掉base中以下不必要的RPM包:

[aidcode]   apmd     ash   autoconfig   dhcpcd  dosfstools  ed   eject   gdm   gettext   gpm gruff ksymoops lokkit mailcap mailx man mktemp mouseconfig ncurses openldap popt procmail pump raidtool readline redhat-logos redhat-release rootfiles sendmail syslinux utemper words [/aidcode]
  在comps文件中增加IDS Sensor component並在此組中添加必要的RPM包,如snort-1.8.1就需要snort , libpcap , mysql , openssl , openssl-clients , perl等RPM包,除此之外,為了方便調試,也保留了一些用於操作和診斷的RPM包,如tcpdump , iputils , zip等,完成的comps請參考附錄C。

  同時,在/RPM目錄中依照上面所有確認保留的RPM包名稱,刪除不予保留的各RPM文件(文件後綴.rpm)。此時在/base中的comps文件和在/RPM中的各rpm文件都已剪裁完成,可以利用genhdlist生成hdlist和hdlist2文件了,genhdlist 在anaconda-7.1的源代碼中的utils目錄里。具體生成方法見附錄D。

3. 存在的問題及今後目標

  此次對NetCop Linux發布的製作是以RPM包作為裁剪單元進行的,所以必然存在很大缺陷,即對RPM包的內部毫無辦法,無法去掉RPM包內部對需求無用的大量文件並且無法對內核,腳本文件等做出制定修改。所以,下一步所要做的工作,是逐一打開每一個候選的RPM包,依需求對包內的每一個文件做出修改或丟棄,這樣才能做出真正適合sensor的Linux發布,無疑,工作量是巨大的。

4. 原始資料及參考文獻

[aidcode]   Bootdisk-HOWTO   CDROM-HOWTO   CD-Writing-HOWTO   Distribution-HOWTO   HP-HOWTO   KickStart-HOWTO   Linux-From-Scratch-HOWTO   RedHat-CD-HOWTO   RPM-HOWTO   http://mail.y-min.or.jp/~nob/ml/linuxppc-jp-dev/199902/msg00150.html [/aidcode]

附錄

  附錄A boot.img和initrd.img的解析過程

  1.首先建立兩個映像文件解析后的裝載點(mount point):

[aidcode]   mkdir /mnt/boot /mnt/initrd [/aidcode]
2.寫shell腳本進行解析和還原:

  解析腳本命名為up

[aidcode]   #!/bin/sh   mount -o loop -t msdos boot.img /mnt/boot   gzip -cd /mnt/boot/initrd.img > /tmp/initrd.ext2   mount -o loop ?t ext2 /tmp/initrd.ext2 /mnt/initrd [/aidcode]
  還原腳本命名為down

[aidcode]   #!/bin/sh   umount /mnt/initrd   gzip -c9 /tmp/initrd.ext2 > /mnt/boot/initrd.img   umount /mnt/boot [/aidcode]
  附錄B stage2.img解析過程

  1.首先建立映像文件解析后的裝載點(mount point):

[aidcode]   mkdir /mnt/stage2 [/aidcode]
  2.寫shell腳本進行解析和還原:

  解析腳本命名為up2

[aidcode]   #!/bin/sh   mount -o loop stage2.img /mnt/stage2 [/aidcode]
  還原腳本命名為down2

[aidcode]   #!/bin/sh   umount /mnt/stage2 [/aidcode]
  附錄C comps文件清單

[aidcode] 4 1 Base { MAKEDEV SysVinit anacron at basesystem bash bdflush bzip2 chkconfig console-tools cpio cracklib cracklib-dicts crontabs cyrus-sasl openssl db1 db2 db3 dev devfsd diffutils e2fsprogs file filesystem fileutils findutils gawk glib glibc glibc-common grep gzip hdparm hotplug lilo info initscripts kbdconfig kernel krb5-libs kudzu less libstdc++ libtermcap logrotate losetup mingetty mkbootdisk mkinitrd modutils mount net-tools newt ntsysv pam passwd pciutils popt procps psmisc pwdb quota rpm sed setserial setup setuptool sh-utils shadow-utils slang slocate sysklogd tar termcap textutils time timeconfig tmpwatch util-linux vim-common vim-minimal vixie-cron which zlib } 1 --hide IDS Sensor { iptables iputils libpcap mysql openssh openssh-clients openssl perl rdate snort tcpdump traceroute unzip zip } [/aidcode]
  附錄D hdlist和hdlist2生成方

  假設在/tmp/cdimage/RedHat/RPMS目錄下收錄著RPM包的話,則通過使用 [aidcode]   genhdlist /tmp/cdimage/ [/aidcode]

  生成hdlist和hdlist2文件,文件的生成位置在目錄/tmp/cdimage/RedHat/base/下

  附錄E sensor.py文件清單

[aidcode]   from installclass import BaseInstallClass   from translate import *   from installclass import FSEDIT_CLEAR_ALL   import os   import iutil   class InstallClass(BaseInstallClass):   name = N_("IDS Sensor")   pixmap = "sensor.png"   sortPriority = 10   def __init__(self, expert): BaseInstallClass.__init__(self) self.setGroups(["IDS Sensor"]) self.addToSkipList("lilo") self.addNewPartition('/boot', (48, -1, 0), (None, -1, 0), (0,0)) self.addNewPartition('/', (256, -1, 0), (None, -1, 0), (0,0)) self.addNewPartition('/usr', (512, -1, 1), (None, -1, 0), (0,0)) self.addNewPartition('/var', (256, -1, 0), (None, -1, 0), (0,0)) self.addNewPartition('/home',(512, -1, 1), (None, -1, 0), (0,0)) self.setClearParts(FSEDIT_CLEAR_ALL, warningText = N_("Automatic partitioning will erase ALL DATA on your hard " "drive to make room for your Linux installation.")) # self.addNewPartition('swap', (64, 256, 1), (None, -1, 0), (0,0)) # 2.4 kernel requires more swap, so base amount we try to get # on amount of memory (minswap, maxswap) = iutil.swapSuggestion() self.addNewPartition('swap', (minswap, maxswap, 1), (None, -1, 0), (0,0)) [/aidcode]
  附錄F syslinux.cfg文件清單

[aidcode]   label linux   kernel vmlinuz   append initrd=initrd.img lang=us devfs=nomount vga=788 [/aidcode]
  附錄G boot.img製作啟動盤方法

[aidcode]   cat boot.img > /dev/fd0 [/aidcode]
  或

[aidcode]   dd if=boot.img of=/dev/fd0 bs=1440 [/aidcode]
  附錄H Linux光碟映像製作方法

  在Linux下光碟映像的製作用mkisofs命令,具體的,假設在/tmp/cdimage/目錄下收錄著將要被製作的光碟內容,則執行

[aidcode]   mkisofs ?v ?r ?T ?J ?V 「NetCop Linux」 ?b images/boot.img    -o /tmp/NetCopLinux.iso [/aidcode]
  即可在/tmp目錄下做出一命名為NetCopLinux.iso的光碟映像文件,它以/tmp/cdimage/images/boot.img 作為光碟啟動文件。

來源:linuxaid





[火星人 via ] Linux發行版製作指南已經有160次圍觀

http://www.coctec.com/docs/program/show-post-71966.html