LFS学习(7)安装基础软件包

虚拟内核文件系统(Virtual Kernel File Systems),是指那些是由内核产生但并不存在于硬盘上(存 在于内存中)的文件系统,他们被用来与内核进行通信。

首先让我们为虚拟内核文件系统建立挂载目录:

mkdir -pv $LFS/{dev,proc,sys}

6.2.1. 创建初始设备节点

内核在引导时要求某些设备节点必须存在(特别是 console 和 null ),这些设备节点必须创建在硬盘 上才能使得内核在 udev 尚未启动之前就可以使用它们,此外还有当Linux以init=/bin/bash 启动。使用下面的命令来创建这些节点:

mknod -m 600 $LFS/dev/console c 5 1
mknod -m 666 $LFS/dev/null c 1 3

6.2.2.挂载并填充 /dev 目录

推荐的向 /dev 目录填充设备的方法是在 /dev 上挂载一个虚拟文件系统(比如 tmpfs),然后在设备 被检测到或被访问到的时候(通常是在系统引导的过程中)动态创建设备节点。既然现在新的系统尚未被引导, 那么就有必要通过手工挂载和填充 /dev 目录。这可以通过绑定挂载宿主系统的 /dev 目录。绑定挂载是一种 特殊的挂载方式,允许你创建一个目录或者是挂载点的镜像到其他的地方。可以使用下面的命令:

mount --bind /dev $LFS/dev

6.2.3. 挂载虚拟内核文件系统

现在挂载虚拟内核文件系统:

mount -vt devpts devpts $LFS/dev/pts
mount -vt tmpfs shm $LFS/dev/shm
mount -vt proc proc $LFS/proc
mount -vt sysfs sysfs $LFS/sys

对于 LFS BOOK,包管理通常被请求加进去。一个包管理器允许跟踪文件的安装,使删除或升级软件包变得简单。在这一部分里,我们不会讨论或者是推荐任何一个包管理器。我们讲述的是一些流行的技术,以及他 们是怎么工作的。对于你来说,一个完美的包管理器可能在这些技术之中,也可能是一些技术的结合。这一部分 简明的描述了当升级软件包的时候会出现的几个问题。

LFS 和 BLFS 中没有涉及包管理器的几个原因有:

  • 把精力拿来做包管理器,就偏离了我们的LFS的初衷:一个Linux系统是如何构建的。

  • 包管理有很多解决方案,每一个都有优点和缺点。任何一个都不会令其他种类的fans满意的。

有一些hints是关于包管理。可以查看 Hints subproject 来选择一个适合你的。

6.3.1. 升级问题

一个包管理器会使升级一个软件包到新的版本变得很简单。通常 LFS 和 BLFS 手册中的说明可以用来升级软件包。 这里有几点,你在升级软件包的时候应该注意的,尤其是在一个运行着的系统上。

  • 如果工具链中的一个软件包 (Glibc, GCC 或 Binutils)需要升级到一个新的次版本,重新构建LFS是比较安全的。 尽管你可以按照依赖关系,只是重新构建一部分的软件包。但我们并不推荐这样做。例如,如果 glibc-2.2.x 需要 升 级到 glibc-2.3.x,重新构建是比较安全的。对于小版本的升级,简单的重新安装通常可以正常的工作,但是不能够保证。 例如,从 glibc-2.3.4 升级到 glibc-2.3.5 通常不会有问题。

  • 如果包含一个共享库的软件包升级,并且共享库的名字发生了变化。动态链接到这个库的所有的 包都需要重新编译链接到新的库(注意包的版本和库的名字没有关系)。例如,一个软件包 foo-1.2.3 安装了一个名为 libfoo.so.1 的共享库。你升级这个包到新版本 foo-1.2.4,这个新版本安装名为 libfoo.so.2 的共享库。这种情况下,所有链接到 libfoo.so.1 的包都需要重新编译链接到 libfoo.so.2。注意在依赖的软件包没有编译完之前,不要删除原来的库。

6.3.2. 包管理技术

下面是一些常用的包管理的技术。在决定安装包管理器之前,对多种包管理技术进行一下研究,找出某一种的缺点。

6.3.2.1. 全部记在心里!

是的,这是一种包管理的技术。一些人不需要包管理器,因为他们对包都非常熟悉,知道每一个包所安装的文件。 一些人也不需要包管理器,是因为当一个软件包改变时,他们重新构建整个系统。

6.3.2.2. 分别安装到不同目录

这是一种最简单的包管理方式,不需要安装额外的软件包来管理安装过程。每一个软件包安装到不同的目录下。 例如,包 foo-1.1 安装到 /usr/pkg/foo-1.1 ,创建一个从 /usr/pkg/foo 指向 /usr/pkg/foo-1.1 的符号链接。当安装一个新版本 foo-1.2 时,它会安装在 /usr/pkg/foo-1.2 ,前面的符号链接也指向新版本。

一些环境变量,像 PATHLD_LIBRARY_PATHMANPATHINFOPATH 和 CPPFLAGS 都需要增加 /usr/pkg/foo。当软件包数量大了之后,就难于管理了。

6.3.2.3. 符号连接风格的包管理

这是前面包管理技术的一个变种。每一个包也是按照类似于前面方法进行安装。但是不是创建符号链接, 而是每一个都被链接到 /usr 目录。这样就不需要添加环境变量了。尽 管有时在安装的时候符号链接自动创建,还是有很多的是采用这种方法的。一些比较流行的有: Stow,Epkg,Graft,和 Depot。

安装过程需要伪造,这样包就会认为自己被安装到了 /usr 目录,尽管实际上 它们安装到 /usr/pkg 目录下。以这种风格安装并不是很麻烦的事情。比如,你要 安装一个包 libfoo-1.1 。用下面的指令安装就不合适:

./configure --prefix=/usr/pkg/libfoo/1.1
make
make install

安装是没有问题,但是依赖的包不能够像你想像的那样链接到 libfoo。如果你编译一个链接到 libfoo 的包, 你就要注意,要链接到 /usr/pkg/libfoo/1.1/lib/libfoo.so.1 ,而不是 像你想像的那样链接到 /usr/lib/libfoo.so.1。正确的方法是使用 DESTDIR 来伪造包的安装。可以这样来使用这种方法:

./configure --prefix=/usr
make
make DESTDIR=/usr/pkg/libfoo/1.1 install

大多数的包都支持这种方法,但还是有一些不支持。对于这些不兼容的包,你可以手工安装,或许把一些有问题的包 安装到 /opt 可能更简单。

6.3.2.4. 基于时间戳

这种技术里,在安装包之前,会创建一个时间戳标记文件。安装之后,简单的使用的 find 命令的某些选项就能生成一个时间戳标记文件创建之后安装的文件的日志。install-log 就是利用这种技术写的包管理器。

尽管这种方法简单,但是它有两个缺点。如果在安装的过程中,安装的文件的时间戳不是当前的时间,这些文件将不会被包管理器记录。 另外,这种方案只能用在一次只有一个包安装时。如果有两个包在两个终端下同时安装,那么这时的日志是不可靠的。

6.3.2.5. 基于LD_PRELOAD

这种方法下,在安装之前会有一个库被提前加载。在安装的过程中,这个库就会跟踪正在安装的包,通过给自己附加上 各种可执行性的动作,像 cpinstallmv 。来跟踪那些修改文件系统系统调用。为了让这种方法正 常的工作,所有的可执行文件需要都是动态链接的且没有设置 suid 和 sgid 位。预先加载库可能会产生一些讨厌的 副作用。因此,建议做一些测试,来确保包管理器不会破坏任何东西,并且能够记录所有适当的文件。

6.3.2.6. 创建包的归档

在这种方案中,包被分别安装到不同的目录树下,就像符号连接风格的包管理描述的。安装之后, 系统就会使用安装的文件创建一个包的归档。这个档案可以在本机上安装包,甚至可以在其他机器上 安装包。

这种方法被大多数商业发行版的包管理器采用。例如,RPM(自然是Linux Standard Base Specification所必需),pkg-utils,Debian 的 apt 和 Gentoo 的 Portage 系统。 有一个描述在 LFS 系统中如何应用这样的包管理器的hint,参见 http://www.linuxfromscratch.org/hints/downloads/files/fakeroot.txt.

6.3.2.7. 基于用户的管理

这种方案是 LFS 特有的,是由 Matthias Benkmann 提出的,可以参考 Hints Project。在这种方案里,每一个包都是以不同的用户安装到标准的目录里。通过检验 user ID 可以很容易的标识一个软件包。这种方法的特点和缺点非常复杂,这里就不描述了。详细内容参见 http://www.linuxfromscratch.org/hints/downloads/files/more_control_and_pkg_man.txt

现在将要进入 chroot 环境开始编译安装最终的 LFS 系统了,注意:在这里我们只使用临时构建的工具。以 root 身份运行以下命令进入构建环境:

chroot "$LFS" /tools/bin/env -i \
    HOME=/root TERM="$TERM" PS1='\u:\w\$ ' \
    PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin \
    /tools/bin/bash --login +h

env 命令的参数 -i 的作用是清除所有 chroot 环境变量。后面是重新设定 HOME, TERM, PS1, PATH 等变量的值。TERM=$TERM 设定虚拟根环境中的 TERM 的值与 chroot 外面的一样。这个值是让像 vim 和 less 之类的程序可以正确操作。如果还需要重新设置其它的值,如 CFLAGS 或 CXXFLAGS ,这里是个不错的位置。

从这里开始,不再需要 LFS 环境变量了,因为所有的工作都被限制在 LFS 文件系统里面。这是由于已经告诉了 Bash shell $LFS 是现在的根目录(/)。

注意,这里 /tools/bin 位于 PATH 的最后面。也就是说当软件包的最终版本安装之后就不再使用临时工具了。为了使 shell 无法"记住"可执行二进制代码的位置,需要通过使用 +h 参数关闭 bash 的散列功能。

注意此时 bash 提示符会显示:I have no name! 这是正常的,因为 /etc/passwd 还没有创建。

现在我们在 LFS 分区中创建目录树结构,用下列命令能创建一个标准的目录树:

mkdir -pv /{bin,boot,etc/opt,home,lib,mnt,opt}
mkdir -pv /{media/{floppy,cdrom},sbin,srv,var}
install -dv -m 0750 /root
install -dv -m 1777 /tmp /var/tmp
mkdir -pv /usr/{,local/}{bin,include,lib,sbin,src}
mkdir -pv /usr/{,local/}share/{doc,info,locale,man}
mkdir -v  /usr/{,local/}share/{misc,terminfo,zoneinfo}
mkdir -pv /usr/{,local/}share/man/man{1..8}
for dir in /usr /usr/local; do
  ln -sv share/{man,doc,info} $dir
done
mkdir -v /var/{lock,log,mail,run,spool}
mkdir -pv /var/{opt,cache,lib/{misc,locate},local}

缺省的目录的权限模式为 755,但也并非所有的目录都如此。以上的命令有两处有所不一样:一个是 root 用户的目录,另外两个是临时文件目录。

第一个权限模式的不同之处是确保禁止任何人进入到 /root 目录中——同样的,这个模式也适用于让其它的普通用户可以工作在自己的目录中。第二个权限模式的不同之处是确保所有用户都可以写 /tmp 和 /var/tmp 目录,但不能从中删除其它用户的文件,这是由"sticky位",也就是"1777"中的"1"来设定的。

6.5.1. FHS 兼容性说明

我们的目录树是按照 FHS(Filesystem Hierarchy Standard) 标准(http://www.pathname.com/fhs/)。 除了上面创建的目录外,该标准还规定了必须有 /usr/local/games 和 /usr/share/games 两个目录,但是作为一个基本系统,我们并不需要这些。如果你要完全的遵守 FHS 标准的话,就自己建立这两个目录。至于 /usr/local/share 目录下的子目录,FHS 标准规定得并不严格,所以我们就创建了(在我们看来)需要的子目录。

现在我们在 LFS 分区中创建目录树结构,用下列命令能创建一个标准的目录树:

mkdir -pv /{bin,boot,etc/opt,home,lib,mnt,opt}
mkdir -pv /{media/{floppy,cdrom},sbin,srv,var}
install -dv -m 0750 /root
install -dv -m 1777 /tmp /var/tmp
mkdir -pv /usr/{,local/}{bin,include,lib,sbin,src}
mkdir -pv /usr/{,local/}share/{doc,info,locale,man}
mkdir -v  /usr/{,local/}share/{misc,terminfo,zoneinfo}
mkdir -pv /usr/{,local/}share/man/man{1..8}
for dir in /usr /usr/local; do
  ln -sv share/{man,doc,info} $dir
done
mkdir -v /var/{lock,log,mail,run,spool}
mkdir -pv /var/{opt,cache,lib/{misc,locate},local}

缺省的目录的权限模式为 755,但也并非所有的目录都如此。以上的命令有两处有所不一样:一个是 root 用户的目录,另外两个是临时文件目录。

第一个权限模式的不同之处是确保禁止任何人进入到 /root 目录中——同样的,这个模式也适用于让其它的普通用户可以工作在自己的目录中。第二个权限模式的不同之处是确保所有用户都可以写 /tmp 和 /var/tmp 目录,但不能从中删除其它用户的文件,这是由"sticky位",也就是"1777"中的"1"来设定的。

6.5.1. FHS 兼容性说明

我们的目录树是按照 FHS(Filesystem Hierarchy Standard) 标准(http://www.pathname.com/fhs/)。 除了上面创建的目录外,该标准还规定了必须有 /usr/local/games 和 /usr/share/games 两个目录,但是作为一个基本系统,我们并不需要这些。如果你要完全的遵守 FHS 标准的话,就自己建立这两个目录。至于 /usr/local/share 目录下的子目录,FHS 标准规定得并不严格,所以我们就创建了(在我们看来)需要的子目录。

一些程序使用固化的路径(hard-wired paths)指向一些目前还不存在的程序上。为了兼容这些程序,可以创建一些符号链接,然后在软件安装之后用实际文件进行替代。

ln -sv /tools/bin/{bash,cat,grep,pwd,stty} /bin
ln -sv /tools/bin/perl /usr/bin
ln -sv /tools/lib/libgcc_s.so{,.1} /usr/lib
ln -sv bash /bin/sh

一个常规的Linux系统在/etc/mtab中有一个已挂载文件系统的列表。 正常情况下,这个文件在我们挂载一个新的文件系统的时候会被创建。因为我们在chroot环境下不会再挂载任何文件系统 ,所以我们需要为那些用到/etc/mtab的程序创建一个空文件:

touch /etc/mtab

为了让 root 用户可以登录而且用户名"root"可以被识别,在这里需要创建相应的 /etc/passwd 和 /etc/group 文件。

使用下面的命令创建 /etc/passwd 文件:

cat > /etc/passwd << "EOF"
root:x:0:0:root:/root:/bin/bash
EOF

root 的真正密码将在后面设置("x"在这里只是一个占位符)。

下面的命令创建 /etc/group 文件:

cat > /etc/group << "EOF"
root:x:0:
bin:x:1:
sys:x:2:
kmem:x:3:
tty:x:4:
tape:x:5:
daemon:x:6:
floppy:x:7:
disk:x:8:
lp:x:9:
dialout:x:10:
audio:x:11:
video:x:12:
utmp:x:13:
usb:x:14:
cdrom:x:15:
EOF

这里创建的用户组并不是某个标准所要求的部分,只是因为在随后 Udev 配置将要用到而以。Linux 标准基础(LSB, Linux Standard Base, http://www.linuxbase.org) 只是推荐"root"组的 GID 为 0,另一个组"bin"的 GID 为 1 。其它所有的组名和 GID 均由系统管理员自由设定,因为比较好的软件包一般都不依赖于 GID ,而只是使用组名。

因为完整的 Glibc 在Chapter 5中已经安装,而且 /etc/passwd 和 /etc/group 文件也已创建,用户名和组名现在可以开始使用了。现在启动新的shell,驱除"I have no name!"提示符:

exec /tools/bin/bash --login +h

注意这里使用了 +h 参数。这是告诉 bash 不能使用其内部哈希表查找路径。如果没有使用这个参数,则 bash 将会记住已经执行的二进制代码的路径。为了让新编译安装的二进制代码可以马上投入使用,在这一章中,我们使用 +h 关闭了此功能。

程序 login, agetty, init (还有其它一些程序) 使用一些日志文件来记录信息,比如谁在什么时候登录了系统等等。然而如果这些日志文件不存在,这些程序则无法写入。下面初始化这些日志文件,并设置适当的权限:

touch /var/run/utmp /var/log/{btmp,lastlog,wtmp}
chgrp -v utmp /var/run/utmp /var/log/lastlog
chmod -v 664 /var/run/utmp /var/log/lastlog

/var/run/utmp 记录着现在登录的用户。/var/log/wtmp 记录所有的登录和退出。/var/log/lastlog 记录每个用户最后的登录信息。/var/log/btmp 记录错误的登录尝试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

q472599451

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值