制作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脚本那必须得分析内容并备忘。

 

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
if [ -d "${DESTDIR}/${target}" ]; then 
# check if already copied 
#目录存在并且exe存在则返回 
[ -e "${DESTDIR}/$target/${src##*/}" ] && return
else 
#目录不存在 则创建目录 
[ -e "${DESTDIR}/$target" ] && return
#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 

 

posted @   愤怒的企鹅  阅读(4286)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示