使用expect实现自动增加、减少LVM分区大小
时间:2008-10-11 来源:skysong1982
由于不定期需要增大或减少磁盘上某个分区的空间大小,每次用命令太麻烦了,故打算用expect试试。
下面是脚本代码:
#!/usr/bin/expect
## 需要2个参数,1个是LVM设备地址,第2个是新的大小
if { $argc != 2 } {
send_error "\nUsage: resize_lvm lvm_device lvm_size\
\n lvm_device: /dev/<vg_name>/<lvm_name>\
\n lvm_size: \[+|-\]<size>\[G|M\]\
\nExample: resize_lvm /dev/vg0/test 3G\n\n"
exit 1
}
set device [lindex $argv 0]
set size [lindex $argv 1]
## 子程序,处理错误信息
proc exit_err {mesg} {
send "ERROR: $mesg\n"
exit 1
}
## 子程序,处理超时
proc exit_timeout {} {
send "ERROR: no respond from command.\n"
exit 1
}
## 判断输入LVM设备是否合法
## LVM 设备是一个连接,比如/dev/vg0/test 是指向 /dev/mapper/vg0-test的
if { [file exists $device] != 1 } {
exit_err "device: $device doest not exists."
} elseif { [file type $device] != "link"} {
exit_err "device: $device is not a valid lvm device."
}
set target [file readlink $device]
if { [file exists $target] != 1 } {
exit_err "target: $target doest not exist."
} elseif { [file type $target] != "blockSpecial" } {
exit_err "target: $target is not a block device."
} elseif { [regexp "/dev/mapper/*" $target] != 1 } {
exit_err "device: $device is not a valid lvm device."
}
send "Target Logical Volume: $device ($target)\n"
send "Target Size: $size\n"
set mountdir "none"
## 判断LVM是否已挂载
set ifmounted [catch {exec grep $device /proc/mounts} result]
if { $ifmounted == 0 } {
send "WARNNING: device: $device was already mounted.\n"
regsub -all / $device "\\/" esc_device
## 获取挂载的目的地
set mountdir [exec awk "{if(/$esc_device/) print \$2}" /proc/mounts ]
## 尝试卸载
set status [catch {exec umount $mountdir} result]
set i 0
while { $status != 0 } {
send "WARNNING: umount failed: $result\n"
## 如果卸载失败,使用fuser杀死相关进程
send "Trying to kill related process ...\n"
set killit [catch {exec fuser -s -mk $mountdir} result]
send "Repeat umount operation ...\n"
set status [catch {exec umount $mountdir} result]
incr i
if { $i > 2 } { ## try for 3 times
exit_err "cannot umount."
}
sleep 1
}
}
## 调用resizelvm程序修改lvm大小
proc resizelvm {device size} {
spawn lvresize -L $size $device
expect {
"really want to reduce" {
send "y\n"
exp_continue
}
timeout {
exit_timeout
}
}
}
## 重建super block
proc rebuild_sb {device} {
set timeout 10
spawn fsck.reiserfs -q $device --rebuild-sb
expect {
"run this" {
send "Yes\n"
exp_continue
}
"use resizer" {
send "y\n"
exp_continue
}
"partition size" {
send "\n"
exp_continue
}
"this ok" {
send "y\n"
exp_continue
}
timeout {
exit_timeout
}
}
}
## 使用fsck检查分区
proc checkfs {device} {
spawn -noecho fsck.reiserfs -q $device --check --fix-fixable
expect {
"run this " {
send "Yes\n"
exp_continue
}
timeout {
exit_timeout
}
}
}
## 调用各个子程序
resizelvm $device $size
rebuild_sb $device
checkfs $device
## 重新挂载LVM分区
if { $mountdir != "none" } {
exec mount -t reiserfs $device $mountdir
}
注:1. 当新的分区大小比原来的小时,请注意新的分区大小最小也要比分区中数据总大小要大,否则会造成数据丢失;
2. 此程序在 LFS 6.x + 2.6.14.5 + LVM2 上测试通过,但发觉这样一个问题:如果不卸载分区,而是以只读的方式重新挂载,没有问题,但是修改分区大小完成后,卸载时会出现段错误,并且umount进程成为僵尸进程。
下面是脚本代码:
#!/usr/bin/expect
## 需要2个参数,1个是LVM设备地址,第2个是新的大小
if { $argc != 2 } {
send_error "\nUsage: resize_lvm lvm_device lvm_size\
\n lvm_device: /dev/<vg_name>/<lvm_name>\
\n lvm_size: \[+|-\]<size>\[G|M\]\
\nExample: resize_lvm /dev/vg0/test 3G\n\n"
exit 1
}
set device [lindex $argv 0]
set size [lindex $argv 1]
## 子程序,处理错误信息
proc exit_err {mesg} {
send "ERROR: $mesg\n"
exit 1
}
## 子程序,处理超时
proc exit_timeout {} {
send "ERROR: no respond from command.\n"
exit 1
}
## 判断输入LVM设备是否合法
## LVM 设备是一个连接,比如/dev/vg0/test 是指向 /dev/mapper/vg0-test的
if { [file exists $device] != 1 } {
exit_err "device: $device doest not exists."
} elseif { [file type $device] != "link"} {
exit_err "device: $device is not a valid lvm device."
}
set target [file readlink $device]
if { [file exists $target] != 1 } {
exit_err "target: $target doest not exist."
} elseif { [file type $target] != "blockSpecial" } {
exit_err "target: $target is not a block device."
} elseif { [regexp "/dev/mapper/*" $target] != 1 } {
exit_err "device: $device is not a valid lvm device."
}
send "Target Logical Volume: $device ($target)\n"
send "Target Size: $size\n"
set mountdir "none"
## 判断LVM是否已挂载
set ifmounted [catch {exec grep $device /proc/mounts} result]
if { $ifmounted == 0 } {
send "WARNNING: device: $device was already mounted.\n"
regsub -all / $device "\\/" esc_device
## 获取挂载的目的地
set mountdir [exec awk "{if(/$esc_device/) print \$2}" /proc/mounts ]
## 尝试卸载
set status [catch {exec umount $mountdir} result]
set i 0
while { $status != 0 } {
send "WARNNING: umount failed: $result\n"
## 如果卸载失败,使用fuser杀死相关进程
send "Trying to kill related process ...\n"
set killit [catch {exec fuser -s -mk $mountdir} result]
send "Repeat umount operation ...\n"
set status [catch {exec umount $mountdir} result]
incr i
if { $i > 2 } { ## try for 3 times
exit_err "cannot umount."
}
sleep 1
}
}
## 调用resizelvm程序修改lvm大小
proc resizelvm {device size} {
spawn lvresize -L $size $device
expect {
"really want to reduce" {
send "y\n"
exp_continue
}
timeout {
exit_timeout
}
}
}
## 重建super block
proc rebuild_sb {device} {
set timeout 10
spawn fsck.reiserfs -q $device --rebuild-sb
expect {
"run this" {
send "Yes\n"
exp_continue
}
"use resizer" {
send "y\n"
exp_continue
}
"partition size" {
send "\n"
exp_continue
}
"this ok" {
send "y\n"
exp_continue
}
timeout {
exit_timeout
}
}
}
## 使用fsck检查分区
proc checkfs {device} {
spawn -noecho fsck.reiserfs -q $device --check --fix-fixable
expect {
"run this " {
send "Yes\n"
exp_continue
}
timeout {
exit_timeout
}
}
}
## 调用各个子程序
resizelvm $device $size
rebuild_sb $device
checkfs $device
## 重新挂载LVM分区
if { $mountdir != "none" } {
exec mount -t reiserfs $device $mountdir
}
注:1. 当新的分区大小比原来的小时,请注意新的分区大小最小也要比分区中数据总大小要大,否则会造成数据丢失;
2. 此程序在 LFS 6.x + 2.6.14.5 + LVM2 上测试通过,但发觉这样一个问题:如果不卸载分区,而是以只读的方式重新挂载,没有问题,但是修改分区大小完成后,卸载时会出现段错误,并且umount进程成为僵尸进程。
相关阅读 更多 +