acpid是用于处理电源相关事件的守护进程,它非常灵活且易于扩展。它侦听/proc/acpi/event
,当某个事件发生时,执行相关程序来处理该事件。这些事件是由某些动作触发的,比如:
- 按下电源按钮
- 按下睡眠/挂起按钮
- 合上笔记本盖子
- 拔下/插上笔记本外接电源
请注意 桌面环境比如 GNOME倾向于使用自己的电源事件管理方法(独立于acpid), systemd的登陆管理器也有它自己的一套管理方法。同时运行多套系统可能产生意想不到的结果,比如,当按下电源键时电脑同时执行挂起和关机;或者当按下睡眠按钮时电脑执行了两次挂起操作。所以,使用多套系统时你应只激活一套系统的电源事件管理方法,以免引起冲突。
acpid预置了许多事件触发行为,比如它定义了当你按下电源按钮时应当发生什么。这些触发行为默认在/etc/acpi/handler.sh
中定义。在/etc/acpi/events/anything
)规定:任何侦测到的电源事件都会按照/etc/acpi/handler.sh
中定义的触发行为执行相关动作。
下面是一个定义触发行为的简单例子。在这个例子中,当按下睡眠按钮时acpid运行命令echo -n mem >/sys/power/state
,这将会使你的电脑挂起:
button/sleep)
case "$2" in
SLPB) echo -n mem >/sys/power/state ;;
*) logger "ACPI action undefined: $2" ;;
esac # esac 表示 case 语句块的结束
;;
不幸的是计算机上的这些电源事件标识并不统一,比如,在一些计算机上睡眠按钮可能被标识为SLPB,而在另一些计算机上为SBTN。
要想确定各种按钮或Fn
快捷键在你的计算机上是如何定义的,以root身份在终端运行:
# tail -f /var/log/messages.log -f如果输入文件是常规文件或如果 File 参数指定 FIFO(先进先出),那么 tail 命令不会在复制了输入文件的最后的指定单元后终止,而是继续从输入文件读取和复制额外 的单元(当这些单元可用时)。如果没有指定 File 参数,并且标准输入是管道,则会忽略 -f 标志。tail -f 命令可用于监视另一个进程正在写入的文件的增长。
现在在你计算机上按下电源按钮或睡眠按钮(比如Fn+Esc
),你会得到类似以下的结果:
logger: ACPI action undefined: PBTN logger: ACPI action undefined: SBTN
如果这不起作用的话,运行:
# acpi_listen
然后按下电源按钮,你会看到类似以下输出:
power/button PBTN 00000000 00000b31
acpi_listen
的输出会被作为$1, $2 , $3 & $4参数发送给/etc/acpi/handler.sh
。举例:
$1 power/button $2 PBTN $3 00000000 $4 00000b31
像你看到的那样,在这个例子中睡眠按钮被识别为SBTN,而不是SLPB(这是/etc/acpi/handler.sh
中默认定义的标识符)。所以,要想让你的睡眠按钮正常工作的话,你需要编辑/etc/acpi/handler.sh
把SLPB)替换为SBTN)。
参照上面的例子,你应该可以很容易的通过定制/etc/acpi/handler.sh
来根据侦测到的电源时间来执行不同的命令。更多例子可参考下面的 小技巧部分。
其它配置方案
默认所有的电源事件都是交由/etc/acpi/handler.sh
处理的。这是由/etc/acpi/events/anything
规定的:
# Pass all events to our one handler script event=.* action=/etc/acpi/handler.sh %e
尽管这样配置工作起来没有任何问题,但一些用户可能更喜欢使用各自独立的脚本来定义不同的电源事件。下面举例说明了如何使用不同的事件定义文件和行为定义文件:
作为root,创建以下文件:
/etc/acpi/events/sleep-button
event=button sleep.* action=/etc/acpi/actions/sleep-button.sh "%e"
然后建立以下文件:
/etc/acpi/actions/sleep-button.sh
#!/bin/sh case "$2" in SLPB) echo -n mem >/sys/power/state ;; *) logger "ACPI action undefined: $2" ;; esac
最后,给脚本加上可执行权限:
# chmod +x /etc/acpi/actions/sleep-button.sh
用这种方法,你可以任意的独立的事件/行为脚本。
小技巧
脚本示例
下面给出的例子可以用在你的/etc/acpi/handler.sh
脚本中,只是在使用的时候记得将事件变量更改为acpi_listen
侦测到的那个。
实现合上笔记本盖子时使用xscreensaver
锁屏:
button/lid) case $3 in close) # The lock command need to be run as the user who owns the xscreensaver process and not as root. # See: man xscreensaver-command. $xs will have the value of the user owning the process, if any. xs=$(ps -C xscreensaver -o user=) if test $xs; then su $xs -c "xscreensaver-command -lock"; fi ;;
实现合上笔记本盖子时挂起系统并用slimlock
锁屏:
button/lid) case $3 in close) #echo "LID switched!">/dev/tty5 /usr/sbin/pm-suspend & DISPLAY=:0.0 su -c - username /usr/bin/slimlock ;;
实现插拔外接电源时自动设置屏幕亮度(数值可能需要调整,参考/sys/class/backlight/acpi_video0/max_brightness
):
ac_adapter) case "$2" in AC*|AD*) case "$4" in 00000000) echo -n 50 > /sys/class/backlight/acpi_video0/brightness ;; 00000001) echo -n 100 > /sys/class/backlight/acpi_video0/brightness ;; esac
音量调整
下面的一系列脚本是用来控制音量的(假设你用的是ALSA)。用上面讲到的方法找到音量键的标识符,然后替换掉下面文件中的事件标识就可以用在自己电脑上了:
/etc/acpi/actions/volume_up.sh
#!/bin/bash /usr/bin/amixer set Master 5%+
/etc/acpi/actions/volume_down.sh
#!/bin/bash /usr/bin/amixer set Master 5%-
定义事件的文件:
/etc/acpi/events/volume_up
event=button[ /]volumeup action=/etc/acpi/actions/volume_up.sh
/etc/acpi/events/volume_down
event=button[ /]volumedown action=/etc/acpi/actions/volume_down.sh
用于切换静音的配置文件:
/etc/acpi/events/volume_mute
event=button[ /]volumemute action=/usr/bin/amixer set Master toggle
关闭笔记本显示器
下面这个小技巧修改自Gentoo Wiki。把下面的内容添加到/etc/acpi/actions/lm_lid.sh
最后,或者添加到/etc/acpi/handler.sh
的button/lid部分。这个配置会实现当合上笔记本盖子时自动切断LCD背光,揭开盖子时自动打开LCD背光。
case $(cat /proc/acpi/button/lid/LID0/state | awk '{print $2}') in closed) XAUTHORITY=$(ps -C xinit -f --no-header | sed -n 's/.*-auth //; s/ -[^ ].*//; p') xset -display :0 dpms force off ;; open) XAUTHORITY=$(ps -C xinit -f --no-header | sed -n 's/.*-auth //; s/ -[^ ].*//; p') xset -display :0 dpms force on ;; esac
如果你想提高、降低亮度或做其他一些跟X有关的事情,你应当明确指定你的X显示接口以及那个神奇的MIT cookie文件(一个用于对X服务器和其它输入设备进行读写访问的安全凭证)。
下面的脚本没有用到XAUTHORITY,使用了sudo:
case $(cat /proc/acpi/button/lid/LID0/state | awk '{print $2}') in closed) sudo -u `ps -o ruser= -C xinit` xset -display :0 dpms force off ;; open) sudo -u `ps -o ruser= -C xinit` xset -display :0 dpms force on ;; esac
在一些难缠的硬件上当使用某些版本的Xorg时,xset dpms force off
只会使屏幕变黑并不会关闭屏幕背光。这个bug可以用 vbetool(来自official repositories)来修复。做以下更改:
case $(cat /proc/acpi/button/lid/LID0/state | awk '{print $2}') in closed) vbetool dpms off ;; open) vbetool dpms on ;; esac
如果显示器只是快速的关闭然后又打开,很可能是xscreensaver自带的电源管理跟dpms的设置冲突了。
获取当前登陆的用户名
你可以使用getuser
函数来获取当前登陆的用户名:
getuser () { export DISPLAY=`echo $DISPLAY | cut -c -2` user=`who | grep " $DISPLAY" | awk '{print $1}' | tail -n1` export XAUTHORITY=/home/$user/.Xauthority eval $1=$user }
然后这个函数就可以被用在下面的例子中,它可以在你按下电源按钮时正常的关闭KDE:
button/power) case "$2" in PBTN) getuser "$user" echo $user > /dev/tty5 su $user -c "dcop ksmserver ksmserver logout 0 2 0" ;; *) logger "ACPI action undefined $2" ;; esac ;;
ACPI 快捷键
您可以直接编辑/etc/acpi/handler.sh
, 将快捷键反应到ACPI事件, 或者您也可以将这些快捷键指向别的自己定义的一些脚本 (例如: /etc/acpi/hotkeys.sh)
在这行之下
case "$1" in
添加如下行的内容:
hkey) case "$4" in 00000b31) echo "PreviousButton pressed!" exailectl p ;; 00000b32) echo "NextButton pressed!" exailectl n ;; 00000b33) echo "Play/PauseButton pressed!" exailectl pp echo "executed.." ;; 00000b30) echo "StopButton pressed!" exailectl s ;; *) echo "Hotkey Else: $4" ;; esac ;;
这个 '00000b31' 之类的值就是通过acpi_listen监听到的快捷键的值.在acpi_listen监听到的值中'hkey VALZ 00000000 00000b31', $4也就是最后部分, 就是区别于其他键的部分.
并且,我为了控制Exaile音乐播放器写了一个简单的 exailectl 脚本. 因为ACPID是在root级别的守护进程, 所以您需要用下面方式来写控制脚本
sudo -u (用户名) exaile
不然的话,快捷键的动作不会检测到您的用户正在运行的程序,它就会去重新启动另一个程序而不是对当前的程序作出反应.
linux 日志logger 2010-04-09 15:10:45
一 通过logger命令记录日志
logger 是一个shell 命令接口,可以通过该接口使用Syslog的系统日志模块,还可以从命令行直接向系统日志文件写入一行信息。
日志的级别
日志的级别分为七级,从紧急程度由高到底:
emerg 系统已经不可用,级别为紧急
alert 警报,需要立即处理和解决
crit 既将发生,得需要预防。事件就要发生
warnig 警告
err 错误信息,普通的错误信息
notice 提醒信息,很重要的信息
info 通知信息,属于一般信息
debug 这是调试类信息
1。解决方法:
编辑syslog.conf,
#vi /etc/syslog.conf
在第一行加入local3.none,使得设备local3的日志不记录在messages文件里,
# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none;local1.none;local3.none /var/log/messages
将设备local3的所有级别的信息都记录在userlog文件里,
#user log
local3.* /var/log/userlog
重新加载syslog服务的配置文件,
[root@KEVEIN Slides]# service syslog reload
Reloading syslogd... [ OK ]
Reloading klogd... [ OK ]
2。测试:
测试机器的环境:
OS:Red Hat Enterprise Linux 5 update 3
Network: 192.168.0.100/24 Gateway:192.168.0.1
[root@KEVEIN Slides]# ping 192.168.0.1 | logger -it logger_test -p local3.notice&
[2] 22484
命令logger -it logger_test -p local3.notice中的参数含义:
-i 在每行都记录进程ID
-t logger_test 每行记录都加上“logger_test”这个标签
-p local3.notice 设置记录的设备和级别
[root@KEVEIN Slides]# tail -f /var/log/userlog
Oct 6 12:48:43 kevein logger_test[22484]: PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
Oct 6 12:48:43 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=1 ttl=253 time=49.7 ms
Oct 6 12:48:44 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=2 ttl=253 time=68.4 ms
Oct 6 12:48:45 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=3 ttl=253 time=315 ms
Oct 6 12:48:46 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=4 ttl=253 time=279 ms
Oct 6 12:48:47 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=5 ttl=253 time=347 ms
Oct 6 12:48:49 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=6 ttl=253 time=701 ms
Oct 6 12:48:50 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=7 ttl=253 time=591 ms
Oct 6 12:48:51 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=8 ttl=253 time=592 ms
Oct 6 12:48:52 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=9 ttl=253 time=611 ms
Oct 6 12:48:53 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=10 ttl=253 time=931 ms
ping命令的输出成功输出到/var/log/userlog文件中,实验成功。
二 日志回卷
系统时时刻刻都在产生日志,如果不及时清理,很快就会灌满硬盘,但如果要手工清理,又很麻烦。这种情况下,logrotate 这个程序很好的完成这个任务。
logrotate 用来把旧的日志文件删除,并创建新的日志文件,我们把它叫做“转储”。我们可以根据日志文件的大小,也可以根据其天数来转储,这个过程一般通过一个叫做crond的守护进程来执行,logrotate 还可以用于压缩日志文件,以及发送日志到指定的E-mail 。
logrotate 的配置文件是 /etc/logrotate.conf。主要参数如下表:
参数 功能
compress 通过gzip 压缩转储以后的日志
nocompress 不需要压缩时,用这个参数
copytruncate 用于还在打开中的日志文件,把当前日志备份并截断
nocopytruncate 备份日志文件但是不截断
create mode owner group 转储文件,使用指定的文件模式创建新的日志文件
nocreate 不建立新的日志文件
delaycompress
和 compress 一起使用时,转储的日志文件到下一次转储时才压缩
nodelaycompress 覆盖 delaycompress 选项,转储同时压缩。
errors address 专储时的错误信息发送到指定的Email 地址
ifempty 即使是空文件也转储,这个是 logrotate 的缺省选项。
notifempty 如果是空文件的话,不转储
mail address 把转储的日志文件发送到指定的E-mail 地址
nomail 转储时不发送日志文件
olddir directory
转储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统
noolddir 转储后的日志文件和当前日志文件放在同一个目录下
prerotate/endscript
在转储以前需要执行的命令可以放入这个对,这两个关键字必须单独成行
postrotate/endscript
在转储以后需要执行的命令可以放入这个对,这两个关键字必须单独成行
daily 指定转储周期为每天
weekly 指定转储周期为每周
monthly 指定转储周期为每月
rotate count
指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份
tabootext [+] list
让logrotate 不转储指定扩展名的文件,缺省的扩展名是:.rpm- orig, .rpmsave, v, 和 ~
size size
当日志文件到达指定的大小时才转储,Size 可以指定bytes (缺省)以及KB (sizek)或者MB (sizem).
系统对 logrotate 的执行和操作:
在/etc/cron.daily/路径下,有一个logrotate 的shell脚本,所以cron程序会每天调用一次logrotate程序,然后logrotate程序回去检查日志文件是否符合回滚条件,并执行相应动作。
执行操作:/usr/sbin/logrotate /etc/cron.daily/logrotate.conf;
在/etc/logrotate.conf文件中,有如下选项:
# RPM packages drop log rotation information into this directory
include /etc/logrotate.d
这个选项说明在执行logrotate程序时,同时执行/etc/logrotated目录下的所有脚本。
执行动作示例:每月清除/var/log/wtmp目录中的相关内容:
/var/log/wtmp {
monthly
create 0664 root utmp
rotate 1
}
实验:
1.
环境: Red Hat Enterprise Linux 5.3
实验描述:
(1)用Cron执行logrotate命令,每分钟检查一次目标日志文件是否满足回卷限制。(2)配置/etc/logrotate.conf 或者建立一个自定义的/etc/logrotate.d /userlog
(3)编辑/etc/syslog.conf 使得记录的日志信息可以写入到/var/log/userlog中。
[root@KEVEIN ~]# crontab -e
* * * * * /usr/sbin/logrotate /etc/logrotate.conf //写入这条命令
[root@KEVEIN ~]# vi /etc/logrotate.conf
***省略***
/var/log/userlog {
daily
size 10k 在这里单位大小写敏感应,应为 k or M
create 0664 root root
rotate 3
prerotate
/bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
/bin/kill -HUP `cat /var/run/rsyslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}
在这里一定要加prerotate这段脚本,这样可以使syslog程序重新读取配置文件,这样做的作用是让syslog程序释放对userlog文件持有的文件描述符,否则即使日志文件
回滚,syslog也不会向新产生的日志文件写数据。举个例子,如果不加这段脚本,即使logrotate程序将userlog文件截断并重命名为userlog.1,但是syslog程序仍然会向原userlog文件即userlog.1中写入数据。
[root@localhost ~]# vi /etc/syslog.conf
*****省略*****
*.info;mail.none;authpriv.none;cron.none;local1.none;local3.none /var/log/messages
#user log
local3.* /var/log/userlog
重新加载配置文件
[root@KEVEIN ~]# service syslog reload
Reloading syslogd... [ OK ]
Reloading klogd... [ OK ]
重启crond服务
[root@KEVEIN ~]# service crond restart
Stopping crond: [ OK ]
Starting crond: [ OK ]
测试:
通过logger命令向userlog中写入数据,测试logrotate的功能
[root@KEVEIN ~]# ping 192.168.1.1 | logger -it logger_test -p local3.notice&
[1] 5144
[root@KEVEIN ~]# cd /var/log/
[root@KEVEIN log]# ll -h userlog*
-rw-r--r-- 1 root root 1.6K Oct 11 19:59 userlog
[root@KEVEIN log]# ll -h userlog*
-rw-r--r-- 1 root root 6.1K Oct 11 20:00 userlog
//虽然执行过logrotate,但是没有达到限制值
[root@KEVEIN log]# ll -h userlog*
-rw-rw-r-- 1 root root 0 Oct 11 20:08 userlog
-rw-rw-r-- 1 root root 15K Oct 11 20:08 userlog.1
-rw-r--r-- 1 root root 18K Oct 11 20:05 userlog.2
需要注意的是,当达到限制条件时,logrotate程序会将目标日志文件userlog截断,并命名为userlog.1,将原userlog.1改名为userlog.2,以此类推,syslog程序始终向userlog文件中写数据。
ACPI是Advanced Configuration and Power Interface缩写,acpid中的d则代表daemon。Acpid是一个用户空间的服务进程,它充当linux内核与应用程序之间通信的接口,负责将kernel中的电源管理事件转发给应用程序。
acpid与内核的通信方式:acpid用poll函数挂在/proc/acpi/event文件上。内核在drivers/acpi/event.c中实现了该文件的接口,一旦总线事件列表(acpi_bus_event_list)上有电源管理事件发生,内核就会唤醒挂在 /proc/acpi/event上的acpid,acpid再从/proc/acpi/event中读取相应的事件。
acpid与应用程序的通信方式有两种,其一是通过本地socket,其文件名为/var/run/acpid.socket,应用程序只要连接到这个socket上,不用发送任何命令就可以接收到acpid转发的电源管理事件。
其二是通过配置文件。在acpid收到来自内核的电源管理事件时,根据配置文件中的规则执行指定的命令。配置文件在/etc/acpi/events/目录下,下面是一个示例:
event=button/power.*
action=/sbin/shutdown -h now
事件的格式为:device_class bus_id type data。device_class和bus_id是字符串,type和data是十六制整数。在配置文件中可以使用通配符,来匹配指定的事件。
acpi与应用程序的通信方式有两种:
其一是通过本地socket,其文件名为/var/run/acpi.socket,应用程序只要连接到这个socket,不用发送任何命令就可以接收到acpid转发的电源管理事件。
其二是通过配置文件。在acpid收到来自内核的电源管理事件时,根据配置文件中的规则执行制定的命令。配置文件在/etc/acpi/events/目录下。例如:
event = button/power.*
action = /sbin/shutdown -h now
事件的格式为:device_class bus_id type data。device_class和bus_id是字符串,type和data是十六进制整数。在配置文件中可以使用通配符,来匹配制定的事件。
Acpid(8)
名字:
acpid - 高级配置与电源接口事件无交互后台程序。
概要:
acpid [控制]
描述:
acpid是有计划的通知用户空闲程序的ACPI事件,默认情况下acpid是在系统启动时作为一个后台进程启动。它将打开一个事件文件(默认为:/proc/acpi/event)并读取所有的行。当读取的行内容是被承认的事件时,acpid将检查一系列规则,并且检查匹配的事件。
规则是简单的配置文件。acpid将查看这些配置目录(默认为:/etc/acpi/events),并且分析所有的不以“.”为开始文件。每个文件必须有两个特征:一个事件和一个动作。任何的空白行和带“#”为开头的字符的行将被忽略。无关的行内容将标记警告,但不是致命的。每个行有三个标识:键值,等号和值。键值能够是除了空格长达63个的字符,并且是不区分大小写的。值能够是长达511个的字符、案例和空格。
事件值是一个规则表达(see regcomp(3)),这个事件值是否符合规则。
动作值是一个命令行,如果这个动作值符合规则,在发生这个命令的时候将调用/bin/sh。命令行可以包括专用的shell字符,并且它们将被保存。动作值里唯一避免使用的专用字符是“%”。动作值里的事件被调用时,“%e”将被字母文本事件代替。
这些字符串可以包含空格,所以,如果想要单独的标识,命令行必须取消“%e”。动作值里的事件被调用时,“%e”将取代字母文本。这些字符串可以包含空格,如果需要单个标识,命令行必须引用“%e”。字符串“%%”将代替字符“%”。所有其他的“%”被换码保留,并将因为规则不能加载。
这种特征允许多个规则被定义为同一事件(虽然没有保准书),以及一个规则被定义为多个事件。强迫向acpid刷新规则配置,发送它一个 SIGHUP。
在一个附加的规则文件中,acpid也能接受一个在UNIX下的套接字(默认为:/var/run/acpid.socket)。任何的应用可以连接这个套接字。一次连接,acpid将发送所有的ACPI事件文件到客户端。客户端有责任过滤信息,并得到有需要的信息。除了SIGHUP或则acpid退出的情况,acpid将不关闭客户端套接字
acpid将记录所有的活动,以及stdout和stderr的任何动作到日记文件(/var/log/acpid by default)。
所有的默认文件和目录可以被命令行选项改变。
选项:
-c,--confdir directory
这个选项改变了acpid规则配置文件的目录。默认是:/etc/acpi/events。
-d,--debug
这个选项增加了acpid调试等级。如果调试等级非零,acpid将在前台运行,并将日记指向stdout/stderr,而不是一个日记文件。
-e,--eventfile filename
这个选项从acpid读取事件并改变事件文件。默认是:/proc/acpi/event。
-g,--socketgroup groupname
这个选项改变LINUX套接字组的权限,并由acpid发布事件。
-l,--logfile filename
这个选项改变日记文件,并由acpid写入。默认是:/var/log/acpid。
-m,--socketmode mode
这个选项改变UNIX套接字的权限,并由acpid发布事件。默认为: 0666。
-s,--socketfile filename
这个选项改变UNIX套接字的名字,并由acpid打开。默认为:/var/run/acpid.socket。
-S,--nosocket filename
这个选项告诉acpid不能打开UNIX套接字。这个选项覆盖了-s选项的功能,并否认了其他所有的套接字选项。
-v,--version
显示版本信息并退出。
-h,--help
显示帮助并退出。
例子:
这个例子“placed in /etc/acpi/events/power”如果你按下电源按钮,将关闭你的系统
event=button/power.*
action=/usr/local/sbin/power.sh "%e"
这个小型程序“power.sh”获得访问,并将查看完成字符串,像参数:$L。
备注:
请确认你最近使用的合适ACPI代码。这些有效的来自:http://developer.intel.com/technology/iapc/acpi/downloads.htm.
文件:
/proc/acpi/event
/etc/acpi/
/var/log/acpid
/var/run/acpid.socket