存档

‘Linux/Uinx操作系统大全’ 分类的存档

LFS linux的安装过程

2016年5月22日 评论已被关闭

LFS linux的安装过程

http://blog.chinaunix.net/uid-20772927-id-579133.html

最近,比较有时间,学了lfs linux,感觉瞒不错,可以让你更清晰的了解linux的内部文件架构,值得,不过需要花费大量的时间去编译大量的工具。^_^
当做完之后,会有很大的成就感!!!也有一种失落感!!^_^
首先介绍一下lfs linux:
LFS linux全称为Linux From Scratch,重点是 Linux From Scratch 这个项目以及使用 LFS 系统带来的好处。用户可以控制系统的所有特征,包括目录布局、脚本设置和安全设置等等。最终的系统将从源代码直接编译生成,用户可以指定在哪里安装、为什么安装以及怎样安装每一个程序。可以完全按照自己的需求定制他们的 Linux 系统,而且使用户对他们的系统有更多的控制权。
安装过程:
这里先介绍以下两个LiveCD下的重要目录
/usr/share/LFS-BOOK-6.3-HTML目录存放的就是LFS手册了
/lfs-sources里面存放的就是建造LFS所需要的源码包,不需要到处下软件了。

磁盘分区:
输入命令:

代码:
cfdisk /dev/hda
将出现分区界面

这里可以按照你自己的需要的分区,这里我按照设置一个根分区和一个交换分区为例,交换分区占用512M,其余的全部分给根分区。
磁盘分区    作用
/dev/hda1    swap
/dev/hda2  作为目标系统根目录

保存退出后进行磁盘分区的格式化

代码:
mkswap /dev/hda1 mkfs.xfs /dev/hda2

相关知识点:
  磁盘格式化一定要在磁盘分区未进行加载前进行。
  mkswap是用于将磁盘分区格式化为交换分区的命令。
  这里我将/dev/hda2格式化了为Xfs格式,如果你喜欢其它格式的文件系统,你可以使用相应的命令来格式化。

如果你的内存不太大,想在编译期间就使用上交换分区的话,可使用下面的命令激活交换分区
swapon /dev/hda1
相关知识点:
swapon用于激活交换分区
swapoff用于将激活的交换分区停用
可以通过free命令来查看当前的内存使用情况

创建LFS的“创作基地”

代码:
export LFS=/mnt/lfs mkdir -pv $LFS

相关知识点:
  export LFS=/mnt/lfs这条命令的作用是为了后面引用“创作基地”的绝对路径方便而设置LFS这样的环境变量。

加载/dev/hda2到“创作基地”

代码:
mount /dev/hda2 $LFS

创建必要的目录并设置属性
创建源代码编译用目录

代码:
mkdir -v $LFS/sources chmod -v a+wt $LFS/sources

相关知识点:
chmod a+wt是将目录或文件的属性设置为1777,这样任何人都可以对其进行读写。

创建工具链目录

代码:
mkdir -v $LFS/tools ln -sv $LFS/tools /

注意:
  ln -sv $LFS/tools执行后应该会输出
    `/tools’ -> `/mnt/lfs/tools’
  表示正确。

相关知识点:
  上面这两句就建立了神奇的工具链目录(是工具链目录不是工具链),这样的创建方式是为了在创建工具链和使用工具链创建目标系统的时候对于工具链的位置都是/tools,这样可保证工具链的正常使用

创建lfs用户

代码:
groupadd lfs useradd -s /bin/bash -g lfs -m -k /dev/null lfs

设置lfs密码,设置为空就行了,也就是输入密码的时候直接回车就成。

代码:
passwd lfs

将tools和sources目录的用户改为lfs,以便后面使用lfs来操作这两个目录

代码:
chown -v lfs $LFS/tools chown -v lfs $LFS/sources

登陆到lfs用户

代码:
su – lfs

这时候你会发现命令行提示符已经由#改为了$
相关知识点:
其实如果不使用lfs用root也是能完成工具链的,不过需要对root的环境变量进行修改,还要防止因为输入错误而导致覆盖主系统下的文件,所以LFS手册中制作工具链部分就是为了解决这种意外的发生而用lfs用户来建立工具链

建立lfs用户的环境

代码:
cat > ~/.bash_profile << “EOF” exec env -i HOME=$HOME TERM=$TERM PS1=’\u:\w\$ ‘ /bin/bash EOF cat > ~/.bashrc << “EOF” set +h umask 022 LFS=/mnt/lfs LC_ALL=POSIX PATH=/tools/bin:/bin:/usr/bin export LFS LC_ALL PATH EOF source ~/.bash_profile

这里利用了bash的环境变量的设置文件将lfs的环境设置为符合编译工具链要求的最少的环境参数
这里面最重要的就是PATH这个参数,目的是为了能够利用工具链里面的工具制作工具链:首先查找/tools/bin下是否有需要的命令,如果没有再到/bin和/usr/bin下找,然后用/bin或/usr/bin下面的命令来帮助生成需要的命令并放在/tools/bin下,这样此消彼涨,最终可完成一个自给自足的工具链。
到此为止就可以开始工具链的制作了,不过制作LFS是一个漫长而浩大的工程,所以要一直开机直到完成有时候比较困难,特别是在机器速度比较慢的情况下,能够重新启动到最后工作的状态是很重要的。在不同的阶段重新启动并恢复状态的步骤不完全相同,所以本文会在不同的阶段讨论重新启动恢复到工作状态的方法和步骤。

从现在开始一直到第五章结束,也就是完成Stripping中间的步骤中如果重新启动的恢复步骤:
  1.重新启动计算机,并从LiveCD启动
相关知识点:在VMWare中因为磁盘已经有了信息了,所以会从磁盘启动,需要在启动虚拟机中的机器时按F2进入虚拟机的虚拟BIOS,然后在BOOT中设置第一启动为CD-ROM,保存退出即可。

2.LiveCD启动过程同第一次启动选择一样。
3.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/hda2 $LFS
4.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/hda1
5.建立工具链的链接
ln -sv $LFS/tools /
6.创建lfs用户
groupadd lfs
useradd -s /bin/bash -g lfs -m -k /dev/null lfs
passwd lfs
chown -v lfs $LFS/tools
chown -v lfs $LFS/sources
su – lfs
7.建立lfs用户的环境
cat > ~/.bash_profile << “EOF”
exec env -i HOME=$HOME TERM=$TERM PS1=’\u:\w\$ ‘ /bin/bash
EOF
cat > ~/.bashrc << “EOF”
set +h
umask 022
LFS=/mnt/lfs
LC_ALL=POSIX
PATH=/tools/bin:/bin:/usr/bin
export LFS LC_ALL PATH
EOF
source ~/.bash_profile
8.检查一下
export命令查看输出,应该是
declare -x HOME=”/home/lfs”
declare -x LC_ALL=”POSIX”
declare -x LFS=”/mnt/lfs”
declare -x OLDPWD
declare -x PATH=”/tools/bin:/bin:/usr/bin”
declare -x PS1=”\\u:\\w\\\$
declare -x PWD=”/home/lfs”
declare -x SHLVL=”1″
declare -x TERM=”linux”
9.进入编译目录
cd $LFS/sources
基本上就恢复工作状态了。

开始工具链的制作
进入LFS包编译目录

代码:
cd $LFS/sources

Binutils-2.17 – Pass 1

代码:
tar xvf /lfs-sources/binutils-2.17.tar.bz2 cd binutils-2.17

相关知识点:
大家可以注意到后面所有的解包命令均使用tar xvf来完成,而不管文件的压缩方式是bz2还是gz,这是因为较新的tar程序都具有自动识别后缀名并自动调用相应的解压缩工具的能力,所以可以不需要指定压缩方式,但对于早期的tar命令则可能不具备这个功能因此需要你根据包的压缩方式来指定,如bz2使用j,gz使用z,对应上面的binutils则是tar xvjf /lfs-sources/binutils-2.17.tar.bz2
因LFS的LiveCD中提供的tar版本比较新,后面制作的tar版本也比较新,因此支持自动识别的能力,同时为了使文章的解压命令看起来比较统一方便维护(同样对于想制作成脚本的朋友也会比较方便)因此后面统一使用tar xvf来解压。

接着我们需要建立一个目录,因为binutils建议使用一个空目录来编译,所以

代码:
mkdir -v ../binutils-build cd ../binutils-build CC=”gcc -B/usr/bin/” ../binutils-2.17/configure –prefix=/tools –disable-nls –disable-werror make make install make -C ld clean make -C ld LIB_PATH=/tools/lib cp -v ld/ld-new /tools/bin cd .. rm -rf binutils-build rm -rf binutils-2.17

GCC-4.1.2 – Pass 1

代码:
tar xvf /lfs-sources/gcc-4.1.2.tar.bz2 mkdir -v gcc-build cd gcc-build CC=”gcc -B/usr/bin/” ../gcc-4.1.2/configure –prefix=/tools \ –with-local-prefix=/tools –disable-nls \ –enable-shared –enable-languages=c make bootstrap make install ln -vs gcc /tools/bin/cc cd .. rm -rf gcc-build rm -rf gcc-4.1.2

注意:这里不要图省事而不删gcc-4.1.2,因为这样可能会给后面的编译产生一些意外的错误。

Linux-2.6.22.5 API Headers

代码:
tar xvf /lfs-sources/linux-2.6.22.5.tar.bz2 cd linux-2.6.22.5 make mrproper make headers_check make INSTALL_HDR_PATH=dest headers_install cp -rv dest/include/* /tools/include cd .. rm -rf linux-2.6.22.5

Glibc-2.5.1

代码:
tar xvf /lfs-sources/glibc-2.5.1.tar.bz2 cd glibc-2.5.1 mkdir -v ../glibc-build cd ../glibc-build ../glibc-2.5.1/configure –prefix=/tools \ –disable-profile –enable-add-ons \ –enable-kernel=2.6.0 –with-binutils=/tools/bin \ –without-gd –with-headers=/tools/include \ –without-selinux make mkdir -v /tools/etc touch /tools/etc/ld.so.conf make install cd .. rm -rf glibc-build rm -rf glibc-2.5.1

相关知识点:
  这里的参数–enable-kernel=2.6.0,只是为了说明kernel的大版本,所以不需要根据实际的kernel版本来改,即使是用linux-2.6.15也一样只写2.6.0就可以了。

调整工具链

代码:
mv -v /tools/bin/{ld,ld-old} mv -v /tools/$(gcc -dumpmachine)/bin/{ld,ld-old} mv -v /tools/bin/{ld-new,ld} ln -sv /tools/bin/ld /tools/$(gcc -dumpmachine)/bin/ld gcc -dumpspecs | sed ‘s@^/lib/ld-linux.so.2@/tools&@g’ > `dirname $(gcc -print-libgcc-file-name)`/specs GCC_INCLUDEDIR=`dirname $(gcc -print-libgcc-file-name)`/include && find ${GCC_INCLUDEDIR}/* -maxdepth 0 -xtype d -exec rm -rvf ‘{}’ \; && rm -vf `grep -l “DO NOT EDIT THIS FILE” ${GCC_INCLUDEDIR}/*` && unset GCC_INCLUDEDIR

相关知识点:
  工具链的调整方法有好几种,而且不同版本GCC的specs可能会有不同,但实际上都是把specs文件中的/lib/ld-linux.so.2替换成了/tools/lib/ld-linux.so.2,所以即使有些文章在调整工具链上的命令和LFS手册上的不一样也不用太奇怪,当然也可以直接用gcc -dumpspecs导出后手工直接编辑specs文件。

测试工具链的调整
echo ‘main(){}’ > dummy.c
cc dummy.c
readelf -l a.out | grep ‘tools’
如果输出大致如下
[Requesting program interpreter: /tools/lib/ld-linux.so.2]
则表示调整成功,因为所有的库已经连接到了/tools/lib下。
rm -rf a.out dummy.c

测试工具安装
说明:这部分将安装3个用于第六章各种源码包编译后的测试的工具,所以如果你不打算做make check之类的事情,那么这3个包可以不装。
Tcl-8.4.15 Expect-5.43.0 DejaGNU-1.4.4

代码:
tar xvf /lfs-sources/tcl8.4.15-src.tar.gz cd tcl8.4.15/unix ./configure –prefix=/tools make make install make install-private-headers ln -sv tclsh8.4 /tools/bin/tclsh cd $LFS/sources tar xvf /lfs-sources/expect-5.43.0.tar.gz cd expect-5.43 patch -Np1 -i /lfs-sources/expect-5.43.0-spawn-1.patch cp configure{,.bak} sed ‘s:/usr/local/bin:/bin:’ configure.bak > configure ./configure –prefix=/tools –with-tcl=/tools/lib –with-tclinclude=/tools/include –with-x=no make make SCRIPTS=”” install cd $LFS/sources tar xvf /lfs-sources/dejagnu-1.4.4.tar.gz cd dejagnu-1.4.4 ./configure –prefix=/tools make install cd .. rm -rf tcl8.4.15 rm -rf expect-5.43 rm -rf dejagnu-1.4.4

GCC-4.1.2 – Pass 2

代码:
tar xvf /lfs-sources/gcc-4.1.2.tar.bz2 cd gcc-4.1.2 cp -v gcc/Makefile.in{,.orig} sed ‘s@\./fixinc\.sh@-c true@’ gcc/Makefile.in.orig > gcc/Makefile.in cp -v gcc/Makefile.in{,.tmp} sed ‘s/^XCFLAGS =$/& -fomit-frame-pointer/’ gcc/Makefile.in.tmp \ > gcc/Makefile.in patch -Np1 -i /lfs-sources/gcc-4.1.2-specs-1.patch mkdir -v ../gcc-build cd ../gcc-build ../gcc-4.1.2/configure –prefix=/tools \ –with-local-prefix=/tools \ –enable-clocale=gnu –enable-shared \ –enable-threads=posix –enable-__cxa_atexit \ –enable-languages=c,c++ –disable-libstdcxx-pch make make install cd .. rm -rf gcc-build rm -rf gcc-4.1.2

再次测试工具链的调整,以确保刚刚编译的gcc正确工作
echo ‘main(){}’ > dummy.c
cc dummy.c
readelf -l a.out | grep ‘tools’
如果输出大致如下
[Requesting program interpreter: /tools/lib/ld-linux.so.2]
则表示调整成功,因为所有的库已经连接到了/tools/lib下。
rm -rf a.out dummy.c

Binutils-2.17 – Pass 2

代码:
tar xvf /lfs-sources/binutils-2.17.tar.bz2 mkdir -v binutils-build cd binutils-build ../binutils-2.17/configure –prefix=/tools –disable-nls \ –with-lib-path=/tools/lib make make install make -C ld clean make -C ld LIB_PATH=/usr/lib:/lib cp -v ld/ld-new /tools/bin cd .. rm -rf binutils-build rm -rf binutils-2.17

Ncurses-5.6

代码:
tar xvf /lfs-sources/ncurses-5.6.tar.gz cd ncurses-5.6 ./configure –prefix=/tools –with-shared –without-debug –without-ada –enable-overwrite make make install cd .. rm -rf ncurses-5.6

Bash-3.2

代码:
tar xvf /lfs-sources/bash-3.2.tar.gz cd bash-3.2 patch -Np1 -i /lfs-sources/bash-3.2-fixes-5.patch ./configure –prefix=/tools –without-bash-malloc make make install ln -vs bash /tools/bin/sh cd .. rm -rf bash-3.2

Bzip2-1.0.4

代码:
tar xvf /lfs-sources/bzip2-1.0.4.tar.gz cd bzip2-1.0.4 make make PREFIX=/tools install cd .. rm -rf bzip2-1.0.4

Coreutils-6.9

代码:
tar xvf /lfs-sources/coreutils-6.9.tar.bz2 cd coreutils-6.9 ./configure –prefix=/tools make make install cp -v src/su /tools/bin/su-tools cd .. rm -rf coreutils-6.9

Diffutils-2.8.1

代码:
tar xvf /lfs-sources/diffutils-2.8.1.tar.gz cd diffutils-2.8.1 ./configure –prefix=/tools make make install cd .. rm -rf diffutils-2.8.1

Findutils-4.2.31

代码:
tar xvf /lfs-sources/findutils-4.2.31.tar.gz cd findutils-4.2.31 ./configure –prefix=/tools make make install cd .. rm -rf findutils-4.2.31

Gawk-3.1.5

代码:
tar xvf /lfs-sources/gawk-3.1.5.tar.bz2 cd gawk-3.1.5 ./configure –prefix=/tools cat >> config.h << “EOF” #define HAVE_LANGINFO_CODESET 1 #define HAVE_LC_MESSAGES 1 EOF make make install cd .. rm -rf gawk-3.1.5

Gettext-0.16.1

代码:
tar xvf /lfs-sources/gettext-0.16.1.tar.gz cd gettext-0.16.1 cd gettext-tools ./configure –prefix=/tools –disable-shared make -C gnulib-lib make -C src msgfmt cp -v src/msgfmt /tools/bin cd $LFS/sources rm -rf gettext-0.16.1

Grep-2.5.1a

代码:
tar xvf /lfs-sources/grep-2.5.1a.tar.bz2 cd grep-2.5.1a ./configure –prefix=/tools –disable-perl-regexp make make install cd .. rm -rf grep-2.5.1a

Gzip-1.3.12

代码:
tar xvf /lfs-sources/gzip-1.3.12.tar.gz cd gzip-1.3.12 ./configure –prefix=/tools make make install cd .. rm -rf gzip-1.3.12

Make-3.81

代码:
tar xvf /lfs-sources/make-3.81.tar.bz2 cd make-3.81 ./configure –prefix=/tools make make install cd .. rm -rf make-3.81

Patch-2.5.4

代码:
tar xvf /lfs-sources/patch-2.5.4.tar.gz cd patch-2.5.4 ./configure –prefix=/tools make make install cd .. rm -rf patch-2.5.4

Perl-5.8.8

代码:
tar xvf /lfs-sources/perl-5.8.8.tar.bz2 cd perl-5.8.8 patch -Np1 -i /lfs-sources/perl-5.8.8-libc-2.patch ./configure.gnu –prefix=/tools -Dstatic_ext=’Data/Dumper Fcntl IO POSIX’ make perl utilities cp -v perl pod/pod2man /tools/bin mkdir -pv /tools/lib/perl5/5.8.8 cp -Rv lib/* /tools/lib/perl5/5.8.8 cd .. rm -rf perl-5.8.8

Sed-4.1.5

代码:
tar xvf /lfs-sources/sed-4.1.5.tar.gz cd sed-4.1.5 ./configure –prefix=/tools make make install cd .. rm -rf sed-4.1.5

Tar-1.18

代码:
tar xvf /lfs-sources/tar-1.18.tar.bz2 cd tar-1.18 ./configure –prefix=/tools make make install cd .. rm -rf tar-1.18

Texinfo-4.9

代码:
tar xvf /lfs-sources/texinfo-4.9.tar.bz2 cd texinfo-4.9 ./configure –prefix=/tools make make install cd .. rm -rf texinfo-4.9

Util-linux-2.12r

代码:
tar xvf /lfs-sources/util-linux-2.12r.tar.bz2 cd util-linux-2.12r sed -i ‘s@/usr/include@/tools/include@g’ configure ./configure make -C lib make -C mount mount umount make -C text-utils more cp -v mount/{,u}mount text-utils/more /tools/bin cd .. rm -rf util-linux-2.12r

Stripping
这步是可有可无的,如果你打算今后还要用/tools里面的东西,那么可以strip一下来减少占用的磁盘空间,但如果做完目标系统后就删除了,不Strip也可以,反正最后也是要删掉的。

代码:
strip –strip-debug /tools/lib/* strip –strip-unneeded /tools/{,s}bin/*

info和man里面的内容在制作过程中没什么用处,所以删掉也没啥关系。

代码:
rm -rf /tools/{info,man}

退出lfs用户(这步不要少了)

代码:
exit

到目前为止,工具链已经制作完成了,接着就要开始制作真正的目标系统了,如果你到目前为止没出什么问题,那么恭喜你成功的通过了一关,不过接着还有相当长的路。

现在你应该是处于root用户状态的,看看你的命令行提示符是不是回到了#。

从现在开始不在需要lfs用户来制作系统了,因此我们用

代码:
chown -R root:root $LFS/tools

重新设置目录权限,便于后面的工作。

创建三个重要目录

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

创建两个目标系统所必须的设备文件

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

这个时候也许你想睡觉关机了,那么重新开机后回到工作状态的步骤是:
  1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/hda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/hda1
相关知识点:
这时候已经制作好了工具链,因此可以不需要建立根目录下的tools链接了。

利用主系统加载几个重要的文件系统,请注意这个步骤对于后面的工作极其重要。

代码:
mount -v –bind /dev $LFS/dev 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

相关知识点:
mount命令加载的分区在重新启动后就失效了,所以在这其中重新启动则需要重新加载。

这里为了方便使用源码包,我将光盘加载到目标系统里
mkdir $LFS/cdrom
mount /dev/cdrom $LFS/cdrom
这个步骤不是必须的,如果你想使用,那么在重新启动后进入工作状态的步骤中在相应的位置上加入。
这里有一个更简单的办法,将lfs-sources里面所有源码包复制到$LFS/sources目录中,这步对于后面在第六章使用源代码将非常方便。

代码:
cp -a /lfs-sources/* $LFS/sources/

关于增加中文显示功能:
为了方便在制作完后的系统能够直接显示中文,这里可以从网络上下载本人写的一个显示UTF-8编码文字的内核补丁。
使用下面的命令来下载:
cd $LFS/sources/
wget http://zdbr.net.cn/download/utf8-kernel-2.6.22.5-core-1.patch.bz2
wget http://zdbr.net.cn/download/utf8-kernel-2.6.22.5-fonts-1.patch.bz2
解压缩这两个补丁
bunzip2 utf8-kernel-2.6.22.5-core-1.patch.bz2
bunzip2 utf8-kernel-2.6.22.5-fonts-1.patch.bz2

Chroot到目标系统的目录下,以便不受主系统的影响来制作目标系统

代码:
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

注意:这个时候你的提示符会是“I have no name!”,没有关系继续我们的工作很快就可以正常了。

这个时候如果你关机或重新启动,那么重新开机后回到工作状态的步骤是:
  1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/hda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/hda1
4.加载必要的文件系统
mount -v –bind /dev $LFS/dev
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
5.Chroot到目标系统下
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

建立目标系统的目录结构

代码:
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 -pv /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 -pv /var/{lock,log,mail,run,spool} mkdir -pv /var/{opt,cache,lib/{misc,locate},local}

创建几个必要的链接,因为在目标系统的编译过程中,部分编译程序会用绝对路径来寻找命令或文件。

代码:
ln -sv /tools/bin/{bash,cat,echo,grep,pwd,stty} /bin ln -sv /tools/bin/perl /usr/bin ln -sv /tools/lib/libgcc_s.so{,.1} /usr/lib ln -sv /tools/lib/libstdc++.so{,.6} /usr/lib ln -sv bash /bin/sh touch /etc/mtab

创建root及nobody用户和必要的组

代码:
cat > /etc/passwd << “EOF” root:x:0:0:root:/root:/bin/bash nobody:x:99:99:Unprivileged User:/dev/null:/bin/false EOF 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: mail:x:34: nogroup:x:99: EOF

重新加载bash,以使root用户起效,这样前面的提示符就不会是“I have no name!”

代码:
exec /tools/bin/bash –login +h

创建和设置几个临时文件和日志文件。

代码:
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

到目前为止,创建目标系统的准备工作以基本完成,下面就要开始目标系统的软件包安装了。

首先进入到源码目录下。

代码:
cd /sources

(此前已经将LFS需要的源码包加载到了/cdrom下,因此后面的命令将从/cdrom/lfs-sources目录下解出,如果你将源码包直接复制到了sources目录下或别的什么目录下,则要相应的修改下面的命令)
export LFS=/cdrom/lfs-sources
如果之前是将所有源码包复制到sources下的,则执行

代码:
export LFS=/sources

从现在开始一直到第六章的Stripping Again之前,这个阶段如果你关机或重新启动,那么重新开机后回到工作状态的步骤是:
  1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/hda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/hda1
4.加载必要的文件系统
mount -v –bind /dev $LFS/dev
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
5.Chroot到目标系统下
chroot “$LFS” /tools/bin/env -i \
HOME=/root TERM=”$TERM” PS1=’\u:\w\$ ‘ \
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin \
/bin/bash –login +h
6.进入编译目录
cd /sources
export LFS=/sources

Linux-2.6.22.5

代码:
tar xvf $LFS/linux-2.6.22.5.tar.bz2 cd linux-2.6.22.5 sed -i ‘/scsi/d’ include/Kbuild make mrproper make headers_check make INSTALL_HDR_PATH=dest headers_install cp -rv dest/include/* /usr/include cd .. rm -rf linux-2.6.22.5

Man-pages-2.63

代码:
tar xvf $LFS/man-pages-2.63.tar.bz2 cd man-pages-2.63 make install cd .. rm -rf man-pages-2.63

man-pages的版本可以使用更新的版本。

Glibc-2.5.1
在进行之前请检查一下是否glibc-2.5.1和glibc-build这两个目录已经被删除,如果没有删除请删除后在继续。

代码:
tar xvf $LFS/glibc-2.5.1.tar.bz2 cd glibc-2.5.1 tar -xvf $LFS/glibc-libidn-2.5.1.tar.gz mv glibc-libidn-2.5.1 libidn sed -i ‘/vi_VN.TCVN/d’ localedata/SUPPORTED sed -i \ ‘s|libs -o|libs -L/usr/lib -Wl,-dynamic-linker=/lib/ld-linux.so.2 -o|’ \ scripts/test-installation.pl sed -i ‘s|@BASH@|/bin/bash|’ elf/ldd.bash.in mkdir -v ../glibc-build cd ../glibc-build ../glibc-2.5.1/configure –prefix=/usr \ –disable-profile –enable-add-ons \ –enable-kernel=2.6.0 –libexecdir=/usr/lib/glibc make make -k check 2>&1 | tee glibc-check-log grep Error glibc-check-log touch /etc/ld.so.conf make install make localedata/install-locales

make localedata/install-locales将安装全部的locale,如果你不想装这么多locale的话就用localedef命令来安装,LFS手册上有例子,如果仅想加入中文的locale,就用
mkdir -pv /usr/lib/locale
localedef -i zh_CN -f GB18030 zh_CN
localedef -i zh_CN -f GBK zh_CN
localedef -i zh_CN -f UTF-8 zh_CN
localedef -i zh_CN -f GB2312 zh_CN
localedef -i zh_HK -f UTF-8 zh_CN
localedef -i zh_HK -f BIG5-HKSCS zh_CN
localedef -i zh_TW -f EUC-TW zh_CN
localedef -i zh_TW -f UTF-8 zh_CN
localedef -i zh_TW -f BIG5 zh_CN
建立几个重要文件:

代码:
cat > /etc/nsswitch.conf << “EOF” # Begin /etc/nsswitch.conf passwd: files group: files shadow: files hosts: files dns networks: files protocols: files services: files ethers: files rpc: files # End /etc/nsswitch.conf EOF cp -v –remove-destination /usr/share/zoneinfo/Asia/Shanghai /etc/localtime cat > /etc/ld.so.conf << “EOF” /usr/local/lib /opt/lib EOF

删除编译目录

代码:
cd .. rm -rf glibc-build rm -rf glibc-2.5.1

相关知识:
  glibc的测试比较容易出现错误,比如机器慢就有可能出现超时的错误,还有一些能引起错误的LFS手册上有所提及,像超时这种错误有时候很难避免,就跳过去吧。

调整工具链

代码:
mv -v /tools/bin/{ld,ld-old} mv -v /tools/$(gcc -dumpmachine)/bin/{ld,ld-old} mv -v /tools/bin/{ld-new,ld} ln -sv /tools/bin/ld /tools/$(gcc -dumpmachine)/bin/ld

调整specs文件:

代码:
gcc -dumpspecs | sed \ -e ‘s@/tools/lib/ld-linux.so.2@/lib/ld-linux.so.2@g’ \ -e ‘/\*startfile_prefix_spec:/{n;s@.*@/usr/lib/ @}’ \ -e ‘/\*cpp:/{n;s@$@ -isystem /usr/include@}’ > \ `dirname $(gcc –print-libgcc-file-name)`/specs

测试工具链是否被调整成功
echo ‘main(){}’ > dummy.c
cc dummy.c -v -Wl,–verbose &> dummy.log
readelf -l a.out | grep ‘/lib’
如果显示[Requesting program interpreter: /lib/ld-linux.so.2]表示调整成功,动态库已经连接到了目标系统的/lib下。
grep -o ‘/usr/lib.*/crt[1in].*succeeded’ dummy.log
应该显示
/usr/lib/crt1.o succeeded
/usr/lib/crti.o succeeded
/usr/lib/crtn.o succeeded
grep -B1 ‘^ /usr/include’ dummy.log
应该显示
#include <…> search starts here:
/usr/include
grep ‘SEARCH.*/usr/lib’ dummy.log |sed ‘s|; |\n|g’
应该显示
SEARCH_DIR(“/tools/i686-pc-linux-gnu/lib”)
SEARCH_DIR(“/usr/lib”)
SEARCH_DIR(“/lib”);
grep “/lib/libc.so.6 ” dummy.log
应该显示
attempt to open /lib/libc.so.6 succeeded
grep found dummy.log
应该显示
found ld-linux.so.2 at /lib/ld-linux.so.2
如果上面均显示正常,那么表明工具链调整成功,可以删除测试文件了
rm -v dummy.c a.out dummy.log

Binutils-2.17

代码:
tar xvf $LFS/binutils-2.17.tar.bz2 mkdir binutils-build cd binutils-build ../binutils-2.17/configure –prefix=/usr –enable-shared make tooldir=/usr

测试:

代码:
make check

这里测试统计可能会出现个别失败。

代码:
make tooldir=/usr install cp -v ../binutils-2.17/include/libiberty.h /usr/include cd .. rm -rf binutils-build rm -rf binutils-2.17

GCC-4.1.2

代码:
tar xvf $LFS/gcc-4.1.2.tar.bz2 cd gcc-4.1.2 sed -i ‘s/install_to_$(INSTALL_DEST) //’ libiberty/Makefile.in sed -i ‘s/^XCFLAGS =$/& -fomit-frame-pointer/’ gcc/Makefile.in sed -i ‘s@\./fixinc\.sh@-c true@’ gcc/Makefile.in sed -i ‘s/@have_mktemp_command@/yes/’ gcc/gccbug.in mkdir -v ../gcc-build cd ../gcc-build ../gcc-4.1.2/configure –prefix=/usr \ –libexecdir=/usr/lib –enable-shared \ –enable-threads=posix –enable-__cxa_atexit \ –enable-clocale=gnu –enable-languages=c,c++ make

测试:

代码:
make -k check

这里check时间比较长,可能会有一些错误发生

代码:
make install ln -sv ../usr/bin/cpp /lib ln -sv gcc /usr/bin/cc cd .. rm -rf gcc-build rm -rf gcc-4.1.2

重新测试工具链是否正确,确定GCC是否安装正确
echo ‘main(){}’ > dummy.c
cc dummy.c -v -Wl,–verbose &> dummy.log
readelf -l a.out | grep ‘lib’
如果显示[Requesting program interpreter: /lib/ld-linux.so.2]表示链接位置正确,动态库已经连接到了目标系统的/lib下。
grep -o ‘/usr/lib.*/crt[1in].*succeeded’ dummy.log
应该显示
/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../crt1.o succeeded
/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../crti.o succeeded
/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/../../../crtn.o succeeded
grep -B3 ‘^ /usr/include’ dummy.log
应该显示
#include <…> search starts here:
/usr/local/include
/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include
/usr/include
grep ‘SEARCH.*/usr/lib’ dummy.log |sed ‘s|; |\n|g’
应该显示
SEARCH_DIR(“/usr/i686-pc-linux-gnu/lib”)
SEARCH_DIR(“/usr/local/lib”)
SEARCH_DIR(“/lib”)
SEARCH_DIR(“/usr/lib”);
grep “/lib/libc.so.6 ” dummy.log
应该显示
attempt to open /lib/libc.so.6 succeeded
grep found dummy.log
应该显示
found ld-linux.so.2 at /lib/ld-linux.so.2
如果上面均显示正常,那么表明工具链正常,可以删除测试文件了
rm -v dummy.c a.out dummy.log

Berkeley DB-4.5.20

代码:
tar xvf $LFS/db-4.5.20.tar.gz cd db-4.5.20 patch -Np1 -i $LFS/db-4.5.20-fixes-1.patch cd build_unix ../dist/configure –prefix=/usr –enable-compat185 –enable-cxx make make docdir=/usr/share/doc/db-4.5.20 install chown -Rv root:root /usr/share/doc/db-4.5.20 cd /sources rm -rf db-4.5.20

Sed-4.1.5

代码:
tar xvf $LFS/sed-4.1.5.tar.gz cd sed-4.1.5 ./configure –prefix=/usr –bindir=/bin –enable-html make

测试:

代码:
make check

这里check不会有错

代码:
make install cd .. rm -rf sed-4.1.5

E2fsprogs-1.40.2

代码:
tar xvf $LFS/e2fsprogs-1.40.2.tar.gz cd e2fsprogs-1.40.2 sed -i -e ‘s@/bin/rm@/tools&@’ lib/blkid/test_probe.in mkdir -v build cd build ../configure –prefix=/usr –with-root-prefix=”” \ –enable-elf-shlibs make

测试:

代码:
make check

这里check不会有错

代码:
make install make install-libs cd ../.. rm -rf e2fsprogs-1.40.2

Coreutils-6.9

代码:
tar xvf $LFS/coreutils-6.9.tar.bz2 cd coreutils-6.9 patch -Np1 -i $LFS/coreutils-6.9-uname-1.patch patch -Np1 -i $LFS/coreutils-6.9-suppress_uptime_kill_su-1.patch patch -Np1 -i $LFS/coreutils-6.9-i18n-1.patch chmod +x tests/sort/sort-mb-tests ./configure –prefix=/usr make

测试:

代码:
make NON_ROOT_USERNAME=nobody check-root echo “dummy:x:1000:nobody” >> /etc/group su-tools nobody -s /bin/bash -c “make RUN_EXPENSIVE_TESTS=yes check”

这个测试应该能正常结束。
删除测试用数据:

代码:
sed -i ‘/dummy/d’ /etc/group
代码:
make install mv -v /usr/bin/{cat,chgrp,chmod,chown,cp,date,dd,df,echo} /bin mv -v /usr/bin/{false,hostname,ln,ls,mkdir,mknod,mv,pwd,readlink,rm} /bin mv -v /usr/bin/{rmdir,stty,sync,true,uname} /bin mv -v /usr/bin/chroot /usr/sbin mv -v /usr/bin/{head,sleep,nice} /bin cd .. rm -rf coreutils-6.9

Iana-Etc-2.20

代码:
tar xvf $LFS/iana-etc-2.20.tar.bz2 cd iana-etc-2.20 make make install cd .. rm -rf iana-etc-2.20

M4-1.4.10

代码:
tar xvf $LFS/m4-1.4.10.tar.bz2 cd m4-1.4.10 ./configure –prefix=/usr make

测试:

代码:
make check

这里check不会有错

代码:
make install cd .. rm -rf m4-1.4.10

Bison-2.3

代码:
tar xvf $LFS/bison-2.3.tar.bz2 cd bison-2.3 ./configure –prefix=/usr echo ‘#define YYENABLE_NLS 1’ >> config.h make

测试:

代码:
make check

这里check不会有错

代码:
make install cd .. rm -rf bison-2.3

Ncurses-5.6

代码:
tar xvf $LFS/ncurses-5.6.tar.gz cd ncurses-5.6 patch -Np1 -i $LFS/ncurses-5.6-coverity_fixes-1.patch ./configure –prefix=/usr –with-shared –without-debug –enable-widec make make install chmod -v 644 /usr/lib/libncurses++w.a mv -v /usr/lib/libncursesw.so.5* /lib ln -sfv ../../lib/libncursesw.so.5 /usr/lib/libncursesw.so for lib in curses ncurses form panel menu ; do \ rm -vf /usr/lib/lib${lib}.so ; \ echo “INPUT(-l${lib}w)” >/usr/lib/lib${lib}.so ; \ ln -sfv lib${lib}w.a /usr/lib/lib${lib}.a ; \ done ln -sfv libncurses++w.a /usr/lib/libncurses++.a rm -vf /usr/lib/libcursesw.so echo “INPUT(-lncursesw)” >/usr/lib/libcursesw.so ln -sfv libncurses.so /usr/lib/libcurses.so ln -sfv libncursesw.a /usr/lib/libcursesw.a ln -sfv libncurses.a /usr/lib/libcurses.a cd .. rm -rf ncurses-5.6

Procps-3.2.7

代码:
tar xvf $LFS/procps-3.2.7.tar.gz cd procps-3.2.7 make make install cd .. rm -rf procps-3.2.7

Libtool-1.5.24

代码:
tar xvf $LFS/libtool-1.5.24.tar.gz cd libtool-1.5.24 ./configure –prefix=/usr make

测试:

代码:
make check

这里check不会有错

代码:
make install cd .. rm -rf libtool-1.5.24

Perl-5.8.8

代码:
tar xvf $LFS/perl-5.8.8.tar.bz2 cd perl-5.8.8 echo “127.0.0.1 localhost $(hostname)” > /etc/hosts ./configure.gnu –prefix=/usr \ -Dman1dir=/usr/share/man/man1 \ -Dman3dir=/usr/share/man/man3 \ -Dpager=”/usr/bin/less -isR” make

测试:

代码:
make test

这里test不会有错

代码:
make install cd .. rm -rf perl-5.8.8

Readline-5.2

代码:
tar xvf $LFS/readline-5.2.tar.gz cd readline-5.2 sed -i ‘/MV.*old/d’ Makefile.in sed -i ‘/{OLDSUFF}/c:’ support/shlib-install patch -Np1 -i $LFS/readline-5.2-fixes-3.patch ./configure –prefix=/usr –libdir=/lib make SHLIB_XLDFLAGS=-lncurses make install mv -v /lib/lib{readline,history}.a /usr/lib rm -v /lib/lib{readline,history}.so ln -sfv ../../lib/libreadline.so.5 /usr/lib/libreadline.so ln -sfv ../../lib/libhistory.so.5 /usr/lib/libhistory.so cd .. rm -rf readline-5.2

Zlib-1.2.3

代码:
tar xvf $LFS/zlib-1.2.3.tar.gz cd zlib-1.2.3 ./configure –prefix=/usr –shared –libdir=/lib make

测试动态链接库:

代码:
make check

这里check不会有错

代码:
make install rm -v /lib/libz.so ln -sfv ../../lib/libz.so.1.2.3 /usr/lib/libz.so make clean ./configure –prefix=/usr make

测试静态库

代码:
make check

这里check不会有错

代码:
make install chmod -v 644 /usr/lib/libz.a cd .. rm -rf zlib-1.2.3

Autoconf-2.61

代码:
tar xvf $LFS/autoconf-2.61.tar.bz2 cd autoconf-2.61 ./configure –prefix=/usr make

测试:

代码:
make check

这里测试时间比较长,但不会有错

代码:
make install cd .. rm -rf autoconf-2.61

Automake-1.10

代码:
tar xvf $LFS/automake-1.10.tar.bz2 cd automake-1.10 ./configure –prefix=/usr make

测试:

代码:
make check

这里测试时间比较长,可能会有3个测试失败,但能顺利结束。

代码:
make install cd .. rm -rf automake-1.10

Bash-3.2

代码:
tar xvf $LFS/bash-3.2.tar.gz cd bash-3.2 tar -xvf $LFS/bash-doc-3.2.tar.gz && sed -i “s|htmldir = @htmldir@|htmldir = /usr/share/doc/bash-3.2|” Makefile.in patch -Np1 -i $LFS/bash-3.2-fixes-5.patch ./configure –prefix=/usr –bindir=/bin –without-bash-malloc –with-installed-readline make

测试:

代码:
sed -i ‘s/LANG/LC_ALL/’ tests/intl.tests sed -i ‘s@tests@& chown -Rv nobody ./ su-tools nobody -s /bin/bash -c “make tests”

这里check不会有错,可能会有不少警告。

代码:
make install cd .. rm -rf bash-3.2

应用刚编译好的/bin/bash:

代码:
exec /bin/bash –login +h


Bzip2-1.0.4

代码:
tar xvf $LFS/bzip2-1.0.4.tar.gz cd bzip2-1.0.4 patch -Np1 -i $LFS/bzip2-1.0.4-install_docs-1.patch make -f Makefile-libbz2_so make clean make make PREFIX=/usr install cp -v bzip2-shared /bin/bzip2 cp -av libbz2.so* /lib ln -sv ../../lib/libbz2.so.1.0 /usr/lib/libbz2.so rm -v /usr/bin/{bunzip2,bzcat,bzip2} ln -sv bzip2 /bin/bunzip2 ln -sv bzip2 /bin/bzcat cd .. rm -rf bzip2-1.0.4


Diffutils-2.8.1

代码:
tar xvf $LFS/diffutils-2.8.1.tar.gz cd diffutils-2.8.1 patch -Np1 -i $LFS/diffutils-2.8.1-i18n-1.patch touch man/diff.1 ./configure –prefix=/usr make make install cd .. rm -rf diffutils-2.8.1


File-4.21

代码:
tar xvf $LFS/file-4.21.tar.gz cd file-4.21 ./configure –prefix=/usr make make install cd .. rm -rf file-4.21


Findutils-4.2.31

代码:
tar xvf $LFS/findutils-4.2.31.tar.gz cd findutils-4.2.31 ./configure –prefix=/usr –libexecdir=/usr/lib/findutils \ –localstatedir=/var/lib/locate make

测试:

代码:
make check

这里check不会有错

代码:
make install mv -v /usr/bin/find /bin sed -i -e ‘s/find:=${BINDIR}/find:=\/bin/’ /usr/bin/updatedb cd .. rm -rf findutils-4.2.31


Flex-2.5.33

代码:
tar xvf $LFS/flex-2.5.33.tar.bz2 cd flex-2.5.33 ./configure –prefix=/usr make

测试:

代码:
make check

这里check不会有错

代码:
make install ln -sv libfl.a /usr/lib/libl.a

创建一个lex的命令。

代码:
cat > /usr/bin/lex << “EOF” #!/bin/sh # Begin /usr/bin/lex exec /usr/bin/flex -l “$@” # End /usr/bin/lex EOF chmod -v 755 /usr/bin/lex
代码:
cd .. rm -rf flex-2.5.33


GRUB-0.97

代码:
tar xvf $LFS/grub-0.97.tar.gz cd grub-0.97 patch -Np1 -i $LFS/grub-0.97-disk_geometry-1.patch ./configure –prefix=/usr make

测试:

代码:
make check

这里check不会有错

代码:
make install mkdir -v /boot/grub cp -v /usr/lib/grub/i386-pc/stage{1,2} /boot/grub cd .. rm -rf grub-0.97


Gawk-3.1.5

代码:
tar xvf $LFS/gawk-3.1.5.tar.bz2 cd gawk-3.1.5 patch -Np1 -i $LFS/gawk-3.1.5-segfault_fix-1.patch ./configure –prefix=/usr –libexecdir=/usr/lib cat >> config.h << “EOF” #define HAVE_LANGINFO_CODESET 1 #define HAVE_LC_MESSAGES 1 EOF make

测试:

代码:
make check

这里check不会有错

代码:
make install cd .. rm -rf gawk-3.1.5


Gettext-0.16.1

代码:
tar xvf $LFS/gettext-0.16.1.tar.gz cd gettext-0.16.1 ./configure –prefix=/usr make

测试:

代码:
make check

这里check的时间比较长,但不会有错。

代码:
make install cd .. rm -rf gettext-0.16.1


Grep-2.5.1a

代码:
tar xvf $LFS/grep-2.5.1a.tar.bz2 cd grep-2.5.1a patch -Np1 -i $LFS/grep-2.5.1a-redhat_fixes-2.patch chmod +x tests/fmbtest.sh ./configure –prefix=/usr –bindir=/bin make

测试:

代码:
make check

这里check不会有错

代码:
make install cd .. rm -rf grep-2.5.1a


Groff-1.18.1.4

代码:
tar xvf $LFS/groff-1.18.1.4.tar.gz cd groff-1.18.1.4 patch -Np1 -i $LFS/groff-1.18.1.4-debian_fixes-1.patch sed -i -e ‘s/2010/002D/’ -e ‘s/2212/002D/’ \ -e ‘s/2018/0060/’ -e ‘s/2019/0027/’ font/devutf8/R.proto PAGE=A4 ./configure –prefix=/usr –enable-multibyte make make install ln -sv eqn /usr/bin/geqn ln -sv tbl /usr/bin/gtbl cd .. rm -rf groff-1.18.1.4


Gzip-1.3.12

代码:
tar xvf $LFS/gzip-1.3.12.tar.gz cd gzip-1.3.12 ./configure –prefix=/usr –bindir=/bin make

测试:

代码:
make check

这里check不会有错

代码:
make install mv -v /bin/{gzexe,uncompress,zcmp,zdiff,zegrep} /usr/bin mv -v /bin/{zfgrep,zforce,zgrep,zless,zmore,znew} /usr/bin cd .. rm -rf gzip-1.3.12


Inetutils-1.5

代码:
tar xvf $LFS/inetutils-1.5.tar.gz cd inetutils-1.5 patch -Np1 -i $LFS/inetutils-1.5-no_server_man_pages-2.patch ./configure –prefix=/usr –libexecdir=/usr/sbin \ –sysconfdir=/etc –localstatedir=/var \ –disable-ifconfig –disable-logger –disable-syslogd \ –disable-whois –disable-servers make make install mv -v /usr/bin/ping /bin cd .. rm -rf inetutils-1.5


IPRoute2-2.6.20-070313

代码:
tar xvf $LFS/iproute2-2.6.20-070313.tar.bz2 cd iproute-2.6.20-070313 sed -i -e ‘/tc-bfifo.8/d’ -e ‘/tc-pfifo.8/s/pbfifo/bfifo/’ Makefile make SBINDIR=/sbin make SBINDIR=/sbin install mv -v /sbin/arpd /usr/sbin cd .. rm -rf iproute-2.6.20-070313


Kbd-1.12

代码:
tar xvf $LFS/kbd-1.12.tar.bz2 cd kbd-1.12 patch -Np1 -i $LFS/kbd-1.12-backspace-1.patch patch -Np1 -i $LFS/kbd-1.12-gcc4_fixes-1.patch ./configure –datadir=/lib/kbd make make install mv -v /usr/bin/{kbd_mode,openvt,setfont} /bin cd .. rm -rf kbd-1.12


Less-406

代码:
tar xvf $LFS/less-406.tar.gz cd less-406 ./configure –prefix=/usr –sysconfdir=/etc make make install cd .. rm -rf less-406


Make-3.81

代码:
tar xvf $LFS/make-3.81.tar.bz2 cd make-3.81 ./configure –prefix=/usr make

测试:

代码:
make check

这里check不会有错

代码:
make install cd .. rm -rf make-3.81


Man-DB-2.4.4

代码:
tar xvf $LFS/man-db-2.4.4.tar.gz cd man-db-2.4.4 mv man/de{_DE.88591,} mv man/es{_ES.88591,} mv man/it{_IT.88591,} sed -i ‘s,\*_\*,??,’ man/Makefile.in sed -i -e ‘\%\t/usr/man%d’ -e ‘\%\t/usr/local/man%d’ src/man_db.conf.in cat >> include/manconfig.h.in << “EOF” #define WEB_BROWSER “exec /usr/bin/lynx” #define COL “/usr/bin/col” #define VGRIND “/usr/bin/vgrind” #define GRAP “/usr/bin/grap” EOF patch -Np1 -i $LFS/man-db-2.4.4-fixes-1.patch ./configure –prefix=/usr –enable-mb-groff –disable-setuid make make install

创建一个用于转换man手册编码的脚本

代码:
cat >> convert-mans << “EOF” #!/bin/sh -e FROM=”$1″ TO=”$2″ shift ; shift while [ $# -gt 0 ] do FILE=”$1″ shift iconv -f “$FROM” -t “$TO” “$FILE” >.tmp.iconv mv .tmp.iconv “$FILE” done EOF
代码:
install -m755 convert-mans /usr/bin cd .. rm -rf man-db-2.4.4


Mktemp-1.5

代码:
tar xvf $LFS/mktemp-1.5.tar.gz cd mktemp-1.5 patch -Np1 -i $LFS/mktemp-1.5-add_tempfile-3.patch ./configure –prefix=/usr –with-libc make make install make install-tempfile cd .. rm -rf mktemp-1.5


Module-Init-Tools-3.2.2

代码:
tar xvf $LFS/module-init-tools-3.2.2.tar.bz2 cd module-init-tools-3.2.2 patch -Np1 -i $LFS/module-init-tools-3.2.2-modprobe-1.patch ./configure make check make distclean ./configure –prefix=/ –enable-zlib make make INSTALL=install install cd .. rm -rf module-init-tools-3.2.2


Patch-2.5.4

代码:
tar xvf $LFS/patch-2.5.4.tar.gz cd patch-2.5.4 ./configure –prefix=/usr make make install cd .. rm -rf patch-2.5.4


Psmisc-22.5

代码:
tar xvf $LFS/psmisc-22.5.tar.gz cd psmisc-22.5 ./configure –prefix=/usr –exec-prefix=”” make make install mv -v /bin/pstree* /usr/bin ln -sv killall /bin/pidof cd .. rm -rf psmisc-22.5


Shadow-4.0.18.1

代码:
tar xvf $LFS/shadow-4.0.18.1.tar.bz2 cd shadow-4.0.18.1 patch -Np1 -i $LFS/shadow-4.0.18.1-useradd_fix-2.patch ./configure –libdir=/lib –sysconfdir=/etc –enable-shared –without-selinux sed -i ‘s/groups$(EXEEXT) //’ src/Makefile find man -name Makefile -exec sed -i ‘s/groups\.1 / /’ {} \; sed -i -e ‘s@#MD5_CRYPT_ENAB.no@MD5_CRYPT_ENAB yes@’ \ -e ‘s@/var/spool/mail@/var/mail@’ etc/login.defs make make install mv -v /usr/bin/passwd /bin mv -v /lib/libshadow.*a /usr/lib rm -v /lib/libshadow.so ln -sfv ../../lib/libshadow.so.0 /usr/lib/libshadow.so

配置增加用户的默认设置。

代码:
pwconv grpconv useradd -D -b /home sed -i ‘s/yes/no/’ /etc/default/useradd

设置root用户密码:

代码:
passwd root

一定要设置root的密码,否则重新启动后无法登陆。

代码:
cd .. rm -rf shadow-4.0.18.1


Sysklogd-1.4.1

代码:
tar xvf $LFS/sysklogd-1.4.1.tar.gz cd sysklogd-1.4.1 patch -Np1 -i $LFS/sysklogd-1.4.1-fixes-2.patch patch -Np1 -i $LFS/sysklogd-1.4.1-8bit-1.patch make make install

设置syslog的配置文件

代码:
cat > /etc/syslog.conf << “EOF” # Begin /etc/syslog.conf auth,authpriv.* -/var/log/auth.log *.*;auth,authpriv.none -/var/log/sys.log daemon.* -/var/log/daemon.log kern.* -/var/log/kern.log mail.* -/var/log/mail.log user.* -/var/log/user.log *.emerg * # End /etc/syslog.conf EOF
代码:
cd .. rm -rf sysklogd-1.4.1


Sysvinit-2.86

代码:
tar xvf $LFS/sysvinit-2.86.tar.gz cd sysvinit-2.86 sed -i ‘s@Sending processes@& configured via /etc/inittab@g’ src/init.c make -C src make -C src install

设置启动配置文件。

代码:
cat > /etc/inittab << “EOF” # Begin /etc/inittab id:3:initdefault: si::sysinit:/etc/rc.d/init.d/rc sysinit l0:0:wait:/etc/rc.d/init.d/rc 0 l1:S1:wait:/etc/rc.d/init.d/rc 1 l2:2:wait:/etc/rc.d/init.d/rc 2 l3:3:wait:/etc/rc.d/init.d/rc 3 l4:4:wait:/etc/rc.d/init.d/rc 4 l5:5:wait:/etc/rc.d/init.d/rc 5 l6:6:wait:/etc/rc.d/init.d/rc 6 ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now su:S016:once:/sbin/sulogin 1:2345:respawn:/sbin/agetty tty1 9600 2:2345:respawn:/sbin/agetty tty2 9600 3:2345:respawn:/sbin/agetty tty3 9600 4:2345:respawn:/sbin/agetty tty4 9600 5:2345:respawn:/sbin/agetty tty5 9600 6:2345:respawn:/sbin/agetty tty6 9600 # End /etc/inittab EOF
代码:
cd .. rm -rf sysvinit-2.86


Tar-1.18

代码:
tar xvf $LFS/tar-1.18.tar.bz2 cd tar-1.18 ./configure –prefix=/usr –bindir=/bin –libexecdir=/usr/sbin make

测试:

代码:
make check

这里check应能通过

代码:
make install cd .. rm -rf tar-1.18


Texinfo-4.9

代码:
tar xvf $LFS/texinfo-4.9.tar.bz2 cd texinfo-4.9 patch -Np1 -i $LFS/texinfo-4.9-multibyte-1.patch patch -Np1 -i $LFS/texinfo-4.9-tempfile_fix-1.patch ./configure –prefix=/usr make

测试:

代码:
make check

这里check不会有错

代码:
make install make TEXMF=/usr/share/texmf install-tex
代码:
cd /usr/share/info rm dir for f in * do install-info $f dir 2>/dev/null done
代码:
cd /sources rm -rf texinfo-4.9


Udev-113

代码:
tar xvf $LFS/udev-113.tar.bz2 cd udev-113 tar -xvf $LFS/udev-config-6.3.tar.bz2 install -dv /lib/{firmware,udev/devices/{pts,shm}} mknod -m0666 /lib/udev/devices/null c 1 3 ln -sv /proc/self/fd /lib/udev/devices/fd ln -sv /proc/self/fd/0 /lib/udev/devices/stdin ln -sv /proc/self/fd/1 /lib/udev/devices/stdout ln -sv /proc/self/fd/2 /lib/udev/devices/stderr ln -sv /proc/kcore /lib/udev/devices/core make EXTRAS=”`echo extras/*/`”

测试:

代码:
make test

这里test可能有错误,不必理会。

代码:
make DESTDIR=/ EXTRAS=”`echo extras/*/`” install cp -v etc/udev/rules.d/[0-9]* /etc/udev/rules.d/ cd udev-config-6.3 make install make install-doc make install-extra-doc cd .. install -m644 -v docs/writing_udev_rules/index.html \ /usr/share/doc/udev-113/index.html cd .. rm -rf udev-113


Util-linux-2.12r

代码:
tar xvf $LFS/util-linux-2.12r.tar.bz2 cd util-linux-2.12r sed -e ‘s@etc/adjtime@var/lib/hwclock/adjtime@g’ \ -i $(grep -rl ‘/etc/adjtime’ .) mkdir -pv /var/lib/hwclock patch -Np1 -i $LFS/util-linux-2.12r-cramfs-1.patch patch -Np1 -i $LFS/util-linux-2.12r-lseek-1.patch ./configure make HAVE_KILL=yes HAVE_SLN=yes make HAVE_KILL=yes HAVE_SLN=yes install cd .. rm -rf util-linux-2.12r


Vim-7.1

代码:
tar xvf $LFS/vim-7.1.tar.bz2 tar xvf $LFS/vim-7.1-lang.tar.gz cd vim71 patch -Np1 -i $LFS/vim-7.1-fixes-1.patch patch -Np1 -i $LFS/vim-7.1-mandir-1.patch echo ‘#define SYS_VIMRC_FILE “/etc/vimrc”‘ >> src/feature.h ./configure –prefix=/usr –enable-multibyte make

测试:

代码:
make test

这里test可能会有个别错误

代码:
make install ln -sv vim /usr/bin/vi for L in “” fr it pl ru; do ln -sv vim.1 /usr/share/man/$L/man1/vi.1 done ln -sv ../vim/vim71/doc /usr/share/doc/vim-7.1

建立vim的默认配置文件

代码:
cat > /etc/vimrc << “EOF” ” Begin /etc/vimrc set nocompatible set backspace=2 syntax on if (&term == “iterm”) || (&term == “putty”) set background=dark endif ” End /etc/vimrc EOF
代码:
cd .. rm -rf vim71

退出chroot环境:

代码:
logout


为Strip而进入chroot环境:

代码:
chroot $LFS /tools/bin/env -i \ HOME=/root TERM=$TERM PS1=’\u:\w\$ ‘ \ PATH=/bin:/usr/bin:/sbin:/usr/sbin \ /tools/bin/bash –login

如果现在重新启动,那么重新开机后回到工作状态的步骤是:
  1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/hda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/hda1
4.加载必要的文件系统
mount -v –bind /dev $LFS/dev
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
5.Chroot到目标系统下
chroot “$LFS” /tools/bin/env -i \
HOME=/root TERM=”$TERM” PS1=’\u:\w\$ ‘ \
PATH=/bin:/usr/bin:/sbin:/usr/sbin \
/tools/bin/bash –login

Strip

代码:
/tools/bin/find /{,usr/}{bin,lib,sbin} -type f \ -exec /tools/bin/strip –strip-debug ‘{}’ ‘;’

退出chroot环境

代码:
logout

为最后的设置进入chroot环境

代码:
chroot “$LFS” /usr/bin/env -i \ HOME=/root TERM=”$TERM” PS1=’\u:\w\$ ‘ \ PATH=/bin:/usr/bin:/sbin:/usr/sbin \ /bin/bash –login cd /sources export LFS=/sources

从现在开始一直到制作结束,重新开机后回到工作状态的步骤是:
  1.重新启动计算机,并从LiveCD启动
2.加载分区
export LFS=/mnt/lfs
mkdir -pv $LFS
mount /dev/hda2 $LFS
3.加载交换分区(如果不想用交换分区或者没有交换分区可跳过此步骤)
swapon /dev/hda1
4.加载必要的文件系统
mount -v –bind /dev $LFS/dev
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
5.Chroot到目标系统下
chroot “$LFS” /usr/bin/env -i \
HOME=/root TERM=”$TERM” PS1=’\u:\w\$ ‘ \
PATH=/bin:/usr/bin:/sbin:/usr/sbin \
/bin/bash –login
6.进入编译目录
cd /sources
export LFS=/sources

LFS-Bootscripts-6.3

代码:
tar xvf $LFS/lfs-bootscripts-6.3.tar.bz2 cd lfs-bootscripts-6.3 make install cd .. rm -rf lfs-bootscripts-6.3


时间设置(Configuring the setclock Script)

代码:
cat > /etc/sysconfig/clock << “EOF” # Begin /etc/sysconfig/clock UTC=1 # End /etc/sysconfig/clock EOF


设置bash下的键盘功能键设置

代码:
cat > /etc/inputrc << “EOF” set horizontal-scroll-mode Off set meta-flag On set input-meta On set convert-meta Off set output-meta On set bell-style none “\eOd”: backward-word “\eOc”: forward-word “\e[1~”: beginning-of-line “\e[4~”: end-of-line “\e[5~”: beginning-of-history “\e[6~”: end-of-history “\e[3~”: delete-char “\e[2~”: quoted-insert “\eOH”: beginning-of-line “\eOF”: end-of-line “\e[H”: beginning-of-line “\e[F”: end-of-line EOF


设置Bash Shell启动文件(The Bash Shell Startup Files)

代码:
cat > /etc/profile << “EOF” # Begin /etc/profile export LANG=zh_CN.UTF-8 export INPUTRC=/etc/inputrc alias ls=”ls –color” export PS1=’\u:\w\$ ‘ # End /etc/profile EOF


设置本地网络名

代码:
echo “HOSTNAME=mylinux” > /etc/sysconfig/network


设置hosts文件

代码:
cat > /etc/hosts << “EOF” # Begin /etc/hosts (no network card version) 127.0.0.1 mylinux localhost # End /etc/hosts (no network card version) EOF


设置网络的静态地址

代码:
cd /etc/sysconfig/network-devices && mkdir -v ifconfig.eth0 && cat > ifconfig.eth0/ipv4 << “EOF” ONBOOT=yes SERVICE=ipv4-static IP=192.168.1.1 GATEWAY=192.168.1.2 PREFIX=24 BROADCAST=192.168.1.255 EOF

注意:IP、GATEWAY、BROADCAST的地址根据自己的实际情况设置。

设置DNS

代码:
cat > /etc/resolv.conf << “EOF” # Begin /etc/resolv.conf nameserver 你的首个DNS的地址 nameserver 你的第二DNS的地址 # End /etc/resolv.conf EOF


建立fstab文件

代码:
cat > /etc/fstab << “EOF” # Begin /etc/fstab # file system mount-point type options dump fsck # order /dev/hda2 / xfs defaults 1 1 /dev/hda1 swap swap pri=1 0 0 proc /proc proc defaults 0 0 sysfs /sys sysfs defaults 0 0 devpts /dev/pts devpts gid=4,mode=620 0 0 shm /dev/shm tmpfs defaults 0 0 # End /etc/fstab EOF

注意:这里的磁盘名以及文件系统名需要根据实际情况修改。

安装内核Linux-2.6.22.5

代码:
cd /sources tar xvf $LFS/linux-2.6.22.5.tar.bz2 cd linux-2.6.22.5

安装显示UTF-8编码文字的补丁
如果之前下载了UTF-8编码文字显示补丁,那么这里可以将这两个补丁打入内核
patch -Np1 -i $LFS/utf8-kernel-2.6.22.5-core-1.patch
patch -Np1 -i $LFS/utf8-kernel-2.6.22.5-fonts-1.patch

代码:
make mrproper make menuconfig

根据你的机器实际情况配置内核选项,这里为了说明方便,以VMWare5.5为基础虚拟的硬件来配置内核
如果在建立虚拟机的时候是选择的BusLogic的SCSI磁盘,那么应该在Device Drivers->SCSI device support->SCSI low-level drivers下加入BusLogic SCSI support的支持,可以采用编译到内核来避免未用initrd脚本来加载模块而导致启动失败

如果想支持网络则应该在Device Drivers->Networking support->Ethernet (10 or 100Mbit)加入AMD PCnet32 PCI support的支持,可以采用编译到内核也可以编译成模块的方式

如果想支持声卡则应该在Device Drivers->Sound->Advanced Linux Sound Architecture->PCI devices加入(Creative) Ensoniq AudioPCI 1371/1373的支持,编译成模块即可

文件系统的支持,需要根据之前将目标系统分区格式化的情况而定,使用了什么文件系统就需要加入该文件系统的支持,因之前采用的是Xfs文件系统,因此在File Systems->XFS support加入XFS的支持,可以采用编译到内核来避免未用initrd脚本来加载模块而导致启动失败

如果之前给内核加入了显示UTF-8编码文字的补丁的话,那么这里需要加入framebuffer的支持才能使补丁生效,在Device Drivers->Graphics support中加入Support for frame buffer devices,并选择上VESA VGA graphics supports,这里将其编译到内核中

同时还需要加入framebuffer字体支持,在Device Drivers->Graphics support->Console display driver support中加入Framebuffer Console support并选择上Select compiled-in fonts,选上VGA 8×16 font这一种字体就可以了,这里将这些选择都编译到内核中

可以保存退出了

代码:
make make modules_install cp -v arch/i386/boot/bzImage /boot/lfskernel-2.6.22.5 cp -v System.map /boot/System.map-2.6.22.5 cp -v .config /boot/config-2.6.22.5 install -d /usr/share/doc/linux-2.6.22.5 cp -r Documentation/* /usr/share/doc/linux-2.6.22.5


安装Grub,使系统能启动,这里设置需要根据情况而修改,这里以之前介绍的分区设置为例:

代码:
grub

输入root (hd0,1)
输入setup (hd0)
quit
设置grub启动菜单

代码:
cat > /boot/grub/menu.lst << “EOF” # Begin /boot/grub/menu.lst # By default boot the first menu entry. default 0 # Allow 30 seconds before booting the default. timeout 30 # Use prettier colors. color green/black light-green/black # The first entry is for LFS. title LFS 6.3 root (hd0,1) kernel /boot/lfskernel-2.6.22.5 root=/dev/hda2 vga=788 EOF

注意:这里root后面的磁盘分区需要根据实际情况调整。
将menu.lst连接到/etc目录下

代码:
mkdir -v /etc/grub ln -sv /boot/grub/menu.lst /etc/grub


退出制作环境:

代码:
logout


现在已经完成了lfs的安装,可以重新启动来运行我们自己的系统咯!
Grub启动界面

启动完成

 

Linux 守护进程的启动方法

2016年5月20日 评论已被关闭

 

Linux 守护进程的启动方法

 http://www.ruanyifeng.com/blog/2016/02/linux-daemon.html

作者: 阮一峰

日期: 2016年2月28日

“守护进程”(daemon)就是一直在后台运行的进程(daemon)。

本文介绍如何将一个 Web 应用,启动为守护进程。

一、问题的由来

Web应用写好后,下一件事就是启动,让它一直在后台运行。

这并不容易。举例来说,下面是一个最简单的Node应用server.js,只有6行。


var http = require('http');

http.createServer(function(req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World');
}).listen(5000);

你在命令行下启动它。


$ node server.js

看上去一切正常,所有人都能快乐地访问 5000 端口了。但是,一旦你退出命令行窗口,这个应用就一起退出了,无法访问了。

怎么才能让它变成系统的守护进程(daemon),成为一种服务(service),一直在那里运行呢?

二、前台任务与后台任务

上面这样启动的脚本,称为”前台任务”(foreground job)。它会独占命令行窗口,只有运行完了或者手动中止,才能执行其他命令。

变成守护进程的第一步,就是把它改成”后台任务”(background job)。


$ node server.js &

只要在命令的尾部加上符号&,启动的进程就会成为”后台任务”。如果要让正在运行的”前台任务”变为”后台任务”,可以先按ctrl + z,然后执行bg命令(让最近一个暂停的”后台任务”继续执行)。

“后台任务”有两个特点。

  1. 继承当前 session (对话)的标准输出(stdout)和标准错误(stderr)。因此,后台任务的所有输出依然会同步地在命令行下显示。
  2. 不再继承当前 session 的标准输入(stdin)。你无法向这个任务输入指令了。如果它试图读取标准输入,就会暂停执行(halt)。

可以看到,”后台任务”与”前台任务”的本质区别只有一个:是否继承标准输入。所以,执行后台任务的同时,用户还可以输入其他命令。

三、SIGHUP信号

变为”后台任务”后,一个进程是否就成为了守护进程呢?或者说,用户退出 session 以后,”后台任务”是否还会继续执行?

Linux系统是这样设计的。

  1. 用户准备退出 session
  2. 系统向该 session 发出SIGHUP信号
  3. session 将SIGHUP信号发给所有子进程
  4. 子进程收到SIGHUP信号后,自动退出

上面的流程解释了,为什么”前台任务”会随着 session 的退出而退出:因为它收到了SIGHUP信号。

那么,”后台任务”是否也会收到SIGHUP信号?

这由 Shell 的huponexit参数决定的。


$ shopt | grep huponexit

执行上面的命令,就会看到huponexit参数的值。

大多数Linux系统,这个参数默认关闭(off)。因此,session 退出的时候,不会把SIGHUP信号发给”后台任务”。所以,一般来说,”后台任务”不会随着 session 一起退出。

四、disown 命令

通过”后台任务”启动”守护进程”并不保险,因为有的系统的huponexit参数可能是打开的(on)。

更保险的方法是使用disown命令。它可以将指定任务从”后台任务”列表(jobs命令的返回结果)之中移除。一个”后台任务”只要不在这个列表之中,session 就肯定不会向它发出SIGHUP信号。


$ node server.js &
$ disown

执行上面的命令以后,server.js进程就被移出了”后台任务”列表。你可以执行jobs命令验证,输出结果里面,不会有这个进程。

disown的用法如下。


# 移出最近一个正在执行的后台任务
$ disown

# 移出所有正在执行的后台任务
$ disown -r

# 移出所有后台任务
$ disown -a

# 不移出后台任务,但是让它们不会收到SIGHUP信号
$ disown -h

# 根据jobId,移出指定的后台任务
$ disown %2
$ disown -h %2

五、标准 I/O

使用disown命令之后,还有一个问题。那就是,退出 session 以后,如果后台进程与标准I/O有交互,它还是会挂掉。

还是以上面的脚本为例,现在加入一行。


var http = require('http');

http.createServer(function(req, res) {
  console.log('server starts...'); // 加入此行
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World');
}).listen(5000);

启动上面的脚本,然后再执行disown命令。


$ node server.js &
$ disown

接着,你退出 session,访问5000端口,就会发现连不上。

这是因为”后台任务”的标准 I/O 继承自当前 session,disown命令并没有改变这一点。一旦”后台任务”读写标准 I/O,就会发现它已经不存在了,所以就报错终止执行。

为了解决这个问题,需要对”后台任务”的标准 I/O 进行重定向。


$ node server.js > stdout.txt 2> stderr.txt < /dev/null &
$ disown

上面这样执行,基本上就没有问题了。

六、nohup 命令

还有比disown更方便的命令,就是nohup


$ nohup node server.js &

nohup命令对server.js进程做了三件事。

  • 阻止SIGHUP信号发到这个进程。
  • 关闭标准输入。该进程不再能够接收任何输入,即使运行在前台。
  • 重定向标准输出和标准错误到文件nohup.out

也就是说,nohup命令实际上将子进程与它所在的 session 分离了。

注意,nohup命令不会自动把进程变为”后台任务”,所以必须加上&符号。

七、Screen 命令与 Tmux 命令

另一种思路是使用 terminal multiplexer (终端复用器:在同一个终端里面,管理多个session),典型的就是Screen 命令和 Tmux 命令。

它们可以在当前 session 里面,新建另一个 session。这样的话,当前 session 一旦结束,不影响其他 session。而且,以后重新登录,还可以再连上早先新建的 session。

Screen 的用法如下。


# 新建一个 session
$ screen
$ node server.js

然后,按下ctrl + Actrl + D,回到原来的 session,从那里退出登录。下次登录时,再切回去。


$ screen -r

如果新建多个后台 session,就需要为它们指定名字。


$ screen -S name

# 切回指定 session
$ screen -r name
$ screen -r pid_number

# 列出所有 session
$ screen -ls

如果要停掉某个 session,可以先切回它,然后按下ctrl + cctrl + d

Tmux 比 Screen 功能更多、更强大,它的基本用法如下。


$ tmux
$ node server.js

# 返回原来的session
$ tmux detach

除了tmux detach,另一种方法是按下Ctrl + Bd ,也可以回到原来的 session。


# 下次登录时,返回后台正在运行服务session
$ tmux attach

如果新建多个 session,就需要为每个 session 指定名字。


# 新建 session
$ tmux new -s session_name

# 切换到指定 session
$ tmux attach -t session_name

# 列出所有 session
$ tmux list-sessions

# 退出当前 session,返回前一个 session 
$ tmux detach

# 杀死指定 session
$ tmux kill-session -t session-name

八、Node 工具

对于 Node 应用来说,可以不用上面的方法,有一些专门用来启动的工具:forevernodemonpm2

forever 的功能很简单,就是保证进程退出时,应用会自动重启。


# 作为前台任务启动
$ forever server.js

# 作为服务进程启动 
$ forever start app.js

# 停止服务进程
$ forever stop Id

# 重启服务进程
$ forever restart Id

# 监视当前目录的文件变动,一有变动就重启
$ forever -w server.js

# -m 参数指定最多重启次数
$ forever -m 5 server.js 

# 列出所有进程
$ forever list

nodemon一般只在开发时使用,它最大的长处在于 watch 功能,一旦文件发生变化,就自动重启进程。


# 默认监视当前目录的文件变化
$ nodemon server.js

# 监视指定文件的变化   
$ nodemon --watch app --watch libs server.js  

pm2 的功能最强大,除了重启进程以外,还能实时收集日志和监控。


# 启动应用
$ pm2 start app.js

# 指定同时起多少个进程(由CPU核心数决定),组成一个集群
$ pm2 start app.js -i max

# 列出所有任务
$ pm2 list

# 停止指定任务
$ pm2 stop 0

# 重启指定任务
$ pm2 restart 0

# 删除指定任务
$ pm2 delete 0

# 保存当前的所有任务,以后可以恢复
$ pm2 save

# 列出每个进程的统计数据
$ pm2 monit

# 查看所有日志
$ pm2 logs

# 导出数据
$ pm2 dump

# 重启所有进程
$ pm2 kill
$ pm2 resurect

# 启动web界面 http://localhost:9615
$ pm2 web

十、Systemd

除了专用工具以外,Linux系统有自己的守护进程管理工具 Systemd 。它是操作系统的一部分,直接与内核交互,性能出色,功能极其强大。我们完全可以将程序交给 Systemd ,让系统统一管理,成为真正意义上的系统服务。

下一篇文章,我就来介绍 Systemd

(完)

 

漫步云端:CoreOS实践指南(一)

2016年5月17日 评论已被关闭

漫步云端:CoreOS实践指南(一)

http://www.csdn.net/article/2014-12-29/2823356

摘要:CoreOS是一个采用了高度精简的系统内核及外围定制的操作系统。ThoughtWorks的软件工程师林帆将带来“漫步云端:CoreOS实践指南”系列文章,介绍CoreOS的精华和推荐的实践方法。本文为基础第一篇:CoreOS俯瞰。

【编者按】Docker和CoreOS都是硅谷创业孵化器的优秀“毕业生”,据说两家老板的私交很好,Docker做容器引擎,CoreOS做容器管理,合作得非常愉快,只是随着Rocket的发布逐步“分道扬镳”。虽然Docker和CoreOS都在求“简”,但是Docker的“简”是力求用户能达到最简便地使用,CoreOS的“简”是追求极致的轻量化,究竟哪个将是Container技术的未来,其实也很难说。今天开始,来自ThoughtWorks的软件工程师林帆将带来“漫步云端:CoreOS实践指南”系列文章,带大家了解CoreOS的精华和推荐的实践方法。本文为基础第一篇:CoreOS俯瞰。


作者简介:

林帆,生在80后尾巴的IT攻城狮,ThoughtWorks成都办公室CloudOps小组成员,平时喜欢在业余时间研究DevOps相关的应用,目前在备考AWS认证和推广Docker相关技术。


引言

相信许多人开始了解CoreOS是从2014年7月底的一则新闻:内置Docker容器的操作系统CoerOS发布首个正式稳定版本。在那之后的半年里CoreOS一路高歌猛进。8月中旬CoreOS收购私有Docker仓库服务商Quay.io,9月初DigitalOcean与CoreOS达成战略合作,9月底微软Azure云服务开始支持CoreOS系统镜像,10月中旬英国的知名云服务商BrightBox也加入支持CoreOS系统镜像的阵营,加上此前已经支持CoreOS镜像的全球主流云服务提供商,包括亚马逊的AWS、云计算巨头Rackspace和Google Computer Engine,CoreOS的名字已经无所不在。

作为一个发布仅仅一年有余的操作系统(首个发布版本在2013年3月),CoreOS在云计算相关的开源社区和大规模服务器集群的领域早已崭露头角,直接与主流Linux服务器操作系统同台竞争。至于后来RedHat祭出内建容器管理服务的系统Atomic,以及Canonical刚刚推出的Ubuntu Core,逐步掀起ContainerOps的大潮,一个全新的集群运维时代正在开启。而走在风头浪尖的CoreOS正是这股潮流的先驱者,它的出现远远不只是“又一个Linux发行版”,而是一个时代理念的颠覆。

这篇系列教程将从最基本的概念开始,顺着大规模集群管理和应用容器化这两条主线带大家了解 CoreOS 系统的独到之处,使得没有接触过这个系统的用户也能够快速的理解其中功能的精华和推荐的实践方法。

CoreOS 是什么

简单的说,它是一种基于 Chrome OS 再定制的轻量级 Linux 发行版本。

作为一个操作系统,CoreOS 采用了高度精简的系统内核及外围定制,将许多原本需要复杂人工操作或者第三方软件支持的功能在操作系统级别进行了实现,同时剔除了其他对于服务器系统非核心的软件,比如GUI和包管理器。

特别值得一提的是 CoreOS 对包管理器的态度和 Docker 的原生支持。这是许多习惯了传统 Linux 管理方式的用户在刚接触 CoreOS 时,最不习惯的地方,因为 CoreOS 没有提供现成的包管理工具。一个典型的困惑是:在 CoreOS 安装软件太不方便了。事实上 CoreOS 并不鼓励用户将各种应用软件直接安装在操作系统之上,而是提倡将所有服务运行在单独的应用容器中,由应用容器提供应用所需要的基础功能环境。这种做法将操作系统和应用程序的职责做了更彻底的分离,降低操作系统和应用程序的耦合度,使运行这些服务器的公司可以更快速、更廉价地更新自己的线上业务。

CoreOS 行走在云端

毫不夸张的说,CoreOS 是为云而生的操作系统。

这个“为云而生”包含两层含义:

  1. 首先,CoreOS 的设计立足点充分的考虑了云端生态系统的分布式部署、大规模伸缩扩展(Scaling)需求,我们将会再后面的内容中充分体会到这一点;
  2. 另一方面,CoreOS 对特定的云环境也有相当的依赖,其启动配置服务 cloud-init 是需要高度定制化的,CoreOS 官方提供了基于Vagrant、VMWare、AZure、AWS、RackSpace 等虚拟机或云服务提供商的定制版本,因此本地直接通过 ISO 安装的 CoreOS 则无法获得 cloud-init 相关的功能,比如集群的自发现和fleet的跨主机管理。

CoreOS 的用户体验

CoreOS 的核心思想来自于 Chrome 浏览器的用户体验:快速启动,后台更新,跨版本无缝更新,每个Tab页采用独立沙盒,单个Tab页崩溃能快速修复,整个浏览器也不会因为单个沙盒进程的崩溃而崩溃。引申到服务器上,试想将一个应用托管在应用容器中的服务从一个服务器转移到另一个服务器上,就像用鼠标将 Tab 页从一个浏览器拖拽到另一个浏览器界面上那样简单。而这些,正是 CoreOS 希望带给每一个用户的体验。

  • 更快的启动速度

因为轻,所以快。做为现代网络的服务器的产物,CoreOS 团队对这个服务器操作系统做了最大的精简,结果不仅使得系统与应用高度分离,更获得了极大的启动速度提升。根据官方数据,其系统运行时内存使用量只有114M(作者注:这是官方数据,实测在Vagrant环境下只有大约80M,比宣传的还要低),只有常见 Linux 服务器系统的一半略多 (约60%)。

此外,CoreOS 使用经 Mac 系统 launchd 的启发而开发的 Systemd 作为默认系统启动和服务管理器 (CentOS 7 也使用 Systemd 取代了过去的 SysV 启动服务)。与 SysV 相比,Systemd 不但可以更好的追踪系统进程,而且也具备优秀的并行化处理能力,加之按需启动等特点,并结合 Docker 的快速启动能力,在 CoreOS 集群中大规模部署 Docker Containers 与使用其他操作系统相比在性能上的优势将更加明显。

  • 平滑版本升级

传统的服务器操作系统,包括大多数Linux发行版,每隔几年都会更换。在这期间,开发者会不断用安全补丁和更新完善这个系统,但是不会进行特别大的改动,最终这个操作系统以及其上的软件会慢慢僵化。但是 CoreOS 的思想是成为一个随时可被更新的操作系统,其本身没有跨发布版本升级的概念,而是使用了类似 Arch Linux 的升级通道(Update Channel)和滚动更新的方式,在任何时候系统都能够直接升级成最新的发布版本。甚至在整个更新的过程中,应用程序的运行不会被打断。有了 CoreOS,基础架构会自动升级,就像无需用户操心的 Chrome 浏览器升级一样。

CoreOS 有两个系统分区 (dual root partition 有些地方翻译为双启动分区,这里实际上应该是系统分区,包括 /bin /sbin /lib 等目录,这些目录都是只读的)。两个分区分别被设置成主动模式和被动模式并在系统运行期间各司其职。主动分区负责系统运行,被动分区负责系统升级。一旦新版本的操作系统被发布,一个完整的系统文件将被下载至被动分区,并在系统下一次重启时从新版本分区启动,原来的被动分区将切换为主动分区,而之前的主动分区则被切换为被动分区。这个个过程中,被更新的机器不需要从负载集群中移除。同时,为了保证其它应用程序不被打断,CoreOS 会通过 Linux cgroups 限制更新过程中的硬盘和网络I/O。

这里值得一提的是,与传统 Linux 服务器不同,CoreOS 的系统分区被设计成在系统运行期间保持只读状态,这样确保了 CoreOS 的安全性,也进一步体现了 CoreOS 不希望用户将应用软件直接安装在操作系统上的态度。同时,集群内高度一致的系统内核和外围应用版本,简化了由于版本问题带来的操作复杂性,使得操作系统自身的维护更加容易。

  • 应用容器化

在 CoreOS 中,所有应用程序都被装在一个个 Docker 容器中,这些容器就像一个个软件代码的集装箱,通过最简单的接口运行在操作系统之上。这意味着它们可以被很轻松的在操作系统和计算机之间转移,就像是在轮船和火车上搬运箱子一样,同时也意味着可以在不中断应用程序的情况下更新操作系统。

Docker 在开发者将应用部署到云基础架构上时变得日益流行。通过容器化 (containerized) 的运算环境向应用程序提供运算资源,应用程序之间共享系统内核和资源,却互不干涉运行。单个容器的故障能够快速的重启修复,并且容器内的应用故障不会引起整个系统的崩溃。这个思想和浏览器的沙盒是如出一辙的。

CoreOS 的分布式系统服务

云的问题,最主要是由集中式到分布式思考方式的转变,分布式服务、分布式部署、分布式管理、分布式数据存储… 而这些都是 CoreOS 带给服务器革命的一部分。

为了从系统层面上解决这些分布式思维所面临的问题,CoreOS 团队提供了一些重要的工具帮助用户管理 CoreOS 集群以及部署 Docker 容器。

  • Cloud-init

在系统启动时,CoreOS 会读取一个平台定制的用户配置文件 (称为 cloud-config) 完成系统的初始化配置。通过配置中的信息,新启动 CoreOS 服务器将初始化必要的服务进程,并自动发现并指定集群的其他服务器交互信息,然后加入这个集群中。这种基于集群的“自发现”组织方式使得集群管理变得简单且高效。

通常来说,cloud-config 配置文件至少应当包括服务器所属的集群通信地址,以及启动 etcd 和 fleet 所需服务的参数。用户可以根据需要,在配置中添加更多定制化的服务,使得节点启动后立即成为功能完备的集群成员投入运行。

  • Etcd

在CoreOS 集群中处于骨架地位的是 etcd。 etcd 是一个分布式 key/value 存储服务,CoreOS 集群中的程序和服务可以通过 etcd 共享信息或做服务发现 。etcd 基于非常著名的 raft 一致性算法:通过选举形式在服务器之中选举 Lead 来同步数据,并以此确保集群之内信息始终一致和可用。etcd 以默认的形式安装于每个 CoreOS 系统之中。

在默认的配置下,etcd 使用系统中的两个端口:4001和7001,其中4001提供给外部应用程序以HTTP+Json的形式读写数据,而7001则用作在每个 etcd 之间进行数据同步。用户更可以通过配置 CA Cert让 etcd 以 HTTPS 的方式读写及同步数据,进一步确保数据信息的安全性。

  • Fleet

fleet 是一个通过 Systemd对CoreOS 集群中进行控制和管理的工具。fleet 与 Systemd 之间通过 D-Bus API 进行交互,每个 fleet agent 之间通过 etcd 服务来注册和同步数据。fleet 提供的功能非常丰富,包括查看集群中服务器的状态、启动或终止 Docker 容器、读取日志内容等。更为重要的是 fleet 可以确保集群中的服务一直处于可用状态。当出现某个通过 fleet 创建的服务在集群中不可用时,如由于某台主机因为硬件或网络故障从集群中脱离时,原本运行在这台服务器中的一系列服务将通过fleet 被重新分配到其他可用服务器中。虽然当前 fleet 还处于非常早期的状态,但是其管理 CoreOS 集群的能力是非常有效的,并且仍然有很大的扩展空间,目前已提供简单的 API 接口供用户集成。

尾声

从下一篇开始我们将从构建一个 CoreOS 集群说起,一步一步来熟悉这个系统的方方面面。(作者/林帆 审校/周小璐)

参考文章:

服务器操作系统 CoreOS

CoreOS:最小化定制版linux系统

CoreOS 实战:CoreOS 及管理工具介绍

An Introduction to CoreOS System Components

服务器操作系统CoreOS初体验

2016年5月17日 评论已被关闭

服务器操作系统CoreOS初体验

http://www.blogjava.net/yongboy/archive/2013/08/26/403325.html

CoreOS官网主页使用一句话概括其理念:“A new way to think about servers”,以及紧接着的“CoreOS is Linux for massive server deployments”, 表示这是一个新思维方式思考未来服务器大规模部署的的Linux服务器操作系统。

CoreOS宣称最小化的定制版linux系统,具有:

  • Linux内核,Linux运行所需
  • 存在两个ROOT分区,一个被用作启动分区,一个被用作更新分区
    更新分区在更新完成后,自动重新启动系统,当前机器不需要从负载集群中移除,为了保证其它应用程序不被打断,会通过Linux cgroup限制更新过程中的磁盘、网络等IO使用。
  • systemd,作为默认系统和服务管理器,其优秀特性:
    支持并行化任务;
    同时采用 socket 式与 D-Bus 总线式激活服务;
    按需启动守护进程(daemon);
    利用 Linux 的 cgroups 监视进程;
    支持快照和系统恢复;
    维护挂载点和自动挂载点;
    各服务间基于依赖关系进行精密控制。
    
  • root分区被设计成只读,用以保证数据的一致性和更新可用
  • CPU、IO等资源隔离,自然要祭出容器(Container)来,CoreOS很明智使用Docker作为容器管理器用以构建、发布应用,从这个层面来看,一个应用其实就是一个容器。
  • etcd组件负责服务发现和配置共享,采用Raft分布式一致性协议算法,承担起,组件之间服务通信使用。很自然的,容器(Container)之间应用、服务的伸缩,就显得很简单了。其基因层面支持集群特性,当然,你也可以解读为云环境的支持。

看起来,这个系统是为类似于拥有众多平台的IT公司准备的。服务之间,粒度变得很细。

刚刚发布第一个0.1.0版本,官方总结特性如下:

  1. 接口简单,HTTP+JSON
  2. 安全,可选择的SSL通信协议
  3. 快速,经测试1000s单一实例写入操作
  4. 可靠,分布式层面使用Raft协议
  5. 坚固,集群的失败可以从磁盘恢复

要想体验,目前看来,最简单方式,需要在一个虚拟环境中尝试一把,当然也是这样做的。本次体验,基于Windows 7 64位系统。以下为简单步骤:

  1. 先安装VirtualBox 4.2.16,建议从官网下载。
  2. Vagrant,这次安装最新的1.2.7版本,下载地址
  3. 安装Git for Windows 1.8.3,可以让命令下直接使用git命令
  4. 安装CoreOS环境,打开windows命令行环境:
    git clone https://github.com/coreos/coreos-vagrant/
    cd coreos-vagrant
    vagrant up
    vagrant ssh
    

    执行完毕 vagrant ssh, 会自动生成一些ssh的一些信息:

    Host: 127.0.0.1
    Port: 2222
    Username: core
    Private key: C:/Users/nieyong/.vagrant.d/insecure_private_key
    

    使用熟悉的SSH终端工具登陆即可,这里推荐xshell,不在细述。SSH成功登入,可以看到欢迎信息:

    coreos-ssh

  5. 体验一把Docker作为容器管理器
    这里快速体验一把,敲入一下命令:

    docker run ubuntu /bin/echo hello world
    

    此时,自动下载Ubuntu系统容器镜像文件:

    CoreOS-ubuntu

    更多Docker操作,请参阅其文档

  6. 进程管理systemd的一处使用这里想让系统启动时,执行一些简单任务。终端下输入
    sudo -i
    

    切换到Ubuntu ROOT用户角色下, 执行vi /media/state/units/hello.service,敲入如下内容:

    [Unit]
    Description=My Service
    After=docker.service
    
    [Service]
    Restart=always
    ExecStart=/usr/bin/docker run ubuntu /bin/sh -c "while true; do echo Hello World; sleep 1; done"
    
    [Install]
    WantedBy=local.target
    

    保存之后,我们需要做到模拟重启:

    systemctl restart local-enable.service
    

    现在查看一下日志,可以看到其输出:

    journalctl -u hello.service -f
    

    coreos-log

    更多systemd细节,请参考http://www.freedesktop.org/wiki/Software/systemd/

  7. 本次浅尝辄止,到此结束

总体看,CoreOS最大特色,专门为大规模服务器部署定制的Linux精简系统,尽可能的精简无关紧要的功能,将操作系统和应用程序完全分离,从而降低操作系统和应用程序的耦合度,同时解决了现有Linux服务器在容器资源、权限管理方面的欠缺。目前若说是颠覆性的操作系统,十分牵强,是不是未来,也不好说,但肯定是一种趋势。

因此,十分值得期待。

进阶阅读:

Docker vs CoreOS:容器战争值得发动

2016年5月17日 评论已被关闭

Docker vs CoreOS:容器战争值得发动

http://tech.hexun.com/2015-05-16/175868575.html

第1页:Docker遇到最大挑战

Docker是一个开源的应用容器引擎,采用Docker来构建和部署云容器,那么我们的程序将变得非常便携。Docker红起来的速度非常快速,不仅拿了融资,还得到了Google等巨头的支持。

可以说对于Docker来说,一路发展起来非常顺利,但是在去年12月,Docker的支持者之一CoreOS发布了一个名为Rocket的开源项目。该CoreOS小组称,Docker过于复杂和笨重,也许是过于专注服务于母公司的需求,因为,它偏离了便携的使命。

可以说对于Docker来说,一路发展起来非常顺利,但是在去年12月,Docker的支持者之一CoreOS发布了一个名为Rocket的开源项目。该CoreOS小组称,Docker过于复杂和笨重,也许是过于专注服务于母公司的需求,因为,它偏离了便携的使命。

同时,CoreOS小组还称,Docker在安全性、可组合性方面是有根本上的缺陷的,而Rocket的设计原型就是为了弥补这些缺陷,相比较要更加优秀。

事实上Docker在最近发布的几个版本里都关注于安全性上,但这对于一个旨在适应大规模企业应用的工具来说实在很正常。

相比之下,CoreOS声称Rocket是一个更好的标准货柜,这也是任何一个公司的控制范围之内的,当然,CoreOS也取得了Red Hat、Google、Vmware及Apcera的支持,但他们一定会继续支持这两种标准。

CoreOS打算继续支持Docker项目,但是当Rocket逐渐成熟之后,他们将重新评估是否继续参与贡献。

第2页:CoreOS此举为何?

CoreOS此举可能是想要一个更大的一块容器的市场,而不是无私的原因。

不过,我并不像分析CoreOS此举是否是一个慈善之举,容器空间领域起火,CoreOS将对Docker带来更多的挑战,这种挑战也将持续一段时间。

当然,目前也有一些相似Docker和Rocket的项目。

与其他热门技术不同,容器的竞争是创造竞争的标准,使用技术的人更容易等到战争的技术才结算。

尽管竞争的效果混乱,但是我更喜欢有两个标准的选择,至少暂时是这样的,由于我们实施的试点应用,每个标准是更好的技术奖很快被识别,追中,IT组织奖决定谁胜,或Docker和Rocket可以共存。

此外,看看其他公有云提供商如何接近容器的标准,将是一个有趣的事情,浙江大大有助于行业的发展。