쉽게 말해 리눅스를 소스로 설치한다고 생각하면 쉬울 것이다. 필자를 포함해서 거의 대부분의 리눅서들이 CD나 다른 매체를 통해서 배포판으로 설치하고 있다. 필자도 LFS라는 말을 들은 지는 한달도 채 되지 않았다. 하지만, LFS의 의미를 알고 나서 왠지 모르는 해보고 싶다는 충동이 일었다. 그동안 써오던 레드햇 기반의 리눅스가 싫증이 난 것도 한 몫 했을 것이다. 이 LFS는 내가 이제까지 해왔던 작업중 가장 힘들고 지루했었다. 밤 12시에 시작해서 아침 7시 30분까지 작업을 했으니….ㅡ.ㅡ;; 이제 본격적인 LFS 설치를 해보자!!
우선 LFS를 설치하기 위해서는 리눅스 파티션이 있어야 한다. 기존의 리눅스 파티션을 이용해도 되고 하드에 여유가 있다면 리눅스 파티션을 하나 만들자!! 하지만 리눅스 파티션을 하나 만들기를 적극 권장한다. 필자는 '/dev/hdd1' 파티션을 만들었다. 만드는 방법은 다음과 같다.
#mke2fs /dev/hdd1
용량은 최대한 충분히 잡아주기 바란다. 필자는 모두 설치했을 때 500메가 정도 되었었다. 여러분들은 최소한 1기가는 잡아주어야 한다. 새 파티션을 만들었다면, LFS 사이트에 가서 설치에 필요한 소스를 다운받아야 한다. 주소는 http://www.linuxfromscratch.org/ 이다. 이 글을 쓰는 현재 3.0 버전이 최신버전이다. LFS를 설치하기 위한 프로그램들은 거의 30여개가 넘는다. 이를 모두 일일이 받는 다는 것은 비효율적이다. 그러므로 이것들을 패키지로 묶어놓은 패키지 파일을 받도록 하자.
필자는 ftp://ftp.linuxfromscratch.org/lfs-packages/3.0/lfs-packages-3.0.tar 를 받았다.
위에서 우리가 만들어 놓은 새 파티션(/dev/hdd1)을 마운트 시킨다. 이 새 파티션에다가 LFS를 설치할 것이다.
#mkdir -p /mnt/lfs #mount /dev/hdd1 /mnt/lfs
마운트 할 디렉토리 이름은 lfs로 한다. 앞으로 우리는 /mnt/lfs 라는 이름 대신에 $LFS 라는 변수로 대신할 것이다. 그러므로 아래와 같이 변수를 지정해준다.
#export LFS=/mnt/lfs
재부팅을 하고 나면 설정이 지워지므로 /root/.bashrc 파일에다가 한줄 추가시켜준다.
그리고 나서 아래를 실행시켜 디렉토리를 만들어준다.
#cd $LFS #mkdir -p bin boot dev/pts etc/opt home lib mnt proc root sbin tmp var opt #for dirname in $LFS/usr $LFS/usr/local do mkdir $dirname cd $dirname mkdir bin etc include lib sbin share src var ln -s share/man man ln -s share/doc doc ln -s share/info info cd $dirname/share mkdir dict doc info locale man nls misc terminfo zoneinfo cd $dirname/share/man mkdir man{1,2,3,4,5,6,7,8} done #cd $LFS/var #mkdir -p lock log mail run spool tmp opt cache lib/misc local #cd $LFS/opt #mkdir bin doc include info lib man #cd $LFS/usr #ln -s ../var/tmp tmp #cd $LFS #chmod 0750 root #chmod 1777 tmp var/tmp
위의 설정까지 마쳤다면 LFS를 설치하기 위한 설정은 모두 마친 셈이다. 이제 본격적으로 설치해보자!
이제부터 우리가 위에서 다운받은 lfs-packages-3.0.tar은 $LFS/usr/src 에다가 옮겨 놓고 압축을 풀고 설치할 것이다.
#cd /usr/lib && ln -s libncurses.a libcurses.a #./configure --enable-static-link --prefix=$LFS/usr \ --bindir=$LFS/bin --with-curses && make && make install && cd $LFS/bin && ln -sf bash sh
#./configure --prefix=$LFS/usr --disable-nls && make LDFLAGS=-all-static tooldir=$LFS/usr && make tooldir=$LFS/usr install
#make CC="gcc -static" && make PREFIX=$LFS/usr install && cd $LFS/usr/bin && mv bzcat bunzip2 bzip2 bzip2recover $LFS/bin
※ glib 버전이 2.1.x 이면, #export CPPFLAGS=-Dre_max_failures=re_max_failures2 && ./configure --prefix=$LFS/usr && unset CPPFLAGS && make LDFLAGS=-static && make install ※ glib 버전이 2.2.x 이면, #./configure --prefix=$LFS/usr && make LDFLAGS=-static && make install
#cp lib/Makefile.in lib/Makefile.in.backup && sed -e 's/\(.*\)\(fopen-safer\.c \)\\/\1\2atexit.c \\/' \ -e 's/\(.*\)\(idcache\$U\.\$.*\)\\/\1\2atexit$U.$(OBJEXT) \\/' \ lib/Makefile.in > lib/Makefile.in~ && mv lib/Makefile.in~ lib/Makefile.in #./configure --disable-nls \ --prefix=$LFS/usr --libexecdir=$LFS/bin --bindir=$LFS/bin && make LDFLAGS=-static && make install && cd $LFS/usr/bin && ln -sf ../../bin/install
#patch -Np1 -i ../gcc-2.95.3-2.patch && mkdir ../gcc-build && cd ../gcc-build && ../gcc-2.95.3/configure --prefix=/usr --enable-languages=c,c++ \ --disable-nls --disable-shared --enable-threads=posix && make BOOT_LDFLAGS=-static bootstrap && make prefix=$LFS/usr install && cd $LFS/lib && ln -sf ../usr/bin/cpp && cd $LFS/usr/lib && ln -sf ../bin/cpp && cd $LFS/usr/bin && ln -sf gcc cc
※ glibc-2.1.x 이면 #export CPPFLAGS=-Dre_max_failures=re_max_failures2 && ./configure --prefix=$LFS/usr --disable-nls && unset CPPFLAGS && make LDFLAGS=-static && make install ※ glibc-2.2.x 이면 #./configure --prefix=$LFS/usr --disable-nls && make LDFLAGS=-static && make install
#patch -Np1 -i ../gzip-1.2.4a.patch #./configure --prefix=$LFS/usr && make LDFLAGS=-static && make install && cp $LFS/usr/bin/gunzip $LFS/usr/bin/gzip $LFS/bin && rm $LFS/usr/bin/gunzip $LFS/usr/bin/gzip
※ 반드시 $LFS/usr/src 에 풀어놓고 작업을 해야 한다. #make mrproper && yes "" | make config && make dep && cd $LFS/usr/include && cp -a ../src/linux/include/linux . && chown -R root.root $LFS/usr/include/linux && mkdir asm && cp -a ../src/linux/include/asm/* asm && chown -R root.root $LFS/usr/include/asm
#./configure --prefix=$LFS/usr --disable-nls && make LDFLAGS=-static && make install
#./configure && make CC="gcc -static" && make BINDIR=$LFS/usr/bin \ MANDIR=$LFS/usr/share/man/man1 install
#./configure --prefix=$LFS/usr && make LDFLAGS=-static && make install
※ glibc-2.1.x export CPPFLAGS=-Dre_max_failures=re_max_failures2 && ./configure --prefix=$LFS/usr --bindir=$LFS/bin && unset CPPFLAGS && make LDFLAGS=-static && make install ※ glibc-2.2.x ./configure --prefix=$LFS/usr --bindir=$LFS/bin && make LDFLAGS=-static && make install
#patch -Np1 -i ../sh-utils-2.0.patch #./configure --prefix=$LFS/usr --disable-nls && make LDFLAGS=-static && make install && cd $LFS/usr/bin && mv date echo false pwd stty $LFS/bin && mv su true uname hostname $LFS/bin
#patch -Np1 -i ../tar-1.13.patch #./configure --prefix=$LFS/usr --disable-nls \ --libexecdir=$LFS/usr/bin --bindir=$LFS/bin && make LDFLAGS=-static && make install
#./configure --prefix=$LFS/usr --disable-nls && make LDFLAGS=-static && make install
#./configure --prefix=$LFS/usr --disable-nls && make LDFLAGS=-static && make install && mv $LFS/usr/bin/cat $LFS/bin
echo "root:x:0:0:root:/root:/bin/bash" > $LFS cat > $LFS/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: EOF
#/lib/libc.so.6 #cp -av /lib/libnss* $LFS/lib
#mount proc $LFS/proc -t proc
#cat > $LFS/root/.bash_profile << "EOF" # Begin /root/.bash_profile PS1='\u:\w\$ ' PATH=/bin:/usr/bin:/sbin:/usr/sbin export PS1 PATH # End /root/.bash_profile EOF
#cd $LFS && chroot $LFS /usr/bin/env -i HOME=/root \ TERM=$TERM /bin/bash --login
※ glibc-linuxthreads를 glibc-2.2.4 디렉토리 안에 풀어서 같이 설치합니다. #mknod -m 0666 /dev/null c 1 3 && touch /etc/ld.so.conf && cp malloc/Makefile malloc/Makefile.backup && sed 's%\$(PERL)%/usr/bin/perl%' malloc/Makefile > tmp~ && mv tmp~ malloc/Makefile && cp login/Makefile login/Makefile.backup && sed 's/root/0/' login/Makefile > tmp~ && mv tmp~ login/Makefile && mkdir ../glibc-build && cd ../glibc-build && ../glibc-2.2.4/configure --prefix=/usr \ --enable-add-ons --libexecdir=/usr/bin && cp config.make config.make.backup && sed 's/cross-compiling = yes/cross-compiling = no/' \ config.make > tmp~ && mv tmp~ config.make && make && make install && make localedata/install-locales && exec /bin/bash --login
#./MAKEDEV -v generic
#patch -Np1 -i ../man-pages-1.39.patch && make install
#patch -Np1 -i ../findutils-4.1.patch && ./configure --prefix=/usr && make && make libexecdir=/usr/bin install
※ 여기서부터 전에 설치했던 것을 다시 설치하는 경우가 생깁니다. 그럴 때는 전에 설치할 때 풀어놓았던 디렉토리를 지우고 새로 압축을 풀어서 설치합니다.
#./configure && make && make BINDIR=/usr/bin \ MANDIR=/usr/share/man/man1 install && cd /usr/bin && ln -sf mawk awk
#./configure --prefix=/usr --libdir=/lib \ --with-shared --disable-termcap && make && make install && cd /lib && mv *.a /usr/lib && chmod 755 *.5.2 && cd /usr/lib && ln -sf libncurses.a libcurses.a && ln -sf ../../lib/libncurses.so && ln -sf ../../lib/libcurses.so && ln -sf ../../lib/libform.so && ln -sf ../../lib/libpanel.so && ln -sf ../../lib/libmenu.so
#echo '#define SYS_VIMRC_FILE "/etc/vimrc"' >> \ src/feature.h && ./configure --prefix=/usr && make && make install && cd /usr/bin && ln -sf vim vi
#patch -Np1 -i ../gcc-2.95.3-2.patch && mkdir ../gcc-build && cd ../gcc-build && ../gcc-2.95.3/configure --prefix=/usr --enable-shared \ --enable-languages=c,c++ --enable-threads=posix && make bootstrap && make install
#./configure --prefix=/usr \ --datadir=/usr/share/bison && make && make install #cat > /usr/bin/yacc << "EOF" #!/bin/sh # Begin /usr/bin/yacc exec /usr/bin/bison -y "$@" # End /usr/bin/yacc EOF #chmod 755 /usr/bin/yacc
#./configure --prefix=/usr --bindir=/bin && make && make install
./configure --prefix=/usr && make && make install
#for i in configure src/Makefile.in src/makewhatis.sh do cp $i $i.backup && sed 's/gawk/awk/g' $i > tmp~ && mv tmp~ $i done && chmod 755 configure && ./configure -default && make && make install
#./Configure -Dprefix=/usr && make && make install
#./configure --prefix=/usr && make && make install
#./configure --prefix=/usr && make && make install && make TEXMF=/usr/share/texmf install-tex
#./configure --prefix=/usr && make && make install
#./configure --prefix=/usr && make install
#./configure --prefix=/usr --with-curses \ --bindir=/bin && make && make install && exec /bin/bash --login
#./configure --prefix=/usr && make && make install && cd /usr/bin && ln -sf flex lex
#cp readelf.h readelf.h.backup && sed $'/#define __/a \\\n#include <stdint.h>' readelf.h.backup > readelf.h && ./configure --prefix=/usr --datadir=/usr/share/misc && make && make install
#./configure --prefix=/usr && make && make install
#make && make PREFIX=/usr install
#./configure --prefix=/usr --enable-shared && make tooldir=/usr && make tooldir=/usr install && make tooldir=/usr install-info
#make -f Makefile-libbz2_so && make bzip2recover libbz2.a && ln -s libbz2.so.1.0.1 libbz2.so && cp bzip2-shared /bin/bzip2 && cp bzip2recover /bin && cp bzip2.1 /usr/share/man/man1 && cp bzlib.h /usr/include && cp -a libbz2.so* /lib && rm /usr/lib/libbz2.a && cp libbz2.a /usr/lib && cd /usr/lib && ln -sf ../../lib/libbz2.so && cd /bin && ln -sf bzip2 bunzip2 && ln -sf bzip2 bzcat && cd /usr/share/man/man1 && ln -sf bzip2.1 bunzip2.1 && ln -sf bzip2.1 bzcat.1 && ln -sf bzip2.1 bzip2recover.1
#cp buf.c buf.c.backup && sed 's/int u/int u, sfd/' buf.c.backup | \ sed '/.*\*mktemp.*/d' | \ sed 's/.*if (mktemp.*/ sfd = mkstemp(sfn);\ if ((sfd == -1) || (sfp = fopen (sfn, "w+")) == NULL)/' > buf.c && ./configure --prefix=/usr && make && make install && mv /usr/bin/ed /usr/bin/red /bin
#./configure --prefix=/usr && make && make install
#./configure --datadir=/usr/share/kbd && make && make install
#./configure --prefix=/usr && make && make install
#./configure --prefix=/usr --with-root-prefix=/ \ --enable-elf-shlibs && make && make install && make install-libs
#./configure --prefix=/usr --bindir=/bin \ --libexecdir=/bin && make && make install
#./configure --prefix=/usr && make && make install
#./configure --prefix=/usr && make && make install && cd /usr/bin && mv gzip /bin && rm gunzip zcat && cd /bin && ln -sf gzip gunzip && ln -sf gzip zcat && ln -sf gzip compress && ln -sf gunzip uncompress
#make && make install
#./configure --prefix=/usr && make && make install
#./configure && make && make install
#./configure && make && make install && cd etc.sample && cp services protocols /etc
#./configure --prefix=/usr && make && make install
#make LDLIBS=-lncurses && make install
#make && make XSCPT='' install && mv /usr/bin/kill /bin
#./configure --prefix=/usr --exec-prefix=/ && make && make install
#patch -Np1 -i ../tar-1.13.patch #./configure --prefix=/usr --libexecdir=/usr/bin \ --bindir=/bin && make && make install
#./configure --prefix=/usr && make && make install && mv /usr/bin/cat /bin
#cp hwclock/hwclock.c hwclock/hwclock.c.backup && sed 's%etc/adjtime%var/lib/hwclock/adjtime%' \ hwclock/hwclock.c > tmp~ && mv tmp~ hwclock/hwclock.c && mkdir -p /var/lib/hwclock
#rm /lib/libnss*.so.1 /lib/libnss*2.0*
#cat > /root/.vimrc << "EOF" " Begin /root/.vimrc set nocompatible set bs=2 " End /root/.vimrc EOF
#cat > /etc/nsswitch.conf << "EOF" # Begin /etc/nsswitch.conf passwd: files group: files shadow: files publickey: files hosts: files dns networks: files protocols: db files services: db files ethers: db files rpc: db files netgroup: db files # End /etc/nsswitch.conf EOF #cd /etc && ln -sf ../usr/share/zoneinfo/<tzselect's output> localtime OR #ln -sf ../usr/share/zoneinfo/EST5EDT localtime Or: #ln -sf ../usr/share/zoneinfo/Canada/Eastern localtime
#cat > /etc/ld.so.conf << "EOF" # Begin /etc/ld.so.conf /lib /usr/lib /usr/local/lib # End /etc/ld.so.conf EOF
#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
#/usr/sbin/pwconv
#cat > /etc/inittab << "EOF" # Begin /etc/inittab id:3:initdefault: si::sysinit:/etc/init.d/rcS l0:0:wait:/etc/init.d/rc 0 l1:S1:wait:/etc/init.d/rc 1 l2:2:wait:/etc/init.d/rc 2 l3:3:wait:/etc/init.d/rc 3 l4:4:wait:/etc/init.d/rc 4 l5:5:wait:/etc/init.d/rc 5 l6:6:wait:/etc/init.d/rc 6 ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now su:S016:respawn:/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
#touch /var/run/utmp /var/log/wtmp \ /var/log/btmp /var/log/lastlog && chmod 644 /var/run/utmp /var/log/wtmp \ /var/log/btmp /var/log/lastlog
#passwd root
#cd /etc && mkdir rc{0,1,2,3,4,5,6,S}.d init.d sysconfig && cd init.d
#cat > /etc/init.d/rc << "EOF" #!/bin/sh # Begin /etc/init.d/rc # # By Jason Pearce - jason.pearce@linux.org # Modified by Gerard Beekmans - gerard@linuxfromscratch.org # print_error_msg based on ideas by Simon Perreault - # nomis80@videotron.ca # # # Include the functions declared in the /etc/init.d/functions file # source /etc/init.d/functions # # The print_error_msg function prints an error message when an unforeseen # error occurred that wasn't trapped for some reason by a evaluate_retval # call or error checking in different ways. print_error_msg() { echo $FAILURE echo -n "You should not read this error message. It means " echo "that an unforeseen error " echo -n "took place and subscript $i exited with " echo "a return value " echo -n "of $error_value for an unknown reason. If you're able " echo "to trace this error down " echo -n "to a bug in one of the files provided by this book, " echo "please be so kind to " echo -n "inform us at lfs-dev@linuxfromscratch.org" $NORMAL echo echo echo "Press a key to continue..." read } # # If you uncomment the debug variable below none of the scripts will be # executed, just the script name and parameters will be echo'ed to the # screen so you can see how the scripts are called by rc. # # Un-comment the following for debugging. # debug=echo # # Start script or program. # startup() { $debug "$@" } # # Ignore CTRL-C only in this shell, so we can interrupt subprocesses. # trap ":" INT QUIT TSTP # # Now find out what the current and what the previous runlevel are. The # $RUNLEVEL variable is set by init for all it's children. This script # runs as a child of init. # runlevel=$RUNLEVEL # # Get first argument. Set new runlevel to this argument. If no runlevel # was passed to this script we won't change runlevels. # [ "$1" != "" ] && runlevel=$1 if [ "$runlevel" = "" ] then echo "Usage: $0 <runlevel>" >&2 exit 1 fi # # The same goes for $PREVLEVEL (see above for $RUNLEVEL). previous will # be set to the previous run level. If $PREVLEVEL is not set it means # that there is no previous runlevel and we'll set previous to N. # previous=$PREVLEVEL [ "$previous" = "" ] && previous=N export runlevel previous # # Is there an rc directory for the new runlevel? # if [ -d /etc/rc$runlevel.d ] then # # If so, first collect all the K* scripts in the new run level. # if [ $previous != N ] then for i in /etc/rc$runlevel.d/K* do [ ! -f $i ] && continue # # the suffix variable will contain the script name without the leading # Kxxx # suffix=${i#/etc/rc$runlevel.d/K[0-9][0-9][0-9]} # # If there is a start script for this K script in the previous runlevel # determine what it's full path is # previous_start=/etc/rc$previous.d/S[0-9][0-9][0-9]$suffix # # If there was no previous run level it could be that something was # started in rcS.d (sysinit level) so we'll determine the path for that # possibility as well. # sysinit_start=/etc/rcS.d/S[0-9][0-9][0-9]$suffix # # Stop the service if there is a start script in the previous run level # or in the sysinit level. If previous_start or sysinit_start do not # exist the 'continue' command is run which causes the script to abort # this iteration of the for loop and continue with the next iteration. # This boils down to that it won't run the commands after the next two # lines and start over from the top of this for loop. See man bash for # more info on this. # [ ! -f $previous_start ] && [ ! -f $sysinit_start ] && continue # # If we found previous_start or sysinit_start, run the K script # startup $i stop error_value=$? # # If the return value of the script is not 0, something went wrong with # error checking inside the script. the print_error_msg function will be # called and the message plus the return value of the K script will be # printed to the screen # if [ $error_value != 0 ] then print_error_msg fi done fi # # Now run the START scripts for this runlevel. # for i in /etc/rc$runlevel.d/S* do [ ! -f $i ] && continue if [ $previous != N ] then # # Find start script in previous runlevel and stop script in this # runlevel. # suffix=${i#/etc/rc$runlevel.d/S[0-9][0-9][0-9]} stop=/etc/rc$runlevel.d/K[0-9][0-9][0-9]$suffix previous_start=/etc/rc$previous.d/S[0-9][0-9][0-9]$suffix # # If there is a start script in the previous level and no stop script in # this level, we don't have to re-start the service; abort this # iteration and start the next one. # [ -f $previous_start ] && [ ! -f $stop ] && continue fi case "$runlevel" in 0|6) # # levels 0 and 6 are halt and reboot levels. We don't really start # anything here so we call with the 'stop' parameter # startup $i stop error_value=$? # # If the return value of the script is not 0, something went wrong with # error checking inside the script. the print_error_msg function will be # called and the message plus the return value of the K script will be # printed to the screen # if [ $error_value != 0 ] then print_error_msg fi ;; *) startup $i start error_value=$? # # If the return value of the script is not 0, something went wrong with # error checking inside the script. the print_error_msg function will be # called and the message plus the return value of the K script will be # printed to the screen # if [ $error_value != 0 ] then print_error_msg fi ;; esac done fi # End /etc/init.d/rc EOF
#cat > /etc/init.d/rcS << "EOF" #!/bin/sh # Begin /etc/init.d/rcS # # See the rc script for the extensive comments on the constructions # used here # source /etc/init.d/functions print_error_msg() { echo $FAILURE echo -n "You should not read this error message. It means " echo "that an unforeseen error " echo -n "took place and subscript $i exited with " echo "a return value " echo -n "of $error_value for an unknown reason. If you're able " echo "to trace this error down " echo -n "to a bug in one of the files provided by this book, " echo "please be so kind to " echo -n "inform us at lfs-dev@linuxfromscratch.org" $NORMAL echo echo echo "Press a key to continue..." read } runlevel=S prevlevel=N umask 022 export runlevel prevlevel trap ":" INT QUIT TSTP # # Collect all the S scripts in /etc/rcS.d and execute them # for i in /etc/rcS.d/S* do [ ! -f "$i" ] && continue; $i start error_value=$? if [ $error_value != 0 ] then print_error_msg fi done # End /etc/init.d/rcS EOF
#cat > /etc/init.d/functions << "EOF" #!/bin/sh # Begin /etc/init.d/functions # # Set a few variables that influence the text that's printed on the # screen. The SET_COL variable starts the text in the column number # decided by the COL and WCOL section (as defined by the COL # variable). NORMAL prints text in normal mode. # SUCCESS prints text in a green colour and FAILURE prints text in a red # colour # # If COLUMNS hasn't been set yet (bash sets it but not when called as # sh), do it ourself if [ -z "$COLUMNS" ] then # Get the console device if we don't have it already # This is ok by the FHS as there is a fallback if # /usr/bin/tty isn't available, for example at bootup. test -x /usr/bin/tty && CONSOLE=`/usr/bin/tty` test -z "$CONSOLE" && CONSOLE=/dev/console # Get the console size (rows columns) SIZE=$(stty size < $CONSOLE) # Strip off the rows leaving the columns COLUMNS=${SIZE#*\ } fi COL=$[$COLUMNS - 10] WCOL=$[$COLUMNS - 30] SET_COL="echo -en \\033[${COL}G" SET_WCOL="echo -en \\033[${WCOL}G" NORMAL="echo -en \\033[0;39m" SUCCESS="echo -en \\033[1;32m" WARNING="echo -en \\033[1;33m" FAILURE="echo -en \\033[1;31m" # # The evaluate_retval function evaluates the return value of the process # that was run just before this function was called. If the return value # was 0, indicating success, the print_status function is called with # the 'success' parameter. Otherwise the print_status function is called # with the failure parameter. # evaluate_retval() { if [ $? = 0 ] then print_status success else print_status failure fi } # # The print_status prints [ OK ] or [FAILED] to the screen. OK appears # in the colour defined by the SUCCESS variable and FAILED appears in # the colour defined by the FAILURE variable. Both are printed starting # in the column defined by the COL variable. # print_status() { # # If no parameters are given to the print_status function, print usage # information. # if [ $# = 0 ] then echo "Usage: print_status {success|failure}" return 1 fi case "$1" in success) $SET_COL echo -n "[ " $SUCCESS echo -n "OK" $NORMAL echo " ]" ;; warning) $SET_COL echo -n "[ " $WARNING echo -n "ATTN" $NORMAL echo " ]" ;; failure) $SET_COL echo -n "[" $FAILURE echo -n "FAILED" $NORMAL echo "]" ;; esac } # # The loadproc function starts a process (often a daemon) with # proper error checking # loadproc() { # # If no parameters are given to the print_status function, print usage # information. # if [ $# = 0 ] then echo "Usage: loadproc {program}" exit 1 fi # # Find the basename of the first parameter (the daemon's name without # the path # that was provided so /usr/sbin/syslogd becomes plain 'syslogd' after # basename ran) # base=$(/usr/bin/basename $1) # # the pidlist variable will contains the output of the pidof command. # pidof will try to find the PID's that belong to a certain string; # $base in this case # pidlist=$(/bin/pidof -o $$ -o $PPID -o %PPID -x $base) pid="" for apid in $pidlist do if [ -d /proc/$apid ] then pid="$pid $apid" fi done # # If the $pid variable contains anything (from the previous for loop) it # means the daemon is already running # if [ ! -n "$pid" ] then # # Empty $pid variable means it's not running, so we run "$@" (all # parameters giving to this function from the script) and then check the # return value # "$@" evaluate_retval else # # The variable $pid was not empty, meaning it was already running. We'll # print [ ATTN ] now # $SET_WCOL echo -n "Already running" print_status warning fi } # # The killproc function kills a process with proper error checking # killproc() { # # If no parameters are given to the print_status function, print usage # information. # if [ $# = 0 ] then echo "Usage: killproc {program} [signal]" exit 1 fi # # Find the basename of the first parameter (the daemon's name without # the path # that was provided so /usr/sbin/syslogd becomes plain 'syslogd' after # basename ran) # base=$(/usr/bin/basename $1) # # Check if we gave a signal to kill the process with (like -HUP, -TERM, # -KILL, etc) to this function (the second parameter). If no second # parameter was provided set the nolevel variable. Else set the # killlevel variable to the value of $2 (the second parameter) # if [ "$2" != "" ] then killlevel=-$2 else nolevel=1 fi # # the pidlist variable will contains the output of the pidof command. # pidof will try to find the PID's that belong to a certain string; # $base in this case # pidlist=$(/bin/pidof -o $$ -o $PPID -o %PPID -x $base) pid="" for apid in $pidlist do if [ -d /proc/$apid ] then pid="$pid $apid" fi done # # If $pid contains something from the previous for loop it means one or # more PID's were found that belongs to the processes to be killed # if [ -n "$pid" ] then # # If no kill level was specified we'll try -TERM first and then sleep # for 2 seconds to allow the kill to be completed # if [ "$nolevel" = 1 ] then /bin/kill -TERM $pid # # If after -TERM the PID still exists we'll wait 2 seconds before # trying to kill it with -KILL. If the PID still exist after that, wait # two more seconds. If the PIDs still exist by then it's safe to assume # that we cannot kill these PIDs. # if /bin/ps h $pid >/dev/null 2>&1 then /usr/bin/sleep 2 if /bin/ps h $pid > /dev/null 2>&1 then /bin/kill -KILL $pid if /bin/ps h $pid > /dev/null 2>&1 then /usr/bin/sleep 2 fi fi fi /bin/ps h $pid >/dev/null 2>&1 if [ $? = 0 ] then # # If after the -KILL it still exists it can't be killed for some reason # and we'll print [FAILED] # print_status failure else # # It was killed, remove possible stale PID file in /var/run and # print [ OK ] # /bin/rm -f /var/run/$base.pid print_status success fi else # # A kill level was provided. Kill with the provided kill level and wait # for 2 seconds to allow the kill to be completed # /bin/kill $killlevel $pid if /bin/ps h $pid > /dev/null 2>&1 then /usr/bin/sleep 2 fi /bin/ps h $pid >/dev/null 2>&1 if [ $? = 0 ] then # # If ps' return value is 0 it means it ran ok which indicates that the # PID still exists. This means the process wasn't killed properly with # the signal provided. Print [FAILED] # print_status failure else # # If the return value was 1 or higher it means the PID didn't exist # anymore which means it was killed successfully. Remove possible stale # PID file and print [ OK ] # /bin/rm -f /var/run/$base.pid print_status success fi fi else # # The PID didn't exist so we can't attempt to kill it. Print [ ATTN ] # $SET_WCOL echo -n "Not running" print_status warning fi } # # The reloadproc functions sends a signal to a daemon telling it to # reload it's configuration file. This is almost identical to the # killproc function with the exception that it won't try to kill it with # a -KILL signal (aka -9) # reloadproc() { # # If no parameters are given to the print_status function, print usage # information. # if [ $# = 0 ] then echo "Usage: reloadproc {program} [signal]" exit 1 fi # # Find the basename of the first parameter (the daemon's name without # the path that was provided so /usr/sbin/syslogd becomes plain 'syslogd' # after basename ran) # base=$(/usr/bin/basename $1) # # Check if we gave a signal to send to the process (like -HUP) # to this function (the second parameter). If no second # parameter was provided set the nolevel variable. Else set the # killlevel variable to the value of $2 (the second parameter) # if [ -n "$2" ] then killlevel=-$2 else nolevel=1 fi # # the pidlist variable will contains the output of the pidof command. # pidof will try to find the PID's that belong to a certain string; # $base in this case # pidlist=$(/bin/pidof -o $$ -o $PPID -o %PPID -x $base) pid="" for apid in $pidlist do if [ -d /proc/$apid ] then pid="$pid $apid" fi done # # If $pid contains something from the previous for loop it means one or # more PID's were found that belongs to the processes to be reloaded # if [ -n "$pid" ] then # # If nolevel was set we will use the default reload signal SIGHUP. # if [ "$nolevel" = 1 ] then /bin/kill -SIGHUP $pid evaluate_retval else # # Else we will use the provided signal # /bin/kill $killlevel $pid evaluate_retval fi else # # If $pid is empty no PID's have been found that belong to the process. # Print [ ATTN ] # $SET_WCOL echo -n "Not running" print_status warning fi } # # The statusproc function will try to find out if a process is running # or not # statusproc() { # # If no parameters are given to the print_status function, print usage # information. # if [ $# = 0 ] then echo "Usage: status {program}" return 1 fi # # $pid will contain a list of PID's that belong to a process # pid=$(/bin/pidof -o $$ -o $PPID -o %PPID -x $1) if [ -n "$pid" ] then # # If $pid contains something, the process is running, print the contents # of the $pid variable # echo "$1 running with Process ID $pid" return 0 fi # # If $pid doesn't contain it check if a PID file exists and inform the # user about this stale file. # if [ -f /var/run/$1.pid ] then pid=$(/usr/bin/head -1 /var/run/$1.pid) if [ -n "$pid" ] then echo "$1 not running but /var/run/$1.pid exists" return 1 fi else echo "$1 is not running" fi } # End /etc/init.d/functions EOF
#cat > /etc/init.d/checkfs << "EOF" #!/bin/sh # Begin /etc/init.d/checkfs # # Include the functions declared in the /etc/init.d/functions file # source /etc/init.d/functions # # Activate all the swap partitions declared in the /etc/fstab file # echo -n "Activating swap..." /sbin/swapon -a evaluate_retval # # If the /fastboot file exists we don't want to run the partition checks # if [ -f /fastboot ] then echo "Fast boot, no file system check" else # # Mount the root partition read-only (just in case the kernel mounts it # read-write and we don't want to run fsck on a read-write mounted # partition). # /bin/mount -n -o remount,ro / if [ $? = 0 ] then # # If the /forcefsck file exists we want to force a partition check even # if the partition was unmounted cleanly the last time # if [ -f /forcefsck ] then echo -n "/forcefsck exists, forcing " echo "file system check" force="-f" else force="" fi # # Check all the file systems mentioned in /etc/fstab that have the # fs_passno value set to 1 or 2 (the 6th field. See man fstab for more # info) # echo "Checking file systems..." /sbin/fsck $force -a -A -C -T # # If something went wrong during the checks of one of the partitions, # fsck will exit with a return value greater than 1. If this is # the case we start sulogin so you can repair the damage manually # if [ $? -gt 1 ] then $FAILURE echo echo -n "fsck failed. Please repair your file " echo "systems manually by running /sbin/fsck" echo "without the -a option" echo echo -n "Please note that the root file system " echo "is currently mounted in read-only mode." echo echo -n "I will start sulogin now. When you " echo "logout I will reboot your system." echo $NORMAL /sbin/sulogin /sbin/reboot -f else print_status success fi else # # If the remount to read-only mode didn't work abort the fsck and print # an error # echo -n "Cannot check root file system because it " echo "could not be mounted in read-only mode." fi fi # End /etc/init.d/checkfs EOF
#cat > /etc/init.d/halt << "EOF" #!/bin/sh # Begin /etc/init.d/halt # # Call halt. See man halt for the meaning of the parameters # /sbin/halt -d -f -i -p # End /etc/init.d/halt EOF
#cat > /etc/init.d/loadkeys << "EOF" #!/bin/sh # Begin /etc/init.d/loadkeys # # Include the functions declared in the /etc/init.d/functions file # source /etc/init.d/functions # # Include /etc/sysconfig/keyboard which contains the LAYOUT variable # source /etc/sysconfig/keyboard # # Load the default keymap file # echo -n "Loading keymap..." /bin/loadkeys $LAYOUT 2>/dev/null evaluate_retval # End /etc/init.d/loadkeys EOF
#cat > /etc/sysconfig/keyboard << "EOF" # Begin /etc/sysconfig/keyboard LAYOUT=<path-to-keymap> # End /etc/sysconfig/keyboard EOF ※<path-to-keymap> == /usr/share/kbd/keymaps/i386/qwerty/us.map.gz
#cat > /etc/init.d/mountfs << "EOF" #!/bin/sh # Begin /etc/init.d/mountfs # # Include the functions declared in the /etc/init.d/functions file # source /etc/init.d/functions case "$1" in start) # # Remount the root partition in read-write mode. -n tells mount # not to # write to the /etc/mtab file (because it can't do this. The # root # partition is most likely still mounted in read-only mode # echo -n "Remounting root file system in read-write mode..." /bin/mount -n -o remount,rw / evaluate_retval # # First empty the /etc/mtab file. Then remount root partition # in read-write # mode again but pass -f to mount. This way mount does # everything # except the mount itself. This is needed for it to write to the # mtab # file which contains a list of currently mounted file systems. # echo > /etc/mtab /bin/mount -f -o remount,rw / # # Remove the possible /fastboot and /forcefsck files. they are # only # supposed to be used during the next reboot's checkfs which just # happened. If you want to fastboot or forcefsck again you'll # have to # recreate the files # /bin/rm -f /fastboot /forcefsck # # Walk through /etc/fstab and mount all file systems that don't # have the noauto option set in the fs_mntops field (the 4th # field. # See man fstab for more info) # echo -n "Mounting other file systems..." /bin/mount -a evaluate_retval ;; stop) # # Deactivate all the swap partitions # echo -n "Deactivating swap..." /sbin/swapoff -a evaluate_retval # # And unmount all the file systems, mounting the root file # system # read-only (all are unmounted but because root can't be # unmounted # at this point mount will automatically mount it read-only # which # is what supposed to happen. This way no data can be written # anymore from disk) # echo -n "Unmounting file systems..." /bin/umount -a -r evaluate_retval ;; *) echo "Usage: $0 {start|stop}" exit 1 ;; esac # End /etc/init.d/mountfs EOF
#cat > /etc/init.d/reboot << "EOF" #!/bin/sh # Begin /etc/init.d/reboot # # Call reboot. See man halt for the meaning of the parameters # echo "System reboot in progress..." /sbin/reboot -d -f -i # End /etc/init.d/reboot EOF
#cat > /etc/init.d/sendsignals << "EOF" #!/bin/sh # Begin /etc/init.d/sendsignals # # Include the functions declared in the /etc/init.d/functions file # source /etc/init.d/functions # # Send all the remaining processes the TERM signal # echo -n "Sending all processes the TERM signal..." /sbin/killall5 -15 evaluate_retval # # Send all the remaining process (after sending them the TERM signal # before) the KILL signal. # echo -n "Sending all processes the KILL signal..." /sbin/killall5 -9 evaluate_retval # End /etc/init.d/sendsignals EOF
#cat > /etc/init.d/setclock << "EOF" #!/bin/sh # Begin /etc/init.d/setclock # # Include the functions declared in the /etc/init.d/functions file # and include the variables from the /etc/sysconfig/clock file # source /etc/init.d/functions source /etc/sysconfig/clock # # Right now we want to set the kernel clock according to the hardware # clock, so we use the -hctosys parameter. # CLOCKPARAMS="--hctosys" # # If the UTC variable is set in the /etc/sysconfig/clock file, add the # -u parameter as well which tells hwclock that the hardware clock is # set to UTC time instead of local time. # case "$UTC" in yes|true|1) CLOCKPARAMS="$CLOCKPARAMS --utc" ;; no|false|0) CLOCKPARAMS="$CLOCKPARAMS --localtime" ;; esac echo -n "Setting clock..." /sbin/hwclock $CLOCKPARAMS evaluate_retval # End /etc/init.d/setclock EOF
#cat > /etc/sysconfig/clock << "EOF" # Begin /etc/sysconfig/clock UTC=0 # End /etc/sysconfig/clock EOF
#cat > /etc/init.d/sysklogd << "EOF" #!/bin/sh # Begin /etc/init.d/sysklogd # # Include the functions declared in the /etc/init.d/functions file # source /etc/init.d/functions case "$1" in start) echo -n "Starting system log daemon..." loadproc /usr/sbin/syslogd -m 0 echo -n "Starting kernel log daemon..." loadproc /usr/sbin/klogd ;; stop) echo -n "Stopping kernel log daemon..." killproc klogd echo -n "Stopping system log daemon..." killproc syslogd ;; reload) echo -n "Reloading system log daemon configuration file..." reloadproc syslogd 1 ;; restart) $0 stop /usr/bin/sleep 1 $0 start ;; status) statusproc /usr/sbin/syslogd statusproc /usr/sbin/klogd ;; *) echo "Usage: $0 {start|stop|reload|restart|status}" exit 1 ;; esac # End /etc/init.d/sysklogd EOF
#cat > /etc/init.d/template << "EOF" #!/bin/sh # Begin /etc/init.d/ # # Include the functions declared in the /etc/init.d/functions file # source /etc/init.d/functions case "$1" in start) echo -n "Starting ..." loadproc ;; stop) echo -n "Stopping ..." killproc ;; reload) echo -n "Reloading ..." reloadproc ;; restart) $0 stop /usr/bin/sleep 1 $0 start ;; status) statusproc ;; *) echo "Usage: $0 {start|stop|reload|restart|status}" exit 1 ;; esac # End /etc/init.d/ EOF
#cat > /etc/init.d/localnet << "EOF" #!/bin/sh # Begin /etc/init.d/localnet # # Include the functions declared in the /etc/init.d/functions file # and include the variables from the /etc/sysconfig/network file. # source /etc/init.d/functions source /etc/sysconfig/network case "$1" in start) echo -n "Bringing up the loopback interface..." /sbin/ifconfig lo 127.0.0.1 evaluate_retval echo -n "Setting up hostname..." /bin/hostname $HOSTNAME evaluate_retval ;; stop) echo -n "Bringing down the loopback interface..." /sbin/ifconfig lo down evaluate_retval ;; restart) $0 stop sleep 1 $0 start ;; *) echo "Usage: $0: {start|stop|restart}" exit 1 ;; esac # End /etc/init.d/localnet EOF
#echo "HOSTNAME=lfs" > /etc/sysconfig/network
#cat > /etc/hosts << "EOF" # Begin /etc/hosts (no network card version) 127.0.0.1 www.mydomain.com <value of HOSTNAME> localhost # End /etc/hosts (no network card version) EOF #cat > /etc/hosts << "EOF" # Begin /etc/hosts (network card version) 127.0.0.1 localhost.localdomain localhost 192.168.1.1 www.mydomain.org <value of HOSTNAME> # End /etc/hosts (network card version) EOF
#cat > /etc/init.d/ethnet << "EOF" #!/bin/sh # Begin /etc/init.d/ethnet # # Main script by Gerard Beekmans - gerard@linuxfromscratch.org # GATEWAY check by Jean-Francois Le Ray - jfleray@club-internet.fr # "Specify which IF to use to reach default GATEWAY" by # Graham Cantin - gcantin@pacbell.net # # # Include the functions declared in the /etc/init.d/functions file # and the variables from the /etc/sysconfig/network file. # source /etc/init.d/functions source /etc/sysconfig/network case "$1" in start) # # Obtain all the network card configuration files # for interface in $(/bin/ls /etc/sysconfig/nic-config/ifcfg* | \ grep -v ifcfg-lo) do # # Load the variables from that file # source $interface # # If the ONBOOT variable is set to yes, process this file and bring the # interface up. # if [ "$ONBOOT" == yes ] then echo -n "Bringing up the $DEVICE interface..." /sbin/ifconfig $DEVICE $IP broadcast $BROADCAST \ netmask $NETMASK evaluate_retval fi done # # If the /etc/sysconfig/network file contains a GATEWAY variable, set # the default gateway and the interface through which the default # gateway can be reached. # if [ "$GATEWAY" != "" ]; then echo -n "Setting up routing for $GATEWAY_IF interface..." /sbin/route add default gateway $GATEWAY \ metric 1 dev $GATEWAY_IF evaluate_retval fi ;; stop) # # Obtain all the network card configuration files # for interface in $(/bin/ls /etc/sysconfig/nic-config/ifcfg* | \ grep -v ifcfg-lo) do # # Load the variables from that file # source $interface # # If the ONBOOT variable is set, process the file and bring the # interface down # if [ $ONBOOT == yes ] then echo -n "Bringing down the $DEVICE interface..." /sbin/ifconfig $DEVICE down evaluate_retval fi done ;; restart) $0 stop sleep 1 $0 start ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 ;; esac # End /etc/init.d/ethnet EOF
#cat >> /etc/sysconfig/network << "EOF" GATEWAY=192.168.1.2 GATEWAY_IF=eth0 EOF
#mkdir /etc/sysconfig/nic-config #cat > /etc/sysconfig/nic-config/ifcfg-eth0 << "EOF" ONBOOT=yes DEVICE=eth0 IP=192.168.1.1 NETMASK=255.255.255.0 BROADCAST=192.168.1.255 EOF
#cd /etc/init.d && chmod 754 rc rcS functions checkfs halt loadkeys mountfs reboot && chmod 754 sendsignals setclock sysklogd template && chmod 754 localnet ethnet && cd ../rc0.d && ln -sf ../init.d/ethnet K800ethnet && ln -sf ../init.d/sysklogd K900sysklogd && ln -sf ../init.d/sendsignals S800sendsignals && ln -sf ../init.d/mountfs S900mountfs && ln -sf ../init.d/halt S999halt && cd ../rc6.d && ln -sf ../init.d/ethnet K800ethnet && ln -sf ../init.d/sysklogd K900sysklogd && ln -sf ../init.d/sendsignals S800sendsignals && ln -sf ../init.d/mountfs S900mountfs && ln -sf ../init.d/reboot S999reboot && cd ../rcS.d && ln -sf ../init.d/localnet S100localnet && ln -sf ../init.d/checkfs S200checkfs && ln -sf ../init.d/mountfs S300mountfs && ln -sf ../init.d/setclock S400setclock && ln -sf ../init.d/loadkeys S500loadkeys && cd ../rc1.d && ln -sf ../init.d/ethnet K800ethnet && ln -sf ../init.d/sysklogd K900sysklogd && cd ../rc2.d && ln -sf ../init.d/sysklogd S100sysklogd && ln -sf ../init.d/ethnet K800ethnet && cd ../rc3.d && ln -sf ../init.d/sysklogd S100sysklogd && ln -sf ../init.d/ethnet S200ethnet && cd ../rc4.d && ln -sf ../init.d/sysklogd S100sysklogd && ln -sf ../init.d/ethnet S200ethnet && cd ../rc5.d && ln -sf ../init.d/sysklogd S100sysklogd && ln -sf ../init.d/ethnet S200ethnet
#cat > /etc/fstab << "EOF" # Begin /etc/fstab # location of filesystem mount point fs-type options /dev/*LFS-partition device* / *fs-type* defaults 1 1 /dev/*swap-partition device* swap swap defaults 0 0 proc /proc proc defaults 0 0 # End /etc/fstab EOF
#cd /usr/src/linux && make mrproper && make menuconfig && make dep && make bzImage && make modules && make modules_install && cp arch/i386/boot/bzImage /boot/lfskernel && cp System.map /boot
#logout #cp $LFS/boot/lfskernel /boot #cat >> /etc/lilo.conf << "EOF" image=/boot/lfskernel label=lfs root=<partition> read-only EOF #/sbin/lilo #cp /etc/lilo.conf $LFS/etc && cp <kernel images> $LFS/boot
길고긴 설치 과정이 끝났다. 이제 제대로 부팅이 되는지 확인해본다.