http://www.aichengxu.com/diannao/81059.htm
制作initrd(2):update-initramfs和mkinitramfs腳本分析
制作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 }