Linux中国 | Linux.cn - 我们的Linux中文社区

 找回密码
 加入

QQ登录

QQ登录

搜索

学习initrd中的init(一)

热度 7已有 1581 次阅读2010-7-26 15:49 |关键词:initrd 学习 加载 ubuntu 脚本 顺序

在上一篇方案中,讲解了如何查看initrd中的文件。其中init这个文件就是加载initrd时执行的脚本,这里记录了加载时的顺序。最近在看这个,所以分享给大家。如果有介绍得不对的地方,还请大家指点。微笑我用的是ubuntu10.04.下面就是init这个文件的内容。

#!/bin/sh

[ -d /dev ] || mkdir -m 0755 /dev
[ -d /root ] || mkdir -m 0700 /root
[ -d /sys ] || mkdir /sys
[ -d /proc ] || mkdir /proc
[ -d /tmp ] || mkdir /tmp
mkdir -p /var/lock
mount -t sysfs -o nodev,noexec,nosuid none /sys 
mount -t proc -o nodev,noexec,nosuid none /proc 

grep -q '\<quiet\>' /proc/cmdline || echo "Loading, please wait..."

# Note that this only becomes /dev on the real filesystem if udev's scripts
# are used; which they will be, but it's worth pointing out
if ! mount -t devtmpfs -o mode=0755 none /dev; then
	mount -t tmpfs -o mode=0755 none /dev
	mknod -m 0600 /dev/console c 5 1
	mknod /dev/null c 1 3
fi
mkdir /dev/pts
mount -t devpts -o noexec,nosuid,gid=5,mode=0620 none /dev/pts || true
> /dev/.initramfs-tools
mkdir /dev/.initramfs

# Export the dpkg architecture
export DPKG_ARCH=
. /conf/arch.conf

# Set modprobe env
export MODPROBE_OPTIONS="-qb"

# Export relevant variables
export ROOT=
export ROOTDELAY=
export ROOTFLAGS=
export ROOTFSTYPE=
export IPOPTS=
export HWADDR=
export break=
export init=/sbin/init
export quiet=n
export readonly=y
export rootmnt=/root
export debug=
export panic=
export blacklist=
export resume_offset=

# Bring in the main config
. /conf/initramfs.conf
for conf in conf/conf.d/*; do
	[ -f ${conf} ] && . ${conf}
done
. /scripts/functions

# Parse command line options
for x in $(cat /proc/cmdline); do
	case $x in
	init=*)
		init=${x#init=}
		;;
	root=*)
		ROOT=${x#root=}
		case $ROOT in
		LABEL=*)
			ROOT="${ROOT#LABEL=}"

			# support / in LABEL= paths (escape to \x2f)
			case "${ROOT}" in
			*[/]*)
			if [ -x "$(command -v sed)" ]; then
				ROOT="$(echo ${ROOT} | sed 's,/,\\x2f,g')"
			else
				if [ "${ROOT}" != "${ROOT#/}" ]; then
					ROOT="\x2f${ROOT#/}"
				fi
				if [ "${ROOT}" != "${ROOT%/}" ]; then
					ROOT="${ROOT%/}\x2f"
				fi
				IFS='/'
				newroot=
				for s in $ROOT; do
					if [ -z "${newroot}" ]; then
						newroot="${s}"
					else
						newroot="${newroot}\\x2f${s}"
					fi
				done
				unset IFS
				ROOT="${newroot}"
			fi
			esac
			ROOT="/dev/disk/by-label/${ROOT}"
			;;
		UUID=*)
			ROOT="/dev/disk/by-uuid/${ROOT#UUID=}"
			;;
		/dev/nfs)
			[ -z "${BOOT}" ] && BOOT=nfs
			;;
		esac
		;;
	rootflags=*)
		ROOTFLAGS="-o ${x#rootflags=}"
		;;
	rootfstype=*)
		ROOTFSTYPE="${x#rootfstype=}"
		;;
	rootdelay=*)
		ROOTDELAY="${x#rootdelay=}"
		case ${ROOTDELAY} in
		*[![:digit:].]*)
			ROOTDELAY=
			;;
		esac
		;;
	resumedelay=*)
		RESUMEDELAY="${x#resumedelay=}"
		;;
	loop=*)
		LOOP="${x#loop=}"
		;;
	loopflags=*)
		LOOPFLAGS="-o ${x#loopflags=}"
		;;
	loopfstype=*)
		LOOPFSTYPE="${x#loopfstype=}"
		;;
	cryptopts=*)
		cryptopts="${x#cryptopts=}"
		;;
	nfsroot=*)
		NFSROOT="${x#nfsroot=}"
		;;
	netboot=*)
		NETBOOT="${x#netboot=}"
		;;
	ip=*)
		IPOPTS="${x#ip=}"
		;;
	hwaddr=*)
		HWADDR="${x#hwaddr=}"
		;;
	boot=*)
		BOOT=${x#boot=}
		;;
	resume=*)
		RESUME="${x#resume=}"
		;;
	resume_offset=*)
		resume_offset="${x#resume_offset=}"
		;;
	noresume)
		noresume=y
		;;
	panic=*)
		panic="${x#panic=}"
		case ${panic} in
		*[![:digit:].]*)
			panic=
			;;
		esac
		;;
	quiet)
		quiet=y
		;;
	ro)
		readonly=y
		;;
	rw)
		readonly=n
		;;
	debug)
		debug=y
		quiet=n
		exec >/dev/.initramfs/initramfs.debug 2>&1
		set -x
		;;
	debug=*)
		debug=y
		quiet=n
		set -x
		;;
	break=*)
		break=${x#break=}
		;;
	break)
		break=premount
		;;
	blacklist=*)
		blacklist=${x#blacklist=}
		;;
	netconsole=*)
		netconsole=${x#netconsole=}
		;;
	esac
done

if [ -z "${noresume}" ]; then
	export resume=${RESUME}
else
	export noresume
fi

[ -n "${netconsole}" ] && modprobe netconsole netconsole=${netconsole}

maybe_break top

# export BOOT variable value for compcache,
# so we know if we run from casper
export BOOT

# Don't do log messages here to avoid confusing usplash
run_scripts /scripts/init-top

maybe_break modules
log_begin_msg "Loading essential drivers..."
load_modules
log_end_msg

maybe_break premount
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-premount"
run_scripts /scripts/init-premount
[ "$quiet" != "y" ] && log_end_msg

maybe_break mount
log_begin_msg "Mounting root file system..."
. /scripts/${BOOT}
parse_numeric ${ROOT}
mountroot
log_end_msg

maybe_break bottom
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-bottom"
run_scripts /scripts/init-bottom
[ "$quiet" != "y" ] && log_end_msg

# Move virtual filesystems over to the real filesystem
mount -n -o move /sys ${rootmnt}/sys
mount -n -o move /proc ${rootmnt}/proc

# Check init bootarg
if [ -n "${init}" ] && [ ! -x "${rootmnt}${init}" ]; then
	echo "Target filesystem doesn't have ${init}."
	init=
fi

# Search for valid init
if [ -z "${init}" ] ; then
	for init in /sbin/init /etc/init /bin/init /bin/sh; do
		if [ ! -x "${rootmnt}${init}" ]; then
			continue
		fi
		break
	done
fi

# No init on rootmount
if [ ! -x "${rootmnt}${init}" ]; then
	panic "No init found. Try passing init= bootarg."
fi

# Confuses /etc/init.d/rc
if [ -n ${debug} ]; then
	unset debug
fi

# Chain to real filesystem
maybe_break init
exec run-init ${rootmnt} ${init} "$@" <${rootmnt}/dev/console >${rootmnt}/dev/console 2>&1
panic "Could not execute run-init."

这章主要是介绍前面几行内容:

#!/bin/sh

[ -d /dev ] || mkdir -m 0755 /dev
[ -d /root ] || mkdir -m 0700 /root
[ -d /sys ] || mkdir /sys
[ -d /proc ] || mkdir /proc
[ -d /tmp ] || mkdir /tmp
mkdir -p /var/lock
mount -t sysfs -o nodev,noexec,nosuid none /sys 
mount -t proc -o nodev,noexec,nosuid none /proc 

第一行是介绍说用bash执行这个脚本,在fedora中这行是#!/bin/nash.nash是linux内核引导initrd中常用的一个简单的类似shell的工具,它只能执行一些内嵌的命令,如mount,mkdir等。之所以fedora使用nash,是不想initrd太大了。

下面的代码就是要建立目录,其中/proc和/sys是kernel必需的。所以下面的内容主要就是讲解这个两个目录。

1. /proc

这个目录主要是用来挂载系统文件中的proc的。proc主要用来存储所有开机后硬件,process相关信息的,全名为process file system.

我们可以查看一下/proc下的文件有哪些

root@alice-desktop:/tmp/initrd/etc# ls /proc
1     1334  1550  1617  1661  1710  18    233  316   38    535  788  928        driver       kmsg           mtrr          sys                zoneinfo
10    1362  1581  1618  1667  1711  1801  234  32    3859  6    8    acpi       execdomains  kpagecount     net           sysrq-trigger
1084  1365  1585  1619  1669  1721  1829  24   3345  4     638  834  asound     fb           kpageflags     pagetypeinfo  sysvipc
11    14    1588  1620  1671  1723  19    251  3413  41    666  839  buddyinfo  filesystems  latency_stats  partitions    timer_list
1102  1469  1589  1622  1673  1725  1989  252  3418  42    672  844  bus        fs           loadavg        sched_debug   timer_stats
12    1487  1592  1623  1675  1728  1990  27   3422  43    684  845  cgroups    interrupts   locks          schedstat     tty
1276  1490  1593  1626  1686  1730  2     28   35    432   7    848  cmdline    iomem        mdstat         scsi          uptime
13    1492  16    1643  1689  1732  20    29   37    433   707  849  cpuinfo    ioports      meminfo        self          version
1312  1493  1600  1647  1697  1736  21    3    3752  44    711  854  crypto     irq          misc           slabinfo      version_signature
1323  15    1602  1653  17    1737  22    30   3753  45    715  855  devices    kallsyms     modules        softirqs      vmallocinfo
1328  1524  1607  1655  1708  1782  23    31   3754  46    719  9    diskstats  kcore        mounts         stat          vmmemctl
1330  1532  1616  1658  1709  1787  232   311  3770  5     728  925  dma        key-users    mpt            swaps         vmstat

目录下的一些数字就是系统在运行时中内存的process ID, 我们可以有ps来查看一下这里面的内容:

root@alice-desktop:/tmp/initrd/etc# ps ax|grep 1532
 1532 ?        Sl     0:00 /usr/bin/gnome-keyring-daemon --daemonize --login
 3877 pts/0    S+     0:00 grep --color=auto 1532
root@alice-desktop:/tmp/initrd/etc# ps ax|grep 1608
 3879 pts/0    S+     0:00 grep --color=auto 1608

当系统运行时,不论有多少process,都会在/proc下建立相应的目录。

/proc/partitions是用来记录硬盘分区的

root@alice-desktop:/tmp/initrd/etc# cat /proc/partitions
major minor  #blocks  name

   8        0   20971520 sda
   8        1   20237312 sda1
   8        2          1 sda2
   8        5     731136 sda5

每一项有两个名称,一个是major,一个是minor.major是从广义上来分的,因为同一个硬盘上的所有分区都是由主板上的SCSI controller管理的,所以所有分区的major都是8.

2. /sys

ls /sys/
block  bus  class  dev  devices  firmware  fs  kernel  module  power

/sys/block是以块设备分类,比如常使用的硬盘,内存和磁盘驱动器

root@alice-desktop:/tmp/initrd/etc# ls /sys/block
fd0    loop1  loop3  loop5  loop7  ram1   ram11  ram13  ram15  ram3  ram5  ram7  ram9  sr0
loop0  loop2  loop4  loop6  ram0   ram10  ram12  ram14  ram2   ram4  ram6  ram8  sda   sr1
这里讲解一下loop这个设备。这个设备是用来挂载文件,把文件当成是块设备来用的。比如你可将一个img文件挂载到/mnt.然后你就可以img操作了。

在fedora中,initrd在自己的目录下创建空的/proc和/sys,当kernel加载完成后,会在里面创建相应的文件。这个与ubuntu不同。

mount -t sysfs -o nodev,noexec,nosuid none /sys 
mount -t proc -o nodev,noexec,nosuid none /proc
上面这段代码就是将相应的系统文件挂载到已经创建好的目录当中。

本文系雪雪原创,版权归雪雪及Linux中国所有,转贴请注明。

发表评论 评论 (6 个评论)

回复 neoman 2010-7-26 19:18
期待下期。。
回复 DeadFire 2010-7-26 20:28
嗯,写的挺好。
回复 wxy 2010-7-26 21:33
是雪雪原创的么?学习的很深入啊。
回复 雪雪 2010-7-27 09:30
wxy: 是雪雪原创的么?学习的很深入啊。
是我的原创,想从底层的东西开始学起,重新好好系统的学习。
回复 wxy 2010-7-27 09:58
雪雪: 是我的原创,想从底层的东西开始学起,重新好好系统的学习。
这种学习态度真不错。
PS,如果是你原创的,建议你勾选“原创”选项。:》
回复 fuhualiang 2011-1-14 12:38

facelist

你需要登录后才可以评论 登录 | 加入

无觅相关文章插件