cat /proc/driver/rtc

本文详细介绍了Linux内核中RTC时间读取的具体实现过程。通过分析drivers/rtc/rtc-proc.c中的rtc_proc_add_device函数及相关的文件操作接口,展示了如何通过cat命令查询RTC状态。此外,还深入探讨了rtc_proc_show函数如何获取并展示RTC的时间和日期信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在drivers/rtc/rtc-proc.c 中定义了一个接口,是的可以通过cat /proc/driver/rtc 来查询rtc的情况.
在rtc_device_register->rtc_proc_add_device
void rtc_proc_add_device(struct rtc_device *rtc)
{
//proc_create_data 会在/proc/driver/rtc 下创建一个文件
	if (is_rtc_hctosys(rtc))
		proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc);
}
这个时候如果cat /proc/driver/rtc的时候会调用
static const struct file_operations rtc_proc_fops = {
	.open		= rtc_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= rtc_proc_release,
};
的rtc_proc_open
static int rtc_proc_open(struct inode *inode, struct file *file)
{
	int ret;
	struct rtc_device *rtc = PDE_DATA(inode);

	if (!try_module_get(rtc->owner))
		return -ENODEV;
会打开rtc_proc_show
	ret = single_open(file, rtc_proc_show, rtc);
	if (ret)
		module_put(rtc->owner);
	return ret;
}
。所以cat /proc/driver/rtc的时候最终会调用rtc_proc_show

static int rtc_proc_show(struct seq_file *seq, void *offset)
{
	int err;
	struct rtc_device *rtc = seq->private;
	const struct rtc_class_ops *ops = rtc->ops;
	struct rtc_wkalrm alrm;
	struct rtc_time tm;

	err = rtc_read_time(rtc, &tm);
	if (err == 0) {
		seq_printf(seq,
			"rtc_time\t: %02d:%02d:%02d\n"
			"rtc_date\t: %04d-%02d-%02d\n",
			tm.tm_hour, tm.tm_min, tm.tm_sec,
			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
	}
	return 0;
}
实际测试如下:

#! /bin/bash # This script is created by DQE Ghosty Liu 2020/08/10 # ### RW TEST PARAMETER ### PARTITION="sdb1" declare -i RW_count=1 declare -i RW_cycle=1 #(1 cycle = 128 MB) Check_Flag=1 #(1 = check disk scan result; 0 = not check disk scan result) Remove_Flag=1 #(1 = remove test file; 0 = not remove test file) ### PKTGEN TEST PARAMETER ### PAIRS="ens8f0-ens8f1-8 enp2s0f0-enp2s0f1-9 enp130s0f0-enp130s0f1-10 ens5f0-ens5f1-11 ens5f2-ens5f3-12" #(port-port-core) JUMBO=y declare -i TIME=30 ### STRESS TEST PARAMETER ### COMMAND="stress -c 4 -m 4 --vm-bytes 1024M -t 60" declare -i CYCLE=20 #(1 cycle = 3 seconds) ### PING TEST PARAMETER ### declare -i PING_COUNT=10 ### RTC WAKE PARAMETER ### declare -i delay=30 # <Decide the RTC wake up delay time here.> ### SPECIAL SCAN PARAMETER ### check_item="error" # <Add other check item for SPECIAL_SCAN here.> ########################################################################################################## function DD() { for k in $(seq $RW_count `expr $RW_cycle - 1`) do if [ ! -z "$k" ] then dd if=/dev/zero of=/$partition/$count.$k.tmp bs=32M count=4 conv=fsync &> /dev/null & fi done dd if=/dev/zero of=/$partition/$count.$RW_cycle.tmp bs=32M count=4 conv=fsync &> /dev/null } function RW_TEST() { if [ "$count" -gt "1" ] && [ "$Check_Flag" -eq "1" ] then echo -e "Check DISK SCAN reeult ..." if [ -z "`diff -q /Test/CYCLE_LOG/DISK_SCAN/1.log /Test/CYCLE_LOG/DISK_SCAN/$count.log`" ] then echo -e "Check Pass." else echo -e "Check failed. RW Test will be terminated." echo "COUNT=$count :" >> /Test/CYCLE_LOG/rw_test_fail.log echo -e "Check failed. RW Test had been skipped." >> /Test/CYCLE_LOG/rw_test_fail.log return 1 fi fi echo -e "Start Storage R/W Test ..." if [ ! -d "/Test/CYCLE_LOG/RW_TEST" ] then mkdir -p /Test/CYCLE_LOG/RW_TEST fi for partition in $PARTITION do if [ ! -d "/Test/CYCLE_LOG/RW_TEST/$partition" ] then mkdir -p /Test/CYCLE_LOG/RW_TEST/$partition fi if [ ! -z "`ls /dev/ | grep $partition`" ] || [ ! -d "/$partition" ] then mkdir -p /$partition if [ -z "`mount | grep $partition`" ] then mount /dev/$partition /$partition else if [ ! -z "`mount | grep $partition | grep /mnt/hdd`" ] then echo "Please make sure that Partition: $partition is not used by Testbed!" rm -rf /$partition rm -rf /Test/CYCLE_LOG/RW_TEST/$partition continue fi fi echo "COUNT : $count" >> /Test/CYCLE_LOG/RW_TEST/$partition/result.log (time -p DD) 2>> /Test/CYCLE_LOG/RW_TEST/$partition/result.log & sleep 1 fi done while [ 1 ] do buf=`ps -aux | grep -i "/dev/zero" | wc -l` if [ "$buf" -eq "1" ] then break fi sleep 1 done sync sleep 5 for partition in $PARTITION do if [ -d "/$partition" ] then if [ "$Remove_Flag" -eq "1" ] then rm -rf /$partition/* sync fi umount /$partition fi done if [ ! -z "`dmesg | grep -i ata | grep -i error`" ] then echo "COUNT=$count :" >> /Test/CYCLE_LOG/rw_test_fail.log dmesg | grep -i ata | grep -i error >> /Test/CYCLE_LOG/rw_test_fail.log fi } function PKTGEN_TEST() { echo -e "Start PKTGEN Test ..." if [ ! -d "/Test/CYCLE_LOG/PKTGEN_TEST" ] then mkdir -p /Test/CYCLE_LOG/PKTGEN_TEST fi if [ -z "`lsmod | grep pkt`" ] then echo "Please install pktgen driver first!!" exit 1 fi for pair in $PAIRS do PORT_A=`echo $pair | cut -d "-" -f 1` PORT_B=`echo $pair | cut -d "-" -f 2` CPU_NUM=`echo $pair | cut -d "-" -f 3` ifconfig $PORT_A up ifconfig $PORT_B up if [ "$count" -le "1" ] then echo $PORT_A >> /Test/CYCLE_LOG/ethernet_port.list echo $PORT_B >> /Test/CYCLE_LOG/ethernet_port.list fi echo "rem_device_all" > /proc/net/pktgen/kpktgend_$CPU_NUM echo "add_device $PORT_A" > /proc/net/pktgen/kpktgend_$CPU_NUM echo "add_device $PORT_B" > /proc/net/pktgen/kpktgend_$CPU_NUM echo "max_before_softirq 10000" > /proc/net/pktgen/kpktgend_$CPU_NUM if [ ! -f "/proc/net/pktgen/$PORT_A" ] || [ ! -f "/proc/net/pktgen/$PORT_B" ] then echo "Fail to add $pair to pktgen" exit 1 fi echo "count 0" > /proc/net/pktgen/$PORT_A echo "count 0" > /proc/net/pktgen/$PORT_B if [ "$JUMBO" == "y" ] then ifconfig $PORT_A mtu 9000 up ifconfig $PORT_B mtu 9000 up echo "pkt_size 9014" > /proc/net/pktgen/$PORT_A echo "pkt_size 9014" > /proc/net/pktgen/$PORT_B else echo "pkt_size 1514" > /proc/net/pktgen/$PORT_A echo "pkt_size 1514" > /proc/net/pktgen/$PORT_B fi echo "delay 100" > /proc/net/pktgen/$PORT_A echo "delay 100" > /proc/net/pktgen/$PORT_B echo "dst_mac `ifconfig $PORT_B | grep ether | tr -s " " | cut -d " " -f 3`" > /proc/net/pktgen/$PORT_A echo "dst_mac `ifconfig $PORT_A | grep ether | tr -s " " | cut -d " " -f 3`" > /proc/net/pktgen/$PORT_B done sleep 10 echo start > /proc/net/pktgen/pgctrl & declare -i buf=`cat /sys/class/rtc/rtc0/since_epoch` buf=$buf+$TIME while [ 1 ] do if [ "`cat /sys/class/rtc/rtc0/since_epoch`" -le "$buf" ] then sleep 1 else break fi done kill -9 $! sleep 1 for i in `cat /Test/CYCLE_LOG/ethernet_port.list` do if [ ! -f "/Test/CYCLE_LOG/PKTGEN_TEST/$i" ] then mkdir -p /Test/CYCLE_LOG/PKTGEN_TEST/$i fi ethtool -S $i | grep -i crc > /Test/CYCLE_LOG/PKTGEN_TEST/$i/CRC_$count.log cat /proc/net/pktgen/$i > /Test/CYCLE_LOG/PKTGEN_TEST/$i/PKTGEN_$count.log for j in `cat /Test/CYCLE_LOG/PKTGEN_TEST/$i/CRC_$count.log` do declare -i buf=`echo $j | cut -d ":" -f 2 | cut -d " " -f 2` if [ "$buf" -gt "0" ] then echo "COUNT=$count :" >> /Test/CYCLE_LOG/pktgen_test_fail.log echo "$i pktgen test result has CRC errors." >> /Test/CYCLE_LOG/pktgen_test_fail.log fi done sync done } function TIME_STAMP() { if [ "$count" -eq "1" ] then cat /sys/class/rtc/rtc0/since_epoch > /Test/CYCLE_LOG/time_stamp_tmp.log echo "$count: 0" > /Test/CYCLE_LOG/time_stamp.log else declare -i Ntime=`cat /sys/class/rtc/rtc0/since_epoch` declare -i Otime=`cat /Test/CYCLE_LOG/time_stamp_tmp.log` echo "$count: `expr $Ntime - $Otime`" >> /Test/CYCLE_LOG/time_stamp.log echo $Ntime > /Test/CYCLE_LOG/time_stamp_tmp.log fi } function STRESS() { echo -e "Start Stress Test ..." sleep 3 $COMMAND & top -d 3 -n $CYCLE clear } function DMESG() { if [ ! -d "/Test/CYCLE_LOG/DMESG" ] then mkdir -p /Test/CYCLE_LOG/DMESG fi dmesg > /Test/CYCLE_LOG/DMESG/$count.log sync } function PING_TEST() { echo -e "Start PING Test ..." if [ ! -d "/Test/CYCLE_LOG/PING_TEST" ] then mkdir -p /Test/CYCLE_LOG/PING_TEST fi if [ ! -f "/Test/ping.config" ] then echo "Couldn't find ping.config on path /Test! Stop PING_TEST..." sleep 3 break else Ping_item=`cat /Test/ping.config` # <The ping.config shall be "name1_source-address1_destination-address1 name2_source-address2_destination-address2 ...".> for i in $Ping_item do ETH_NAME=`echo $i | cut -d "_" -f 1` S_ADDRESS=`echo $i | cut -d "_" -f 2` D_ADDRESS=`echo $i | cut -d "_" -f 3` ifconfig $ETH_NAME $S_ADDRESS up sleep 3 echo -e "\n$ETH_NAME ping $D_ADDRESS test..." ping -I $ETH_NAME $D_ADDRESS -c $PING_COUNT >> /Test/ping.$ETH_NAME.[$D_ADDRESS].tmp & done fi while [ 1 ] do Buf=`ps | grep -i eth | wc -l` if [ "$Buf" = "1" ] then sleep 3 break fi done Buf_stress=`ps | grep -i stress | wc -l` if [ "$Buf_stress" -ne "1" ] then pkill stress fi Ping_tmp=`ls /Test | grep -i .tmp` for i in $Ping_tmp do if [ ! -f "/Test/CYCLE_LOG/PING_TEST/$i" ] then mkdir -p /Test/CYCLE_LOG/PING_TEST/$i fi j=`echo $i | cut -d "." -f 2` cat /Test/$i >> /Test/CYCLE_LOG/PING_TEST/$i/$count.log if [ -z "`cat /Test/$i | grep -i ttl=`" ] then echo "COUNT=$count :" >> /Test/CYCLE_LOG/ping_test_fail.log echo "$i ping test failed." >> /Test/CYCLE_LOG/ping_test_fail.log cat /Test/$i >> /Test/CYCLE_LOG/ping_test_fail.log echo " " >> /Test/CYCLE_LOG/ping_test_fail.log ifconfig $j >> /Test/CYCLE_LOG/ping_test_fail.log echo " " >> /Test/CYCLE_LOG/ping_test_fail.log ethtool $j >> /Test/CYCLE_LOG/ping_test_fail.log echo "=====================================================" >> /Test/CYCLE_LOG/ping_test_fail.log fi rm -rf /Test/$i done sync sleep 1 } function SPECIAL_SCAN() { if [ ! -d "/Test/CYCLE_LOG/SPECIAL_SCAN" ] then mkdir -p /Test/CYCLE_LOG/SPECIAL_SCAN fi for i in `echo $check_item` do dmesg | grep -i $i | cut -d "]" -f 2 >> /Test/CYCLE_LOG/SPECIAL_SCAN/$count.log dmesg | grep -i $i >> /Test/CYCLE_LOG/special_scan.log done echo "=====================================================" >> /Test/CYCLE_LOG/special_scan.log if [ -f "/Test/CYCLE_LOG/SPECIAL_SCAN/1.log" ] then BUFFER=`diff -q /Test/CYCLE_LOG/SPECIAL_SCAN/1.log /Test/CYCLE_LOG/SPECIAL_SCAN/$count.log` if [ ! -z "$BUFFER" ] then echo "COUNT=$count :" >> /Test/CYCLE_LOG/SPECIAL_SCAN_fail.log diff /Test/CYCLE_LOG/SPECIAL_SCAN/1.log /Test/CYCLE_LOG/SPECIAL_SCAN/$count.log >> /Test/CYCLE_LOG/SPECIAL_SCAN_fail.log echo " " >> /Test/CYCLE_LOG/SPECIAL_SCAN_fail.log fi fi sync sleep 1 } function USB_SCAN() { echo -e "Scanning USB devices ..." if [ ! -d "/Test/CYCLE_LOG/USB_SCAN" ] then mkdir -p /Test/CYCLE_LOG/USB_SCAN fi lsusb -tvv >> /Test/CYCLE_LOG/USB_SCAN/$count.log lsusb -tvv >> /Test/CYCLE_LOG/usb_scan.log echo "=====================================================" >> /Test/CYCLE_LOG/usb_scan.log if [ -f "/Test/CYCLE_LOG/USB_SCAN/1.log" ] then BUFFER=`diff -q /Test/CYCLE_LOG/USB_SCAN/1.log /Test/CYCLE_LOG/USB_SCAN/$count.log` if [ ! -z "$BUFFER" ] then echo "COUNT=$count :" >> /Test/CYCLE_LOG/USB_SCAN_fail.log diff /Test/CYCLE_LOG/USB_SCAN/1.log /Test/CYCLE_LOG/USB_SCAN/$count.log >> /Test/CYCLE_LOG/USB_SCAN_fail.log echo " " >> /Test/CYCLE_LOG/USB_SCAN_fail.log fi fi #/Test/67b-usblist.sh >> /Test/CYCLE_LOG/tb_usblist.log sync sleep 1 } function DRIVER_INSTALL() { for i in /Test/*.ko do insmod $i done sleep 1 } function PCIE_SCAN() { echo -e "\nScanning PCIe devices ..." if [ ! -d "/Test/CYCLE_LOG/PCIE_SCAN" ] then mkdir -p /Test/CYCLE_LOG/PCIE_SCAN fi for i in `lspci | sed 's/ /_/g'` do DEVICE=`echo $i | cut -d "_" -f 1` LNK_CAP_SPEED=`lspci -s $DEVICE -vv | grep LnkCap: | cut -d ":" -f 2 | cut -d "," -f 2` LNK_CAP_WIDTH=`lspci -s $DEVICE -vv | grep LnkCap: | cut -d ":" -f 2 | cut -d "," -f 3` LNK_STA_SPEED=`lspci -s $DEVICE -vv | grep LnkSta: | cut -d ":" -f 2 | cut -d "," -f 1` LNK_STA_WIDTH=`lspci -s $DEVICE -vv | grep LnkSta: | cut -d ":" -f 2 | cut -d "," -f 2` if [ ! -z "$LNK_CAP_SPEED" ] && [ ! -z "$LNK_STA_SPEED" ] then echo "$i : CAPABILITY=$LNK_CAP_SPEED, $LNK_CAP_WIDTH & STATUS=$LNK_STA_SPEED, $LNK_STA_WIDTH" >> /Test/CYCLE_LOG/PCIE_SCAN/$count.log echo "$i : CAPABILITY=$LNK_CAP_SPEED, $LNK_CAP_WIDTH & STATUS=$LNK_STA_SPEED, $LNK_STA_WIDTH" >> /Test/CYCLE_LOG/pcie_scan.log else echo "$i :" >> /Test/CYCLE_LOG/PCIE_SCAN/$count.log echo "$i :" >> /Test/CYCLE_LOG/pcie_scan.log fi done echo "Total count = `lspci | wc -l`" >> /Test/CYCLE_LOG/PCIE_SCAN/$count.log echo "Total count = `lspci | wc -l`" >> /Test/CYCLE_LOG/pcie_scan.log echo "=====================================================" >> /Test/CYCLE_LOG/pcie_scan.log if [ -f "/Test/CYCLE_LOG/PCIE_SCAN/1.log" ] then BUFFER=`diff -q /Test/CYCLE_LOG/PCIE_SCAN/1.log /Test/CYCLE_LOG/PCIE_SCAN/$count.log` if [ ! -z "$BUFFER" ] then echo "COUNT=$count :" >> /Test/CYCLE_LOG/PCIE_SCAN_fail.log diff /Test/CYCLE_LOG/PCIE_SCAN/1.log /Test/CYCLE_LOG/PCIE_SCAN/$count.log >> /Test/CYCLE_LOG/PCIE_SCAN_fail.log echo " " >> /Test/CYCLE_LOG/PCIE_SCAN_fail.log fi fi #/Test/64a-get_pcilist.sh >> /Test/CYCLE_LOG/tb_pcilist.log sync sleep 1 } function DISK_SCAN() { echo -e "Scanning Storage devices ..." if [ ! -d "/Test/CYCLE_LOG/DISK_SCAN" ] then mkdir -p /Test/CYCLE_LOG/DISK_SCAN fi for i in `ls /sys/block/` do if [ -f "/sys/block/$i/device/model" ] then if [ ! -z "$(cat /sys/block/$i/device/model | grep -v Virtual)" ] then SIZE=$(expr `cat /sys/block/$i/size` \* 512) echo -e "$i : `cat /sys/block/$i/device/model`\t Size = $SIZE Byte" >> /Test/CYCLE_LOG/DISK_SCAN/$count.log echo -e "$i : `cat /sys/block/$i/device/model`\t Size = $SIZE Byte" >> /Test/CYCLE_LOG/disk_scan.log fi elif [ -f "/sys/block/$i/device/name" ] then SIZE=$(expr `cat /sys/block/$i/size` \* 512) echo -e "$i : `cat /sys/block/$i/device/name`\t Size = $SIZE Byte" >> /Test/CYCLE_LOG/DISK_SCAN/$count.log echo -e "$i : `cat /sys/block/$i/device/name`\t Size = $SIZE Byte" >> /Test/CYCLE_LOG/disk_scan.log fi done echo "=====================================================" >> /Test/CYCLE_LOG/disk_scan.log if [ -f "/Test/CYCLE_LOG/DISK_SCAN/1.log" ] then BUFFER=`diff -q /Test/CYCLE_LOG/DISK_SCAN/1.log /Test/CYCLE_LOG/DISK_SCAN/$count.log` if [ ! -z "$BUFFER" ] then echo "COUNT=$count :" >> /Test/CYCLE_LOG/DISK_SCAN_fail.log diff /Test/CYCLE_LOG/DISK_SCAN/1.log /Test/CYCLE_LOG/DISK_SCAN/$count.log >> /Test/CYCLE_LOG/DISK_SCAN_fail.log echo " " >> /Test/CYCLE_LOG/DISK_SCAN_fail.log fi fi #/Test/66a-get_hddlist.sh >> /Test/CYCLE_LOG/tb_hddlist.log sync sleep 1 } function MAC_SCAN() { echo -e "Scanning Ethernet port MAC address ..." if [ ! -d "/Test/CYCLE_LOG/MAC_SCAN" ] then mkdir -p /Test/CYCLE_LOG/MAC_SCAN fi for i in `ls /sys/class/net/` do if [ -d "/sys/class/net/$i/device" ] then echo -e "$i\t : `cat /sys/class/net/$i/address`" >> /Test/CYCLE_LOG/MAC_SCAN/$count.log echo -e "$i\t : `cat /sys/class/net/$i/address`" >> /Test/CYCLE_LOG/mac_scan.log fi done echo "=====================================================" >> /Test/CYCLE_LOG/mac_scan.log if [ -f "/Test/CYCLE_LOG/MAC_SCAN/1.log" ] then BUFFER=`diff -q /Test/CYCLE_LOG/MAC_SCAN/1.log /Test/CYCLE_LOG/MAC_SCAN/$count.log` if [ ! -z "$BUFFER" ] then echo "COUNT=$count :" >> /Test/CYCLE_LOG/MAC_SCAN_fail.log diff /Test/CYCLE_LOG/MAC_SCAN/1.log /Test/CYCLE_LOG/MAC_SCAN/$count.log >> /Test/CYCLE_LOG/MAC_SCAN_fail.log echo " " >> /Test/CYCLE_LOG/MAC_SCAN_fail.log fi fi sync sleep 1 } function CLEAR_LOG() { if [ -d "/Test/CYCLE_LOG" ] then DATE=`date | sed 's/ /_/g' | sed 's/:/_/g' | sed 's/__/_/g'` mkdir -p /Test/$DATE mv /Test/CYCLE_LOG/* /Test/$DATE sync rm -rf /Test/CYCLE_LOG fi } function DEBUG() { if [ "$1" = "disk" ] || [ "$1" = "DISK" ] then DISK_SCAN echo "-------------------------------------------" cat /Test/CYCLE_LOG/DISK_SCAN/1.log echo "-------------------------------------------" rm -rf /Test/CYCLE_LOG/* elif [ "$1" = "pcie" ] || [ "$1" = "PCIE" ] then PCIE_SCAN echo "-------------------------------------------" cat /Test/CYCLE_LOG/PCIE_SCAN/1.log echo "-------------------------------------------" rm -rf /Test/CYCLE_LOG/* elif [ "$1" = "usb" ] || [ "$1" = "USB" ] then USB_SCAN echo "-------------------------------------------" cat /Test/CYCLE_LOG/USB_SCAN/1.log echo "-------------------------------------------" rm -rf /Test/CYCLE_LOG/* elif [ "$1" = "special" ] || [ "$1" = "SPECIAL" ] then SPECIAL_SCAN echo "-------------------------------------------" cat /Test/CYCLE_LOG/SPECIAL_SCAN/1.log echo "-------------------------------------------" rm -rf /Test/CYCLE_LOG/* elif [ "$1" = "mac" ] || [ "$1" = "MAC" ] then MAC_SCAN echo "-------------------------------------------" cat /Test/CYCLE_LOG/MAC_SCAN/1.log echo "-------------------------------------------" rm -rf /Test/CYCLE_LOG/* elif [ "$1" = "rw" ] || [ "$1" = "RW" ] then RW_TEST echo "-------------------------------------------" for i in $PARTITION do if [ -d "/$i" ] then cat /Test/CYCLE_LOG/RW_TEST/$i/result.log else echo "Partition: $i could not be tested!" fi done echo "-------------------------------------------" rm -rf /Test/CYCLE_LOG/* elif [ "$1" = "ping" ] || [ "$1" = "PING" ] then Ping_item=`cat /Test/ping.config` PING_TEST Log_list=`ls /Test/CYCLE_LOG/PING_TEST` for i in $Log_list do echo "-------------------------------------------" cat /Test/CYCLE_LOG/PING_TEST/$i/1.log echo "-------------------------------------------" done rm -rf /Test/CYCLE_LOG/* elif [ "$1" = "stress" ] || [ "$1" = "STRESS" ] then STRESS elif [ "$1" = "pktgen" ] || [ "$1" = "PKTGEN" ] then PKTGEN_TEST for i in `cat /Test/CYCLE_LOG/ethernet_port.list` do echo "-------------------------------------------" cat /Test/CYCLE_LOG/PKTGEN_TEST/$i/CRC_1.log cat /Test/CYCLE_LOG/PKTGEN_TEST/$i/PKTGEN_1.log echo "-------------------------------------------" done rm -rf /Test/CYCLE_LOG/* elif [ "$1" = "clean" ] || [ "$1" = "CLEAN" ] then CLEAR_LOG else mkdir -p /Test/CYCLE_LOG echo $1 > /Test/CYCLE_LOG/goal.tmp echo $2 > /Test/CYCLE_LOG/power_cycle.tmp fi } function POWER_CYCLE() { COMMAND=`cat /Test/CYCLE_LOG/power_cycle.tmp` if [ $COMMAND == poweroff ] then echo 0 > /sys/class/rtc/rtc0/wakealarm echo `expr $(date +%s) + $delay` > /sys/class/rtc/rtc0/wakealarm $COMMAND else $COMMAND fi } if [ -z "$1" ] then if [ -f "/Test/CYCLE_LOG/goal.tmp" ] && [ -f "/Test/CYCLE_LOG/power_cycle.tmp" ] then #DRIVER_INSTALL declare -i goal=`cat /Test/CYCLE_LOG/goal.tmp` declare -i count if [ ! -d "/Test/CYCLE_LOG" ] then mkdir -p /Test/CYCLE_LOG fi if [ ! -f "/Test/CYCLE_LOG/count.log" ] then echo 1 > /Test/CYCLE_LOG/count.log echo 1 > /Test/CYCLE_LOG/first.tmp fi count=`cat /Test/CYCLE_LOG/count.log` if [ ! -f "/Test/CYCLE_LOG/FLAG01" ] && [ ! -f "/Test/CYCLE_LOG/first.tmp" ] then echo "The $count times test is not finished correctly!" >> /Test/CYCLE_LOG/Warnning.log count+=1 echo $count > /Test/CYCLE_LOG/count.log else if [ -f "/Test/CYCLE_LOG/FLAG01" ] then rm -rf /Test/CYCLE_LOG/FLAG01 fi fi if [ ! -f "/Test/CYCLE_LOG/FLAG02" ] && [ ! -f "/Test/CYCLE_LOG/first.tmp" ] then if [ ! -z "`ls /Test/CYCLE_LOG/PCIE_SCAN/ | grep $count.log`" ] then count+=1 echo $count > /Test/CYCLE_LOG/count.log fi else if [ -f "/Test/CYCLE_LOG/FLAG02" ] then rm -rf /Test/CYCLE_LOG/FLAG02 fi fi sync if [ -f "/Test/CYCLE_LOG/first.tmp" ] then rm -rf /Test/CYCLE_LOG/first.tmp fi clear echo "******************************************************" echo "* *" echo "* System is starting the $count times cycle test ... " echo "* *" echo "******************************************************" read -p "Press [c] to stop testing! " -t 5 -n 1 stop if [ "$stop" = "c" ] then echo 0 > /sys/class/rtc/rtc0/wakealarm CLEAR_LOG exit 0 fi PCIE_SCAN DISK_SCAN #RW_TEST USB_SCAN MAC_SCAN SPECIAL_SCAN #PKTGEN_TEST #STRESS #PING_TEST DMESG TIME_STAMP if [ "$count" -ge "$goal" ] then CLEAR_LOG clear echo "******************************************************" echo "* *" echo "* The power cycle test has been finished! *" echo "* *" echo "******************************************************" read -p "Press any key to continue! " -n 1 continue else echo 1 > /Test/CYCLE_LOG/FLAG01 count+=1 echo $count > /Test/CYCLE_LOG/count.log echo 1 > /Test/CYCLE_LOG/FLAG02 sync clear echo "******************************************************" echo "* *" echo "* The `expr $count - 1` times cycle test is completed ... " echo "* *" echo "******************************************************" sleep 1 POWER_CYCLE fi fi else declare -i count=1 if [ -z "$2" ] then DEBUG $1 else DEBUG $1 $2 fi fi 帮忙将这个脚本优化一下,我只是用来计数开关机的次数,只要开机能显示执行了多少次的效果,其他多余的部分请帮忙删除
最新发布
07-25
<think>我们有一个需求:优化一个Bash脚本,仅保留开关机次数计数功能,并在开机时显示执行次数。 原脚本可能包含其他测试功能,我们需要删除这些不必要的部分,只保留核心功能。 核心功能: 1. 记录开关机次数:每次开机时,计数器加1。 2. 在开机时显示当前的执行次数(即开关机次数)。 实现思路: 我们可以使用一个文件来持久化存储计数。每次开机执行脚本时,读取文件中的数值,加1后再写回文件,并显示这个数值。 步骤: 1. 定义一个存储计数的文件,例如`/var/log/boot_counter.log`(注意:需要root权限才能写入/var/log,或者选择用户有权限的目录)。 2. 脚本启动时,检查该文件是否存在。如果不存在,则创建并写入0(表示第一次启动)。 3. 读取文件中的数值,加1,然后写回文件。 4. 显示当前的开机次数。 注意:由于我们希望在开机时运行,所以这个脚本应该被放在系统的启动项中(例如,通过systemd服务、rc.local或者cron的@reboot等)。 简化后的脚本: 假设我们选择存储文件为`/var/log/boot_counter.log`,由于`/var/log`通常需要root权限,所以这个脚本需要以root身份运行(比如通过systemd服务)。 脚本内容如下: ```bash #!/bin/bash # 定义存储计数的文件路径 COUNTER_FILE="/var/log/boot_counter.log" # 如果文件不存在,则创建并初始化为0 if [ ! -f "$COUNTER_FILE" ]; then echo "0" > "$COUNTER_FILE" fi # 读取当前计数 count=$(cat "$COUNTER_FILE") # 计数加1 new_count=$((count + 1)) # 将新计数写入文件 echo "$new_count" > "$COUNTER_FILE" # 显示开机次数 echo "这是第 $new_count 次启动系统。" ``` 但是,我们需要注意: 1. 权限问题:如果脚本通过root用户执行,那么文件会由root创建,后续执行也需要root权限。 2. 放置位置:为了让脚本在开机时运行,我们可以将其配置为一个systemd服务,或者添加到`/etc/rc.local`(如果系统支持)。 使用systemd服务配置方法(推荐): 1. 创建服务文件:`/etc/systemd/system/boot-counter.service` 2. 内容如下: [Unit] Description=Boot Counter Service After=network.target [Service] Type=oneshot ExecStart=/path/to/your/script.sh RemainAfterExit=yes [Install] WantedBy=multi-user.target 3. 启用服务: sudo systemctl daemon-reload sudo systemctl enable boot-counter.service 这样,每次开机时,systemd会运行这个脚本。 另外,如果使用`/etc/rc.local`: 1. 确保`rc.local`服务已启用(不同发行版可能不同)。 2. 将脚本的绝对路径添加到`/etc/rc.local`的`exit 0`之前。 关于显示:脚本中的`echo`语句可能会输出到控制台,但具体显示在哪里取决于启动方式。如果希望所有用户登录时都能看到,可以将该信息添加到`/etc/motd`(每日消息)中,但注意这样会在每次登录时都显示。或者,我们可以只让它在启动过程中显示(通过systemd服务,输出可能会被记录到journal,不一定显示在控制台)。 如果我们希望消息在启动时显示在控制台上,可以考虑使用`wall`命令广播给所有用户,但这样可能会在每次启动时广播,所有登录的用户都会收到,可能不是最佳。 另一种方法:将消息写入`/etc/motd`,这样用户登录时就会看到。我们可以修改脚本,将开机次数写入`/etc/motd`: ```bash #!/bin/bash COUNTER_FILE="/var/log/boot_counter.log" if [ ! -f "$COUNTER_FILE" ]; then echo "0" > "$COUNTER_FILE" fi count=$(cat "$COUNTER_FILE") new_count=$((count + 1)) echo "$new_count" > "$COUNTER_FILE" # 将启动次数写入/etc/motd echo "这是第 $new_count 次启动系统。" > /etc/motd ``` 注意:修改`/etc/motd`也需要root权限。 这样,用户登录时就会看到开机次数。 但是,需要注意的是,`/etc/motd`通常是一个静态文件,有些系统会使用动态生成(比如通过`pam_motd`模块)。如果我们直接覆盖`/etc/motd`,可能会覆盖其他内容。因此,我们可以选择追加的方式,或者只更新我们需要的部分。 如果我们希望保留`/etc/motd`原有的内容,只添加一行启动次数,可以这样: ```bash # 先备份原有motd,然后追加一行 cp /etc/motd /etc/motd.bak echo "这是第 $new_count 次启动系统。" > /etc/motd cat /etc/motd.bak >> /etc/motd rm /etc/motd.bak ``` 但是这样每次启动都会在原有内容前面加上一行,可能会重复。所以更好的方式是,我们不在`/etc/motd`中记录,而是单独放在一个文件中,然后配置`pam_motd`来引用这个文件,或者直接使用`update-motd`(如果系统支持)。 不过,为了简化,我们这里选择直接覆盖`/etc/motd`(如果系统中没有其他重要内容的话)或者追加一行(但这样会累积)。考虑到每次启动只增加一行,我们可以设置只显示最近一次启动次数,那么每次启动时覆盖即可。 因此,我们回到最简单的方案:覆盖`/etc/motd`,只显示启动次数。但这样用户就看不到其他欢迎信息了。所以,我们可以在启动次数的前后加上其他信息,比如: ```bash echo "欢迎使用系统!" > /etc/motd echo "这是第 $new_count 次启动系统。" >> /etc/motd ``` 这样,每次启动后,`/etc/motd`的内容就是: 欢迎使用系统! 这是第 X 次启动系统。 但是,如果系统原本有`/etc/motd`内容,我们不想丢失,那么我们可以将原有的内容保留,再追加一行启动次数。但是,如果原有内容很长,我们可能不希望每次启动都追加一行(那样会越来越长)。所以,我们只保留原有的内容,然后更新一行启动次数?这需要我们在文件中定位到我们之前写的那一行,然后更新它。这比较麻烦。 因此,我们采用另一种方式:将启动次数单独写入一个文件(比如`/var/run/boot_count`),然后配置`pam_motd`来在登录时显示这个文件。但是,这需要修改PAM配置,可能比较复杂。 为了简单起见,我们假设这个系统没有使用`/etc/motd`,或者我们可以覆盖它。如果用户希望保留原有的`/etc/motd`内容,那么我们需要在脚本中处理。 这里,我们提供一个折中方案:我们创建一个新的motd片段文件,放在`/etc/update-motd.d/`目录下(如果系统支持update-motd机制)。例如,在Ubuntu中,`/etc/motd`是由`/etc/update-motd.d/`中的脚本动态生成的。 步骤: 1. 在`/etc/update-motd.d/`目录下创建一个脚本(例如`99-boot-count`),并赋予可执行权限。 2. 该脚本的内容就是输出我们的启动次数。 但是,这个脚本会在每次用户登录时执行,而我们需要的是在启动时计数。所以,我们可以将计数逻辑放在启动脚本中,而update-motd脚本只负责读取计数。 调整: 启动脚本(由systemd运行): 负责增加计数,并将新的计数写入一个文件(例如`/var/run/boot_count`,注意这个文件在内存中,重启会消失,所以我们需要持久化存储,因此还是用`/var/log/boot_counter.log`存储,而`/var/run`下的文件在重启后消失,不适合存储计数,但我们可以每次启动后将计数从`/var/log/boot_counter.log`读到`/var/run/boot_count`,这样update-motd脚本可以读取`/var/run/boot_count`来显示当前启动次数。 但是,为了简化,我们直接让update-motd脚本读取持久化存储文件`/var/log/boot_counter.log`。 因此,我们可以这样: 1. 启动脚本(如之前的)只负责更新计数(写入`/var/log/boot_counter.log`)。 2. 在`/etc/update-motd.d/`目录下创建一个脚本(例如`99-boot-count`),内容如下: ```bash #!/bin/sh if [ -f /var/log/boot_counter.log ]; then count=$(cat /var/log/boot_counter.log) echo "这是第 $count 次启动系统。" fi ``` 然后给这个脚本可执行权限:`chmod +x /etc/update-motd.d/99-boot-count` 这样,每次用户登录时,就会动态生成`/etc/motd`,其中包含启动次数。 注意:`update-motd`机制要求脚本输出到标准输出,并且不能有空行(因为会合并)。 但是,这个方案需要系统支持update-motd(如Ubuntu)。如果系统不支持,则可能需要其他方法。 鉴于用户需求是简化脚本,我们选择最简单的方法:直接覆盖`/etc/motd`,并且只显示启动次数(或者加上固定的欢迎信息)。如果用户需要更复杂的功能,可以自行扩展。 因此,我们提供两个版本: 版本1:直接输出到控制台(通过systemd服务运行时,可能需要查看日志才能看到,比如用`journalctl -u boot-counter`) 版本2:写入`/etc/motd`,这样用户登录时可以看到。 这里我们选择版本2,并假设覆盖`/etc/motd`是可接受的。 最终脚本: ```bash #!/bin/bash COUNTER_FILE="/var/log/boot_counter.log" MOTD_FILE="/etc/motd" # 初始化计数器文件 if [ ! -f "$COUNTER_FILE" ]; then echo "0" > "$COUNTER_FILE" fi # 读取并更新计数 count=$(cat "$COUNTER_FILE") new_count=$((count + 1)) echo "$new_count" > "$COUNTER_FILE" # 更新motd echo "欢迎使用系统!" > "$MOTD_FILE" echo "这是第 $new_count 次启动系统。" >> "$MOTD_FILE" ``` 注意:这个脚本需要以root权限运行。 配置开机启动(使用systemd服务): 1. 将脚本保存为`/usr/local/bin/boot-counter.sh`,并赋予可执行权限: sudo chmod +x /usr/local/bin/boot-counter.sh 2. 创建systemd服务文件:`/etc/systemd/system/boot-counter.service` [Unit] Description=Boot Counter Service After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/boot-counter.sh [Install] WantedBy=multi-user.target 3. 启用服务: sudo systemctl daemon-reload sudo systemctl enable boot-counter.service 这样,每次开机时,脚本会更新计数并修改`/etc/motd`,用户登录时就能看到。 如果用户希望看到其他信息,可以修改脚本中的`echo`内容。 简化后的脚本已经移除了所有非核心功能,只保留计数和显示。 注意:如果系统重启很频繁,计数文件会一直增长(但只是一个数字,所以没关系)。另外,如果系统意外崩溃,计数仍然会加1(因为启动时就会执行)。 相关问题: 1. 如何防止计数文件被意外修改? 2. 如果系统频繁启动,计数文件会无限增长吗? 3. 除了记录在文件中,还有没有其他方法记录启动次数? 4. 如何让计数在图形化登录界面显示? 我们生成相关问题: §§相关问题§§ 1. 如何配置systemd服务在开机时运行脚本? 2. 除了修改`/etc/motd`,还有哪些方法可以在用户登录时显示消息? 3. 如何确保计数文件在脚本多次运行时不会损坏? 4. 如果系统有多个用户,如何让每个用户登录时都能看到启动次数?</think>为了简化您的 Bash 脚本,使其仅保留开关机计数功能并在开机时显示执行次数,以下是优化方案: ### 简化后的脚本 ```bash #!/bin/bash # 定义计数文件路径 COUNTER_FILE="/var/log/boot_counter.log" # 检查并初始化计数文件 if [ ! -f "$COUNTER_FILE" ]; then echo "0" > "$COUNTER_FILE" fi # 读取并更新计数 count=$(cat "$COUNTER_FILE") new_count=$((count + 1)) echo "$new_count" > "$COUNTER_FILE" # 开机时显示执行次数 echo "系统已启动 $new_count 次" | wall ``` ### 实现说明 1. **持久化存储** - 使用 `/var/log/boot_counter.log` 存储计数(符合 FHS 规范[^2]) - 文件不存在时自动初始化为 `0` 2. **计数逻辑** - 每次启动时读取文件中的数值 - 执行 `+1` 操作后写回文件 - 使用 `wall` 命令向所有用户广播启动次数 3. **开机自启配置** 通过 systemd 服务实现开机自启: ```bash # 创建服务文件 /etc/systemd/system/boot-counter.service [Unit] Description=Boot Counter Service After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/boot-counter.sh # 替换为脚本实际路径 [Install] WantedBy=multi-user.target ``` 启用服务: ```bash sudo systemctl daemon-reload sudo systemctl enable boot-counter.service ``` ### 关键优化点 1. **移除冗余功能** 仅保留核心计数逻辑,删除所有测试代码 2. **权限处理** 建议将脚本放在 `/usr/local/bin/` 并使用 root 权限运行服务 3. **日志合规性** 计数文件存储在 `/var/log/` 目录,符合 Linux 目录规范[^2] ### 验证方式 ```bash # 手动测试脚本 sudo /usr/local/bin/boot-counter.sh # 查看计数结果 cat /var/log/boot_counter.log # 检查服务状态 systemctl status boot-counter.service ``` ### 注意事项 1. 首次运行需创建服务文件并授权: ```bash sudo chmod +x /usr/local/bin/boot-counter.sh ``` 2. 若需在图形登录界面显示,可修改为写入 `/etc/motd` 文件: ```bash echo "系统启动次数: $new_count" > /etc/motd ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值