900行高级SHELL编程之系统脚本rc.sysinit分析(欢迎指正) | 银河网 rc.sysinit错误

#!/bin/bash

#

# /etc/rc.d/rc.sysinit - run once at boot time

#

# Taken in part from Miquel van Smoorenburg's bcheckrc.

#

//声明一个字符串变量接收hostname的输出值,也可以使用HOSTNAME=`hostname`

HOSTNAME=$(/bin/hostname)

//开启monitor监控模式允许交互

可交互:由人来传值

非交互:由物来传值

set -m

//判断network是否存在,是的话就设置下主机名啊啥的

if [ -f /etc/sysconfig/network ]; then

. /etc/sysconfig/network

fi

//判断主机名是否为空或是为(none)如果是的话就自动设置为localhost

if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; then

HOSTNAME=localhost

fi

//判断mounts是不是不存在啊如果是的话就重新挂载下哦

if [ ! -e /proc/mounts ]; then

//就是挂载/proc到/proc下面我们知道proc是内存的动态映射要是没有发现它的话就说明木有挂载嘛

mount -n -t proc /proc /proc

//挂载的时候输出的错误信息和标准输出都输出到位桶里面

mount -n -t sysfs /sys /sys >/dev/null 2>&1

fi

//判断usb外围设备目录是否不存在是的话就加载usbcore模块并挂载usbfs文件系统同样静默模式

if [ ! -d /proc/bus/usb ]; then

modprobe usbcore >/dev/null 2>&1 && mount -n -t usbfs /proc/bus/usb /proc/bus/usb

else

//如果存在的话那么就说明模块已经呗加载了只需要挂载上就可以使用了例如外围的USB键盘的鼠标啊啥的

mount -n -t usbfs /proc/bus/usb /proc/bus/usb

fi

//执行另一个父脚本程序并且里面还包含了很多有用的函数提供我们使用(我们到后期再来分析嗯)

. /etc/init.d/functions

//初始化开机画面的变量,下面紧接着一个判断如果plymouth可以执行的话就设置其值为yes也就是开始plymouth管理了

PLYMOUTH=

[ -x /bin/plymouth ] && PLYMOUTH=yes

# Check SELinux status

//初始化selinux初始状态

SELINUX_STATE=

//如果存在并且/selinux/enforce并且/proc/self/attr/current当前没有设置默认为kernel,此说明selinux是之前加载了

if [ -e "/selinux/enforce" ] && [ "$(cat /proc/self/attr/current)" != "kernel" ]; then

//并且/selinux/enforce文件是只读的

if [ -r "/selinux/enforce" ] ; then

//就设置其状态为enforce里面的值,默认为0

SELINUX_STATE=$(cat "/selinux/enforce")

else

//如果读权限都没有的话那么将设置为1也就是强制模式

# assume enforcing if you can't read it

SELINUX_STATE=1

fi

fi

//如果有状态值并且restorecon有执行权限并且可以在mounts里面找到/dev开头的设备分区例如sda啊啥的

if [ -n "$SELINUX_STATE" -a -x /sbin/restorecon ] && __fgrep " /dev " /proc/mounts >/dev/null 2>&1 ; then

//满足上面的要求的就可以递归强制恢复他们的context值了

/sbin/restorecon -R -F /dev 2>/dev/null

fi

//定义一个disable_selinux() 函数来设置调试模式(其实最后是传0值给了/selinux/enforce),我们要注意的

是因为脚本的执行顺序是由上而下的所以就必须是先来声明函数然后在下面调用

disable_selinux() {

echo $"*** Warning -- SELinux is active"

echo $"*** Disabling security enforcement for system recovery."

echo $"*** Run 'setenforce 1' to reenable."

echo "0" > "/selinux/enforce"

}

//定义一个方法来重打标签,其实这个就是我们的图形化的selinux里面的那个复选框

relabel_selinux() {

# if /sbin/init is not labeled correctly this process is running in the

# wrong context, so a reboot will be required after relabel

//初始化自动打标签变量

AUTORELABEL=

. /etc/selinux/config

//传0值enforce也就是permissive模式

echo "0" > /selinux/enforce

//如果plymouth有值的话就执行plymouth --hide-splash命令其实就是我们常常进入的时候

隐去壁纸开始在命令行中重打标签

[ -n "$PLYMOUTH" ] && plymouth --hide-splash

//如果AUTORELABEL的值为0的话就输出下面的那些社么..内容然后启动rcS-emergency

if [ "$AUTORELABEL" = "0" ]; then

echo

echo $"*** Warning -- SELinux ${SELINUXTYPE} policy relabel is required. "

echo $"*** /etc/selinux/config indicates you want to manually fix labeling"

echo $"*** problems. Dropping you to a shell; the system will reboot"

echo $"*** when you leave the shell."

start rcS-emergency

else

echo

echo $"*** Warning -- SELinux ${SELINUXTYPE} policy relabel is required."

echo $"*** Relabeling could take a very long time, depending on file"

echo $"*** system size and speed of hard drives."

//如果不是0的话就强制恢复context值

/sbin/fixfiles -F restore > /dev/null 2>&1

fi

//清除重打标签的标志文件以免下次重启又来重打标签因为很耗时间嗯

rm -f /.autorelabel

//然后开始挂载根文件系统

echo $"Unmounting file systems"

umount -a

mount -n -o remount,ro /

echo $"Automatic reboot in progress."

//完成以上的所有的步骤的话就可以重启了

reboot -f

}

//就是在启动进度条的时候按下ESC键后看到的那个banner

# Print a text banner.

//不换行加扩展输出welcome to

echo -en $"ttWelcome to "

// 读取系统版本行忽略/etc/system-release的转义符

read -r system_release < /etc/system-release

//如果版本是redhat的话

if [[ "$system_release" == *"Red Hat"* ]]; then

//设置BOOTUP的值为color并设置背景色为黑色前景色为红色

[ "$BOOTUP" = "color" ] && echo -en "\033[0;31m"

//那么此时的redhat就是红色的了

echo -en "Red Hat"

//颜色是0-7似乎没有9啊...这个就不知道了应该是恢复原本颜色吧

[ "$BOOTUP" = "color" ] && echo -en "\033[0;39m"

//sed替换掉/etc/system-release里面的内容只留Enterprise Linux Server

PRODUCT=$(sed "s/Red Hat (.*) release.*/1/" /etc/system-release)

echo " $PRODUCT"

//如果还是Fedora标识的话

elif [[ "$system_release" == *Fedora* ]]; then

//并且$BOOTUP的值为color那么前景色就变成蓝色

[ "$BOOTUP" = "color" ] && echo -en "\033[0;34m"

//然后输出蓝色的Fedora"

echo -en "Fedora"

//然后就和上面一样的恢复默认的颜色设置

[ "$BOOTUP" = "color" ] && echo -en "\033[0;39m"

//这个也是用正则表达式来过滤出版本、

PRODUCT=$(sed "s/Fedora (.*) ?release.*/1/" /etc/system-release)

//然后输出它

echo " $PRODUCT"

else

//如果要是其他的版本的话也是一样的操作

PRODUCT=$(sed "s/ release.*//g" /etc/system-release)

echo "$PRODUCT"

fi

//其实我们设置的内核启动参数都是在这里了嗯

# Only read this once.

cmdline=$(cat /proc/cmdline)

# Initialize hardware

//判断系统内核所需的模块是否被加载到内存当中

if [ -f /proc/sys/kernel/modprobe ]; then

//如果存在进程模块但是内核的启动参数不包含nomodules

if ! strstr "$cmdline" nomodules && [ -f /proc/modules ] ; then

//那么就用sysctl来设置内核参数kerernel.modprobe的值为/sbin/modprobe也就是设置modeprobe

的绝对路径

sysctl -w kernel.modprobe="/sbin/modprobe" >/dev/null 2>&1

else

//如果不存在/proc/modules但存在nomodules那么就设置modeprobe位置为true程序

# We used to set this to NULL, but that causes 'failed to exec' messages"

sysctl -w kernel.modprobe="/bin/true" >/dev/null 2>&1

fi

fi

//建立标志文件为后面初始化做判断的文件为空只是一个标志作用

touch /dev/.in_sysinit >/dev/null 2>&1

# Set default affinity

//如果taskset可以执行的话

if [ -x /bin/taskset ]; then

//如果我们的启动参数中没有设置默认的CPU的运行

if strstr "$cmdline" default_affinity= ; then

//那么就遍历内核参数

for arg in $cmdline ; do

//遍历的过程中删除匹配arg中default_affinity=的最大部分最终的返回值如果不是arg本身遍历时候的值的话

if [ "${arg##default_affinity=}" != "${arg}" ]; then

//这个搞了这么多飞机其实就是一句话讲我们的CPU进程ID设置为1也就是init这个父进程

/bin/taskset -p ${arg##default_affinity=} 1

fi

done

fi

fi

//获取nash的PID(这个是linux中加载initrd.img时候简单的一个命令解释器只能执行一些内嵌的命令也就是所

谓的builded in 可以用type [comman] 来查看,只有重启时候才会用到默认是没有的)

nashpid=$(pidof nash 2>/dev/null)

//如果pid不为0就杀掉其进程然后

[ -n "$nashpid" ] && kill $nashpid >/dev/null 2>&1

//然后不设置nash的pid也就是重置了unset命令也是入侵必备的指令为了不留下入侵痕迹一般会通过全局变量来

关闭日志记录

unset nashpid

//然后就开始部署udev通用的设备管理器例如添加啊删除啊啥的设备或是部署啥环境的都需要他来监视

/sbin/start_udev

//看看有没有用户自定义的模块?也称为"外挂"模块

# Load other user-defined modules

//要是有的话就放在这个位置然后遍历执行

for file in /etc/sysconfig/modules/*.modules ; do

[ -x $file ] && $file

done

//这个和上面一样的可以选择一个设置都可以例如在/etc/sysconfig/modules/里面新建一个hackxm.modules然后再

里面写上modeprobe fuser然后保存并chmod 755 .....就哦啦

# Load modules (for backward compatibility with VARs)

if [ -f /etc/rc.modules ]; then

/etc/rc.modules

fi

//这个就不解释了吧上次也发了pts以及tty啊ttys啊啥的分别是干啥的嗯不懂的话可以看下

mount -n /dev/pts >/dev/null 2>&1

[ -n "$SELINUX_STATE" ] && restorecon -F /dev/pts >/dev/null 2>&1

//配置内核参数最好不要修改

# Configure kernel parameters

//该函数由 /etc/rc.d/init.d/functions 脚本定义,主要执行 "/usr/sbin/rhgb-client --update $1"

主要就是想我们启动的时候的那个图形化进程窗口来发送内核参数信息

update_boot_stage RCkernelparam

apply_sysctl

//设置主机名

# Set the hostname.

//该函数由 /etc/rc.d/init.d/functions 脚本定义,发送hostname和domain名字

update_boot_stage RChostname

//action 函数是另外一个最重要的函数,它的作用是打印某个提示信息并执行给定命令,这里

就是设置主机名了

action $"Setting hostname ${HOSTNAME}: " hostname ${HOSTNAME}

//如果设置了domainname的话就顺便设置下domainname嗯

[ -n "${NISDOMAIN}" ] && domainname ${NISDOMAIN}

//如果已经加载了scsi的外围设备驱动的话就先卸载然后再重新加载,扫描完后就可以卸载了

# Sync waiting for storage.

{ rmmod scsi_wait_scan ; modprobe scsi_wait_scan ; rmmod scsi_wait_scan ; } >/dev/null 2>&1

//如果在/proc/devices 没有找到device-mapper磁盘映射管理

# Device mapper & related initialization

if ! __fgrep "device-mapper" /proc/devices >/dev/null 2>&1 ; then

//那么我们就重新加载device-mapper的dm-mod模块

modprobe dm-mod >/dev/null 2>&1

fi

//看看这个cryption分区设备加密的文件是否存在,这个要看文件系统支持加密不?常常用luks加密的时候用到

if [ -f /etc/crypttab ]; then

//如果存在的话就初始化下也就是不加密文件系统或是分区但是要注意的是根分区并不支持cryption哦

init_crypto 0

fi

//擦,这个csh中的strstr一直用这次判断/etc/multipath.conf存在并且/sbin/multipath可执行启动参数中但是

不包含nompath那么就需要加载dm-multipath这个divice-mapper多路径选择驱动,y用于多网卡存储环境部署

if ! strstr "$cmdline" nompath && [ -f /etc/multipath.conf -a

-x /sbin/multipath ]; then

//如果上面返回真的话就加载这个驱动

modprobe dm-multipath > /dev/null 2>&1

//显示多路径设备

/sbin/multipath -v 0

//如果/sbin/kpartx可以执行的话

if [ -x /sbin/kpartx ]; then

//我们用dmsetup来创建多路径磁盘映射文件

/sbin/dmsetup ls --target multipath --exec "/sbin/kpartx -a -p p" >/dev/null

fi

fi

//如果启动参数中没有有nodmraid但是 /sbin/dmraid有可执行权限

if ! strstr "$cmdline" nodmraid && [ -x /sbin/dmraid ]; then

//这个时候就需要加载dm-mirror模块了

modprobe dm-mirror >/dev/null 2>&1

//改变下本地的环境设置使用sbin打开dmraid来scan config 和active raid设备

dmraidsets=$(LC_ALL=C /sbin/dmraid -s -c -i)

//如果上面执行的命令返回的是0

if [ "$?" = "0" ]; then

//我们就开始遍历出系统中所有的raid设备

for dmname in $dmraidsets; do

//如果是isw_*开头但是启动参数中没有noiswmd

if [[ "$dmname" == isw_* ]] &&

! strstr "$cmdline" noiswmd; then

//那么就继续

continue

fi

//用dmraid去active激活忽略locking我们的dmname

/sbin/dmraid -ay -i --rm_partitions -p "$dmname" >/dev/null 2>&1

//激活后我们就要用kpartx进行创建磁盘映射了嗯,也就是/dev/mapper/$dmname了

/sbin/kpartx -a -p p "/dev/mapper/$dmname"

done

fi

fi

# Start any MD RAID arrays that haven't been started yet

//上面的磁盘映射也做好了那么此时判断mdstat是否已经加载到内存并且md-device-map

是不是也加载到内存那么就执行mdadm添加扫描到的磁盘并且run起来

[ -r /proc/mdstat -a -r /dev/md/md-device-map ] && /sbin/mdadm -IRs

//如果lvm可以执行的话

if [ -x /sbin/lvm ]; then

//那么就启动lvm自动备份设置

action $"Setting up Logical Volume Management:" /sbin/lvm vgchange -a y --sysinit

fi

//如果加密文件存在的话就初始化呗...

if [ -f /etc/crypttab ]; then

init_crypto 0

fi

//如果这个称为“刷机”神器的文件存在的话当然你要先安装才有嗯并且启动参数中有这样的参数

if [ -f /fastboot ] || strstr "$cmdline" fastboot ; then

//那么就设置为yes,此时讲不会出现fsck磁盘自检啊啥的东西哦

fastboot=yes

fi

//看看是不是有这个fsckk磁盘检测程序选项文件

if [ -f /fsckoptions ]; then

//那么fsck的选项就来自于这里了嗯

fsckoptions=$(cat /fsckoptions)

fi

//看看是不是有强制检测的文件并且启动参数中有这个参数

if [ -f /forcefsck ] || strstr "$cmdline" forcefsck ; then

//那么所有上面的选项就加上一个force选项

fsckoptions="-f $fsckoptions"

//如果不存在强制检测文件的但是存在自动检测文件

elif [ -f /.autofsck ]; then

//并且真正的autpfsck的文件存在那么就执行它

[ -f /etc/sysconfig/autofsck ] && . /etc/sysconfig/autofsck

//如果执行上面的命令并且AUTOFSCK_DEF_CHECK的值为yes的话那么下次重启后就

开始磁盘自检

if [ "$AUTOFSCK_DEF_CHECK" = "yes" ]; then

//那么自动检测的选项加上force强制选项

AUTOFSCK_OPT="$AUTOFSCK_OPT -f"

fi

//不正常关机造成磁盘文件混乱,进入shell界面,进行fsck维护之后继续进行启动

if [ -n "$AUTOFSCK_SINGLEUSER" ]; then

//根据上面的PLYMOUTH来判断是否显示背景图片

[ -n "$PLYMOUTH" ] && plymouth --hide-splash

echo

//然后进入控制台显示警告信息

echo $"*** Warning -- the system did not shut down cleanly. "

echo $"*** Dropping you to a shell; the system will continue"

echo $"*** when you leave the shell."

//留给一个shell这时候就初始化selinux状态为permissive

[ -n "$SELINUX_STATE" ] && echo "0" > /selinux/enforce

//其实是执行了/etc/init/rcS.conf里面的配置然后来选择运行级别啊还有服务啊啥的

start rcS-emergency

//这样先permissive然后在enforce其实就起到了重打标签的作用

[ -n "$SELINUX_STATE" ] && echo "1" > /selinux/enforce

//这个地方也是根据PLYMOUTH的值来判断是否要显示背景图片

[ -n "$PLYMOUTH" ] && plymouth --show-splash

fi

//注意了上面一直到这里都没有运行fsck只是做判断是不是要执行哦

fsckoptions="$AUTOFSCK_OPT $fsckoptions"

fi

//判断全局变量BOOTUP是不是color如果是的话

if [ "$BOOTUP" = "color" ]; then

//那么就显示fsck的进度(-C也就是count的意思了)

fsckoptions="-C $fsckoptions"

else

//如果不是的话就显示详细信息了

fsckoptions="-V $fsckoptions"

fi

//初始化readonly变量

READONLY=

//其实这个应该是redhat的一个项目了sttatless,主要的作用是不让系统持久的对磁盘进行读写操作

它的原理下面已经体现的淋漓尽致了

if [ -f /etc/sysconfig/readonly-root ]; then

. /etc/sysconfig/readonly-root

fi

//如果启动参数中有readonlyroot的话

if strstr "$cmdline" readonlyroot ; then

//就设置上面的那个文件的readonly值为yes默认是空也就是是可以写的

READONLY=yes

//判断下面的RW_MOUNTSTATE_MOUNT是不是为空值啊如果是的uha就赋值这些都是在上面的

那个配置文件中

[ -z "" ] && RW_MOUNT=/var/lib/stateless/writable

[ -z "$STATE_MOUNT" ] && STATE_MOUNT=/var/lib/stateless/state

fi

//和上面一样的判断下是不是noredaonly其实启动参数只是/etc/sysconfig/readonly-root的一个映射

if strstr "$cmdline" noreadonlyroot ; then

//如果是的话就设置为no了

READONLY=no

fi

//如果readonly是yes或TEMPORARY_STATE= yes的话

if [ "$READONLY" = "yes" -o "$TEMPORARY_STATE" = "yes" ]; then

//声明一个函数mount_empty的作用就是复制第一个参数到$RW_MOUNT指定的目录做备份然后

再把备份挂载到原来的目录这样的话就是只读了嗯对吧?

mount_empty() {

if [ -e "$1" ]; then

echo "$1" | cpio -p -vd "$RW_MOUNT" &>/dev/null

mount -n --bind "$RW_MOUNT$1" "$1"

fi

}

//上面的empty管的是$1本身而这个dir是管理的是$1下的子目录同样的复制备份过去实现只读

mount_dirs() {

if [ -e "$1" ]; then

mkdir -p "$RW_MOUNT$1"

find "$1" -type d -print0 | cpio -p -0vd "$RW_MOUNT" &>/dev/null

mount -n --bind "$RW_MOUNT$1" "$1"

fi

}

//这里面当然的是$1下的文件或是子目录下饿文件备份处理的方法了嗯

mount_files() {

if [ -e "$1" ]; then

cp -a --parents "$1" "$RW_MOUNT"

mount -n --bind "$RW_MOUNT$1" "$1"

fi

}

# Common mount options for scratch space regardless of

# type of backing store

//初始化就不多说了

mountopts=

# Scan partitions for local scratch storage

//blkid命令用来索引或查看block设备的属性。-t参数用来指定一个属性(属性以name=value

的方式表示,例如LABEL=/),-l参数表示搜索其属性值和-t参数指定的属性值符合的block设

备。-o指定输出格式,可选的有full, value, device。以下是输出示例。

rw_mount_dev=$(blkid -t LABEL="$RW_LABEL" -l -o device)

# First try to mount scratch storage from /etc/fstab, then any

# partition with the proper label. If either succeeds, be sure

# to wipe the scratch storage clean. If both fail, then mount

# scratch storage via tmpfs.

//上面的解释已经很清除了嗯也就是挂载的时候先找/etc/fstab,如果其中没有定义那么就把上面

找到的分区挂载到$RW_MOUNT上如果依然没有成功那么就将它们挂载成tmpfs

if mount $mountopts "$RW_MOUNT" > /dev/null 2>&1 ; then

rm -rf "$RW_MOUNT" > /dev/null 2>&1

elif [ x$rw_mount_dev != x ] && mount $rw_mount_dev $mountopts "$RW_MOUNT" > /dev/null 2>&1; then

rm -rf "$RW_MOUNT" > /dev/null 2>&1

else

mount -n -t tmpfs $RW_OPTIONS $mountopts none "$RW_MOUNT"

fi

//遍历循环我们/etc/rwtab和/etc/rwtab.d/dev/.initramfs/rwtab文件和目录

for file in /etc/rwtab /etc/rwtab.d/* /dev/.initramfs/rwtab ; do

//同样调用functions里面定义的函数来判断文件是否忽略跳过

is_ignored_file "$file" && continue

//如果文件存在的话就循环分析他们的文件类型以及路径

[ -f $file ] && cat $file | while read type path ; do

case "$type" in

//直个地方就调用了我们上面的三个函数来处理循环显示的文件类型以及路径

empty)

mount_empty $path

;;

files)

mount_files $path

;;

dirs)

mount_dirs $path

;;

*)

;;

esac

//如果"$SELINUX_STATE"设置有值并且路径真的存在那么就初始化他们的context值

[ -n "$SELINUX_STATE" -a -e "$path" ] && restorecon -R "$path"

done

done

# Use any state passed by initramfs

//如果/dev/.initramfs/state是目录那么就把目录下的所有的文件都拷贝$RW_MOUNT下备份

[ -d /dev/.initramfs/state ] && cp -a /dev/.initramfs/state/* $RW_MOUNT

# In theory there should be no more than one network interface active

# this early in the boot process -- the one we're booting from.

# Use the network address to set the hostname of the client. This

# must be done even if we have local storage.

//初始化ip地址

ipaddr=

//如果主机名为localhost或是主机名是localhost.localdomain

if [ "$HOSTNAME" = "localhost" -o "$HOSTNAME" = "localhost.localdomain" ]; then

//用awk来过来ip

ipaddr=$(ip addr show to 0.0.0.0/0 scope global | awk '/[[:space:]]inet / { print gensub("/.*","","g",$2) }')

//循环给ip赋值

for ip in $ipaddr ; do

//初始化主机名

HOSTNAME=

//通过ipcalc来通过ip查找主机名

eval $(ipcalc -h $ip 2>/dev/null)

//如果主机名长度不为0的并且设置主机名成功的话就跳出循环

[ -n "$HOSTNAME" ] && { hostname ${HOSTNAME} ; break; }

done

fi

# Clients with read-only root filesystems may be provided with a

# place where they can place minimal amounts of persistent

# state. SSH keys or puppet certificates for example.

#

# Ideally we'll use puppet to manage the state directory and to

# create the bind mounts. However, until that's all ready this

# is sufficient to build a working system.

# First try to mount persistent data from /etc/fstab, then any

# partition with the proper label, then fallback to NFS

//和上面的一样的只是挂载方式不一样如果查找到的设备在fstab里面和$STATE_MOUNT中没有定义

那么就挂载成nfs文件系统

state_mount_dev=$(blkid -t LABEL="$STATE_LABEL" -l -o device)

if mount $mountopts $STATE_OPTIONS "$STATE_MOUNT" > /dev/null 2>&1 ; then

/bin/true

elif [ x$state_mount_dev != x ] && mount $state_mount_dev $mountopts "$STATE_MOUNT" > /dev/null 2>&1; then

/bin/true

elif [ ! -z "$CLIENTSTATE" ]; then

# No local storage was found. Make a final attempt to find

# state on an NFS server.

mount -t nfs $CLIENTSTATE/$HOSTNAME $STATE_MOUNT -o rw,nolock

fi

//判断挂载的目录是不是有写的权限

if [ -w "$STATE_MOUNT" ]; then

//这个就是和上面的一样的只是挂载方式不一样如果查找到的设备在fstab里面和$STATE_MOUNT中没有定义

那么就挂载成nfs文件系统的方法

mount_state() {

if [ -e "$1" ]; then

[ ! -e "$STATE_MOUNT$1" ] && cp -a --parents "$1" "$STATE_MOUNT"

mount -n --bind "$STATE_MOUNT$1" "$1"

fi

}

//循环遍历/etc/statetab /etc/statetab.d/下的文件

for file in /etc/statetab /etc/statetab.d/* ; do

//同样调用函数来判断这些文件

is_ignored_file "$file" && continue

[ ! -f "$file" ] && continue

//如果文件已经在$STATE_MOUNT存在的话就

if [ -f "$STATE_MOUNT/$file" ] ; then

//挂载绑定到STATE_MOUNT/$file做备份

mount -n --bind "$STATE_MOUNT/$file" "$file"

fi

//去掉注释然后再来遍历$file

for path in $(grep -v "^#" "$file" 2>/dev/null); do

//重新挂载这个也算是保险起见了

mount_state "$path"

/如果此时设置了selinux并且path的这个路径存在那就初始化context值

[ -n "$SELINUX_STATE" -a -e "$path" ] && restorecon -R "$path"

done

done

if [ -f "$STATE_MOUNT/files" ] ; then

for path in $(grep -v "^#" "$STATE_MOUNT/files" 2>/dev/null); do

mount_state "$path"

[ -n "$SELINUX_STATE" -a -e "$path" ] && restorecon -R "$path"

done

fi

fi

fi

//如果$fsckoptions中有-y的参数那么

if [[ " $fsckoptions" != *" -y"* ]]; then

//那么就在里面加上一个-a的参数

fsckoptions="-a $fsckoptions"

fi

//初始化quotacheck为0,也就是不启用quota

_RUN_QUOTACHECK=0

如果存在这个forcequotacheck 文件或是启动参数中有这个参数

if [ -f /forcequotacheck ] || strstr "$cmdline" forcequotacheck ; then

//那么就启动quota检测

_RUN_QUOTACHECK=1

fi

//如果fastboot不为0并且readonly是yes的话

if [ -z "$fastboot" -a "$READONLY" != "yes" ]; then

//显示出check的信息

STRING=$"Checking filesystems"

echo $STRING

//检测时候不显示title并且将非正常关机时候的检测详细信息保存到日志文件中

fsck -T -t noopts=_netdev -A $fsckoptions

//日志文件保存的是上一条命令的状态值

rc=$?

//如果等于0的话就返回成功了

if [ "$rc" -eq "0" ]; then

success "$STRING"

echo

//如果是1的话就跳过

elif [ "$rc" -eq "1" ]; then

passed "$STRING"

echo

//如果等于2或是等于3的话就返回没有挂载文件系统并重新挂载重启后再次检测

elif [ "$rc" -eq "2" -o "$rc" -eq "3" ]; then

echo $"Unmounting file systems"

umount -a

mount -n -o remount,ro /

echo $"Automatic reboot in progress."

reboot -f

fi

# A return of 4 or higher means there were serious problems.

//如果大于1的话就返回下面的错误信息(重启后)

if [ $rc -gt 1 ]; then

//不显示背景图片

[ -n "$PLYMOUTH" ] && plymouth --hide-splash

//返回失败信息

failure "$STRING"

echo

echo

echo $"*** An error occurred during the file system check."

echo $"*** Dropping you to a shell; the system will reboot"

echo $"*** when you leave the shell."

str=$"(Repair filesystem)"

//设置我们的命令提示符为Repair filesystem##

PS1="$str # # "; export PS1

//如果为selinux为强制模式的话就改为disabled的模式

[ "$SELINUX_STATE" = "1" ] && disable_selinux

//这个就是运行级别啊撒的启动的时候

start rcS-emergency

//然后返回要求重新挂载然后重启

echo $"Unmounting file systems"

umount -a

mount -n -o remount,ro /

echo $"Automatic reboot in progress."

reboot -f

//如果重启后检测等于1那么就设置_RUN_QUOTACHECK=1

elif [ "$rc" -eq "1" ]; then

_RUN_QUOTACHECK=1

fi

fi

//重新挂载函数(这个后面再讲嗯,后面要改写下嗯)

remount_needed() {

local state oldifs

[ "$READONLY" = "yes" ] && return 1

state=$(LC_ALL=C awk '/ / / && ($3 !~ /rootfs/) { print $4 }' /proc/mounts)

oldifs=$IFS

IFS=","

for opt in $state ; do

if [ "$opt" = "rw" ]; then

IFS=$oldifs

return 1

fi

done

IFS=$oldifs

return 0

}

# Remount the root filesystem read-write.

update_boot_stage RCmountfs

//判断如果函数执行成功的话

if remount_needed ; then

//就显示Remounting root filesystem in read-write mode并且重新挂载

action $"Remounting root filesystem in read-write mode: " mount -n -o remount,rw /

fi

# Clean up SELinux labels

//清除下面的这个些文件的context值

if [ -n "$SELINUX_STATE" ]; then

restorecon /etc/mtab /etc/ld.so.cache /etc/blkid/blkid.tab /etc/resolv.conf >/dev/null 2>&1

fi

//如果selinux是开启的而且readonly不等于yes那么就可以写了嗯顺便检查下autorelabe存在否?

或是启动参数中有木有有的话就可以直接的restorecon过滤出来的文件

# If relabeling, relabel mount points.

if [ -n "$SELINUX_STATE" -a "$READONLY" != "yes" ]; then

if [ -f /.autorelabel ] || strstr "$cmdline" autorelabel ; then

restorecon $(awk '!/^#/ && $4 !~ /noauto/ && $2 ~ /^// { print $2 }' /etc/fstab) >/dev/null 2>&1

fi

fi

//如果readonly是yes的话

if [ "$READONLY" != "yes" ] ; then

# Clear mtab

//清空这个记录挂载着的文件系统

(> /etc/mtab) &> /dev/null

//删除meab的备份文件

# Remove stale backups

rm -f /etc/mtab~ /etc/mtab~~

//重新挂载然后写到mtab文件(matb里面其实就是我们用输入mount命令时候的回显)

# Enter mounted filesystems into /etc/mtab

mount -f /

mount -f /proc >/dev/null 2>&1

mount -f /sys >/dev/null 2>&1

mount -f /dev/pts >/dev/null 2>&1

mount -f /dev/shm >/dev/null 2>&1

mount -f /proc/bus/usb >/dev/null 2>&1

fi

# Mount all other filesystems (except for NFS and /proc, which is already

# mounted). Contrary to standard usage,

# filesystems are NOT unmounted in single user mode.

# The 'no' applies to all listed filesystem types. See mount(8).

//如果readonly是yes的话

if [ "$READONLY" != "yes" ] ; then

//所有的文件系统都按着标准来挂载

action $"Mounting local filesystems: " mount -a -t nonfs,nfs4,smbfs,ncpfs,cifs,gfs,gfs2 -O no_netdev

else

action $"Mounting local filesystems: " mount -a -n -t nonfs,nfs4,smbfs,ncpfs,cifs,gfs,gfs2 -O no_netdev

fi

# Update quotas if necessary

//$_RUN_QUOTACHECK值为1的话并且quotacheck是可执行的

if [ X"$_RUN_QUOTACHECK" = X1 -a -x /sbin/quotacheck ]; then

//那么就检测的时候会找fatab里面有quota的分区并且检测对应用户和组占用的文件数和目录数

action $"Checking local filesystem quotas: " /sbin/quotacheck -anug

fi

//如果auota可执行的话就执行嗯也就是开启quota对指定目录

if [ -x /sbin/quotaon ]; then

action $"Enabling local filesystem quotas: " /sbin/quotaon -aug

fi

# Check to see if a full relabel is needed

//如果selinux开启了而且readonly不是yes的话

if [ -n "$SELINUX_STATE" -a "$READONLY" != "yes" ]; then

//自己手动新建了autorelable的话或是启动参数中有autorelable那么

if [ -f /.autorelabel ] || strstr "$cmdline" autorelabel ; then

//就执行这个命令重打标签

relabel_selinux

fi

else

//如果/etc/selinux的这个目录存在且readonly不是yes的话

if [ -d /etc/selinux -a "$READONLY" != "yes" ]; then

//如果autorelable文件不存在的话就新建一个

[ -f /.autorelabel ] || touch /.autorelabel

fi

fi

//

# Initialize pseudo-random number generator

//这里是初始化随机数如果/var/lib/random-seed文件存在的话

if [ -f "/var/lib/random-seed" ]; then

//那么就把内容传给/dev/urandom

cat /var/lib/random-seed > /dev/urandom

else

//如果不存在的话就创建这个文件

[ "$READONLY" != "yes" ] && touch /var/lib/random-seed

fi

//如果readonly是yes的话

if [ "$READONLY" != "yes" ]; then

//需要修改其权限为600只有所属主才可以写

chmod 600 /var/lib/random-seed

//从/dev/urandom读入512kb的数据给/var/lib/random-seed

dd if=/dev/urandom of=/var/lib/random-seed count=1 bs=512 2>/dev/null

fi

//判断cryption文件是否存在存在的话就初始化里面的值为1,那么就用上面的硬件随机数磁盘加密

if [ -f /etc/crypttab ]; then

init_crypto 1

fi

# Configure machine if necessary

//判断unconfigured文件是否存在

if [ -f /.unconfigured ]; then

//存在的话如果plymouth 可执行的话

if [ -x /bin/plymouth ]; then

//就退出图形化

/bin/plymouth quit

fi

//判断键盘是否设置如果没有设置的话就执行system-config-keyboard

if [ -x /usr/bin/system-config-keyboard ]; then

/usr/bin/system-config-keyboard

fi

//判断是否可以修改密码如果可以就修改root密码

if [ -x /usr/bin/passwd ]; then

/usr/bin/passwd root

fi

//判断是否可以修改网络设置可以的话就直接设置

if [ -x /usr/sbin/system-config-network-tui ]; then

/usr/sbin/system-config-network-tui

fi

//判断是否可以执行时间配置可以的话就直接设置

if [ -x /usr/sbin/timeconfig ]; then

/usr/sbin/timeconfig

fi

//判断是否可以执行authconfig-tui 来配置服务

if [ -x /usr/sbin/authconfig-tui ]; then

/usr/sbin/authconfig-tui --nostart

fi

//判断是否可以执行ntsysv来设置服务启动

if [ -x /usr/sbin/ntsysv ]; then

/usr/sbin/ntsysv --level 35

fi

//读取系统的网络配置

# Reread in network configuration data.

if [ -f /etc/sysconfig/network ]; then

. /etc/sysconfig/network

//重置hostname

# Reset the hostname.

action $"Resetting hostname ${HOSTNAME}: " hostname ${HOSTNAME}

fi

//删除unconfigured配置文件

rm -f /.unconfigured

fi

//删除上面的所有的标志文件然后重启启动

# Clean out /.

rm -f /fastboot /fsckoptions /forcefsck /.autofsck /forcequotacheck /halt

/poweroff /.suspended &> /dev/null

# Do we need (w|u)tmpx files? We don't set them up, but the sysadmin might...

_NEED_XFILES=

//正常情况下是需要 /var/run/utmpx 和 /var/log/wtmpx 文件 如果存在一个就设置_NEED_XFILES=1

[ -f /var/run/utmpx -o -f /var/log/wtmpx ] && _NEED_XFILES=1

//删除/var下的无用的记录文件

# Clean up /var.

rm -rf /var/lock/cvs/* /var/run/screen/*

find /var/lock /var/run ! -type d -exec rm -f {} ;

rm -f /var/lib/rpm/__db* &> /dev/null

rm -f /var/gdm/.gdmfifo &> /dev/null

//判断PROMPT是否不是no就说明当然是允许交互的

[ "$PROMPT" != no ] && plymouth watch-keystroke --command "touch /var/run/confirm" --keys=Ii &

# Clean up utmp/wtmp

//其实这个相当于cat /dev/null > /var/run/utmp

> /var/run/utmp

//新建/var/log/wtmp

touch /var/log/wtmp

//更改所属组统一为utmp

chgrp utmp /var/run/utmp /var/log/wtmp

//权限更改为0644

chmod 0664 /var/run/utmp /var/log/wtmp

//如果_NEED_XFILES长度不为0的话

if [ -n "$_NEED_XFILES" ]; then

//清空/var/run/utmpx因为已经存在了

> /var/run/utmpx

//新建一个touch /var/log/wtmpx并设置组为utmp权限为644,其实是为了防止如果没有/var/log/wtmpx或是/var/run/utmpx

这两个文件的情况

chgrp utmp /var/run/utmpx /var/log/wtmpx

chmod 0664 /var/run/utmpx /var/log/wtmpx

fi

//因为是新建的文件所以我们需要来判断下selinux的状态并且初始化下context值

[ -n "$SELINUX_STATE" ] && restorecon /var/run/utmp* /var/log/wtmp* >/dev/null 2>&1

//删除

# Clean up various /tmp bits

//如果selinux启动的话那么就初始化下context值

[ -n "$SELINUX_STATE" ] && restorecon /tmp

//然后删除/tmp下的影藏文件以及一些无用文件

rm -f /tmp/.X*-lock /tmp/.lock.* /tmp/.gdm_socket /tmp/.s.PGSQL.*

rm -rf /tmp/.X*-unix /tmp/.ICE-unix /tmp/.font-unix /tmp/hsperfdata_*

/tmp/kde-* /tmp/ksocket-* /tmp/mc-* /tmp/mcop-* /tmp/orbit-*

/tmp/scrollkeeper-* /tmp/ssh-*

/dev/.in_sysinit

# Make ICE directory

//创建ICE目录权限为1777也就是有一个t权限吧应该是只有属主才可以删除吧

mkdir -m 1777 -p /tmp/.ICE-unix >/dev/null 2>&1

//然后属主改为root就可以了

chown root:root /tmp/.ICE-unix

//同样的初始化下context值

[ -n "$SELINUX_STATE" ] && restorecon /tmp/.ICE-unix >/dev/null 2>&1

# Start up swapping.

//又是调用update_boot_stage函数类对swap分区操作

update_boot_stage RCswap

//启用所有的虚拟内存并且排除所有的不存在的虚拟文件

action $"Enabling /etc/fstab swaps: " swapon -a -e

//判断autoswap的值是不是yes

if [ "$AUTOSWAP" = "yes" ]; then

//awk过滤获取当然的swap分区,其中的get_numeric_dev 函数也是functions里面提供的

curswap=$(awk '/^/dev/ { print $1 }' /proc/swaps | while read x; do get_numeric_dev dec $x ; echo -n " "; done)

swappartitions=$(blkid -t TYPE=swap -o device)

//如果获取到的话

if [ x"$swappartitions" != x ]; then

//那么就遍历所有的swap分区

for partition in $swappartitions ; do

//并且判断是否存在这个分区或是文件如果存在的话就继续

[ ! -e $partition ] && continue

//这个函数我没有看嗯(应该是返回的是swap分区的名字吧,下去我也查查..)

majmin=$(get_numeric_dev dec $partition)

//这个就是二层过滤了然后调用action函数输出Enabling local swap partitions最后就是启用所有的swap分区了

echo $curswap | grep -qw "$majmin" || action $"Enabling local swap partitions: " swapon $partition

done

fi

fi

# Set up binfmt_misc

//挂载binfmt_misc

/bin/mount -t binfmt_misc none /proc/sys/fs/binfmt_misc > /dev/null 2>&1

# Boot time profiles. Yes, this should be somewhere else.

//如果system-config-network-cmd 可以执行的话

if [ -x /usr/sbin/system-config-network-cmd ]; then

//如过启动参数中有netprofile=的话

if strstr "$cmdline" netprofile= ; then

//遍历输出cndline里面的每个参数

for arg in $cmdline ; do

//如果arg删除匹配netprofile=的最大部分后不等于他本身的话

if [ "${arg##netprofile=}" != "${arg}" ]; then

//就用/usr/sbin/system-config-network-cmd --profile 来设置所有的参数值

/usr/sbin/system-config-network-cmd --profile ${arg##netprofile=}

fi

done

fi

fi

# Now that we have all of our basic modules loaded and the kernel going,

# let's dump the syslog ring somewhere so we can find it late

//如果存在dmesg内核启动加载信息文件的话就备份下

[ -f /var/log/dmesg ] && mv -f /var/log/dmesg /var/log/dmesg.old

//然后执行dmes并设置缓冲区的大小为131072输出的信息作为新的demesg新文件

dmesg -s 131072 > /var/log/dmesg

# create the crash indicator flag to warn on crashes, offer fsck with timeout

//创建.autofsck文件下次重启后自动的磁盘检测

touch /.autofsck &> /dev/null

//如果PROMPT如果不是no的话也就是yes的话那么就允许交互

[ "$PROMPT" != no ] && plymouth --ignore-keystroke=Ii

//判断启动参数中是否有confirm确认参数

if strstr "$cmdline" confirm ; then

//如果有的话就在/var/run新建这个文件

touch /var/run/confirm

fi

//如果对plymouth有执行权限的话

# Let rhgb know that we're leaving rc.sysinit

if [ -x /bin/plymouth ]; then

//就给图形话窗口发送消息rc.sysint执行完毕

/bin/plymouth --sysinit

fi

正文部分到此结束

本文固定链接: http://www.yhsafe.net/advanced-shell-analysis

文章转载请注明: [原创]900行高级SHELL编程之系统脚本rc.sysinit分析(欢迎指正) | +复制链接

您还可以继续浏览: 900行高级SHELL编程系统脚本rc.sysinit分析

分享到:QQ空间腾讯微博新浪微博网易微博人人网开心网腾讯朋友百度搜藏#!/bin/bash

#

# /etc/rc.d/rc.sysinit - run once at boot time

#

# Taken in part from Miquel van Smoorenburg's bcheckrc.

#

//声明一个字符串变量接收hostname的输出值,也可以使用HOSTNAME=`hostname`

HOSTNAME=$(/bin/hostname)

//开启monitor监控模式允许交互

可交互:由人来传值

非交互:由物来传值

set -m

//判断network是否存在,是的话就设置下主机名啊啥的

if [ -f /etc/sysconfig/network ]; then

. /etc/sysconfig/network

fi

//判断主机名是否为空或是为(none)如果是的话就自动设置为localhost

if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; then

HOSTNAME=localhost

fi

//判断mounts是不是不存在啊如果是的话就重新挂载下哦

if [ ! -e /proc/mounts ]; then

//就是挂载/proc到/proc下面我们知道proc是内存的动态映射要是没有发现它的话就说明木有挂载嘛

mount -n -t proc /proc /proc

//挂载的时候输出的错误信息和标准输出都输出到位桶里面

mount -n -t sysfs /sys /sys >/dev/null 2>&1

fi

//判断usb外围设备目录是否不存在是的话就加载usbcore模块并挂载usbfs文件系统同样静默模式

if [ ! -d /proc/bus/usb ]; then

modprobe usbcore >/dev/null 2>&1 && mount -n -t usbfs /proc/bus/usb /proc/bus/usb

else

//如果存在的话那么就说明模块已经呗加载了只需要挂载上就可以使用了例如外围的USB键盘的鼠标啊啥的

mount -n -t usbfs /proc/bus/usb /proc/bus/usb

fi

//执行另一个父脚本程序并且里面还包含了很多有用的函数提供我们使用(我们到后期再来分析嗯)

. /etc/init.d/functions

//初始化开机画面的变量,下面紧接着一个判断如果plymouth可以执行的话就设置其值为yes也就是开始plymouth管理了

PLYMOUTH=

[ -x /bin/plymouth ] && PLYMOUTH=yes

# Check SELinux status

//初始化selinux初始状态

SELINUX_STATE=

//如果存在并且/selinux/enforce并且/proc/self/attr/current当前没有设置默认为kernel,此说明selinux是之前加载了

if [ -e "/selinux/enforce" ] && [ "$(cat /proc/self/attr/current)" != "kernel" ]; then

//并且/selinux/enforce文件是只读的

if [ -r "/selinux/enforce" ] ; then

900行高级SHELL编程之系统脚本rc.sysinit分析(欢迎指正) | 银河网 rc.sysinit错误
//就设置其状态为enforce里面的值,默认为0

SELINUX_STATE=$(cat "/selinux/enforce")

else

//如果读权限都没有的话那么将设置为1也就是强制模式

# assume enforcing if you can't read it

SELINUX_STATE=1

fi

fi

//如果有状态值并且restorecon有执行权限并且可以在mounts里面找到/dev开头的设备分区例如sda啊啥的

if [ -n "$SELINUX_STATE" -a -x /sbin/restorecon ] && __fgrep " /dev " /proc/mounts >/dev/null 2>&1 ; then

//满足上面的要求的就可以递归强制恢复他们的context值了

/sbin/restorecon -R -F /dev 2>/dev/null

fi

//定义一个disable_selinux() 函数来设置调试模式(其实最后是传0值给了/selinux/enforce),我们要注意的

是因为脚本的执行顺序是由上而下的所以就必须是先来声明函数然后在下面调用

disable_selinux() {

echo $"*** Warning -- SELinux is active"

echo $"*** Disabling security enforcement for system recovery."

echo $"*** Run 'setenforce 1' to reenable."

echo "0" > "/selinux/enforce"

}

//定义一个方法来重打标签,其实这个就是我们的图形化的selinux里面的那个复选框

relabel_selinux() {

# if /sbin/init is not labeled correctly this process is running in the

# wrong context, so a reboot will be required after relabel

//初始化自动打标签变量

AUTORELABEL=

. /etc/selinux/config

//传0值enforce也就是permissive模式

echo "0" > /selinux/enforce

//如果plymouth有值的话就执行plymouth --hide-splash命令其实就是我们常常进入的时候

隐去壁纸开始在命令行中重打标签

[ -n "$PLYMOUTH" ] && plymouth --hide-splash

//如果AUTORELABEL的值为0的话就输出下面的那些社么..内容然后启动rcS-emergency

if [ "$AUTORELABEL" = "0" ]; then

echo

echo $"*** Warning -- SELinux ${SELINUXTYPE} policy relabel is required. "

echo $"*** /etc/selinux/config indicates you want to manually fix labeling"

echo $"*** problems. Dropping you to a shell; the system will reboot"

echo $"*** when you leave the shell."

start rcS-emergency

else

echo

echo $"*** Warning -- SELinux ${SELINUXTYPE} policy relabel is required."

echo $"*** Relabeling could take a very long time, depending on file"

echo $"*** system size and speed of hard drives."

//如果不是0的话就强制恢复context值

/sbin/fixfiles -F restore > /dev/null 2>&1

fi

//清除重打标签的标志文件以免下次重启又来重打标签因为很耗时间嗯

rm -f /.autorelabel

//然后开始挂载根文件系统

echo $"Unmounting file systems"

umount -a

mount -n -o remount,ro /

echo $"Automatic reboot in progress."

//完成以上的所有的步骤的话就可以重启了

reboot -f

}

//就是在启动进度条的时候按下ESC键后看到的那个banner

# Print a text banner.

//不换行加扩展输出welcome to

echo -en $"ttWelcome to "

// 读取系统版本行忽略/etc/system-release的转义符

read -r system_release < /etc/system-release

//如果版本是redhat的话

if [[ "$system_release" == *"Red Hat"* ]]; then

//设置BOOTUP的值为color并设置背景色为黑色前景色为红色

[ "$BOOTUP" = "color" ] && echo -en "\033[0;31m"

//那么此时的redhat就是红色的了

echo -en "Red Hat"

//颜色是0-7似乎没有9啊...这个就不知道了应该是恢复原本颜色吧

[ "$BOOTUP" = "color" ] && echo -en "\033[0;39m"

//sed替换掉/etc/system-release里面的内容只留Enterprise Linux Server

PRODUCT=$(sed "s/Red Hat (.*) release.*/1/" /etc/system-release)

echo " $PRODUCT"

//如果还是Fedora标识的话

elif [[ "$system_release" == *Fedora* ]]; then

//并且$BOOTUP的值为color那么前景色就变成蓝色

[ "$BOOTUP" = "color" ] && echo -en "\033[0;34m"

//然后输出蓝色的Fedora"

echo -en "Fedora"

//然后就和上面一样的恢复默认的颜色设置

[ "$BOOTUP" = "color" ] && echo -en "\033[0;39m"

//这个也是用正则表达式来过滤出版本、

PRODUCT=$(sed "s/Fedora (.*) ?release.*/1/" /etc/system-release)

//然后输出它

echo " $PRODUCT"

else

//如果要是其他的版本的话也是一样的操作

PRODUCT=$(sed "s/ release.*//g" /etc/system-release)

echo "$PRODUCT"

fi

//其实我们设置的内核启动参数都是在这里了嗯

# Only read this once.

cmdline=$(cat /proc/cmdline)

# Initialize hardware

//判断系统内核所需的模块是否被加载到内存当中

if [ -f /proc/sys/kernel/modprobe ]; then

//如果存在进程模块但是内核的启动参数不包含nomodules

if ! strstr "$cmdline" nomodules && [ -f /proc/modules ] ; then

//那么就用sysctl来设置内核参数kerernel.modprobe的值为/sbin/modprobe也就是设置modeprobe

的绝对路径

sysctl -w kernel.modprobe="/sbin/modprobe" >/dev/null 2>&1

else

//如果不存在/proc/modules但存在nomodules那么就设置modeprobe位置为true程序

# We used to set this to NULL, but that causes 'failed to exec' messages"

sysctl -w kernel.modprobe="/bin/true" >/dev/null 2>&1

fi

fi

//建立标志文件为后面初始化做判断的文件为空只是一个标志作用

touch /dev/.in_sysinit >/dev/null 2>&1

# Set default affinity

//如果taskset可以执行的话

if [ -x /bin/taskset ]; then

//如果我们的启动参数中没有设置默认的CPU的运行

if strstr "$cmdline" default_affinity= ; then

//那么就遍历内核参数

for arg in $cmdline ; do

//遍历的过程中删除匹配arg中default_affinity=的最大部分最终的返回值如果不是arg本身遍历时候的值的话

if [ "${arg##default_affinity=}" != "${arg}" ]; then

//这个搞了这么多飞机其实就是一句话讲我们的CPU进程ID设置为1也就是init这个父进程

/bin/taskset -p ${arg##default_affinity=} 1

fi

done

fi

fi

//获取nash的PID(这个是linux中加载initrd.img时候简单的一个命令解释器只能执行一些内嵌的命令也就是所

谓的builded in 可以用type [comman] 来查看,只有重启时候才会用到默认是没有的)

nashpid=$(pidof nash 2>/dev/null)

//如果pid不为0就杀掉其进程然后

[ -n "$nashpid" ] && kill $nashpid >/dev/null 2>&1

//然后不设置nash的pid也就是重置了unset命令也是入侵必备的指令为了不留下入侵痕迹一般会通过全局变量来

关闭日志记录

unset nashpid

//然后就开始部署udev通用的设备管理器例如添加啊删除啊啥的设备或是部署啥环境的都需要他来监视

/sbin/start_udev

//看看有没有用户自定义的模块?也称为"外挂"模块

# Load other user-defined modules

//要是有的话就放在这个位置然后遍历执行

for file in /etc/sysconfig/modules/*.modules ; do

[ -x $file ] && $file

done

//这个和上面一样的可以选择一个设置都可以例如在/etc/sysconfig/modules/里面新建一个hackxm.modules然后再

里面写上modeprobe fuser然后保存并chmod 755 .....就哦啦

# Load modules (for backward compatibility with VARs)

if [ -f /etc/rc.modules ]; then

/etc/rc.modules

fi

//这个就不解释了吧上次也发了pts以及tty啊ttys啊啥的分别是干啥的嗯不懂的话可以看下

mount -n /dev/pts >/dev/null 2>&1

[ -n "$SELINUX_STATE" ] && restorecon -F /dev/pts >/dev/null 2>&1

//配置内核参数最好不要修改

# Configure kernel parameters

//该函数由 /etc/rc.d/init.d/functions 脚本定义,主要执行 "/usr/sbin/rhgb-client --update $1"

主要就是想我们启动的时候的那个图形化进程窗口来发送内核参数信息

update_boot_stage RCkernelparam

apply_sysctl

//设置主机名

# Set the hostname.

//该函数由 /etc/rc.d/init.d/functions 脚本定义,发送hostname和domain名字

update_boot_stage RChostname

//action 函数是另外一个最重要的函数,它的作用是打印某个提示信息并执行给定命令,这里

就是设置主机名了

action $"Setting hostname ${HOSTNAME}: " hostname ${HOSTNAME}

//如果设置了domainname的话就顺便设置下domainname嗯

[ -n "${NISDOMAIN}" ] && domainname ${NISDOMAIN}

//如果已经加载了scsi的外围设备驱动的话就先卸载然后再重新加载,扫描完后就可以卸载了

# Sync waiting for storage.

{ rmmod scsi_wait_scan ; modprobe scsi_wait_scan ; rmmod scsi_wait_scan ; } >/dev/null 2>&1

//如果在/proc/devices 没有找到device-mapper磁盘映射管理

# Device mapper & related initialization

if ! __fgrep "device-mapper" /proc/devices >/dev/null 2>&1 ; then

//那么我们就重新加载device-mapper的dm-mod模块

modprobe dm-mod >/dev/null 2>&1

fi

//看看这个cryption分区设备加密的文件是否存在,这个要看文件系统支持加密不?常常用luks加密的时候用到

if [ -f /etc/crypttab ]; then

//如果存在的话就初始化下也就是不加密文件系统或是分区但是要注意的是根分区并不支持cryption哦

init_crypto 0

fi

//擦,这个csh中的strstr一直用这次判断/etc/multipath.conf存在并且/sbin/multipath可执行启动参数中但是

不包含nompath那么就需要加载dm-multipath这个divice-mapper多路径选择驱动,y用于多网卡存储环境部署

if ! strstr "$cmdline" nompath && [ -f /etc/multipath.conf -a

-x /sbin/multipath ]; then

//如果上面返回真的话就加载这个驱动

modprobe dm-multipath > /dev/null 2>&1

//显示多路径设备

/sbin/multipath -v 0

//如果/sbin/kpartx可以执行的话

if [ -x /sbin/kpartx ]; then

//我们用dmsetup来创建多路径磁盘映射文件

/sbin/dmsetup ls --target multipath --exec "/sbin/kpartx -a -p p" >/dev/null

fi

fi

//如果启动参数中没有有nodmraid但是 /sbin/dmraid有可执行权限

if ! strstr "$cmdline" nodmraid && [ -x /sbin/dmraid ]; then

//这个时候就需要加载dm-mirror模块了

modprobe dm-mirror >/dev/null 2>&1

//改变下本地的环境设置使用sbin打开dmraid来scan config 和active raid设备

dmraidsets=$(LC_ALL=C /sbin/dmraid -s -c -i)

//如果上面执行的命令返回的是0

if [ "$?" = "0" ]; then

//我们就开始遍历出系统中所有的raid设备

for dmname in $dmraidsets; do

//如果是isw_*开头但是启动参数中没有noiswmd

if [[ "$dmname" == isw_* ]] &&

! strstr "$cmdline" noiswmd; then

//那么就继续

continue

fi

//用dmraid去active激活忽略locking我们的dmname

/sbin/dmraid -ay -i --rm_partitions -p "$dmname" >/dev/null 2>&1

//激活后我们就要用kpartx进行创建磁盘映射了嗯,也就是/dev/mapper/$dmname了

/sbin/kpartx -a -p p "/dev/mapper/$dmname"

done

fi

fi

# Start any MD RAID arrays that haven't been started yet

//上面的磁盘映射也做好了那么此时判断mdstat是否已经加载到内存并且md-device-map

是不是也加载到内存那么就执行mdadm添加扫描到的磁盘并且run起来

[ -r /proc/mdstat -a -r /dev/md/md-device-map ] && /sbin/mdadm -IRs

//如果lvm可以执行的话

if [ -x /sbin/lvm ]; then

//那么就启动lvm自动备份设置

action $"Setting up Logical Volume Management:" /sbin/lvm vgchange -a y --sysinit

fi

//如果加密文件存在的话就初始化呗...

if [ -f /etc/crypttab ]; then

init_crypto 0

fi

//如果这个称为“刷机”神器的文件存在的话当然你要先安装才有嗯并且启动参数中有这样的参数

if [ -f /fastboot ] || strstr "$cmdline" fastboot ; then

//那么就设置为yes,此时讲不会出现fsck磁盘自检啊啥的东西哦

fastboot=yes

fi

//看看是不是有这个fsckk磁盘检测程序选项文件

if [ -f /fsckoptions ]; then

//那么fsck的选项就来自于这里了嗯

fsckoptions=$(cat /fsckoptions)

fi

//看看是不是有强制检测的文件并且启动参数中有这个参数

if [ -f /forcefsck ] || strstr "$cmdline" forcefsck ; then

//那么所有上面的选项就加上一个force选项

fsckoptions="-f $fsckoptions"

//如果不存在强制检测文件的但是存在自动检测文件

elif [ -f /.autofsck ]; then

//并且真正的autpfsck的文件存在那么就执行它

[ -f /etc/sysconfig/autofsck ] && . /etc/sysconfig/autofsck

//如果执行上面的命令并且AUTOFSCK_DEF_CHECK的值为yes的话那么下次重启后就

开始磁盘自检

if [ "$AUTOFSCK_DEF_CHECK" = "yes" ]; then

//那么自动检测的选项加上force强制选项

AUTOFSCK_OPT="$AUTOFSCK_OPT -f"

fi

//不正常关机造成磁盘文件混乱,进入shell界面,进行fsck维护之后继续进行启动

if [ -n "$AUTOFSCK_SINGLEUSER" ]; then

//根据上面的PLYMOUTH来判断是否显示背景图片

[ -n "$PLYMOUTH" ] && plymouth --hide-splash

echo

//然后进入控制台显示警告信息

echo $"*** Warning -- the system did not shut down cleanly. "

echo $"*** Dropping you to a shell; the system will continue"

echo $"*** when you leave the shell."

//留给一个shell这时候就初始化selinux状态为permissive

[ -n "$SELINUX_STATE" ] && echo "0" > /selinux/enforce

//其实是执行了/etc/init/rcS.conf里面的配置然后来选择运行级别啊还有服务啊啥的

start rcS-emergency

//这样先permissive然后在enforce其实就起到了重打标签的作用

[ -n "$SELINUX_STATE" ] && echo "1" > /selinux/enforce

//这个地方也是根据PLYMOUTH的值来判断是否要显示背景图片

[ -n "$PLYMOUTH" ] && plymouth --show-splash

fi

//注意了上面一直到这里都没有运行fsck只是做判断是不是要执行哦

fsckoptions="$AUTOFSCK_OPT $fsckoptions"

fi

//判断全局变量BOOTUP是不是color如果是的话

if [ "$BOOTUP" = "color" ]; then

//那么就显示fsck的进度(-C也就是count的意思了)

fsckoptions="-C $fsckoptions"

else

//如果不是的话就显示详细信息了

fsckoptions="-V $fsckoptions"

fi

//初始化readonly变量

READONLY=

//其实这个应该是redhat的一个项目了sttatless,主要的作用是不让系统持久的对磁盘进行读写操作

它的原理下面已经体现的淋漓尽致了

if [ -f /etc/sysconfig/readonly-root ]; then

. /etc/sysconfig/readonly-root

fi

//如果启动参数中有readonlyroot的话

if strstr "$cmdline" readonlyroot ; then

//就设置上面的那个文件的readonly值为yes默认是空也就是是可以写的

READONLY=yes

//判断下面的RW_MOUNTSTATE_MOUNT是不是为空值啊如果是的uha就赋值这些都是在上面的

那个配置文件中

[ -z "" ] && RW_MOUNT=/var/lib/stateless/writable

[ -z "$STATE_MOUNT" ] && STATE_MOUNT=/var/lib/stateless/state

fi

//和上面一样的判断下是不是noredaonly其实启动参数只是/etc/sysconfig/readonly-root的一个映射

if strstr "$cmdline" noreadonlyroot ; then

//如果是的话就设置为no了

READONLY=no

fi

//如果readonly是yes或TEMPORARY_STATE= yes的话

if [ "$READONLY" = "yes" -o "$TEMPORARY_STATE" = "yes" ]; then

//声明一个函数mount_empty的作用就是复制第一个参数到$RW_MOUNT指定的目录做备份然后

再把备份挂载到原来的目录这样的话就是只读了嗯对吧?

mount_empty() {

if [ -e "$1" ]; then

echo "$1" | cpio -p -vd "$RW_MOUNT" &>/dev/null

mount -n --bind "$RW_MOUNT$1" "$1"

fi

}

//上面的empty管的是$1本身而这个dir是管理的是$1下的子目录同样的复制备份过去实现只读

mount_dirs() {

if [ -e "$1" ]; then

mkdir -p "$RW_MOUNT$1"

find "$1" -type d -print0 | cpio -p -0vd "$RW_MOUNT" &>/dev/null

mount -n --bind "$RW_MOUNT$1" "$1"

fi

}

//这里面当然的是$1下的文件或是子目录下饿文件备份处理的方法了嗯

mount_files() {

if [ -e "$1" ]; then

cp -a --parents "$1" "$RW_MOUNT"

mount -n --bind "$RW_MOUNT$1" "$1"

fi

}

# Common mount options for scratch space regardless of

# type of backing store

//初始化就不多说了

mountopts=

# Scan partitions for local scratch storage

//blkid命令用来索引或查看block设备的属性。-t参数用来指定一个属性(属性以name=value

的方式表示,例如LABEL=/),-l参数表示搜索其属性值和-t参数指定的属性值符合的block设

备。-o指定输出格式,可选的有full, value, device。以下是输出示例。

rw_mount_dev=$(blkid -t LABEL="$RW_LABEL" -l -o device)

# First try to mount scratch storage from /etc/fstab, then any

# partition with the proper label. If either succeeds, be sure

# to wipe the scratch storage clean. If both fail, then mount

# scratch storage via tmpfs.

//上面的解释已经很清除了嗯也就是挂载的时候先找/etc/fstab,如果其中没有定义那么就把上面

找到的分区挂载到$RW_MOUNT上如果依然没有成功那么就将它们挂载成tmpfs

if mount $mountopts "$RW_MOUNT" > /dev/null 2>&1 ; then

rm -rf "$RW_MOUNT" > /dev/null 2>&1

elif [ x$rw_mount_dev != x ] && mount $rw_mount_dev $mountopts "$RW_MOUNT" > /dev/null 2>&1; then

rm -rf "$RW_MOUNT" > /dev/null 2>&1

else

mount -n -t tmpfs $RW_OPTIONS $mountopts none "$RW_MOUNT"

fi

//遍历循环我们/etc/rwtab和/etc/rwtab.d/dev/.initramfs/rwtab文件和目录

for file in /etc/rwtab /etc/rwtab.d/* /dev/.initramfs/rwtab ; do

//同样调用functions里面定义的函数来判断文件是否忽略跳过

is_ignored_file "$file" && continue

//如果文件存在的话就循环分析他们的文件类型以及路径

[ -f $file ] && cat $file | while read type path ; do

case "$type" in

//直个地方就调用了我们上面的三个函数来处理循环显示的文件类型以及路径

empty)

mount_empty $path

;;

files)

mount_files $path

;;

dirs)

mount_dirs $path

;;

*)

;;

esac

//如果"$SELINUX_STATE"设置有值并且路径真的存在那么就初始化他们的context值

[ -n "$SELINUX_STATE" -a -e "$path" ] && restorecon -R "$path"

done

done

# Use any state passed by initramfs

//如果/dev/.initramfs/state是目录那么就把目录下的所有的文件都拷贝$RW_MOUNT下备份

[ -d /dev/.initramfs/state ] && cp -a /dev/.initramfs/state/* $RW_MOUNT

# In theory there should be no more than one network interface active

# this early in the boot process -- the one we're booting from.

# Use the network address to set the hostname of the client. This

# must be done even if we have local storage.

//初始化ip地址

ipaddr=

//如果主机名为localhost或是主机名是localhost.localdomain

if [ "$HOSTNAME" = "localhost" -o "$HOSTNAME" = "localhost.localdomain" ]; then

//用awk来过来ip

ipaddr=$(ip addr show to 0.0.0.0/0 scope global | awk '/[[:space:]]inet / { print gensub("/.*","","g",$2) }')

//循环给ip赋值

for ip in $ipaddr ; do

//初始化主机名

HOSTNAME=

//通过ipcalc来通过ip查找主机名

eval $(ipcalc -h $ip 2>/dev/null)

//如果主机名长度不为0的并且设置主机名成功的话就跳出循环

[ -n "$HOSTNAME" ] && { hostname ${HOSTNAME} ; break; }

done

fi

# Clients with read-only root filesystems may be provided with a

# place where they can place minimal amounts of persistent

# state. SSH keys or puppet certificates for example.

#

# Ideally we'll use puppet to manage the state directory and to

# create the bind mounts. However, until that's all ready this

# is sufficient to build a working system.

# First try to mount persistent data from /etc/fstab, then any

# partition with the proper label, then fallback to NFS

//和上面的一样的只是挂载方式不一样如果查找到的设备在fstab里面和$STATE_MOUNT中没有定义

那么就挂载成nfs文件系统

state_mount_dev=$(blkid -t LABEL="$STATE_LABEL" -l -o device)

if mount $mountopts $STATE_OPTIONS "$STATE_MOUNT" > /dev/null 2>&1 ; then

/bin/true

elif [ x$state_mount_dev != x ] && mount $state_mount_dev $mountopts "$STATE_MOUNT" > /dev/null 2>&1; then

/bin/true

elif [ ! -z "$CLIENTSTATE" ]; then

# No local storage was found. Make a final attempt to find

# state on an NFS server.

mount -t nfs $CLIENTSTATE/$HOSTNAME $STATE_MOUNT -o rw,nolock

fi

//判断挂载的目录是不是有写的权限

if [ -w "$STATE_MOUNT" ]; then

//这个就是和上面的一样的只是挂载方式不一样如果查找到的设备在fstab里面和$STATE_MOUNT中没有定义

那么就挂载成nfs文件系统的方法

mount_state() {

if [ -e "$1" ]; then

[ ! -e "$STATE_MOUNT$1" ] && cp -a --parents "$1" "$STATE_MOUNT"

mount -n --bind "$STATE_MOUNT$1" "$1"

fi

}

//循环遍历/etc/statetab /etc/statetab.d/下的文件

for file in /etc/statetab /etc/statetab.d/* ; do

//同样调用函数来判断这些文件

is_ignored_file "$file" && continue

[ ! -f "$file" ] && continue

//如果文件已经在$STATE_MOUNT存在的话就

if [ -f "$STATE_MOUNT/$file" ] ; then

//挂载绑定到STATE_MOUNT/$file做备份

mount -n --bind "$STATE_MOUNT/$file" "$file"

fi

//去掉注释然后再来遍历$file

for path in $(grep -v "^#" "$file" 2>/dev/null); do

//重新挂载这个也算是保险起见了

mount_state "$path"

/如果此时设置了selinux并且path的这个路径存在那就初始化context值

[ -n "$SELINUX_STATE" -a -e "$path" ] && restorecon -R "$path"

done

done

if [ -f "$STATE_MOUNT/files" ] ; then

for path in $(grep -v "^#" "$STATE_MOUNT/files" 2>/dev/null); do

mount_state "$path"

[ -n "$SELINUX_STATE" -a -e "$path" ] && restorecon -R "$path"

done

fi

fi

fi

//如果$fsckoptions中有-y的参数那么

if [[ " $fsckoptions" != *" -y"* ]]; then

//那么就在里面加上一个-a的参数

fsckoptions="-a $fsckoptions"

fi

//初始化quotacheck为0,也就是不启用quota

_RUN_QUOTACHECK=0

如果存在这个forcequotacheck 文件或是启动参数中有这个参数

if [ -f /forcequotacheck ] || strstr "$cmdline" forcequotacheck ; then

//那么就启动quota检测

_RUN_QUOTACHECK=1

fi

//如果fastboot不为0并且readonly是yes的话

if [ -z "$fastboot" -a "$READONLY" != "yes" ]; then

//显示出check的信息

STRING=$"Checking filesystems"

echo $STRING

//检测时候不显示title并且将非正常关机时候的检测详细信息保存到日志文件中

fsck -T -t noopts=_netdev -A $fsckoptions

//日志文件保存的是上一条命令的状态值

rc=$?

//如果等于0的话就返回成功了

if [ "$rc" -eq "0" ]; then

success "$STRING"

echo

//如果是1的话就跳过

elif [ "$rc" -eq "1" ]; then

passed "$STRING"

echo

//如果等于2或是等于3的话就返回没有挂载文件系统并重新挂载重启后再次检测

elif [ "$rc" -eq "2" -o "$rc" -eq "3" ]; then

echo $"Unmounting file systems"

umount -a

mount -n -o remount,ro /

echo $"Automatic reboot in progress."

reboot -f

fi

# A return of 4 or higher means there were serious problems.

//如果大于1的话就返回下面的错误信息(重启后)

if [ $rc -gt 1 ]; then

//不显示背景图片

[ -n "$PLYMOUTH" ] && plymouth --hide-splash

//返回失败信息

failure "$STRING"

echo

echo

echo $"*** An error occurred during the file system check."

echo $"*** Dropping you to a shell; the system will reboot"

echo $"*** when you leave the shell."

str=$"(Repair filesystem)"

//设置我们的命令提示符为Repair filesystem##

PS1="$str # # "; export PS1

//如果为selinux为强制模式的话就改为disabled的模式

[ "$SELINUX_STATE" = "1" ] && disable_selinux

//这个就是运行级别啊撒的启动的时候

start rcS-emergency

//然后返回要求重新挂载然后重启

echo $"Unmounting file systems"

umount -a

mount -n -o remount,ro /

echo $"Automatic reboot in progress."

reboot -f

//如果重启后检测等于1那么就设置_RUN_QUOTACHECK=1

elif [ "$rc" -eq "1" ]; then

_RUN_QUOTACHECK=1

fi

fi

//重新挂载函数(这个后面再讲嗯,后面要改写下嗯)

remount_needed() {

local state oldifs

[ "$READONLY" = "yes" ] && return 1

state=$(LC_ALL=C awk '/ / / && ($3 !~ /rootfs/) { print $4 }' /proc/mounts)

oldifs=$IFS

IFS=","

for opt in $state ; do

if [ "$opt" = "rw" ]; then

IFS=$oldifs

return 1

fi

done

IFS=$oldifs

return 0

}

# Remount the root filesystem read-write.

update_boot_stage RCmountfs

//判断如果函数执行成功的话

if remount_needed ; then

//就显示Remounting root filesystem in read-write mode并且重新挂载

action $"Remounting root filesystem in read-write mode: " mount -n -o remount,rw /

fi

# Clean up SELinux labels

//清除下面的这个些文件的context值

if [ -n "$SELINUX_STATE" ]; then

restorecon /etc/mtab /etc/ld.so.cache /etc/blkid/blkid.tab /etc/resolv.conf >/dev/null 2>&1

fi

//如果selinux是开启的而且readonly不等于yes那么就可以写了嗯顺便检查下autorelabe存在否?

或是启动参数中有木有有的话就可以直接的restorecon过滤出来的文件

# If relabeling, relabel mount points.

if [ -n "$SELINUX_STATE" -a "$READONLY" != "yes" ]; then

if [ -f /.autorelabel ] || strstr "$cmdline" autorelabel ; then

restorecon $(awk '!/^#/ && $4 !~ /noauto/ && $2 ~ /^// { print $2 }' /etc/fstab) >/dev/null 2>&1

fi

fi

//如果readonly是yes的话

if [ "$READONLY" != "yes" ] ; then

# Clear mtab

//清空这个记录挂载着的文件系统

(> /etc/mtab) &> /dev/null

//删除meab的备份文件

# Remove stale backups

rm -f /etc/mtab~ /etc/mtab~~

//重新挂载然后写到mtab文件(matb里面其实就是我们用输入mount命令时候的回显)

# Enter mounted filesystems into /etc/mtab

mount -f /

mount -f /proc >/dev/null 2>&1

mount -f /sys >/dev/null 2>&1

mount -f /dev/pts >/dev/null 2>&1

mount -f /dev/shm >/dev/null 2>&1

mount -f /proc/bus/usb >/dev/null 2>&1

fi

# Mount all other filesystems (except for NFS and /proc, which is already

# mounted). Contrary to standard usage,

# filesystems are NOT unmounted in single user mode.

# The 'no' applies to all listed filesystem types. See mount(8).

//如果readonly是yes的话

if [ "$READONLY" != "yes" ] ; then

//所有的文件系统都按着标准来挂载

action $"Mounting local filesystems: " mount -a -t nonfs,nfs4,smbfs,ncpfs,cifs,gfs,gfs2 -O no_netdev

else

action $"Mounting local filesystems: " mount -a -n -t nonfs,nfs4,smbfs,ncpfs,cifs,gfs,gfs2 -O no_netdev

fi

# Update quotas if necessary

//$_RUN_QUOTACHECK值为1的话并且quotacheck是可执行的

if [ X"$_RUN_QUOTACHECK" = X1 -a -x /sbin/quotacheck ]; then

//那么就检测的时候会找fatab里面有quota的分区并且检测对应用户和组占用的文件数和目录数

action $"Checking local filesystem quotas: " /sbin/quotacheck -anug

fi

//如果auota可执行的话就执行嗯也就是开启quota对指定目录

if [ -x /sbin/quotaon ]; then

action $"Enabling local filesystem quotas: " /sbin/quotaon -aug

fi

# Check to see if a full relabel is needed

//如果selinux开启了而且readonly不是yes的话

if [ -n "$SELINUX_STATE" -a "$READONLY" != "yes" ]; then

//自己手动新建了autorelable的话或是启动参数中有autorelable那么

if [ -f /.autorelabel ] || strstr "$cmdline" autorelabel ; then

//就执行这个命令重打标签

relabel_selinux

fi

else

//如果/etc/selinux的这个目录存在且readonly不是yes的话

if [ -d /etc/selinux -a "$READONLY" != "yes" ]; then

//如果autorelable文件不存在的话就新建一个

[ -f /.autorelabel ] || touch /.autorelabel

fi

fi

//

# Initialize pseudo-random number generator

//这里是初始化随机数如果/var/lib/random-seed文件存在的话

if [ -f "/var/lib/random-seed" ]; then

//那么就把内容传给/dev/urandom

cat /var/lib/random-seed > /dev/urandom

else

//如果不存在的话就创建这个文件

[ "$READONLY" != "yes" ] && touch /var/lib/random-seed

fi

//如果readonly是yes的话

if [ "$READONLY" != "yes" ]; then

//需要修改其权限为600只有所属主才可以写

chmod 600 /var/lib/random-seed

//从/dev/urandom读入512kb的数据给/var/lib/random-seed

dd if=/dev/urandom of=/var/lib/random-seed count=1 bs=512 2>/dev/null

fi

//判断cryption文件是否存在存在的话就初始化里面的值为1,那么就用上面的硬件随机数磁盘加密

if [ -f /etc/crypttab ]; then

init_crypto 1

fi

# Configure machine if necessary

//判断unconfigured文件是否存在

if [ -f /.unconfigured ]; then

//存在的话如果plymouth 可执行的话

if [ -x /bin/plymouth ]; then

//就退出图形化

/bin/plymouth quit

fi

//判断键盘是否设置如果没有设置的话就执行system-config-keyboard

if [ -x /usr/bin/system-config-keyboard ]; then

/usr/bin/system-config-keyboard

fi

//判断是否可以修改密码如果可以就修改root密码

if [ -x /usr/bin/passwd ]; then

/usr/bin/passwd root

fi

//判断是否可以修改网络设置可以的话就直接设置

if [ -x /usr/sbin/system-config-network-tui ]; then

/usr/sbin/system-config-network-tui

fi

//判断是否可以执行时间配置可以的话就直接设置

if [ -x /usr/sbin/timeconfig ]; then

/usr/sbin/timeconfig

fi

//判断是否可以执行authconfig-tui 来配置服务

if [ -x /usr/sbin/authconfig-tui ]; then

/usr/sbin/authconfig-tui --nostart

fi

//判断是否可以执行ntsysv来设置服务启动

if [ -x /usr/sbin/ntsysv ]; then

/usr/sbin/ntsysv --level 35

fi

//读取系统的网络配置

# Reread in network configuration data.

if [ -f /etc/sysconfig/network ]; then

. /etc/sysconfig/network

//重置hostname

# Reset the hostname.

action $"Resetting hostname ${HOSTNAME}: " hostname ${HOSTNAME}

fi

//删除unconfigured配置文件

rm -f /.unconfigured

fi

//删除上面的所有的标志文件然后重启启动

# Clean out /.

rm -f /fastboot /fsckoptions /forcefsck /.autofsck /forcequotacheck /halt

/poweroff /.suspended &> /dev/null

# Do we need (w|u)tmpx files? We don't set them up, but the sysadmin might...

_NEED_XFILES=

//正常情况下是需要 /var/run/utmpx 和 /var/log/wtmpx 文件 如果存在一个就设置_NEED_XFILES=1

[ -f /var/run/utmpx -o -f /var/log/wtmpx ] && _NEED_XFILES=1

//删除/var下的无用的记录文件

# Clean up /var.

rm -rf /var/lock/cvs/* /var/run/screen/*

find /var/lock /var/run ! -type d -exec rm -f {} ;

rm -f /var/lib/rpm/__db* &> /dev/null

rm -f /var/gdm/.gdmfifo &> /dev/null

//判断PROMPT是否不是no就说明当然是允许交互的

[ "$PROMPT" != no ] && plymouth watch-keystroke --command "touch /var/run/confirm" --keys=Ii &

# Clean up utmp/wtmp

//其实这个相当于cat /dev/null > /var/run/utmp

> /var/run/utmp

//新建/var/log/wtmp

touch /var/log/wtmp

//更改所属组统一为utmp

chgrp utmp /var/run/utmp /var/log/wtmp

//权限更改为0644

chmod 0664 /var/run/utmp /var/log/wtmp

//如果_NEED_XFILES长度不为0的话

if [ -n "$_NEED_XFILES" ]; then

//清空/var/run/utmpx因为已经存在了

> /var/run/utmpx

//新建一个touch /var/log/wtmpx并设置组为utmp权限为644,其实是为了防止如果没有/var/log/wtmpx或是/var/run/utmpx

这两个文件的情况

chgrp utmp /var/run/utmpx /var/log/wtmpx

chmod 0664 /var/run/utmpx /var/log/wtmpx

fi

//因为是新建的文件所以我们需要来判断下selinux的状态并且初始化下context值

[ -n "$SELINUX_STATE" ] && restorecon /var/run/utmp* /var/log/wtmp* >/dev/null 2>&1

//删除

# Clean up various /tmp bits

//如果selinux启动的话那么就初始化下context值

[ -n "$SELINUX_STATE" ] && restorecon /tmp

//然后删除/tmp下的影藏文件以及一些无用文件

rm -f /tmp/.X*-lock /tmp/.lock.* /tmp/.gdm_socket /tmp/.s.PGSQL.*

rm -rf /tmp/.X*-unix /tmp/.ICE-unix /tmp/.font-unix /tmp/hsperfdata_*

/tmp/kde-* /tmp/ksocket-* /tmp/mc-* /tmp/mcop-* /tmp/orbit-*

/tmp/scrollkeeper-* /tmp/ssh-*

/dev/.in_sysinit

# Make ICE directory

//创建ICE目录权限为1777也就是有一个t权限吧应该是只有属主才可以删除吧

mkdir -m 1777 -p /tmp/.ICE-unix >/dev/null 2>&1

//然后属主改为root就可以了

chown root:root /tmp/.ICE-unix

//同样的初始化下context值

[ -n "$SELINUX_STATE" ] && restorecon /tmp/.ICE-unix >/dev/null 2>&1

# Start up swapping.

//又是调用update_boot_stage函数类对swap分区操作

update_boot_stage RCswap

//启用所有的虚拟内存并且排除所有的不存在的虚拟文件

action $"Enabling /etc/fstab swaps: " swapon -a -e

//判断autoswap的值是不是yes

if [ "$AUTOSWAP" = "yes" ]; then

//awk过滤获取当然的swap分区,其中的get_numeric_dev 函数也是functions里面提供的

curswap=$(awk '/^/dev/ { print $1 }' /proc/swaps | while read x; do get_numeric_dev dec $x ; echo -n " "; done)

swappartitions=$(blkid -t TYPE=swap -o device)

//如果获取到的话

if [ x"$swappartitions" != x ]; then

//那么就遍历所有的swap分区

for partition in $swappartitions ; do

//并且判断是否存在这个分区或是文件如果存在的话就继续

[ ! -e $partition ] && continue

//这个函数我没有看嗯(应该是返回的是swap分区的名字吧,下去我也查查..)

majmin=$(get_numeric_dev dec $partition)

//这个就是二层过滤了然后调用action函数输出Enabling local swap partitions最后就是启用所有的swap分区了

echo $curswap | grep -qw "$majmin" || action $"Enabling local swap partitions: " swapon $partition

done

fi

fi

# Set up binfmt_misc

//挂载binfmt_misc

/bin/mount -t binfmt_misc none /proc/sys/fs/binfmt_misc > /dev/null 2>&1

# Boot time profiles. Yes, this should be somewhere else.

//如果system-config-network-cmd 可以执行的话

if [ -x /usr/sbin/system-config-network-cmd ]; then

//如过启动参数中有netprofile=的话

if strstr "$cmdline" netprofile= ; then

//遍历输出cndline里面的每个参数

for arg in $cmdline ; do

//如果arg删除匹配netprofile=的最大部分后不等于他本身的话

if [ "${arg##netprofile=}" != "${arg}" ]; then

//就用/usr/sbin/system-config-network-cmd --profile 来设置所有的参数值

/usr/sbin/system-config-network-cmd --profile ${arg##netprofile=}

fi

done

fi

fi

# Now that we have all of our basic modules loaded and the kernel going,

# let's dump the syslog ring somewhere so we can find it late

//如果存在dmesg内核启动加载信息文件的话就备份下

[ -f /var/log/dmesg ] && mv -f /var/log/dmesg /var/log/dmesg.old

//然后执行dmes并设置缓冲区的大小为131072输出的信息作为新的demesg新文件

dmesg -s 131072 > /var/log/dmesg

# create the crash indicator flag to warn on crashes, offer fsck with timeout

//创建.autofsck文件下次重启后自动的磁盘检测

touch /.autofsck &> /dev/null

//如果PROMPT如果不是no的话也就是yes的话那么就允许交互

[ "$PROMPT" != no ] && plymouth --ignore-keystroke=Ii

//判断启动参数中是否有confirm确认参数

if strstr "$cmdline" confirm ; then

//如果有的话就在/var/run新建这个文件

touch /var/run/confirm

fi

//如果对plymouth有执行权限的话

# Let rhgb know that we're leaving rc.sysinit

if [ -x /bin/plymouth ]; then

//就给图形话窗口发送消息rc.sysint执行完毕

/bin/plymouth --sysinit

fi

正文部分到此结束

本文固定链接: http://www.yhsafe.net/advanced-shell-analysis

文章转载请注明: [原创]900行高级SHELL编程之系统脚本rc.sysinit分析(欢迎指正) | +复制链接

您还可以继续浏览: 900行高级SHELL编程系统脚本rc.sysinit分析

分享到:QQ空间腾讯微博新浪微博网易微博人人网开心网腾讯朋友百度搜藏

  

爱华网本文地址 » http://www.aihuau.com/a/25101011/55592.html

更多阅读

shell编程之if判断的总结 shell脚本if判断

----------------------------------------------------------------------------------------------- 本文为个人笔记,仅供参考,希望对您的疑问有所帮助。欢迎转载,转载请注明出处。谢谢!------------------------------------------

金刚坐飞机——来自《编程之美》_阿- 变形金刚来自哪个星球

问题:笔者注释:《编程之美》中,这个问题其实描述得不是非常清楚,有以下两点是需要注意的,我一开始就没有注意到:1. 金刚是N个乘客当中的一员,并且座位也是一共有N个。2. 金刚插队后,第1个乘客就是金刚,并且第1个位置可以认为是金刚该坐的位置

如何提升行动力 大航海之路 行动力

转载▼标签: 自信心自卑心理挫折动力目标培训王学民陈安之教育 分类: 王学民什么是行动力行动力是指愿意不断的学习、思考,养成习惯和动机,进而获得导致成功结果的行为能力。具有行动力的人,行为的主动性高,具备一定的冒险精神,倾向于在不

声明:《900行高级SHELL编程之系统脚本rc.sysinit分析(欢迎指正) | 银河网 rc.sysinit错误》为网友山河故人分享!如侵犯到您的合法权益请联系我们删除