Here's updated version which can do glob matching and other stuff. I've
also set up a git tree.
http://git.kernel.org/?p=linux/kernel/git/tj/storage-fixup.git
--
tejun
#! /bin/bash
#
# storage-fixup - Tejun Heo <teheo@xxxxxxx>
#
# Script to issue fix up commands for weird disks. This is primarily
# to adjust ATA APM setting. Some laptop BIOSen set this value too
# aggressively causing frequent head unloads which can kill the drive
# quickly. This script should be called during boot and resume. It
# examines rules from /etc/stroage-fixup.conf and executes matching
# commands.
#
# In stroage-fixup.conf, empty lines and lines starting w/ # are
# ignored. Each line starts with rule, dmi, hal or act.
#
# rule RULENAME
# Starts a rule. $RULENAME can't contain whitespaces.
#
# dmi KEY PATTERN
# Checks whether DMI value for KEY matches PATTERN. If not, the
# rule is skipped.
#
# hal KEY PATTERN
# Checks whether there are devices which has KEY value matching
# PATTERN. storage-fixup determines applies actions to devices
# which match all hal matches, so all rules should have at least
# one hal match.
#
# act ACTION
# Executes ACTION on matched devices. ACTION can contain $DEV
# which will be substituted with device file of matching device.
#
# PATTERN is bash glob pattern.
#
# For example, the following (useless) rule disables APM on the first
# harddrive of my machine.
#
# rule p5w64
# dmi baseboard-product-name P5W64 WS Pro
# dmi baseboard-manufacturer ASUSTeK Computer INC.
# hal storage.model WDC WD5000YS-01M
# hal storage.serial *-01_WD-WMANU1217262
# act hdparm -B 255 $DEV
#
declare usage="
Usage: storage-fixup [-h] [-V] [-v] [-b] [-c config_file]
-h Print this help message and exit
-V Print version and exit
-v Verbose
-d Dry run, don't actually execute action
-c Use config_file instead of /etc/storage-fixup.conf
"
declare hal_find_by_capability=${HAL_FIND_BY_CAPABILITY:-hal-find-by-capability}
declare hal_get_property=${HAL_GET_PROPERTY:-hal-get-property}
declare dmidecode=${DMIDECODE:-dmidecode}
declare version=0.1
declare conf_file=/etc/storage-fixup.conf
declare newline=$'\n'
declare dry_run=0 verbose=0 lineno=0 skip=0 rule_name="" reply
declare -a storage_ids
declare -a hal_cache
declare -a matches
log() {
echo "storage-fixup: $@"
}
warn() {
log "$@" 1>&2
}
debug() {
if [ $verbose -ne 0 ]; then
warn "$@"
fi
}
#
# do_dmi - perform DMI match
# @key: DMI key to be passed as --string argument to dmidecode
# @pattern: glob pattern to match
#
# Returns 0 on match, 1 on mismatch, 2 on invalid match (triggers
# warning).
#
do_dmi() {
local key="$1" pattern="$2"
local val
if [ -z "$key" -o -z "$pattern" ]; then
return 1
fi
val=$($dmidecode --string "$key")
if [ "$?" -ne 0 ]; then
return 2
fi
if [ -z "${val##$pattern}" ]; then
debug "Y $lineno $rule_name dmi $key=$pattern"
return 0
fi
debug "N $lineno $rule_name dmi $key=$pattern"
return 1
}
#
# search_hal_cache - search hal cache
# @id: udi of the device to search for
# @key: key of hal property to search
#
# Searches hal cache and returns 0 if found, 1 if @key properties are
# cached but matching entry is not found, 2 if @key properties are not
# cached yet. On success, the matched property is returned in $reply.
#
search_hal_cache() {
local id="$1" key="$2"
local i key_found=0 cache len match
reply=
for ((i=0;i<${#hal_cache[@]};i++)); do
cache=${hal_cache[i]}
len=${#cache}
match="${cache#$key }"
if [ ${#match} -ne $len ]; then
key_found=1
elif [ $key_found -eq 1 ]; then
return 1
fi
match="${cache#$key $id }"
if [ ${#match} -ne $len ]; then
reply="$match"
return 0
fi
done
if [ $key_found -eq 1 ]; then
return 1
else
return 2
fi
}
#
# fetch_hal_property - fetch hal property matching id and key
# @id: udi of the device to fetch property for
# @key: key of the property to fetch
#
# Fetch @key property for udi @id. If @key properties are already
# cached, it's returned from cache. If not, cache is populated with
# @key properties and searched again.
#
# Returns 0 if found, 1 if not found, 2 if something went wrong. On
# success, the matched property is returned in $reply.
#
fetch_hal_property() {
local id="$1" key="$2" property
local i ret tid cnt=0
# search cache
search_hal_cache "$id" "$key"
ret=$?
if [ $ret -ne 2 ]; then
return $ret
fi
# $key wasn't in the cache, populate the cache
# placeholder indicating $key has been populated
hal_cache+=("$key ")
# run hal-get-property on each storage device and put the result in cache
for ((i=0;i<${#storage_ids[@]};i++)); do
tid="${storage_ids[i]}"
property="$($hal_get_property --udi "$tid" --key "$key")"
if [ -n "$property" ]; then
hal_cache+=("$key $tid $property")
true $((cnt++))
fi
done
debug "C $cnt entries added to hal cache for $key"
# and retry
search_hal_cache "$id" "$key"
return $?
}
#
# do_hal - perform HAL match
# @key: property key of interest
# @pattern: pattern to match
#
# Walk through $matches array and match each id against @key and
# @pattern. Entries which don't match are removed from $matches.
#
# Returns 0 if $matches contain any entry after matching, 1 if it's
# empty, 2 if something went wrong.
#
do_hal() {
local key="$1" pattern="$2" property i
local -a old_matches=("${matches[@]}")
if [ -z "$1" -o -z "$2" ]; then
return 2
fi
matches=()
for ((i=0;i<${#old_matches[@]};i++)); do
fetch_hal_property "${old_matches[i]}" "$key"
if [ $? -eq 0 -a -z "${reply##$pattern}" ]; then
matches+=("${old_matches[i]}")
fi
done
if [ ${#matches[@]} -eq 0 ]; then
debug "N $lineno $rule_name hal $1=$2"
return 1
fi
debug "Y $lineno $rule_name hal nr_devs=${#matches[@]} $1=$2"
return 0
}
#
# do_act - execute action
# @act: action to execute
#
# Execute @act for each device in $matches. "$DEV" in @act is
# substituted with the /dev node of each match. If $dry_run is set,
# the action is logged but not actually executed.
#
# Returns 0.
#
do_act() {
local act="$1"
local id dev
for id in "${matches[@]}"; do
if ! DEV=$($hal_get_property --udi "$id" --key block.device); then
warn "can't find device node for $id"
continue
fi
if [ $dry_run -eq 0 ]; then
eval log "$rule_name: executing \"$act\""
eval "$1"
else
eval log "$rule_name: dry-run \"$act\""
fi
done
return 0
}
#
# Execution starts here
#
while getopts "dvVc:h" option; do
case $option in
d)
dry_run=1;;
v)
verbose=1;;
V)
echo "$version"
exit 0;;
c)
conf_file=$OPTARG;;
*)
echo "$usage" 2>&1
exit 1;;
esac
done
storage_ids=($($hal_find_by_capability --capability storage))
debug "I ${#storage_ids[@]} storage devices"
while read f0 f1 f2; do
true $((lineno++))
if [ -z ${f0###*} ]; then
continue
fi
if [ "$f0" = rule ]; then
rule_name=$f1
skip=0
matches=("${storage_ids[@]}")
continue
fi
if [ $skip -ne 0 ]; then
continue
fi
case "$f0" in
dmi)
do_dmi "$f1" "$f2"
;;
hal)
do_hal "$f1" "$f2"
;;
act)
do_act "$f1 $f2"
;;
*)
false
;;
esac
ret=$?
if [ $ret -ne 0 ]; then
if [ $ret -eq 2 ]; then
warn "malformed line $lineno \"$f0 $f1 $f2\","\
"skipping rule $rule_name" 2>&1
fi
skip=1
fi
done < $conf_file
#
# /etc/storage-fixup.conf - Configuration file for storage-fixup
#
# Blank lines and lines starting with # are ignored. Please read
# comment at the top of storage-fixup for more information.
#
# Drive model patterns are generalized to cover drives from the same
# family. Drive manufacturers usually have datasheets or web pages
# listing all models of the same family.
#
# The DMI part is difficult to generalize as there's no such
# information. We'll have to generalize as we collect entries.
#
# If you have a harddrive which does crazy unloading but not listed
# here, please write to linux-ide@xxxxxxxxxxxxxxx with the outputs of
# "dmidecode" and "hdparm -I DRIVE", on a laptop the DRIVE is usually
# /dev/sda.
#
# Reported drive model: Hitachi HTS722020K9SA00
rule tp-t60
dmi system-manufacturer LENOVO
dmi system-product-name 1952W5R
dmi system-version ThinkPad T60
hal storage.model Hitachi HTS7220*K9*A*
act hdparm -B 255 $DEV
# Reported drive model: SAMSUNG HM250JI
rule hp-dv6500
dmi system-manufacturer Hewlett-Packard
dmi system-product-name HP Pavilion dv6500 Notebook PC
dmi system-version Rev 1
hal storage.model SAMSUNG HM*I
act hdparm -B 255 $DEV
# Reported drive model: ST9100824AS
rule dell-e1505
dmi system-manufacturer Dell Inc.
dmi system-product-name MM061
hal storage.model ST9*AS
act hdparm -B 255 $DEV