Debian 基本系统安装关键技术

来自Jack's Lab
跳转到: 导航, 搜索

目录

1 缘起

原文发表于 openrays 社区的 blog http://comcat.blog.openrays.org/blog-htm-do-showone-tid-214.html

发表时间是:2006-12-31 20:58

现在 Ubuntu/Debian 依然流行,这套东西对于想升入了解的朋友应该还是有些帮助的



2 概述

基本系统,是一个最小化的debian系统,可以在其上使用debian的apt-get 机制,进一步的安装你所需要的软件包。多用于开发测试用,比如在现有系统下交叉编译一个64位的系统为了不影响当前系统的环境,可以在某个工作目录下安装一个基本系统,然后在这个子系统里构建交叉编译环境。


安装程序也用到。在将目标磁盘分区完后,安装程序会将要安装整个系统的分区挂载在某个目录下然后调用debootstrap 脚本在该目录下安装一个基本系统,完了进入这个基本系统,使用 apt-get 进一步的安装 X-Windows、Gnome、KDE 等。



3 deb 包格式

deb 包实际上是一个二进制归档文件(使用 ar 创建),一般包含3个文件:debian-binary, control.tar.gz, data.tar.gz


其中:

debian-binary 是deb包格式的版本号,我的系统里 $cat debian-binary 显示 2.0

control.tar.gz 包含deb包的控制信息和一些辅助脚本

如一个典型的control.tar.gz 解开为:

control.tar.gz
|
`|--- control   控制信息文件,就是源码目录中的debian/control
|--- md5sum     软件包中所有文件的 md5 值,文本文件
|--- conffiles   软件包的配置文件列表,在升级包的过程中不会被覆盖(可有可无)
|--- preinst   辅助脚本,在包解压前执行 (可有可无)
|--- postinst   辅助脚本,在包解压后执行 (可有可无)
|--- prerm     辅助脚本,在包删除之前执行 (可有可无)
`--- postrm     辅助脚本,在包删除之后执行 (可有可无) 


data.tar.gz 即是真实的安装数据所在,一个真实的data.tar.gz解开后的目录树为:

data.tar.gz
|
|-- etc
|   `-- rarfiles.lst
`-- usr
  |-- bin
  |   `-- rar
  |-- lib
  |   `-- default.sfx
  `-- share
    |-- doc
    |   `-- rar
    |     |-- changelog.Debian.gz
    |     |-- copyright
    |     |-- order.htm
    |     |-- rar.txt.gz
    |     |-- rar_faq.txt.gz
    |     |-- readme.txt
    |     |-- technote.txt.gz
    |     `-- whatsnew.txt
    |-- lintian
    |   `-- overrides
    |     `-- rar
    `-- man
        `-- man1
          `-- rar.1.gz


可以通过如下命令解包:

 ar x rar_3.20-2_i386.deb 

以下命令查看包的内容:

 ar t rar_3.20-2_mipsel.deb


明白了这一层,我们就可以自己提供 debian-binary,control.tar.gz,data.tar.gz 随心所欲地制作deb 包 ^-^


如下命令制作deb包:

 ar r rar.deb debian-binary control.tar.gz data.tar.gz
 dpkg -c rar.deb #显示包的内容了


注意 debian-binary 要放在第一位,

否则 dpkg 会报: 文件“rar.deb”不是 debian 的二进制包文件


亦可直接解包获取我们所需的数据文件,绕开 dpkg 的控制,如:

   ar -p ./rar.deb data.tar.gz | zcat | tar -xf -




4 基本系统软件包的下载

debian 对核心的基本系统包进行了分类,一类用Essential: yes; Priority: required 标识,一类用Priority: important 标识。 加上一些额外常用的包,可以形成两个列表:

required = "base-files base-passwd bash bsdutils coreutils libacl1 libattr1 debianutils diff dpkg dselect libblkid1 e2fsprogs e2fslibs libcomerr2 libss2
 libuuid1 findutils grep gzip hostname libcap1 libdb1-compat libdb3 libncurses5 libnewt0.51 libpam-modules libpam-runtime libpam0g login makedev mawk
 mount ncurses-base ncurses-bin passwd perl-base procps sed slang1a-utf8 initscripts sysvinit sysv-rc tar util-linux libgcc1 gcc-3.3-base libstdc++5 zlib1g libc6"
base = "adduser apt apt-utils libdb4.2 base-config aptitude libsigc++-1.2-5c102 bsdmainutils console-common console-tools libconsole console-data cpio cron
 dhcp-client ed libgnutls11 libgcrypt11 libgpg-error0 libncursesw5 libopencdk8 libtasn1-2 fdutils gettext-base groff-base ifupdown info klogd libssl0.9.7
 liblzo1 liblockfile1 libpcre3 libwrap0 logrotate man-db libgdbm3 manpages nano net-tools netbase netkit-inetd iputils-ping nvi ppp pppconfig pppoe
 pppoeconf libpcap0.7 sysklogd tasksel libtextwrap1 tcpd telnet wget libpopt0 modutils whiptail "


有了基本软件包的列表,就可以使用 apt 的机制来下载这些包到指定的目录。

假定我们的工作目录在$TARGET_DIR,下面建立工作目录:

  mkdir -p "$TARGET_DIR/var/lib/dpkg"
  mkdir -p "$TARGET_DIR/var/lib/apt/lists/partial"
  mkdir -p "$TARGET_DIR/var/cache/apt/archives/partial"
  : >"$TARGET_DIR/var/cache/apt/archives/lock"
  : >"$TARGET_DIR/var/lib/dpkg/status"
  : >"$TARGET_DIR/var/lib/dpkg/status"
  : >"$TARGET_DIR/var/lib/dpkg/lock"
  : >"$TARGET_DIR/var/lib/dpkg/available"
  : >"$TARGET_DIR/var/lib/apt/lists/lock"
  mkdir -p "$TARGET_DIR/etc/apt"
  cp /etc/apt/sources.list $TARGET_DIR/etc/apt/


下面解析包依赖关系,使用 apt-get -d install 下载之:

  all_debs="$required $base"

  options=" -q \
      -o Dir::State::status=$TARGET_DIR/var/lib/dpkg/status   \
      -o Dir::State=$TARGET_DIR/var/lib/apt     \
      -o Dir::Cache=$TARGET_DIR/var/cache/apt   \
      -o Dir::Etc=$TARGET_DIR/etc/apt   \
      -o APT::Cache::AllVersions=0 "

  # 更新源索引于 $TARGET_DIR/var/lib/apt/list/ 下
  apt-get $options update -f>/dev/null 2>&1   

  # 解析依赖关系,并扩展所有基本系统软件包列表
  apt-get install -s $all_debs $options       
  expand_list=$(apt-get install -s $all_debs $options | awk '{if ($0 ~ /^Inst/) print $2}') 

  # 下载软件包于 $TARGET_DIR/var/cache/apt/archives/ 下
  for f in $expand_list;do
    apt-get install -d -y --force-yes $f $options 
  done

有关这里所用的 apt-get 的高级选项,参见我的另一篇 blog 文章:《深入 Debian APT 包管理系统》

注意: 传给apt-get 的options,其中的 $TARGET_DIR 必须为绝对路径。




5 强制解压核心包

核心包即上面 required 列表所示的包,由于目标目录目前仅有一些 dpkg 所必须的工作目录及刚 下载的基本系统软件包,并无一些基本程序、基本文件的实体,这些通过强制解压所有核心包于目 标目录来是实现:

   ar -p ./$pkg_full_path data.tar.gz | zcat | tar -xf -


然后向 dpkg 的控制信息文件写入 dpkg 自己的控制信息:

    # 获取 dpkg 的版本号
    ver="$(
        ar -p "$TARGET_DIR/var/cache/apt/archives/dpkg_*.deb" control.tar.gz | zcat |
          tar -O -xf - control ./control 2>/dev/null |
          sed -ne 's/^Version: *//Ip' | head -n 1
    )"

    mkdir -p "$TARGET_DIR/var/lib/dpkg/info"

    echo \
      "Package: dpkg
      Version: $ver
      Status: install ok installed" >> "$TARGET_DIR/var/lib/dpkg/status"

    touch "$TARGET_DIR/var/lib/dpkg/info/${pkg}.list"


告诉 dpkg 自己已经安装了 ^-^



6 使用dpkg 安装基本系统软件包

要保证我们的基本系统能使用apt-get 安装后序的开发包,则所有的基本系统包还是要纳入 dpkg 的管理机制的。故而所有包都要重新用 dpkg 安装。

经第3步强制解压后,目标目录已经有了最基本的文件,可以chroot 过去,使用dpkg 依序安装了:

  ln -s mawk $TARGET_DIR/usr/bin/awk

  pkg_path=var/cache/apt/archives     # 所有基本系统deb包所在目录

  chroot $TARGET_DIR                       # 将当前进程的根目录设为目标目录

  dpkg --force-depends --install $pkg_path/base-files_*.deb 
  dpkg --force-depends --install $pkg_path/base-passwd_*.deb
  dpkg --force-depends --install $pkg_path/dpkg_*.deb

  if [ ! -e "$TARGET_DIR/etc/localtime" ]; then       
        ln -sf /usr/share/zoneinfo/UTC "$TARGET_DIR/etc/localtime"         # 设置子系统时区
  fi

  dpkg --force-depends --install $pkg_path/libc6_*.deb
  dpkg --force-depends --install $pkg_path/perl-base_*.deb

  rm $TARGET_DIR/usr/bin/awk

  dpkg --force-depends --install $pkg_path/mawk_*.deb
  dpkg --force-depends --install $pkg_path/debconf_*.deb


收拾了最基本的,就可以批量处理了,使用如下命令安装 required 列表的所有软件包:

 dpkg --force-depends --unpack $pkg_path/pkgname_*.deb

--force-depends 告诉 dpkg 忽略依赖关系

--unpack: 解压软件包,但不配置之。 --install 的话包括 --unpack 和 --configure

    # 设置 dselect 使用 apt 
    echo "apt apt" > "$TARGET_DIR/var/lib/dpkg/cmethopt"
    chmod 644 "$TARGET_DIR/var/lib/dpkg/cmethopt"

    # 配置刚刚忽略依赖关系 unpack 的所有软件包
    dpkg --configure --pending --force-configure-any --force-depends 

--configure: 重新配置一个 unpack 的软件包,加 -a 或 --pending 则重新配置所有

--force-configure-any: 不重新配置该包依赖的软件包


搞定了 required 列表的,现在来收拾 base 列表的软件包:

dpkg --force-auto-select --force-overwrite --force-confold --skip-same-version
     --unpack $pkg_path/pkgname_*.deb

--force-overwrite:如有新的文件,则用新的

--force-confold:若原有配置文件被修改,则保留之

--skip-same-version: 如果已经安装了相同版本号的包,就不再安装


配置刚刚忽略依赖关系 unpack 的所有软件包,-a 等价于 --pending:

 dpkg --force-confold --skip-same-version --configure -a


至此基本系统就安装在目标目录了,chroot $TARGET_DIR 就可以这个子系统里想干嘛就干嘛了 ^-^



个人工具
名字空间

变换
操作
导航
工具箱