启动流程
嵌入式设备下Linux的内核系统启动的流程并不复杂,从最早的父进程init开始,为创建各种服务进程:系统会从 inittab
文件中,读取每一行作为执行命令👇
# Note: BusyBox init doesn't support runlevels. The runlevels field is completely ignored by BusyBox init. If you want runlevels, use
# sysvinit.
#
# Format for each entry: <id>:<runlevels>:<action>:<process>
#
# id == tty to run on, or empty for /dev/console
# runlevels == ignored
# action == one of sysinit, respawn, askfirst, wait, and once
# process == program to run
# Startup the system
::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -o remount,ro,noatime /
::sysinit:/bin/mount -t tmpfs tmpfs /dev
::sysinit:/bin/mkdir -p /dev/pts
::sysinit:/bin/mkdir -p /dev/shm
::sysinit:/bin/mount -a
::sysinit:/bin/hostname -F /etc/hostname
# now run any rc scripts
::sysinit:/etc/init.d/rcS
# Put a getty on the serial port
ttySLB0::respawn:/sbin/getty -L -n -l /bin/autologin ttySLB0 0 vt100 # GENERIC_SERIAL
# Stuff to do for the 3-finger salute
#::ctrlaltdel:/sbin/reboot
# Stuff to do before rebooting
::shutdown:/etc/init.d/rcK
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
sysinit
即为系统启动时要做的内容
- 挂载目录文件
- 创建目录
- 读取
fstab
内容实现自动挂在 - 设置主机名信息
- 到
/etc/init.d
目录下指定rcS
脚本
rcS 脚本
查看rcS脚本文件,可知,rcS是为了启动 /etc/init.d 目录下一个个以 S
开头的可执行脚本,若不是以sh
作为后缀,则执行 并直接传参为 start
#!/bin/sh
# Start all init scripts in /etc/init.d
# executing them in numerical order.
#
for i in /etc/init.d/S??* ;do
# Ignore dangling symlinks (if any).
[ ! -f "$i" ] && continue
case "$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set start
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i start
;;
esac
done
查看S*脚本
# cat S50telnet
#!/bin/sh
# Start telnet....
TELNETD_ARGS=-F
[ -r /etc/default/telnet ] && . /etc/default/telnet
start() {
printf "Starting telnetd: "
start-stop-daemon -S -q -m -b -p /var/run/telnetd.pid \
-x /usr/sbin/telnetd -- $TELNETD_ARGS
[ $? = 0 ] && echo "OK" || echo "FAIL"
}
stop() {
printf "Stopping telnetd: "
start-stop-daemon -K -q -p /var/run/telnetd.pid \
-x /usr/sbin/telnetd
[ $? = 0 ] && echo "OK" || echo "FAIL"
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit $?
脚本中判断传入参数是否为start
,以start-stop-daemon
命令启动守护进程。
start-stop-daemon
查看该命令的相关参数,常用的一些参数为👇
# start-stop-daemon --help
Usage: start-stop-daemon [OPTIONS] [-S|-K] ... [-- ARGS...]
Search for matching processes, and then
-K: stop all matching processes #停止所有匹配进程
-S: start a process unless a matching process is found #除非找到匹配的进程,否则启动进程
Process matching:
-u USERNAME|UID Match only this user's processes
-n NAME Match processes with NAME in comm field in /proc/PID/stat
-x EXECUTABLE Match processes with this command in /proc/PID/cmdline
-p FILE Match a process with PID from FILE
All specified conditions must match
-S only:
-x EXECUTABLE Program to run #执行命令
-a NAME Zeroth argument #第零个参数
-b Background #后台执行
-N N Change nice level #更改nice等级
-c USER[:[GRP]] Change user/group #更改用户组
-m Write PID to pidfile specified by -p #将进程的PID写入-p指定的pid文件
-K only:
-s SIG Signal to send # 发送信号
-t Match only, exit with 0 if found
Other:
-o Exit with status 0 if nothing is done
-v Verbose
-q Quiet #不输出进程信息
一个简单的示例example.sh,来自Debian /etc/init.d/ssh,不过在嵌入式的设备下,start-stop-daemon 源命令程序大多是轻量化裁剪过的,参数用较精简的-s -q -m -p
等即可(👆)
#!/bin/sh
# Quick start-stop-daemon example, derived from Debian /etc/init.d/ssh
set -e
# Must be a valid filename
NAME=foo
PIDFILE=/var/run/$NAME.pid
#This is the command to be run, give the full pathname
DAEMON=/usr/local/bin/bar
DAEMON_OPTS="--baz=quux"
export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
case "$1" in
start)
echo -n "Starting daemon: "$NAME
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- $DAEMON_OPTS
#无输出启动进程,将其PID存在$PIDFILE文件中,命令跟着的参数是 $DAEMON_OPTS
echo "."
;;
stop)
echo -n "Stopping daemon: "$NAME
start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
echo "."
;;
restart)
echo -n "Restarting daemon: "$NAME
start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile $PIDFILE
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- $DAEMON_OPTS
echo "."
;;
*)
echo "Usage: "$1" {start|stop|restart}"
exit 1
esac
exit 0