3. 添加修改启动配置¶
在buildroot系统中/etc/init.d/目录下的文件是系统初始化脚本,在系统启动、关闭或运行级别切换等过程中起着重要作用。
如果我们需要添加初始化配置也可以在/etc/init.d/目录下添加自己的脚本。
3.1. 系统默认配置脚本¶
本小节使用“Buildroot根文件系统的构建”章节编译出来的最基础的文件系统进行说明,排除额外软件包添加的配置脚本。
查看/etc/init.d/目录下的文件,有以下的配置脚本:
1 2 3 | ls /etc/init.d/
S01syslogd S02sysctl S20urandom rcK
S02klogd S10mdev S40network rcS
|
配置脚本说明如下:
S01syslogd:用于启动系统日志服务,负责将系统中的各种日志信息记录到指定的日志文件中。
S02sysctl:用于在系统启动时设置内核参数,如内存管理、进程调度等。
S02klogd:用于处理内核日志,负责从内核获取日志消息,并将其传递给系统日志机制进行记录或显示。
S10mdev:用于管理和创建设备节点,负责在系统启动时根据内核检测到的设备信息,动态地创建和删除相应的设备节点。
S20urandom:用于初始化系统的随机数生成器,为系统提供随机数源。
S40network:用于配置和启动网络服务,包括设置网络接口的IP地址、子网掩码、网关等参数。
rcS:是系统启动时,用于按顺序执行/etc/init.d目录下以S开头的初始化脚本,从而启动系统所需的各项服务。
rcK:是系统关闭或重启等需要停止服务的场景时,用于按逆序来停止/etc/init.d目录下以S开头的初始化脚本。
3.1.1. rcS¶
rcS是系统启动阶段的关键脚本,负责初始化系统的基本服务和环境,确保系统在启动后能够正常运行。它会遍历/etc/init.d目录下符合特定命名规则的脚本,并根据脚本的类型采用不同的执行方式来启动相应的服务。
rcS内容如下:
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 | #!/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
|
第4-5行:注释说明了脚本的主要功能,即启动/etc/init.d目录下的所有初始化脚本,并按照文件名中的数字顺序执行。
第7行:使用for循环遍历/etc/init.d目录下以S开头且后面跟着两位字符的所有文件和目录。
第10行:检查当前遍历到的$i是否为一个普通文件,如果不是普通文件则跳出本次循环。
第12-25行:使用case语句根据脚本的文件名是否以 .sh 结尾来决定执行方式。
第16行:用于忽略INT(中断信号),QUIT(退出信号)和TSTP(暂停信号)。
第17行:设置脚本的参数为start。
第18行:在当前shell环境中执行该脚本,这样可以避免创建新的进程,提高执行速度。
第23行:直接在新的子进程中执行该脚本,并传递start参数,以启动相应的服务。
3.1.2. rcK¶
系统在关闭、重启或进入特定维护状态时,需要确保所有正在运行的服务和进程能够被正确地停止,以保证系统资源的干净释放, 避免数据丢失或系统错误,rcK脚本就是用于实现这一功能的关键脚本。
rcK内容如下:
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 | #!/bin/sh
# Stop all init scripts in /etc/init.d
# executing them in reversed numerical order.
#
for i in $(ls -r /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 stop
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i stop
;;
esac
done
|
rcK和rcS内容相似,区别如下:
第7行:使用for循环遍历/etc/init.d目录下以S开头且后面跟着两位字符的所有文件和目录,并按照逆序排列。
第17行:设置脚本的参数为stop。
第23行:直接在新的子进程中执行该脚本,并传递stop参数,以停止相应的服务。
3.1.3. S40network¶
S40network用于管理系统的网络服务,包括启动、停止和重启网络连接。
S40network内容如下:
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 | #!/bin/sh
#
# Start the network....
#
# Debian ifupdown needs the /run/network lock directory
mkdir -p /run/network
case "$1" in
start)
printf "Starting network: "
/sbin/ifup -a
[ $? = 0 ] && echo "OK" || echo "FAIL"
;;
stop)
printf "Stopping network: "
/sbin/ifdown -a
[ $? = 0 ] && echo "OK" || echo "FAIL"
;;
restart|reload)
"$0" stop
"$0" start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit $?
|
第7行:创建/run/network目录,ifupdown工具需要这个目录作为锁目录,用于管理网络接口的操作。
第12行:ifup -a命令的作用是启动/etc/network/interfaces文件中配置的所有网络接口。
第13行:$?获取ifup命令的退出状态码,如果状态码为0打印 “OK”,否则打印 “FAIL”。
第17-18行:和第12-13行类似,只是停止操作。
第20-22行:传递restart或者reload参数,先执行stop或者执行start,用于重启操作。
/etc/network/interfaces是一个重要的网络配置文件,通常用于配置Linux系统中的网络接口和网络参数。 它在Debian系统及其衍生版本(如 Ubuntu)中广泛使用,用于定义网络接口的配置信息,如IP地址、子网掩码、网关、DNS等。
/etc/network/interfaces的内容如下:
1 2 3 4 | # interface file auto-generated by buildroot
auto lo
iface lo inet loopback
|
默认只对lo网卡进行配置,lo也即本地回环网卡,没有对板卡eth0、eth1网卡进行配置,因此eth0、eth1网卡默认是down状态的。
在interfaces文件添加eth0、eth1网卡配置,修改后内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | # interface file auto-generated by buildroot
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
auto eth1
iface eth1 inet static
address 192.168.103.180·
netmask 255.255.255.0
gateway 192.168.103.254
|
以上eth0使用dhcp动态获取网络信息,eth1作静态配置,可根据需求自行修改,配置完成后重启系统或者重启S40network:
1 | /etc/init.d/S40network restart
|
3.2. 添加或修改配置脚本¶
3.2.1. 网络相关¶
3.2.1.1. 网口配置¶
除了使用/etc/network/interfaces配置网络,也可以自己写一个脚本配置网络,在/etc/init.d/添加一个名为S40eth0的脚本,内容如下:
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 | #!/bin/sh
. /etc/profile
if [ ! -d "/boot" ] ; then
mkdir /boot
fi
start() {
printf "start ethernet: "
if [ ! -e /boot/boot_mac_eth0 ]; then
#不存在boot_mac_eth0则获取网口mac地址并保存
mac_address_eth0=$(ifconfig eth0 | grep HWaddr | awk '{print $5}')
echo "$mac_address_eth0" > /boot/boot_mac_eth0
else
#存在boot_mac_eth0则使用保存的mac地址
ifconfig eth0 down
mac_address_eth0=$(cat /boot/boot_mac_eth0)
ifconfig eth0 hw ether $mac_address_eth0
ifconfig eth0 up
fi
if [ ! -e /boot/eth.nodhcp ]
then
#udhcpc动态获取eth0网络信息
(udhcpc -i eth0 -t 10 -T 1 -A 5 -b -p /run/udhcpc.eth0.pid) &
fi
echo "OK"
}
stop() {
kill `cat /run/udhcpc.eth0.pid`
rm /run/udhcpc.eth0.pid
}
restart() {
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
restart
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
|
给脚本添加执行权限:
1 | chmod 777 /etc/init.d/S40eth0
|
以上脚本只配置了eth0网口,如需配置eth1可自行参考添加。
3.2.1.2. WIFI配置¶
在“外设接口使能”章节的开启wifi接口小节,我们已经讲解了如何使能wifi接口、添加网卡固件、连接wifi,本小节将介绍添加启动脚本来自动连接wifi。
在/etc/init.d/添加一个名为S40wifi的脚本,内容如下:
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 | #!/bin/sh
start() {
printf "start wifi: "
if ! ifconfig -a | grep -q "wlan0"; then
echo "wlan0 does not exist"
exit 0
fi
if [ ! -e /etc/wpa_supplicant/wpa_supplicant.conf ]; then
echo "wpa_supplicant.conf does not exist"
exit 0
fi
#打开wifi
ip link set wlan0 up
#连接wifi
wpa_supplicant -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf &
#申请动态ip
udhcpc -b -i wlan0 -t 10 -T 1 -A 5 > /dev/null 2>&1 &
echo "OK"
}
stop() {
ip link set wlan0 down
}
restart() {
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
restart
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
|
给脚本添加执行权限:
1 | chmod 777 /etc/init.d/S40wifi
|
3.2.1.3. RNDIS配置¶
在野火Debian系统usb otg口支持虚拟串口、RNDIS虚拟网卡、虚拟U盘功能,是怎么实现的呢?其实只需要执行一行命令即可,命令如下:
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 | #emmc版本执行
modprobe g_multi file=/dev/mmcblk1p1 removable=1 cdrom=0 ro=0 stall=0 nofua=1 iManufacturer=embedfire iProduct=embedfire iSerialNumber=1234fire5678
#sd版本执行
modprobe g_multi file=/dev/mmcblk0p1 removable=1 cdrom=0 ro=0 stall=0 nofua=1 iManufacturer=embedfire iProduct=embedfire iSerialNumber=1234fire5678
#nand执行
#创建40MB的空文件
dd if=/dev/zero of=disk.img bs=1M count=40
#将文件格式化为fat32文件系统
mkfs.vfat -F 32 disk.img
#将文件映射到回环设备
losetup /dev/loop0 disk.img
#加载驱动
modprobe g_multi file=/dev/loop0 removable=1 cdrom=0 ro=0 stall=0 nofua=1 iManufacturer=embedfire iProduct=embedfire iSerialNumber=1234fire5678
#nand驱动信息输出如下
[ 544.634653] using random self ethernet address
[ 544.639132] using random host ethernet address
[ 544.645432] Mass Storage Function, version: 2009/09/11
[ 544.650606] LUN: removable file: (no medium)
[ 544.655852] LUN: removable file: /dev/loop0
[ 544.660058] Number of LUNs=1
[ 544.666237] usb0: HOST MAC 22:43:9f:93:d1:18
[ 544.670721] usb0: MAC 76:de:6d:f1:2b:5d
[ 544.675615] g_multi gadget: Multifunction Composite Gadget
[ 544.681291] g_multi gadget: userspace failed to provide iSerialNumber
[ 544.687746] g_multi gadget: g_multi ready
[ 544.903388] g_multi gadget: high-speed config #1: Multifunction with RNDIS
[ 544.910532] gs_console_connect: port num [0] is not support console
|
也即加载g_multi.ko时指定需要映射的分区,驱动加载后将分区从usb otg口映射成虚拟U盘的同时,也会添加RNDIS虚拟网卡以及虚拟串口功能。其中,nand需要创建disk.img,需要格式化为fat32或exFAT等windows可识别格式,此操作需要格式化工具,板卡如果没有工具可以在虚拟机创建,然后拷贝到板卡。
除了系统分区,也可以将板卡USB口插入的U盘再从usb otg口映射出去,命令如下:
1 2 | #/dev/sda1是U盘分区
modprobe g_multi file=/dev/sda1 removable=1 cdrom=0 ro=0 stall=0 nofua=1 iManufacturer=embedfire iProduct=embedfire iSerialNumber=1234fire5678
|
在知道如何生成RNDIS虚拟网卡后,下面我们来自启动配置,在/etc/init.d/添加一个名为S40rdnis的脚本,内容如下:
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 | #!/bin/sh
start() {
printf "start rndis: "
fat_media="/root/disk.img"
unset root_drive
#获取系统分区信息
root_drive="$(cat /proc/cmdline | sed 's/ /\n/g' | grep root=UUID= | awk -F 'root=' '{print $2}' || true)"
if [ ! "x${root_drive}" = "x" ] ; then
root_drive="$(/sbin/findfs ${root_drive} || true)"
else
root_drive="$(cat /proc/cmdline | sed 's/ /\n/g' | grep root= | awk -F 'root=' '{print $2}' || true)"
fi
#区分emmc、sd、nand
if echo ${root_drive} | grep -q "/dev/mmcblk[0-9]p[0-9]"; then
actual_image_file="${root_drive%?}1"
else
media_loop=$(losetup -f || true)
losetup ${media_loop} "${fat_media}"
actual_image_file=${media_loop}
fi
#加载驱动
modprobe g_multi file=${actual_image_file} removable=1 cdrom=0 ro=0 stall=0 nofua=1 iManufacturer=embedfire iProduct=embedfire iSerialNumber=1234fire5678
#判断usb0网卡是否生成
if ! ifconfig -a | grep -q "usb0"; then
echo "usb0 does not exist"
exit 0
fi
#设置静态ip和网关
ifconfig usb0 192.168.137.10 up
route add default gw 192.168.137.1 metric 800
echo "OK"
}
stop() {
#卸载驱动
rmmod g_multi.ko
#卸载/dev/loop0映射
if losetup -a | grep -q "/dev/loop0:"; then
losetup -d /dev/loop0
fi
}
restart() {
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
restart
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
|
给脚本添加执行权限:
1 | chmod 777 /etc/init.d/S40rndis
|
3.2.1.4. SSH配置¶
如果在添加软件包章节添加了OpenSSH软件包,会在/etc/init.d/多出一个S50sshd的文件,默认配置下加载会很慢很慢,导致登录服务要很久才能弹出,原因是默认配置下每次都执行生成缺失的SSH主机密钥命令以及执行sshd命令启动需要很长时间,因此可优化S50sshd文件,解决长期“堵塞”问题,文件修改后如下:
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 | #!/bin/sh
#
# sshd Starts sshd.
#
# Make sure the ssh-keygen progam exists
[ -f /usr/bin/ssh-keygen ] || exit 0
umask 077
start() {
# Create any missing keys
if [ ! -e "/etc/ssh/ssh_host_ecdsa_key" ] ; then
/usr/bin/ssh-keygen -A
fi
printf "Starting sshd: "
/usr/sbin/sshd &
touch /var/lock/sshd
echo "OK"
}
stop() {
printf "Stopping sshd: "
killall sshd
rm -f /var/lock/sshd
echo "OK"
}
restart() {
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
restart
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit $?
|
第13-15行:根据判断是否缺失密钥再执行/usr/bin/ssh-keygen -A命令。
第17行:将sshd后台执行,避免“堵塞”。
除了S50sshd配置文件外,/etc/ssh/sshd_config文件也是配置ssh十分重要的配置文件,默认配置了不允许root用户ssh登录,又因为buildroot默认用户为root,因此需要修改sshd_config文件允许root用户ssh登录,找到PermitRootLogin配置项,修改为PermitRootLogin yes
1 2 3 4 5 6 7 8 9 10 11 | /* 省略前面内容 */
# Authentication:
#LoginGraceTime 2m
PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
/* 省略后面内容 */
|
如果root用户没有密码,还需要为root用户添加密码:
1 | passwd root
|
修改完成后,重启板卡,连接网络,等待ssh服务启动后即可ssh远程登录板卡。