制作initrd(2):update-initramfs和mkinitramfs腳本分析


http://www.aichengxu.com/diannao/81059.htm

制作initrd(2):update-initramfs和mkinitramfs腳本分析

2015-11-26 01:10 本站整理 瀏覽(90)

制作initrd(2):update-initramfs和mkinitramfs腳本分析,有需要的朋友可以參考下。

 

前一篇文章<制作initrd(1):向initrd內部更新驅動模塊>提到更新initrd.img鏡像時需要運行update-initramfs命令。

起初以為是二進制文件,網上胡亂搜索一通發現update-initramfs和mkinitramfs兩個命令同為腳本文件,既然是shell腳本那必須得分析內容並備忘。

 

root@ubuntu:~# file `which update-initramfs`
/usr/sbin/update-initramfs: POSIX shell script, ASCII text executable
root@ubuntu:~# file `which mkinitramfs`
/usr/sbin/mkinitramfs: POSIX shell script, ASCII text executable

 

總的來說,編譯內核的最后一步執行make install時會調用update-initramfs,update-initramfs繼而調用mkinitramfs生成initrd.img。因此,mkinitramfs是核心腳本,他的作用是啥?如果你有手工做過initrd.img的經歷,一定記得這是一個往臨時initrd目錄copy文件的繁瑣過程,mkinitramfs則用腳本替代了手工操作(真偉大,還把人逼失業了!):

1).在臨時initrd目錄下構建FHS規定的文件系統;

2).按/etc/initramfs-tools/module和/etc/modules文件的配置,往lib/modules/目錄拷貝模塊,同時生成模塊依賴文件modules.dep,以后內核啟動后會從initramfs中(initrd.img被解壓到內存中)按模塊依賴關系modprobe模塊;

3).拷貝/etc/initramfs-tools/scripts和/usr/share/initramfs-tools/scripts下的配置文件到conf/目錄下,以后內核啟動,創建第一個進程init(initrd.img根目錄下init.sh文件)會從conf/*讀取配置,按一定的順序加載模塊/執行程序;

4).模塊的加載離不開modprobe工具集,因此需要拷貝modprobe工具集及其他工具到initrd目錄結構下,同時解決這些工具的依賴關系(依賴的so文件的路徑);

5).所有步驟完成,調用cpio和gzip工具打包壓縮臨時initrd目錄結構。

上面是mkinitramfs整體流程的概括,下面直接貼注釋后腳本,如注釋有誤請在留言欄告訴我,謝謝~

 

首先是update-initramfs腳本,僅注釋了執行update-initramfs -u更新initrd.img時的腳本執行流。腳本的開始定義了一些變量,然后跳去執行L400+之后的while getopts... do--按命令參數設置不同的運行模式。之后,按運行模式,進入不同的函數,以執行update-initramfs -u為例,進入update函數。

 

#!/bin/sh

STATEDIR=/var/lib/initramfs-tools
BOOTDIR=/boot
CONF=/etc/initramfs-tools/update-initramfs.conf
USETRIGGERS=true
mode=""
version=""
update_initramfs=yes
backup_initramfs=no

set -e
#CONF存在且可讀 則source ${CONF}中的設置 即source <span style="font-family: Arial, Helvetica, sans-serif;">/etc/initramfs-tools/update-initramfs.conf文件里的變量</span>

[ -r ${CONF} ] && . ${CONF}

case "$DPKG_MAINTSCRIPT_PACKAGE" in
linux-image-*)
	#INITRAMFS_TOOLS_KERNEL_HOOK 長度為0
	if [ -z "$INITRAMFS_TOOLS_KERNEL_HOOK" ]; then
		# kernel maintainer script called us directly; ignore
		# it and let the hook script handle it instead
		echo "update-initramfs: deferring update (hook will be called later)"
		exit 0
	fi
	;;
?*)
	if	   $USETRIGGERS						\ #USETRIGGERS=true
		&& [ $# = 1 ]						\ #參數數量==1
		&& [ x"$1" = x-u ]					\ #第一個參數是-u
		&& dpkg-trigger --check-supported 2>/dev/null
	then
		if dpkg-trigger --no-await update-initramfs; then
			echo "update-initramfs: deferring update (trigger activated)"
			exit 0
		fi
	fi
	;;
esac
#開始定義一些函數 先搜索getopts,定位到那繼續
usage()
{
	if [ -n "${1:-}" ]; then
		printf "${*}\n\n" >&2
	fi
	cat >&2 << EOF
Usage: ${0} [OPTION]...

Options:
 -k [version]	Specify kernel version or 'all'
 -c		Create a new initramfs
 -u		Update an existing initramfs
 -d		Remove an existing initramfs
 -t		Take over a custom initramfs with this one
 -b		Set alternate boot directory
 -v		Be verbose
 -h		This message

EOF
	exit 1
}

# chroot check
chrooted()
{
	# borrowed from udev's postinst
	if [ "$(stat -c %d/%i /)" = "$(stat -Lc %d/%i /proc/1/root 2>/dev/null)" ]; then
		# the devicenumber/inode pair of / is the same as that of
		# /sbin/init's root, so we're *not* in a chroot and hence
		# return false.
		return 1
	fi
return 0
}

mild_panic()
{
	if [ -n "${1:-}" ]; then
		printf "${*}\n" >&2
	fi
	exit 0
}

panic()
{
	if [ -n "${1:-}" ]; then
		printf "${*}\n" >&2
	fi
	exit 1
}

verbose()
{
	if [ "${verbose}" = 1 ]; then
		printf "${*}\n"
	fi
}

version_exists()
{
	[ -e "${STATEDIR}/${1}" ] && [ -e "${initramfs}" ]
	return $?
}

set_initramfs()
{
	initramfs="${BOOTDIR}/initrd.img-${version}"
}


# backup initramfs while running
backup_initramfs()
{
	[ ! -r "${initramfs}" ] && return 0
	initramfs_bak="${initramfs}.dpkg-bak"
	[ -r "${initramfs_bak}" ] && rm -f "${initramfs_bak}"
	ln -f "${initramfs}" "${initramfs_bak}" \
		|| cp -a "${initramfs}" "${initramfs_bak}"
	verbose "Keeping ${initramfs_bak}"
}

# keep booted initramfs
backup_booted_initramfs()
{
	initramfs_bak="${initramfs}.dpkg-bak"

	# first time run thus no backup
	[ ! -r "${initramfs_bak}" ] && return 0

	# chroot with no /proc
	[ ! -r /proc/uptime ] && rm -f "${initramfs_bak}" && return 0

	# no kept backup wanted
	[ "${backup_initramfs}" = "no" ] && rm -f "${initramfs_bak}" && return 0

	# no backup yet
	if [ ! -r "${initramfs}.bak" ]; then
		mv -f ${initramfs_bak} "${initramfs}.bak"
		verbose "Backup ${initramfs}.bak"
		return 0
	fi

	# keep booted initramfs
	boot_initramfs=
	uptime_days=$(awk '{printf "%d", $1 / 3600 / 24}' /proc/uptime)
	if [ -n "$uptime_days" ]; then
		boot_initramfs=$(find "${initramfs}.bak" -mtime +${uptime_days})
	fi
	if [ -n "${boot_initramfs}" ]; then
		mv -f "${initramfs_bak}" "${initramfs}.bak"
		verbose "Backup ${initramfs}.bak"
		return 0
	fi
	verbose "Removing current backup ${initramfs_bak}"
	rm -f ${initramfs_bak}
}

# nuke generated copy
remove_initramfs_bak()
{
	[ -z "${initramfs_bak:-}" ] && return 0
	rm -f "${initramfs_bak}"
	verbose "Removing ${initramfs_bak}"
}


generate_initramfs()
{
	echo "update-initramfs: Generating ${initramfs}"
	OPTS="-o"
	if [ "${verbose}" = 1 ]; then
		OPTS="-v ${OPTS}"
	fi
	#if分支其實做這兩件事
	#mkinitramfs -o /boot/initrd.img-`uname -r`.new  ${version}
	#mv /boot/initrd.img-`uname -r`.new /boot/initrd.img-`uname -r`
	
	if mkinitramfs ${OPTS} "${initramfs}.new" "${version}"; then
		mv -f "${initramfs}.new" "${initramfs}"
		set_sha1
	else
		mkinitramfs_return="$?"
		remove_initramfs_bak
		rm -f "${initramfs}.new"
		if [ "$mkinitramfs_return" = "2" ]; then
			# minversion wasn't met, exit 0
			exit 0
		fi
		echo "update-initramfs: failed for ${initramfs} with $mkinitramfs_return." >&2
		exit $mkinitramfs_return
	fi
}

# lilo call
run_lilo()
{
	# show lilo errors on failure
	if ! lilo -t  > /dev/null 2>&1 ; then
		echo "ERROR lilo fails for new ${initramfs}:" >&2
		echo
		lilo -t
	fi
	lilo
}

# Invoke bootloader
run_bootloader()
{
	# invoke policy conformant bootloader hooks
	if [ -d /etc/initramfs/post-update.d/ ]; then
		run-parts --arg=${version} --arg=${initramfs} \
			/etc/initramfs/post-update.d/
		return 0
	fi
}

compare_sha1()
{
	sha1sum "${initramfs}" | diff "${STATEDIR}/${version}" - >/dev/null 2>&1
	return $?
}

# Note that this must overwrite so that updates work.
set_sha1()
{
	sha1sum "${initramfs}" > "${STATEDIR}/${version}"
}

delete_sha1()
{
	rm -f "${STATEDIR}/${version}"
}

# ro /boot is not modified
ro_boot_check()
{
	# check irrelevant inside of a chroot
	if [ ! -r /proc/mounts ] || chrooted; then
		return 0
	fi

	boot_opts=$(awk '/boot/{if ((match($4, /^ro/) || match($4, /,ro/)) \
		&& $2 == "/boot") print "ro"}' /proc/mounts)
	if [ -n "${boot_opts}" ]; then
		echo "WARNING: /boot is ro mounted."
		echo "update-initramfs: Not updating ${initramfs}"
		exit 0
	fi
}

get_sorted_versions()
{
	version_list=""

	for gsv_x in "${STATEDIR}"/*; do
		gsv_x="$(basename "${gsv_x}")"
		if [ "${gsv_x}" = '*' ]; then
			return 0
		fi
		worklist=""
		for gsv_i in $version_list; do
			if dpkg --compare-versions "${gsv_x}" '>' "${gsv_i}"; then
				worklist="${worklist} ${gsv_x} ${gsv_i}"
				gsv_x=""
			else
				worklist="${worklist} ${gsv_i}"
			fi
		done
		if [ "${gsv_x}" != "" ]; then
			worklist="${worklist} ${gsv_x}"
		fi
		version_list="${worklist}"
	done

	verbose "Available versions: ${version_list}"
}

set_current_version()
{
	if [ -f /boot/initrd.img-`uname -r` ]; then
		version=`uname -r`
	fi
}

set_linked_version()
{
	linktarget=
	if [ -e /initrd.img ] && [ -L /initrd.img ]; then
		linktarget="$(basename "$(readlink /initrd.img)")"
	fi

	if [ -e /boot/initrd.img ] && [ -L /boot/initrd.img ]; then
		linktarget="$(basename "$(readlink /boot/initrd.img)")"
	fi

	if [ -z "${linktarget}" ]; then
		return
	fi

	version="${linktarget##initrd.img-}"
}

set_highest_version()
{
	get_sorted_versions
	if [ -z "${version_list}" ]; then
		version=
		return
	fi
	set -- ${version_list}
	version=${1}
}

create()
{
	if [ -z "${version}" ]; then
		usage "Create mode requires a version argument"
	fi

	set_initramfs

	if [ "${takeover}" = 0 ]; then
		if version_exists "${version}"; then
			panic "Cannot create version ${version}: already exists"
		fi

		if [ -e "${initramfs}" ]; then
			panic "${initramfs} already exists, cannot create."
		fi
	fi

	generate_initramfs
}

update()
{
	#update_initramfs定義在/etc/initramfs-tools/update_initramfs.conf文件中
	#在本文件開始處被包含進來,值為update_initramfs=yes
	if [ "${update_initramfs}" = "no" ]; then
		echo "update-initramfs: Not updating initramfs."
		exit 0
	fi

	if [ -z "${version}" ]; then
		set_highest_version
	fi

	if [ -z "${version}" ]; then
		set_linked_version
	fi

	if [ -z "${version}" ]; then
		#等效version=`uname -r`
		set_current_version
	fi

	if [ -z "${version}" ]; then
		verbose "Nothing to do, exiting."
		exit 0
	fi
	#initramfs="/boot/initrd.img-`uname -r`"
	set_initramfs

	ro_boot_check

	altered_check

	backup_initramfs
	#准備調用mkinitramfs,進入函數generate_initramfs
	generate_initramfs
	#如果系統中存在/etc/initramfs/post-update.d/,就調用函數run_bootloader,ubuntu12.04並不存在這個目錄
	run_bootloader

	backup_booted_initramfs
}

delete()
{
	if [ -z "${version}" ]; then
		usage "Delete mode requires a version argument"
	fi

	set_initramfs

	if [ "${takeover}" = 0 ]; then
		if [ ! -e "${initramfs}" ]; then
			panic "Cannot delete ${initramfs}, doesn't exist."
		fi

		if ! version_exists "${version}"; then
			panic "Cannot delete version ${version}: Not created by this utility."
		fi
	fi

	altered_check

	echo "update-initramfs: Deleting ${initramfs}"

	delete_sha1

	rm -f "${initramfs}" "${initramfs}.bak"
}

# Check for update mode on existing and modified initramfs
altered_check()
{
	# No check on takeover
	[ "${takeover}" = 1 ] && return 0
	if [ ! -e "${initramfs}" ]; then
		mild_panic "${initramfs} does not exist. Cannot update."
	fi
	if ! compare_sha1; then
		echo "update-initramfs: ${initramfs} has been altered." >&2
		mild_panic "update-initramfs: Cannot update. Override with -t option."
	fi
}

# Defaults
verbose=0
yes=0
# We default to takeover=1 in Ubuntu, but not Debian
takeover=1

##
#可選參數-k和-b后面帶其他參數
#參數存放到flag中,供case判斷
while getopts "k:cudyvtb:h?" flag; do
	case "${flag}" in
	k)
		#-k 后面有值,則保存在OPTARG(-k kernel version)
		version="${OPTARG}"
		;;
	c)
		mode="c"
		;;
	d)
		mode="d"
		;;
	u)
		mode="u"
		;;
	v)
		verbose="1"
		;;
	y)
		yes="1"
		;;
	t)
		takeover="1"
		;;
	b)
		BOOTDIR="${OPTARG}"
		if [ ! -d "${BOOTDIR}" ]; then
			echo "Error: ${BOOTDIR} is not a directory." >&2
			exit 1
		fi
		;;
	h|?)
		usage
		;;
	esac
done
#常見的獲取參數的最后一項的方法
shift $((${OPTIND} - 1))

if [ $# -ne 0 ]; then
	echo "Invalid argument for option -k." >&2
	usage
fi

# Validate arguments
#${mode}為空
if [ -z "${mode}" ]; then
	usage "You must specify at least one of -c, -u, or -d."
fi

#如果輸入-k all 或者/etc/initramfs-tools/update-initramfs中的update_initramfs的值為all
if [ "${version}" = "all" ] \
	|| ( [ "${update_initramfs}" = "all" ] && [ -z "${version}" ] ); then
	: FIXME check for --yes, and if not ask are you sure
	get_sorted_versions
	if [ -z "${version_list}" ]; then
		verbose "Nothing to do, exiting."
		exit 0
	fi

	OPTS="-b ${BOOTDIR}"
	if [ "${verbose}" = "1" ]; then
		OPTS="${OPTS} -v"
	fi
	if [ "${takeover}" = "1" ]; then
		OPTS="${OPTS} -t"
	fi
	if [ "${yes}" = "1" ]; then
		OPTS="${OPTS} -y"
	fi
	for u_version in ${version_list}; do
		verbose "Execute: ${0} -${mode} -k \"${u_version}\" ${OPTS}"
		"${0}" -${mode} -k "${u_version}" ${OPTS}
	done
	exit 0
fi

#只討論update-initramfs -u的情況
case "${mode}" in
	c)
		create
		;;
	d)
		delete
		;;
	u)
		#-u 則調用update函數
		update
		;;
esac

 

如果你耐心夠好,看到這,差不多也該跟着執行流進入到mkinitramfs腳本。update函數的結尾依次執行generate_initramfs函數和mkinitramfs命令。就此進入mkinitramfs腳本。mkinitramfs腳本開始處也是定義一些變量,然后include兩個重要的輔助腳本/usr/share/initramfs-tools/scripts/functions和/usr/share/initramfs-tools/hook-functions。一些重要的函數定義在這兩個腳本中。mkinitramfs在這兩個腳本的輔助下完成了前述臨時initrd目錄的制作

#!/bin/sh

umask 0022
export PATH='/usr/bin:/sbin:/bin'

# Defaults
keep="n"
CONFDIR="/etc/initramfs-tools"
verbose="n"
#如果/bin/busybox文件夾存在 變量BUSYBOXDIR=/bin
test -e /bin/busybox && BUSYBOXDIR=/bin
test -e /usr/lib/initramfs-tools/bin/busybox && BUSYBOXDIR=/usr/lib/initramfs-tools/bin
export BUSYBOXDIR

OPTIONS=`getopt -o c:d:ko:r:v -n "$0" -- "$@"`

# Check for non-GNU getopt
if [ $? != 0 ] ; then echo "W: non-GNU getopt" >&2 ; exit 1 ; fi

eval set -- "$OPTIONS"
#update-initramfs調用mkinitramfs時命令為
#mkinitramfs -o /boot/initrd.img-`uname -r`.new ${version},因此進入-o分支
while true; do
	case "$1" in
	-c)
		compress="$2"
		shift 2
		;;
	-d)
		CONFDIR="$2"
		shift 2
		if [ ! -d "${CONFDIR}" ]; then
			echo "${0}: ${CONFDIR}: Not a directory" >&2
			exit 1
		fi
		;;
	-o)
		#outfile=/boot/initrd.img-`uname -r`.new
		outfile="$2"
		shift 2
		;;
	-k)
		keep="y"
		shift
		;;
	-r)
		ROOT="$2"
		shift 2
		;;
	-v)
		verbose="y"
		shift
		;;
	--)
		shift
		break
		;;
	*)
		echo "Internal error!" >&2
		exit 1
		;;
	esac
done

# For dependency ordered mkinitramfs hook scripts.
#引用這兩處的文件 這是一些幫助函數
. /usr/share/initramfs-tools/scripts/functions
. /usr/share/initramfs-tools/hook-functions

#引用/etc/initramfs-tools/initramfs.conf 這個文件有關於本地啟動或者nfs啟動的信息
. "${CONFDIR}/initramfs.conf"
EXTRA_CONF=''
#/usr/share/initramfs-tools/conf.d/目錄下為空
#/etc/initramfs-tools/initramfs.conf/conf.d/ 目錄下只有resume文件
for i in /usr/share/initramfs-tools/conf.d/* ${CONFDIR}/conf.d/*; do
	[ -e $i ] && EXTRA_CONF="${EXTRA_CONF} $(basename $i \
		| grep '^[[:alnum:]][[:alnum:]\._-]*$' | grep -v '\.dpkg-.*$')";
done
# FIXME: deprecated those settings on mkinitramfs run
# 	 these conf dirs are for boot scripts and land on initramfs
for i in ${EXTRA_CONF}; do
	if [ -e  ${CONFDIR}/conf.d/${i} ]; then
		. ${CONFDIR}/conf.d/${i}
	elif [ -e  /usr/share/initramfs-tools/conf.d/${i} ]; then
		. /usr/share/initramfs-tools/conf.d/${i}
	fi
done

# source package confs
for i in /usr/share/initramfs-tools/conf-hooks.d/*; do
	if [ -e "${i}" ]; then
		. "${i}"
	fi
done
#UMASK 非空 不過沒找到何處設置了這個變量
if [ -n "${UMASK:-}" ]; then
	umask "${UMASK}"
fi
#outfile為空 也不成立
if [ -z "${outfile}" ]; then
	usage
fi

#生成新的空的initrd.img-`uname -r`文件
touch "$outfile"
outfile="$(readlink -f "$outfile")"

# And by "version" we really mean path to kernel modules
# This is braindead, and exists to preserve the interface with mkinitrd
if [ ${#} -ne 1 ]; then
	version="$(uname -r)"
else
	version="${1}"
fi

# Check that we're using a new enough kernel version, first for ourselves,
# then for each of the hooks, which can have a MINKVER variable defined
check_minkver ${version}
check_minkver ${version} /usr/share/initramfs-tools/hooks
check_minkver ${version} ${CONFDIR}/hooks

case "${version}" in
#/lib/modules/*/目錄下除了/以外的文件,這是指除了該目錄下除了子目錄以外的所有文件?
/lib/modules/*/[!/]*)
	;;
/lib/modules/[!/]*)
	version="${version#/lib/modules/}"
	version="${version%%/*}"
	;;
esac

case "${version}" in
*/*)
	echo "$PROG: ${version} is not a valid kernel version" >&2
	exit 1
	;;
esac

# Check userspace and kernel support for compressed initramfs images
if [ -z "${compress:-}" ]; then
	#COMPRESS=gzip gzip壓縮
	compress=${COMPRESS}
else
	COMPRESS=${compress}
fi

if ! command -v "${compress}" >/dev/null 2>&1; then
	compress=gzip
	[ "${verbose}" = y ] && \
		echo "No ${COMPRESS} in ${PATH}, using gzip"
	COMPRESS=gzip
fi

#/boot/config-${version}匹配以config_rd_${COMPRESS%p}開頭
if ! `grep -q -i ^config_rd_${COMPRESS%p} /boot/config-${version}` ; then
	compress=gzip
	[ "${verbose}" = y ] && \
		echo "linux-2.6 misses ${COMPRESS} support, using gzip"
fi

[ "${compress}" = lzop ] && compress="lzop -9"
[ "${compress}" = xz ] && compress="xz -8 --check=crc32"

if [ -d "${outfile}" ]; then
	echo "${outfile} is a directory" >&2
	exit 1
fi
#要編譯內核的版本
MODULESDIR="/lib/modules/${version}"

if [ ! -e "${MODULESDIR}" ]; then
	echo "WARNING: missing ${MODULESDIR}"
	echo "Device driver support needs thus be built-in linux image!"
fi
#檢測模塊依賴性 不存在模塊依賴文件 怎生成
if [ ! -e "${MODULESDIR}/modules.dep" ]; then
	depmod ${version}
fi
#在/tmp下生成名為mkinitramfs_fb9BN這樣的文件
DESTDIR="$(mktemp -d ${TMPDIR:-/tmp}/mkinitramfs_XXXXXX)" || exit 1
chmod 755 "${DESTDIR}"

# do not execute cache_run_scripts() if mounted with noexec
NOEXEC=""
#找到臨時文件的掛載點 fs=/
fs=$(df -P $DESTDIR | tail -1 | awk '{print $6}')
if [ -n "$fs" ] && mount | grep -q "on $fs .*noexec" ; then
	NOEXEC=1
fi

__TMPCPIOGZ="$(mktemp ${TMPDIR:-/tmp}/mkinitramfs-OL_XXXXXX)" || exit 1

DPKG_ARCH=`dpkg --print-architecture`

# Export environment for hook scripts.
#
export MODULESDIR
export version
export CONFDIR
export DESTDIR
export DPKG_ARCH
export verbose
export MODULES
export BUSYBOX
export COMPCACHE_SIZE

# Private, used by 'catenate_cpiogz'.
export __TMPCPIOGZ

#在/tmp/mkinitramfs_fb9BNB文件夾下生成bin conf/conf.d etc lib/modules run sbin scripts /lib/modules/${version}這些文件夾
#這是在制作根文件系統
for d in bin conf/conf.d etc lib/modules run sbin scripts ${MODULESDIR}; do
	mkdir -p "${DESTDIR}/${d}"
done

# Copy the modules.order file in
if [ -f "${MODULESDIR}/modules.order" ]; then
	cp -p "${MODULESDIR}/modules.order" \
		"${DESTDIR}${MODULESDIR}/modules.order"
fi

# MODULES=list case.  Always honour.
for x in "${CONFDIR}/modules" /usr/share/initramfs-tools/modules.d/*; do
	if [ -f "${x}" ]; then
		#add_modules_from_file定義在/usr/share/initramfs-tools/hook-functions中
		#這里就是add_modules_from_file /etc/initramfs-tools/modules
		#/etc/initramfs-tools/modules中含有要添加到initrd鏡像中的modules
		add_modules_from_file "${x}"
	fi
done

# 沒有找到MODULES定義的文件 按注釋MODULES=most
# MODULES=most is default
case "${MODULES}" in
dep)
	dep_add_modules
	;;
most)
	#auto_add_modules仍然定義在/usr/share/initramfs-tools/hook-functions中
	auto_add_modules
	;;
netboot)
	auto_add_modules base
	auto_add_modules net
	;;
list)
	# nothing to add
	;;
*)
	echo "W: mkinitramfs: unsupported MODULES setting: ${MODULES}."
	echo "W: mkinitramfs: Falling back to MODULES=most."
	auto_add_modules
	;;
esac

# Resolve hidden dependencies
hidden_dep_add_modules

# First file executed by linux-2.6
#拷貝init文件,init是系統啟動后進入根文件系統之后啟動的第一個進程
cp -p /usr/share/initramfs-tools/init ${DESTDIR}/init

# add existant boot scripts
#遞歸搜索/usr/share/initramfs-tools/scripts/目錄下所有配置文件(init-top/all_generic_ide udev...),如果文件中不含有"OPTION="字段,
#則在${DESTDIR}/scripts/目錄中創建對應目錄,並把文件拷貝到該目錄中
for b in $(cd /usr/share/initramfs-tools/scripts/ && find . \
	-regextype posix-extended -regex '.*/[[:alnum:]\._-]+$' -type f); do
	option=$(sed '/^OPTION=/!d;$d;s/^OPTION=//;s/[[:space:]]*$//' "/usr/share/initramfs-tools/scripts/${b}")
	[ -z "${option}" ] || eval test -n \"\${$option}\" -a \"\${$option}\" != \"n\" || continue

	[ -d "${DESTDIR}/scripts/$(dirname "${b}")" ] \
		|| mkdir -p "${DESTDIR}/scripts/$(dirname "${b}")"
	cp -p "/usr/share/initramfs-tools/scripts/${b}" \
		"${DESTDIR}/scripts/$(dirname "${b}")/"
done
#對於/etc/initramfs-tools/scripts下的文件使用同樣的操作
for b in $(cd "${CONFDIR}/scripts" && find . \
	-regextype posix-extended -regex '.*/[[:alnum:]\._-]+$' -type f); do
	option=$(sed '/^OPTION=/!d;$d;s/^OPTION=//;s/[[:space:]]*$//' "${CONFDIR}/scripts/${b}")
	[ -z "${option}" ] || eval test -n \"\${$option}\" -a \"\${$option}\" != \"n\" || continue

	[ -d "${DESTDIR}/scripts/$(dirname "${b}")" ] \
		|| mkdir -p "${DESTDIR}/scripts/$(dirname "${b}")"
	cp -p "${CONFDIR}/scripts/${b}" "${DESTDIR}/scripts/$(dirname "${b}")/"
done

echo "DPKG_ARCH=${DPKG_ARCH}" > ${DESTDIR}/conf/arch.conf
#把/etc/initramfs-tools/initramfs.conf拷貝到${DESTDIR}/conf目錄下,
#這個文件涉及本地啟動和nfs啟動,以及加載的驅動MODULES=most
cp -p "${CONFDIR}/initramfs.conf" ${DESTDIR}/conf
for i in ${EXTRA_CONF}; do
	if [ -e "${CONFDIR}/conf.d/${i}" ]; then
		copy_exec "${CONFDIR}/conf.d/${i}" /conf/conf.d
	elif [ -e "/usr/share/initramfs-tools/conf.d/${i}" ]; then
		copy_exec "/usr/share/initramfs-tools/conf.d/${i}" /conf/conf.d
	fi
done

# ROOT hardcoding
if [ -n "${ROOT:-}" ]; then
	echo "ROOT=${ROOT}" > ${DESTDIR}/conf/conf.d/root
fi

if ! command -v ldd >/dev/null 2>&1 ; then
	echo "WARNING: no ldd around - install libc-bin" >&2
	exit 1
fi
#copy_exec定義在hook-functions中
copy_exec /usr/lib/initramfs-tools/bin/wait-for-root /sbin

# module-init-tools
copy_exec /sbin/modprobe /sbin
copy_exec /sbin/rmmod /sbin
mkdir -p "${DESTDIR}/etc/modprobe.d"
#拷貝/etc/modprobe.d/下文件到${DESTDIR}/etc/modprobe.d/下
#這些文件關系到modprobe mod時的行為
cp -a /etc/modprobe.d/* "${DESTDIR}/etc/modprobe.d/"

# util-linux
copy_exec /sbin/blkid /sbin

# workaround: libgcc always needed on old-abi arm
if [ "$DPKG_ARCH" = arm ] || [ "$DPKG_ARCH" = armeb ]; then
	cp -a /lib/libgcc_s.so.1 "${DESTDIR}/lib/"
fi

run_scripts /usr/share/initramfs-tools/hooks optional
run_scripts "${CONFDIR}"/hooks optional

# cache boot run order
if [ -n "$NOEXEC" ]; then
	echo "W: TMPDIR is mounted noexec, will not cache run scripts."
else
	for b in $(cd "${DESTDIR}/scripts" && find . -mindepth 1 -type d); do
		cache_run_scripts "${DESTDIR}" "/scripts/${b#./}"
	done
fi

# generate module deps
#生成模塊依賴文件
depmod -a -b "${DESTDIR}" ${version}
rm -f "${DESTDIR}/lib/modules/${version}"/modules.*map

# make sure that library search path is up to date
#拷貝/etc/ld.so.conf*到initrd目錄結構中對應位置,可執行程序可能依賴非標准路徑下的so文件,
#因此在此調用ldconfig -r分析/${DESTDIR}/etc/ld.so.conf*中列出的非標准搜索路徑,並生成
#緩存文件加速鏈接速度
#ldconfig -r ROOT : 此選項改變應用程序的根目錄為ROOT(是調用chroot函數實現的).選擇此項時,系統默認的配置文件
#/etc/ld.so.conf,實際對應的為 ROOT/etc/ld.so.conf.如用-r /usr/zzz時,打開配置文件 /etc/ld.so.conf時,實際打開的
#是/usr/zzz/etc/ld.so.conf文件.用此選項,可以大大增加動態鏈接庫管理的靈活性
cp -ar /etc/ld.so.conf* "$DESTDIR"/etc/
if ! ldconfig -r "$DESTDIR" ; then
	[ $(id -u) != "0" ] \
	&& echo "ldconfig might need uid=0 (root) for chroot()" >&2
fi

# Apply DSDT to initramfs
if [ -e "${CONFDIR}/DSDT.aml" ]; then
	copy_exec "${CONFDIR}/DSDT.aml" /
fi

# Remove any looping or broken symbolic links, since they break cpio.
[ "${verbose}" = y ] && xargs_verbose="-t"
(cd "${DESTDIR}" && find . -type l -printf '%p %Y\n' | sed -n 's/ [LN]$//p' \
	| xargs ${xargs_verbose:-} -rL1 rm -f)

# dirty hack for armhf's double-linker situation; if we have one of
# the two known eglibc linkers, nuke both and re-create sanity
if [ "$DPKG_ARCH" = armhf ]; then
	if [ -e "${DESTDIR}/lib/arm-linux-gnueabihf/ld-linux.so.3" ] || \
	   [ -e "${DESTDIR}/lib/ld-linux-armhf.so.3" ]; then
		rm -f "${DESTDIR}/lib/arm-linux-gnueabihf/ld-linux.so.3"
		rm -f "${DESTDIR}/lib/ld-linux-armhf.so.3"
		cp -aL /lib/ld-linux-armhf.so.3 "${DESTDIR}/lib/"
		ln -sf /lib/ld-linux-armhf.so.3 "${DESTDIR}/lib/arm-linux-gnueabihf/ld-linux.so.3"
	fi
fi

[ "${verbose}" = y ] && echo "Building cpio ${outfile} initramfs"
(
# work around lack of "set -o pipefail" for the following pipe:
# cd "${DESTDIR}" && find . | cpio --quiet -R 0:0 -o -H newc | gzip >"${outfile}" || exit 1
#這是創建initramfs的最后一步了 調用cpio和gzip 打包並壓縮initramfs目錄
exec 3>&1
eval `
	# http://cfaj.freeshell.org/shell/cus-faq-2.html
	exec 4>&1 >&3 3>&-
	cd  "${DESTDIR}"
	{
		find . 4>&-; echo "ec1=$?;" >&4
	} | {
		cpio --quiet -R 0:0 -o -H newc 4>&-; echo "ec2=$?;" >&4
	} | ${compress} >"${outfile}"
	echo "ec3=$?;" >&4
`
if [ "$ec1" -ne 0 ]; then
	echo "E: mkinitramfs failure find $ec1 cpio $ec2 $compress $ec3"
	exit "$ec1"
fi
if [ "$ec2" -ne 0 ]; then
	echo "E: mkinitramfs failure cpio $ec2 $compress $ec3"
	exit "$ec2"
fi
if [ "$ec3" -ne 0 ]; then
	echo "E: mkinitramfs failure $compress $ec3"
	exit "$ec3"
fi
) || exit 1

if [ -s "${__TMPCPIOGZ}" ]; then
	cat "${__TMPCPIOGZ}" >>"${outfile}" || exit 1
fi

if [ "${keep}" = "y" ]; then
	echo "Working files in ${DESTDIR} and overlay in ${__TMPCPIOGZ}"
else
	rm -rf "${DESTDIR}"
	rm -rf "${__TMPCPIOGZ}"
fi

exit 0

 

最后貼出hook-functions中用到的幾個函數的注釋

    force_load()  
    {  
            manual_add_modules ${@}  
            #調用mkinitramfs時設置DESTDIR=/tmp/mkinitramfs_fb9BNB---一個臨時根文件系統結構,  
            #把/etc/initramfs-tools/modules中讀到的modules加入到/tmp/mkinitramfs_fb9BNB/conf/modules中  
            #前面已經說過update-initramfs -u時會將/etc/initramfs-tools/modules文件中的模塊加入到initrd  
            #文件,作為引導加載modules,看來就是在這實現的  
            echo "${@}" >>"${DESTDIR}/conf/modules"  
    }  

 

    add_modules_from_file()  
    {  
    # Sanity check  
    if [ ! -e "${1}" ]; then  
    echo "W: add_modules_from_file: arg1='${1}' does not exist." >&2  
    return  
    fi  
    #從/etc/initramfs-tools/modules中讀取非注釋的行,模塊名和參數分別讀入module和args  
    #並調用force_load函數  
    grep '^[^#]' ${1} | while read module args; do  
    [ -n "$module" ] || continue  
    force_load "${module}" "${args}"  
    done  
    }  

 

    # $1 = file to copy to ramdisk  
    # $2 (optional) Name for the file on the ramdisk  
    # Location of the image dir is assumed to be $DESTDIR  
    # We never overwrite the target if it exists.  
    #拷貝可執行程序到$DESTDIR對應目錄下,同時解決可執行程序的依賴庫(ldd)  
    copy_exec() {  
    local src target x nonoptlib  
    local libname dirname  
      
      
    src="${1}"  
    #如果$2(可執行程序所在的目錄)為空 則返回$1的值   
    target="${2:-$1}"  
    #可執行程序不存在就return,否則往下執行  
    [ -f "${src}" ] || return 1  
    if [ -d "${DESTDIR}/${target}" ]; then  
    # check if already copied  
    #目錄存在並且exe存在則返回  
    [ -e "${DESTDIR}/$target/${src##*/}" ] && return 0  
    else  
    #目錄不存在 則創建目錄  
    [ -e "${DESTDIR}/$target" ] && return 0  
    #FIXME: inst_dir  
    mkdir -p "${DESTDIR}/${target%/*}"  
    fi  
    #拷貝host系統的exe文件到initrd目錄結構中  
    [ "${verbose}" = "y" ] && echo "Adding binary ${src}"  
    cp -pL "${src}" "${DESTDIR}/${target}"  
    # Copy the dependant libraries  
    #ldd的輸出形式為 xxx ==> yyy  
    #for循環中的第一個sed是提取第3列中的yyy  
    for x in $(ldd ${src} 2>/dev/null | sed -e '  
    /\//!d;/linux-gate/d;/ {s/.*=>[[:blank:]]*[[:blank:]]∗.*/\1/};s/[[:blank:]]*[[:blank:]]∗ (.*)/\1/' 2>/dev/null); do  
      
      
    # Try to use non-optimised libraries where possible.  
    # We assume that all HWCAP libraries will be in tls,  
    # sse2, vfp or neon.  
    nonoptlib=$(echo "${x}" | sed -e 's#/lib/tls∥i686∥sse2∥neon∥vfp.*/lib.∗#/lib/\2#')  
      
    if [ -e "${nonoptlib}" ]; then  
    x="${nonoptlib}"  
    fi  
      
      
    libname=$(basename "${x}")  
    dirname=$(dirname "${x}")  
    # FIXME inst_lib  
    #從host機上拷貝依賴庫到initrd目錄結構中  
    mkdir -p "${DESTDIR}/${dirname}"  
    if [ ! -e "${DESTDIR}/${dirname}/${libname}" ]; then  
    cp -pL "${x}" "${DESTDIR}/${dirname}"  
    [ "${verbose}" = "y" ] && echo "Adding library ${x}" || true  
    fi  
    done  
    }  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM