我是靠谱客的博主 凶狠星月,这篇文章主要介绍Openwrt 系统初始化分析,现在分享给大家,希望可以做个参考。

openwrt固件启动后,进入uboot,加载内核,启动init进程,而init进程包含在procd进程中,启动代码如下:

复制代码
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
int main(int argc, char **argv) { pid_t pid; sigaction(SIGTERM, &sa_shutdown, NULL); sigaction(SIGUSR1, &sa_shutdown, NULL); sigaction(SIGUSR2, &sa_shutdown, NULL); early();//初始化根文件系统中的需要的文件和设置,early.c cmdline(); //从proc/cmdline获取命令行启动参数 watchdog_init(1); //初始化watchdog, watchdog.c pid = fork(); if (!pid) { char *kmod[] = { "/sbin/kmodloader", "/etc/modules-boot.d/", NULL }; if (debug < 3) { int fd = open("/dev/null", O_RDWR); if (fd > -1) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); if (fd > STDERR_FILENO) close(fd); } } execvp(kmod[0], kmod); ERROR("Failed to start kmodloadern"); exit(-1); } if (pid <= 0) ERROR("Failed to start kmodloader instancen"); else waitpid(pid, NULL, 0); uloop_init(); preinit(); //执行初始脚本 uloop_run(); return 0; }
  • 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

preinit()函数中启动了/etc/preinit启动脚本:

复制代码
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
void preinit(void) { char *init[] = { "/bin/sh", "/etc/preinit", NULL }; char *plug[] = { "/sbin/procd", "-h", "/etc/hotplug-preinit.json", NULL }; LOG("- preinit -n"); plugd_proc.cb = plugd_proc_cb; plugd_proc.pid = fork(); if (!plugd_proc.pid) { execvp(plug[0], plug); ERROR("Failed to start plugdn"); exit(-1); } if (plugd_proc.pid <= 0) { ERROR("Failed to start new plugd instancen"); return; } uloop_process_add(&plugd_proc); setenv("PREINIT", "1", 1); preinit_proc.cb = spawn_procd; preinit_proc.pid = fork(); if (!preinit_proc.pid) { execvp(init[0], init); ERROR("Failed to start preinitn"); exit(-1); } if (preinit_proc.pid <= 0) { ERROR("Failed to start new preinit instancen"); return; } uloop_process_add(&preinit_proc); DEBUG(4, "Launched preinit instance, pid=%dn", (int) preinit_proc.pid); }
  • 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

在preinit函数中同时启动procd进程/sbin/procd, procd的执行代码如下:

复制代码
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
int main(int argc, char **argv) { int ch; char *dbglvl = getenv("DBGLVL"); if (dbglvl) { debug = atoi(dbglvl); unsetenv("DBGLVL"); } while ((ch = getopt(argc, argv, "d:s:h:")) != -1) { switch (ch) { case 'h': return hotplug_run(optarg); case 's': ubus_socket = optarg; break; case 'd': debug = atoi(optarg); break; default: return usage(argv[0]); } } uloop_init(); procd_signal(); trigger_init(); if (getpid() != 1) procd_connect_ubus();//ubusd进程存在则连接ubus else procd_state_next(); //不存在则,启动ubusd进程 uloop_run(); return 0; }
  • 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

在函数procd_state_next中调用state_enter 启动ubusd进程

复制代码
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
static void state_enter(void) { char ubus_cmd[] = "/sbin/ubusd"; switch (state) { case STATE_EARLY: LOG("- early -n"); watchdog_init(0); hotplug("/etc/hotplug.json"); procd_coldplug(); break; case STATE_INIT: // try to reopen incase the wdt was not available before coldplug watchdog_init(0); LOG("- ubus -n"); procd_connect_ubus(); LOG("- init -n"); service_init(); service_start_early("ubus", ubus_cmd); procd_inittab(); procd_inittab_run("respawn"); procd_inittab_run("askconsole"); procd_inittab_run("askfirst"); procd_inittab_run("sysinit"); break; case STATE_RUNNING: LOG("- init complete -n"); break; case STATE_SHUTDOWN: LOG("- shutdown -n"); procd_inittab_run("shutdown"); sync(); break; case STATE_HALT: LOG("- reboot -n"); reboot(reboot_event); break; default: ERROR("Unhandled state %dn", state); return; }; }
  • 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

启动preinit时执行的/etc/preinit脚本,内容如下:

复制代码
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
#!/bin/sh # Copyright (C) 2006 OpenWrt.org # Copyright (C) 2010 Vertical Communications [ -z "$PREINIT" ] && exec /sbin/init export PATH=/bin:/sbin:/usr/bin:/usr/sbin pi_ifname= pi_ip=192.168.1.1 pi_broadcast=192.168.1.255 pi_netmask=255.255.255.0 fs_failsafe_ifname= fs_failsafe_ip=192.168.1.1 fs_failsafe_broadcast=192.168.1.255 fs_failsafe_netmask=255.255.255.0 fs_failsafe_wait_timeout=2 pi_suppress_stderr="y" pi_init_suppress_stderr="y" pi_init_path="/bin:/sbin:/usr/bin:/usr/sbin" pi_init_cmd="/sbin/init" . /lib/functions.sh . /lib/functions/preinit.sh . /lib/functions/system.sh boot_hook_init preinit_essential boot_hook_init preinit_main boot_hook_init failsafe boot_hook_init initramfs boot_hook_init preinit_mount_root for pi_source_file in /lib/preinit/*; do . $pi_source_file done boot_run_hook preinit_essential pi_mount_skip_next=false pi_jffs2_mount_success=false pi_failsafe_net_message=false boot_run_hook preinit_main
  • 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

/etc/preinit脚本是一系列初始化脚本的入口,定义了初始化的各种参数,preinit的一系列脚本放在/lib/preinit/文件夹下:

复制代码
1
2
3
4
5
6
7
8
9
10
02_default_set_state 50_indicate_regular_preinit 03_preinit_do_ralink.sh 70_initramfs_test 10_indicate_failsafe 80_mount_root 10_indicate_preinit 81_urandom_seed 10_sysinfo 99_10_failsafe_login 30_failsafe_wait 99_10_run_init 40_run_failsafe_hook
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

由于脚本众多,因此openwrt的设计者将这些脚本分成下面几类:

复制代码
1
2
3
4
5
6
7
8
preinit_essential preinit_main failsafe initramfs preinit_mount_root
  • 1
  • 2
  • 3
  • 4
  • 5

每一类函数按照脚本的开头数字的顺序运行。

preinit执行的最后一个脚本为99_10_run_init,运行

复制代码
1
2
3
4
exec env - PATH=$pi_init_path $pi_init_env $pi_init_cmd
  • 1

pi_init_cmd

复制代码
1
2
3
4
pi_init_cmd="/sbin/init"
  • 1

因此开始运行busybox的init命令

busybox的init命令执行/etc/inittab的脚本,/etc/inittab 内容如下:

复制代码
1
2
3
4
5
6
7
8
::sysinit:/etc/init.d/rcS S boot ::shutdown:/etc/init.d/rcS K stop tts/0::askfirst:/bin/ash --login ttyS0::askfirst:/bin/ash --login tty1::askfirst:/bin/ash --login
  • 1
  • 2
  • 3
  • 4
  • 5

sysinit为系统初始化运行的 /etc/init.d/rcS S boot脚本
shutdown为系统重启或关机运行的脚本
tty开头的是,如果用户通过串口或者telnet登录,则运行/bin/ash --login
askfirst和respawn相同,只是在运行前提示”Please press Enter to activate
this console.”

当前启动转到运行 /etc/init.d/rcS S boot,/etc/init.d/rcS和preinit类似,rcS也是一系列脚本的入口,其运行/etc/rc.d目录下S开头的的所
有脚本(如果运行rcS K stop,则运行K开头的所有脚本)

复制代码
1
2
3
4
5
6
7
K50dropbear S02nvram S40network S50dropbear S96led K90network S05netconfig S41wmacfixup S50telnet S97watchdog K98boot S10boot S45firewall S60dnsmasq S98sysntpd K99umount S39usb S50cron S95done S99sysctl
  • 1
  • 2
  • 3
  • 4

上面的脚本文件来自/etc/init.d/,在该文件夹下包含了各种应用程序的初始化脚本,这些脚本通过/etc/rc.common脚本,将init.d的脚
本链接到/etc/rc.d目录下,并且根据 这些脚本中的START和STOP的关键字,添加K${STOP}S${START}的前缀,这样就决定了脚本的先后的运行次序。

openwrt的shell脚本比较复杂,因此看脚本时可以通过添加set -xecho等命令,直接看shell脚本的结果,而不要花太多的时间硬看脚本,主要是理解其主要的意思和设计思路。

博客原文链接:https://blog.csdn.net/viewsky11/article/details/73201162

最后

以上就是凶狠星月最近收集整理的关于Openwrt 系统初始化分析的全部内容,更多相关Openwrt内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(91)

评论列表共有 0 条评论

立即
投稿
返回
顶部