制作initrd(2):update-initramfs和mkinitramfs脚本分析
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脚本那必须得分析内容并备忘。
1 2 3 4 | 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函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 | #!/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目录的制作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | #!/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中用到的几个函数的注释
1 2 3 4 5 6 7 8 9 | 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" } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | # $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 } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!