|
击左上方蓝色“一口Linux”,选择“设为星标”
第一时间看干货文章
?【干货】嵌入式驱动工程师学习路线?【干货】Linux嵌入式知识点-思维导图-免费获取?【就业】一个可以写到简历的基于Linux物联网综合项目?【就业】找工作简历模版
xotgicnm1wn6409102514.gif
在Linux嵌入式系统的开发和维护过程中,了解系统启动和服务管理机制是至关重要的。其中,/etc/init.d/目录扮演了关键角色,它包含了用于初始化、启动、重启或停止各种服务的脚本。本文将深入浅出地介绍这个目录下常见启动文件的作用,帮助读者更好地理解如何管理和优化嵌入式Linux设备。init.d是指包含一系列Shell脚本的目录,这些脚本用于控制服务(也称为守护进程)的生命周期。当系统启动时,init进程会根据预定义的规则执行这些脚本,以确保必要的服务能够正确启动。/etc/init.d/目录下的所有文件[cloud@localhost ~]$ lsS01logging* S30dbus* S50telnet* S90start_userapp.sh* S10udev* S40network* S70vsftpd* socketcand*S13portmap* S50dropbear* S80mount-opt* rcK*S20urandom* S50sshd* S81web.sh* rcS*file:rcS
先看一下rcS文件,它是本目录在开机时最先启动的文件。
#!/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) #.sh结尾的脚本 # Source shell script for speed. ( trap - INT QUIT TSTP #重置陷阱为启动shell时的陷阱 set start #设置传入的参数 . $i #执行,携带start参数 ) ;; *) #其他脚本 # No sh extension, so fork subprocess. $i start #执行,携带start参数 ;; esacdone总结:检测大写S开头的所有脚本并执行它们。
file:rcK
rcK文件是设备关机或重启执行的文件,它和rcS差不多,只有传入的参数有微微差别。
#!/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 #$()相当于反引号,首先执行命令,-r倒序排列 # Ignore dangling symlinks (if any). [ ! -f "$i" ] && continue #如果不存在则遍历下一个 case "$i" in *.sh) # Source shell script for speed. ( trap - INT QUIT TSTP set stop . $i #执行,携带stop参数 ) ;; *) # No sh extension, so fork subprocess. $i stop #执行,携带stop参数 ;; esacdone总结:关机时还需要启动一遍启动脚本,只不过传入的参数是stop,需要处理一些后续工作才关机。
file:S01logging
#!/bin/sh## Start logging#
start() { echo -n "Starting logging: " start-stop-daemon -b -S -q -m -p /var/run/syslogd.pid --exec /sbin/syslogd -- -n start-stop-daemon -b -S -q -m -p /var/run/klogd.pid --exec /sbin/klogd -- -n echo "OK"}
stop() { echo -n "Stopping logging: " start-stop-daemon -K -q -p /var/run/syslogd.pid start-stop-daemon -K -q -p /var/run/klogd.pid echo "OK"}
case "$1" in start) start ;; stop) stop ;; restart|reload) stop start ;; *) echo "Usage: $0 {start|stop|restart}" exit 1esac
exit $? #最后一次命令的执行状态码,0为正常。由rcS或者rcK脚本调用的子进程运行此脚本,传递start或stop参数来控制执行start函数或stop函数。
参数-b | --background 后台运行-S | --start – 开启一个系统守护程序,并传递参数给它-K | --stop 停止一个程序-q | --quiet 不要输出警告-m| --make-pidfile 当命令本身不创建pidfile时,由start-stop-daemon创建-p | --pidfile 要检查的pid文件-x | --exec 程序启动/检查它是否正在运行-n | --name 要检查的进程名称file:S10udev
#!/bin/sh## udev This is a minimal non-LSB version of a UDEV startup script. It# was derived by stripping down the udev-058 LSB version for use# with buildroot on embedded hardware using Linux 2.6.34+ kernels.## You may need to customize this for your system's resource limits# (including startup time!) and administration. For example, if# your early userspace has a custom initramfs or initrd you might# need /dev much earlier; or without hotpluggable busses (like USB,# PCMCIA, MMC/SD, and so on) your /dev might be static after boot.## This script assumes your system boots right into the eventual root# filesystem, and that init runs this udev script before any programs# needing more device nodes than the bare-bones set -- /dev/console,# /dev/zero, /dev/null -- that's needed to boot and run this script.#
# Check for missing binariesUDEV_BIN=/sbin/udevdtest -x $UDEV_BIN || exit 5 #文件不可执行则退出,退出码:5
# Check for config file and read itUDEV_CONFIG=/etc/udev/udev.conftest -r $UDEV_CONFIG || exit 6 #文件不可读则退出,退出码:6. $UDEV_CONFIG
case "$1" in start) #设备开机时 printf "Populating ${udev_root:-/dev} using udev: " printf '\000\000\000\000' > /proc/sys/kernel/hotplug $UDEV_BIN -d || (echo "FAIL" && exit 1) #执行失败打印“FAIL”并退出 udevadm trigger --type=subsystems --action=add udevadm trigger --type=devices --action=add udevadm settle --timeout=30 || echo "udevadm settle failed" echo "done" ;; stop) #设备关机或重启 # Stop execution of events udevadm control --stop-exec-queue killall udevd ;; *) echo "Usage: $0 {start|stop}" exit 1 ;;esac
exit 0udevadm命令详解udevadm trigger [options] 接收内核发送来的设备事件。主要用于重放coldplug事件信息–type=type 触发一个特殊的设备。合法的类型:devices,subsystem,failed.默认是devices–action=action 被触发的事件,默认是changeudevadm settle [options] 查看udev事件队列,如果所有事件全部处理完就退出。–timeout=seconds 等待事件队列空的最大时间。默认是180秒。如果是0则立即退出。udevadm control [options] 控制udev守护进程(systemd-udevd)的内部状态。-s, --stop-exec-queue 向 systemd-udevd 发送"禁止处理事件"信号, 这样所有新发生的事件都将进入等候队列。file:S13portmap
#! /bin/sh
[ -f /sbin/portmap ] || exit 0 #不存在此文件就退出
start() { echo -n "Starting portmap: " portmap mkdir -p /var/lock/subsys touch /var/lock/subsys/portmap #锁定此服务 echo "done"}
stop() { echo -n "Stopping portmap: " echo killall portmap rm -rf /var/lock/subsys echo "done"}
restart() { stop start rm -f /var/run/portmap.state}
# See how we were called.case "$1" in start) start ;; stop) stop ;; restart|reload) restart ;; *) echo "Usage: $0 {start|stop|reload|restart}" exit 1esac
exit $? portmap进程的主要功能是把RPC程序号转化为Internet的端口号。当一个RPC服务器启动时,会选择一个空闲的端口号并在上面监听(每次启动后的端口号各不相同),同时它作为一个可用的服务会在portmap进程注册。一个RPC服务器对应惟一一个RPC程序号,RPC服务器告诉portmap进程它在哪个端口号上监听连接请求和为哪个RPC程序号提供服务。经过这个过程,portmap进程就知道了每一个已注册的RPC服务器所用的Internet端口号,而且还知道哪个程序号在这个端口上是可用的。portmap进程维护着一张RPC程序号到Internet端口号之间的映射表,它的字段包括程序号、版本号、所用协议、端口号和服务名,portmap进程通过这张映射表来提供程序号-端口号之间的转化功能
如果portmap进程停止了运行或异常终止,那么该系统上的所有RPC服务器必须重新启动。首先停止NFS服务器上的所有NFS服务进程,然后启动portmap进程,再启动服务器上的NFS进程。
但portmap只在第一次建立连接的时候起作用,帮助网络应用程序找到正确的通讯端口,但是一旦这个双方正确连接,端口和应用就绑定,portmap也就不起作用了。但对其他任何第一次需要找到端口建立通讯的应用仍然有用。
简单的说,portmap就是应用和端口的婚姻介绍人,双方成事了以后,媒婆就没用了。
file:S20urandom
#! /bin/sh## urandom This script saves the random seed between reboots.# It is called from the boot, halt and reboot scripts.## Version: @(#)urandom 1.33 22-Jun-1998 miquels@cistron.nl#
[ -c /dev/urandom ] || exit 0 #不存在字符设备urandom就退出#. /etc/default/rcS
case "$1" in start|"") # check for read only file system if ! touch /etc/random-seed 2>/dev/null #如果无法创建random-seed文件 then echo "read-only file system detected...done" #检测到只读文件系统 exit #退出 fi if [ "$VERBOSE" != no ] then echo -n "Initializing random number generator... " fi # Load and then save 512 bytes, # which is the size of the entropy pool cat /etc/random-seed >/dev/urandom rm -f /etc/random-seed umask 077 #配置文件夹默认权限 dd if=/dev/urandom of=/etc/random-seed count=1 \ >/dev/null 2>&1 || echo "urandom start: failed." umask 022 [ "$VERBOSE" != no ] && echo "done." ;; stop) if ! touch /etc/random-seed 2>/dev/null then exit fi # Carry a random seed from shut-down to start-up; # see documentation in linux/drivers/char/random.c [ "$VERBOSE" != no ] && echo -n "Saving random seed... " umask 077 dd if=/dev/urandom of=/etc/random-seed count=1 \ >/dev/null 2>&1 || echo "urandom stop: failed." [ "$VERBOSE" != no ] && echo "done." ;; *) echo "Usage: urandom {start|stop}" >&2 exit 1 ;;esacfile:S30dbus#!/bin/sh## messagebus: The D-BUS systemwide message bus## chkconfig: 345 97 03# description: This is a daemon which broadcasts notifications of system events \# and other messages. See http://www.freedesktop.org/software/dbus/## processname: dbus-daemon# pidfile: /var/run/messagebus.pid#
# Sanity checks.[ -x /usr/bin/dbus-daemon ] || exit 0 #非可执行文件则退出
# Create needed directories.[ -d /var/run/dbus ] || mkdir -p /var/run/dbus #无此目录则创建, -p 循环创建,多层目录结构[ -d /var/lock/subsys ] || mkdir -p /var/lock/subsys[ -d /tmp/dbus ] || mkdir -p /tmp/dbus
RETVAL=0
start() { echo -n "Starting system message bus: "
dbus-uuidgen --ensure dbus-daemon --system RETVAL=$? echo "done" [ $RETVAL -eq 0 ] && touch /var/lock/subsys/dbus-daemon #dbus-daemon命令执行正常,锁定}
stop() { echo -n "Stopping system message bus: "
## we don't want to kill all the per-user $processname, we want ## to use the pid file *only*; because we use the fake nonexistent ## program name "$servicename" that should be safe-ish killall dbus-daemon RETVAL=$? echo "done" if [ $RETVAL -eq 0 ]; then rm -f /var/lock/subsys/dbus-daemon rm -f /var/run/messagebus.pid fi}
# See how we were called.case "$1" in start) start ;; stop) stop ;; status) status $processname RETVAL=$? ;; restart) stop start ;; condrestart) if [ -f /var/lock/subsys/$servicename ]; then stop start fi ;; reload) echo "Message bus can't reload its configuration, you have to restart it" RETVAL=$? ;; *) echo "Usage: $0 {start|stop|status|restart|condrestart|reload}" ;;esacexit $RETVALdbus-uuidgen 命令生成或读取一个全局唯一ID–ensure[=FILENAME]如果未提供文件名,则默认为 localstatedir / lib / dbus / machine-id(localstatedir通常为/ var)。如果该文件存在,则将对其进行验证,如果包含错误的内容,则返回失败代码。如果该文件不存在,则将使用新的uuid创建该文件。成功时,不输出任何输出。dbus-daemon — Message bus daemon 消息总线守护进程–system 使用系统范围消息总线的标准配置文件。file:S40network#!/bin/sh## Start the network....#
# Debian ifupdown needs the /run/network lock directorymkdir -p /run/network
case "$1" in start) echo "Starting network..." /sbin/ifup -a ;; stop) echo -n "Stopping network..." /sbin/ifdown -a ;; restart|reload) "$0" stop "$0" start ;; *) echo "Usage: $0 {start|stop|restart}" exit 1esac
exit $?ifup eth0 #激活eth0ifdown eth0 #禁用eth0-a 自动配置(禁用)所有接口file:S50dropbear#!/bin/sh## Starts dropbear sshd.#
# Allow a few customizations from a config filetest -r /etc/default/dropbear && . /etc/default/dropbear #为可读文件则执行
start() { DROPBEAR_ARGS="$DROPBEAR_ARGS -R"
# If /etc/dropbear is a symlink to /var/run/dropbear, and # - the filesystem is RO (i.e. we can not rm the symlink), # create the directory pointed to by the symlink. # - the filesystem is RW (i.e. we can rm the symlink), # replace the symlink with an actual directory if [ -L /etc/dropbear \ #是一个符号链接 -a "$(readlink /etc/dropbear)" = "/var/run/dropbear" ] #文件存在 then if rm -f /etc/dropbear >/dev/null 2>&1; then #错误输出重定向到标准输出,标准输出重定向到空文件(不打印任何东西) mkdir -p /etc/dropbear #成功删除则创建此目录 else echo "No persistent location to store SSH host keys. New keys will be" echo "generated at each boot. Are you sure this is what you want to do?" mkdir -p "$(readlink /etc/dropbear)" fi fi
echo -n "Starting dropbear sshd: " umask 077
start-stop-daemon -S -q -p /var/run/dropbear.pid \ --exec /usr/sbin/dropbear -- $DROPBEAR_ARGS [ $? = 0 ] && echo "OK" || echo "FAIL"}stop() { echo -n "Stopping dropbear sshd: " start-stop-daemon -K -q -p /var/run/dropbear.pid [ $? = 0 ] && echo "OK" || echo "FAIL"}restart() { stop start}
case "$1" in start) start ;; stop) stop ;; restart|reload) restart ;; *) echo "Usage: $0 {start|stop|restart}" exit 1esac
exit $?start-stop-daemon守护进程启停工具命令参数-S | --start – 开启一个系统守护程序,并传递参数给它-K | --stop 停止一个程序-q | --quiet 不要输出警告-p | --pidfile 要检查的pid文件-x | --exec 程序启动/检查它是否正在运行file:S50sshd
#!/bin/sh## sshd Starts sshd.#
# Make sure the ssh-keygen progam exists[ -f /usr/bin/ssh-keygen ] || exit 0
# Create any missing keys/usr/bin/ssh-keygen -A
umask 077
start() { echo -n "Starting sshd: " /usr/sbin/sshd wr touch /var/lock/sshd echo "OK"}stop() { echo -n "Stopping sshd: " wr killall sshd wr 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 1esac
exit $?ssh-keygen -A
对于主机密钥不存在的每个密钥类型(rsa1、rsa、dsa、ecdsa和ed25519),生成带有默认密钥文件路径、空口令、密钥类型的默认位和默认注释的主机密钥。系统管理脚本使用它来生成新的主机密钥。因此,如果您的系统还没有主机密钥,ssh-keygen -A将创建它们。
file:S50telnet
#!/bin/sh## Start telnet....#
start() { echo -n "Starting telnetd: " start-stop-daemon -S -q -m -b -p /var/run/telnetd.pid \ -x /usr/sbin/telnetd -- -F [ $? = 0 ] && echo "OK" || echo "FAIL"}
stop() { echo -n "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 1esac
exit $?start-stop-daemon守护进程启停工具命令
参数-S | --start – 开启一个系统守护程序,并传递参数给它-K | --stop 停止一个程序-q | --quiet 不要输出警告-m| --make-pidfile 当命令本身不创建pidfile时,由start-stop-daemon创建-b | --background 后台运行-p | --pidfile 要检查的pid文件-x | --exec 程序启动/检查它是否正在运行file:S70vsftpd
#! /bin/sh
set -e
DESC="vsftpd"NAME=vsftpdDAEMON=/usr/sbin/$NAME
case "$1" in start) echo -n "Starting $DESC: " start-stop-daemon -S -b -x $NAME echo "OK" ;; stop) echo -n "Stopping $DESC: " start-stop-daemon -K -x $NAME echo "OK" ;; restart|force-reload) echo "Restarting $DESC: " $0 stop sleep 1 $0 start echo "" ;; *) echo "Usage: $0 {start|stop|restart|force-reload}" >&2 exit 1 ;;esac
exit 0start-stop-daemon守护进程启停工具命令
参数-S | --start – argument> 开启一个系统守护程序,并传递参数给它-K | --stop 停止一个程序-b | --background 后台运行-x | --exec executable> 程序启动/检查它是否正在运行file:S80mount-opt
#!/bin/sh## mount /dev/mtdblock6 of nandflash in /opt directory#
start() { echo -n "Start mount /opt: " ubiattach /dev/ubi_ctrl -m 6 -d 1 && mount -t ubifs ubi1_0 /opt #ubifs文件系统ubi1_0挂载到/opt目录下
if [ $? == 0 ]; then #上一条命令:挂载成功返回0 echo "Mount /opt ok" else echo "flash_erase /dev/mtd6" ubidetach -p /dev/mtd6 flash_erase /dev/mtd6 0 0 ubiformat /dev/mtd6 ubiattach /dev/ubi_ctrl -m 6 -d 1 ubimkvol /dev/ubi1 -N opt -m mount -t ubifs ubi1_0 /opt fi }stop() { echo -n "Unmount /opt: " umount /opt ubidetach -p /dev/mtd6 echo "Unmount /opt OK"}restart() { stop start}
case "$1" in start) start ;; stop) stop ;; restart|reload) restart ;; *) echo "Usage: $0 {start|stop|restart}" exit 1esac
exit $?ubi命令用法
ubiattach-m, --mtdn=此选项是必须的MTD device number to attach (alternative method, e.g if the character device node does not exist) 。附加的MTD设备编号(替代方法,e.g 如果字符设备节点不存在)注意:是从0开始的。-d, --devn=the number to assign to the newly created UBI device (assigned automatically if this is not specified)分配给新创建的UBI设备的号码(如果没有指定,则自动分配)ubidetach-p, --dev-path=要附加的MTD设备节点的路径。ubiformat格式化MTD设备,擦除Flash,保存擦除计数,写入UBI镜像到Flash。flash_erase命令有类似的效果。ubimkvol从UBI设备上创建UBI卷。-N, --name=卷名 。-m, --maxavsize将卷大小设置为最大可用大小。file:S81web.sh
#!/bin/sh
/usr/local/webs/bin/webs &file:S90start_userapp.sh
#!/bin/sh
# set ipifconfig eth0 192.168.1.131 #配置eth0接口网络ifconfig eth1 192.168.2.136
# disable rtc clk_out pins defaultecho 0 > /sys/class/rtc/rtc0/device/clk_out_ctl #禁用RTC clk_out引脚
# if test function in sd card then execif [ -f "/media/mmcblk0p1/function/functiontest.sh" ]; then #内存卡自定义程序 echo "Start functiontest.sh" cd /media/mmcblk0p1/function ./functiontest.sh &fi
# you can add your app start_command herefile:socketcand
#! /bin/sh
### BEGIN INIT INFO# Provides: socketcand# Required-Start: $remote_fs# Required-Stop: $remote_fs# Default-Start: 2 3 4 5# Default-Stop:# Short-Description: socketcand# Description: daemon that provides network access to local CAN busses### END INIT INFO
[ -f /etc/default/rcS ] && . /etc/default/rcS #一般文件(非目录或设备文件)PATH=/bin:/usr/bin:/sbin:/usr/sbinprefix=/usrexec_prefix=/usrDAEMON=${exec_prefix}/bin/socketcandDESC="SocketCAN daemon"NAME="socketcand"PIDFILE=/var/run/socketcand.pid
test -x $DAEMON || exit 0 #/usr/bin/socketcand文件非可执行文件则退出
case "$1" in start) echo "Starting $DESC" "$NAME" start-stop-daemon --start --quiet --background --pidfile $PIDFILE --startas $DAEMON -m -- --daemon ;; stop) echo "Stopping $DESC" "$NAME" start-stop-daemon --stop --quiet --pidfile $PIDFILE --oknodo --startas $DAEMON rm -f $PIDFILE ;; restart) $0 stop sleep 1 $0 start ;; force-reload) if start-stop-daemon --stop --test --quiet --pidfile $PIDFILE --startas $DAEMON ; then $0 restart fi ;; *) echo "Usage: /etc/init.d/socketcand {start|stop|restart|force-reload}" exit 1 ;;esac
exit 0start-stop-daemon守护进程启停工具命令
参数-S | --start – 开启一个系统守护程序,并传递参数给它-K | --stop 停止一个程序-q | --quiet 不要输出警告-b | --background 后台运行-p | --pidfile 要检查的pid文件-a | --startas 要启动的程序(默认为)-m| --make-pidfile 当命令本身不创建pidfile时,由start-stop-daemon创建-x | --exec 程序启动/检查它是否正在运行-o | --oknodo 如果未执行任何操作,退出状态为0(不是1)示例:
Start the food daemon, unless one is already running (a process named food, running as user food, with pid in food.pid).启动food守护进程,除非它已经在运行(一个名为food的进程,以用户food的身份运行,在foo.pid中使用pid):
start-stop-daemon --start --oknodo --user food --name food --pidfile /var/run/food.pid --startas /usr/sbin/food --chuid food -- --daemon总结
理解/etc/init.d/目录及其下的启动文件对于掌握Linux嵌入式系统的运作至关重要。通过本文的介绍,希望读者能够更加熟悉这些文件的作用,并学会有效地管理和优化自己的嵌入式Linux环境。当然,随着技术的进步,新的初始化系统如systemd正在逐渐取代传统的init.d方式,但对于许多现有的和一些资源受限的嵌入式项目而言,init.d仍然是不可或缺的一部分。关于作者『小流+跬步』是一名热爱技术分享的技术爱好者,希望通过这篇文章能给广大读者带来启发和帮助。欢迎关注我的微信公众号『小流+跬步』,获取更多有趣有用的技术文章!end
一口Linux
关注,回复【1024】海量Linux资料赠送
精彩文章合集
文章推荐
?【专辑】ARM?【专辑】粉丝问答?【专辑】所有原创?【专辑】linux入门?【专辑】计算机网络?【专辑】Linux驱动?【干货】嵌入式驱动工程师学习路线?【干货】Linux嵌入式所有知识点-思维导图 |
|