리눅스 부팅 과정

리눅스를 이해하기 위해 우선 부팅과정부터 차근히 살펴 가봅시다

1. 초기 부팅과정 - Lilo

우선 리눅스가 초기에 부팅될때에 흔히들
lilo라는 부트 로더를 사용하고 있습니다

1.1 lilo

실행 명령 : /sbin/lilo - install boot loader
환경 설정 : /etc/lilo.conf

이 lilo에서 우리는 선택적으로 커널을 로딩할 수 있습니다.
그래서, 도스를 로딩 할 것인지 linux를 로딩할것인지를 부팅할때마다
선택 할 수 있게 해주지요.

이 lilo에서 우리는 linux 커널 이미지를 불러오게 됩니다.
일반적으로 lilo에서 커널을 로딩하는 것은 /vmlinuz를 통하게 되어있지만
경우에 따라서는 /boot/vmlinuz를 부르기도 하고, 한 컴퓨터에
두개 이상의 커널을 가지고 있을 경우에는 환경 설정화일을 편집함으로써
선택할 수 있습니다.

만약 lilo 실행중에 'li'라고만 출력되고 멈춘다거나 'lil'까지만 출력되고
멈춘다거나 하는 경우가 있는데, 이 경우 출력된 글자의 갯수를 보고
어떤 부분에서 문제가 발생해서 멈춘것인지 짐작할 수 있게 됩니다.
자세한 것은 관련 문서를 찾아 보십시요.



2. 커널 로딩

자, 이제 우리는 lilo에서 리눅스 커널을 로딩하도록 합시다.
그러면, 이제 커널의 압축이 풀리고(1), 커널이 로딩됩니다.
(리눅스 커널은 압축된 형태로 저장되어있습니다)
커널 로딩과정은 해당 커널을 컴파일 하는 방법에 따라 다르게 됩니다.
커널 컴파일 부분에서 make config부분을 참고 하시기 바랍니다.



3. inittab

그러면 이제 커널의 로딩이 끝나면 커널은
/etc/inittab 화일을 참고해서 부팅과정을 계속 진행시킵니다.  

3.1 inittab

설정 화일 : /etc/inittab
이 화일을 열어보면 각 줄이 4개의 필드로 구성되어 있음을 확인할수 있습니다
('#'문자로 시작하는 부분은 주석 부분입니다.)
각 필드를 설명하면 아래와 같습니다.



id:runlevels:action:process
id : 1-4개의 글자로 이루어진 고유이름(identifies)입니다.
runlevel : 현재의 runlevel과 이곳에 기술된 숫자가 같으면 뒷부분을
수행하게 됩니다.
action : 적절한 행동을 기술해 줍니다.
(respawn,wait,once,boot,bootwait,off,ondemand,initdefault,
sysinit,powerwait,powerfail,powerokwait,powerfailnow,
ctrlaltdel,kbrequest가 올수 있습니다.)
process : 실행시킬 프로세서를 명시해 줍니다.



여기서 runlevel은 다시 7가지가 있습니다.
0 - 시스템 종료(halt) 되는 상태
1 - Root User만 시스템을 사용할 수 있는 Single user mode
2 - 네트웍이 안되는 Multiuser
3 - Full multiuser mode
4 - 사용자 정의를 위해 비어있음
5 - X 윈도우가 실행되는 상태
6 - 시스템을 껏다켬 (Reboot)


이 runlevel은 참 재미 있는 개념입니다.
컴퓨터라는 물건이 갖을 수 있는 상태를 모두 6가지 상태로 정의한것입니다
즉, '꺼져 있는 상태', 'Root만 쓰는 상태', '네트웍이 안되는 다중사용자 상태',
'모든 기능이 다되는 다중사용자 상태', 'X가 실행되는 상태', '껏다켜지는 상태'
로 말이죠...

(4번 runlevel은 사용자가 자기마음대로 정의해서 쓸 수 있도록 비워놓은
것입니다. 뭐, '게임에 최적화 상태'등을 정의해서 쓰면 좋겠죠? ^^;;)

그래서 리눅스는 커널이 로드되는 순간부터 runlevel을 갖게 되는 것이구요,
각 runlevel에서 해야할 일들을 적어 놓는 것이 inittab이 하는 일입니다.
이후에 설명하게 될 rc도 이 runlevel의 개념을 갖고서 보셔야 합니다.



inittab을 설명하기 위해 예제를 봅시다

---- 인용 시작 ----

[root@mind /etc]# pwd

/etc

[root@mind /etc]# cat inittab | grep "^[^#]"

id:5:initdefault:

si::sysinit:/etc/rc.d/rc.sysinit

l0:0:wait:/etc/rc.d/rc 0

l1:1:wait:/etc/rc.d/rc 1

l2:2:wait:/etc/rc.d/rc 2

l3:3:wait:/etc/rc.d/rc 3

l4:4:wait:/etc/rc.d/rc 4

l5:5:wait:/etc/rc.d/rc 5

l6:6:wait:/etc/rc.d/rc 6

ud::once:/sbin/update

ca::ctrlaltdel:/sbin/shutdown -t3 -r now

pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"

pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"

1:2345:respawn:/sbin/mingetty tty1

2:2345:respawn:/sbin/mingetty tty2

3:2345:respawn:/sbin/mingetty tty3

4:2345:respawn:/sbin/mingetty tty4

5:2345:respawn:/sbin/mingetty tty5

6:2345:respawn:/sbin/mingetty tty6

x:5:respawn:/etc/X11/prefdm -nodaemon

[root@mind /etc]#

---- 인용 끝 ----

(보기 편하게 하기 위해서 주석을 뺐습니다)
커널은 우선 처음 부팅시의 runlevel값을 얻기 위해
action필드가 initdefault인 것의 runlevel값을 취합니다.
즉, 이 예에서는
id:5:initdefault:
에 의해 5가 됩니다.
즉, 컴퓨터가 켜지고 커널이 로드되었을때 처음 runlevel은 5가 되며,
그 의미는 '이 컴퓨터는 X가 실행되고 있는 컴퓨터이다'라는 의미가 됩니다.

그다음에는 inittab화일중에 runlevel필드에 '5'가 있는 것은
주어진 action값의 방식으로 모두 수행하게 됩니다.
(단, 위의 예에서는
si::sysinit:/etc/rc.d/rc.sysinit
에 의해 runlevel에 관계없이 /etc/rc.d/rc.sysinit 스크립트가
먼저 한번 실행되어 시스템을 초기화(sysinit)를 하게 됩니다.)



3.1.1 /etc/rc.d/rc.sysinit

실행 화일 : /etc/rc.d/rc.sysinit
이 화일은 시스템에 프로그램이 실행되는데 기본적으로 필요한 작업을
수행합니다.
(화일을 분석해 보면
기본적인 path 설정, 여러 Config data 로드, keymap로드, system font 로드,
swapping 시작, hostname 설정, NIS 설정, ISA PNP 설정,
root filesystem mounting, Quota 체크, Module들의 의존성 검사,
RAID 장치 작동, filesystem 체크&마운트
등의 일을 하게 됩니다.)



다음은 runlevel 항목에 5가 있는 것들입니다

l5:5:wait:/etc/rc.d/rc 5

pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelle

d"

1:2345:respawn:/sbin/mingetty tty1

2:2345:respawn:/sbin/mingetty tty2

3:2345:respawn:/sbin/mingetty tty3

4:2345:respawn:/sbin/mingetty tty4

5:2345:respawn:/sbin/mingetty tty5

6:2345:respawn:/sbin/mingetty tty6

x:5:respawn:/etc/X11/prefdm -nodaemon

을 수행하게 되는데요.
여기서 '/etc/rc.d/rc 5'가 수행되고, 곧이어 '/sbin/mingetty tty1~6'이
실행되고, '/etc/X11/prefdm -nodaemon'이 실행됨을 알 수 있습니다.
(주의 깊게 보시면 가장 많이 사용하게되는 runlevel 3과 5의 차이는
끝에 있는 prefdm이 실행되느냐 안되느냐의 차이라는 것을 아실겁니다.)
(mingetty는 우리가 흔히 아는 login 화면이라고 생각하시면 될듯(?))
이렇게 하고나면 inittab의 할일은 모두 끝나는 것입니다.



3.1.2 /etc/rc.d/rc 5

실행 화일 : /etc/rc.d/rc
Arguments : 0 1 2 3 4 5 6 중의 하나 (runlevel값)

이것은 현제의 runlevel에서 실행되어야 할 프로그램들을 실행시켜주는
기능을 합니다.
우리가 알고 있는 부팅시에 실행되는 프로그램들은 모두 이 rc에서
실행 시켜주는 것입니다.

/etc/rc.d/rc 5

라고 하면
'지금 runlevel이 5이니 runlevel이 5일때
실행되어야 할 프로그램들을 실행시켜라'
라는 의미가 됩니다.

/etc/rc.d/rc 화일을 분석해 보면,

여러가지 기능을 갖고 있지만, 가장 중요한 기능은
앞에서도 말했듯이, '프로그램 실행'입니다.
이 경우 Argument로 5값이 들어오게 되면

/etc/rc.d/rc5.d

아래에 있는 모든 화일을 한번씩 실행시키게 됩니다.
같은 방식으로 Argument가 3이 들어오게 되면

/etc/rc.d/rc3.d

아래에 있는 모든 화일을 한번씩 실행시키게 되고요,
또 같은 방식으로 Argument가 0이 되면 '시스템을 꺼라' 라는 의미이므로

/etc/rc.d/rc0.d

아래의 모든 화일을 한번씩 실행하게 됩니다.
즉, 이경우는 컴퓨터를 끄기 전에 수행해야 할 스크립트들을

'/etc/rc.d/rc0.d'에 모아두면 되는 것입니다.

자 여기서 /etc/rc.d이하의 디렉토리들을 살펴 봅시다.

---- 인용 시작 ----

[root@mind rc.d]# pwd

/etc/rc.d

[root@mind rc.d]# ls

init.d/ rc.local* rc.sysinit* rc1.d/ rc3.d/ rc5.d/

rc* rc.local.mine* rc0.d/ rc2.d/ rc4.d/ rc6.d/

[root@mind rc.d]#

---- 인용 끝 ----

보시면, init.d, rc0.d, rc1.d, rc2.d, rc3.d, rc4.d, rc5.d, rc6.d
이렇게 8개가 있습니다.

그런데, 이상한 것이 있지요?
rc0.d ... rc6.d까지는 이해가 되는데 init.d는 뭘까요?

3.1.3 /etc/rc.d/init.d

init.d 디렉토리를 이해 하기 위해서
우선 앞에서 사용하던 runlevel이 5인 경우를 계속해서 살펴 봅시다.
runlevel이 5일때 실행될 프로그램이 저장된 rc5.d 디렉토리를 살펴 봅시다.

---- 인용 시작 ----

[root@mind rc5.d]# pwd

/etc/rc.d/rc5.d

[root@mind rc5.d]# ls

K08autofs@ K35dhcpd@ S11portmap@ S60lpd@ S85sound@

K10xntpd@ K35smb@ S15netfs@ S72amd@ S90mysql@

K15ircd@ K60mars-nwe@ S20random@ S75keytable@ S90xfs@

K20bootparamd@ K80nscd@ S30syslog@ S80sendmail@ S99linuxconf@

K20nfs@ K88ypserv@ S40atd@ S85gpm@ S99local@

K25squid@ K96pcmcia@ S40crond@ S85httpd@

K30mcserv@ S05apmd@ S50inet@ S85postgresql@

K34yppasswdd@ S10network@ S55named@ S85proftpd@

[root@mind rc5.d]#

---- 인용 끝 ----

이 디렉토리를 보면 모두 링크(link) 화일임을 확인할 수 있습니다.
(Link에 대해 여기서는 설명하지 않겠습니다.)
그럼 이제 이 링크 들이 어디에 링크 되어있는지 살펴 봅시다.

---- 인용 시작 ---

[root@mind rc5.d]# pwd

/etc/rc.d/rc5.d

[root@mind rc5.d]# ls -l | gawk ' /-/ {print $9 " " $10 " " $11} '

K08autofs -> ../init.d/autofs*

K10xntpd -> ../init.d/xntpd*

K15ircd -> ../init.d/ircd*

K20bootparamd -> ../init.d/bootparamd*

K20nfs -> ../init.d/nfs

K25squid -> ../init.d/squid*

K30mcserv -> ../init.d/mcserv*

K34yppasswdd -> ../init.d/yppasswdd

K35dhcpd -> ../init.d/dhcpd

K35smb -> ../init.d/smb

K60mars-nwe -> ../init.d/mars-nwe*

K80nscd -> ../init.d/nscd*

K88ypserv -> ../init.d/ypserv

K96pcmcia -> ../init.d/pcmcia

S05apmd -> ../init.d/apmd*

S10network -> ../init.d/network*

S11portmap -> ../init.d/portmap*

S15netfs -> ../init.d/netfs*

S20random -> ../init.d/random*

S30syslog -> ../init.d/syslog*

S40atd -> ../init.d/atd*



S40crond -> ../init.d/crond*

S50inet -> ../init.d/inet*

S55named -> ../init.d/named*

S60lpd -> ../init.d/lpd*

S72amd -> ../init.d/amd*

S75keytable -> ../init.d/keytable*

S80sendmail -> ../init.d/sendmail*

S85gpm -> ../init.d/gpm*

S85httpd -> ../init.d/httpd*

S85postgresql -> ../init.d/postgresql

S85proftpd -> ../init.d/proftpd*

S85sound -> ../init.d/sound*

S90mysql -> ../init.d/mysql

S90xfs -> ../init.d/xfs*

S99linuxconf -> ../init.d/linuxconf*

S99local -> ../rc.local*

[root@mind rc5.d]#

---- 인용 끝 ----

(ls 부분은 그냥 알아 보기 쉽게 하기 위해 gawk을 사용했습니다.
초보자 분들은 그냥 'ls -l' 해서 확인해 보시면 됩니다.
gawk에 대해 여기서는 설명하지 않겠습니다.)
위와 같습니다.
rc0.d와 rc1.d, rc2.d, rc3.d, rc4.d, rc6.d의 경우도 마찬가지로
모두 init.d에 실제 화일을 두고 있고 모두 링크 되어있음을
확인 하실 수 있을 겁니다.
왜 이런식이냐하면, 부팅시 실행되는 samba 써버 스크립트의 예를들면
runlevel이 3일때 실행될 samba 스크립트와
runlevel이 5일때 실행될 samba 스크립트가 특별히 다를 이유가 없기
때문에 중복을 줄이기 위해 위와 같은 방식을 사용하는 것입니다.
runlevel이 0, 1, 2, 4, 6의 경우도 마찬가지 입니다.
그런데, 여기서 또 한가지 주의해야 할것이 있습니다.
바로 실행 순서 입니다.
다시 위의 samba 써버 스크립트의 예를 들어봅시다.

K35smb -> ../init.d/smb

가 바로 samba 시작및 종료 스크립트 입니다.
여기서 실제 스크립트 이름은 단지 smb인데,
link화일은 앞에 'K35'가 붙어서 'K35smb'입니다.
이것은 무슨 뜻인고하니,
앞에서 설명한 rc 스크립트가 프로그램을 실행시키는 순서를 의미합니다
다시말해 rc 스크립트가 runlevel 5일때 /etc/rc.d/rc5.d아래의
스크립트들을 모두 실행시키는데 있어 실행 순서를 의미하며,
이 실행 순서는 알파벳 순서 입니다.
쭉~ 살펴 보시면 K??와 S??가 있습니다. 같은 K로 시작하는 것들끼리는
뒤에 오는 숫자가 낮은 것이 먼저 실행되고요, S도 마찬가집니다.

그리고, 짐작하시다시피 K와 S간의 실행순서는 K가 먼저 실행된후
S가 실행됩니다.
그리고 이 순서를 의미하는 앞의 세글자가 모두 같은 경우,
예를 들어 아래와 같은 경우

---- 인용 시작 ----

[root@mind rc5.d]# pwd

/etc/rc.d/rc5.d

[root@mind rc5.d]# ls S40*

S40atd@ S40crond@

[root@mind rc5.d]#

---- 인용 끝 ----

atd와 crond 간의 실행 우선순위는 없는 경우 입니다.
즉 atd와 crond는 어느 것이 먼저 실행되어도 상관 없다는 것이지요..
이 실행 순서는 각 runlevel 마다 달라지게 됩니다...
그렇기 때문에 더더욱 init.d를 사용해서 link해서 쓰게 되는 겁니다.
(제 말솜씨가 부족해서 이해가 가실지... ^_^;;)
그리고, /etc/rc.d/init.d 아래에 있는 스크립트들은 모두 공통된
방식으로 실행및 실행 종료 됩니다.
다시 samba 서버 스크립트의 예를 들면,
이 samba 서버 스크립트를 실행시키기 위해서는 아래와 같이 해야합니다.

---- 인용 시작 ----

[root@mind rc5.d]# pwd

/etc/rc.d/rc5.d

[root@mind rc5.d]# ./K35smb

Usage: smb {start|stop|restart|status}

[root@mind rc5.d]#



---- 인용 끝 ----

와 같이 하면 위와 같은 에러가 뜹니다.
즉, /etc/rc.d/init.d 아래에 모여 있는 스크립트들은
모두 실행시에는 Argument로 'start'를, 종료시에는 'stop'을
넘겨 주어야 하는 것입니다.
(경우에 따라서는 restart나 status도 Argument로 줄 수 있습니다.)
이것 참 편리하겠지요?
samba 써버 실행 스크립트와 종료 스크립트가 하나의 스크립트로 되잖아요

4. 부팅끝 컴퓨터 사용 시작 그리고 시스템 종료

자 이제, 부팅 과정에 대한 설명은 여기까지가 끝입니다.
알고 보면 간단하지요?
정리 해보면,
lilo -> kernel로딩 -> inittab -> 시스템 종료
이구요. inittab에서는 다시
초기 runlevel 읽기 -> runlevel에 따른 프로그램 실행
이구요.
이렇게 컴퓨터를 잘 쓰다가 runlevel 값을 0으로 바꿔주기만하면
시스템은 꺼지는 절차를 거쳐서 꺼지게 됩니다.
(아마도 이것은 '/sbin/shutdown now' 등의 명령으로 runlevel을 0으로
바꿔주게 되는거겠죠?
물론 '/sbin/reboot'라고 하면 runlevel 값이 6이 되는거겠죠...)
이제 Linux Box가 어떻게 동작하게 되는지 감이 잡히시죠? ^_^

<출저 : 나우누리 리눅스 동호회>

<글쓴이 : jhkwak (곽재혁)

'KB > linux' 카테고리의 다른 글

리눅스 커널 부팅 과정  (0) 2006.06.16
임베디드 리눅스 포팅  (0) 2006.06.15
Linux Time Slice  (0) 2006.06.14
Linux Kernel 문서 모음  (0) 2006.06.13
Using as The GNU Assembler  (0) 2006.06.12

+ Recent posts