您的位置:首页 > 其它

debian 基本系统安装关键技术

2007-04-02 17:36 393 查看
0. 缘起

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

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

1. 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 -

2. 基本系统软件包的下载

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 文章:《深入 APT 系统》

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

3. 强制解压核心包

核心包即上面 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 自己已经安装了 ^-^

4. 使用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 就可以这个子系统里想干嘛就干嘛了 ^-^
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: