kexec-tools/mkdumprd
dyoung@redhat.com 4b9c868b8d use findmnt instead of blkid in mkdumprd
Previously to_dev_name use blkid to get dev name from dump target,
but blkid can not handle UUID/LABEL with quotes so to_dev_name will
silently fail.

Because we enforce dump target being mounted before creating kdump
initrd, so change to use findmnt is fine. findmnt can handle input
params with quotes.

to_dev_name is not necessary anymore, just remove it.
Also there's another user of it is for checking if the dev is root
or not, here change to use findmnt for this as well.

Tested the rootfs dump, UUID with/without quotes dump.

Signed-off-by: Dave Young <dyoung@redhat.com>
Reviewed-by: Caspar Zhang <czhang@redhat.com>
Acked-by: Baoquan He <bhe@redhat.com>
2013-03-14 10:35:22 +08:00

303 lines
7.0 KiB
Bash

#!/bin/bash --norc
# New mkdumprd
#
# Copyright 2011 Red Hat, Inc.
#
# Written by Cong Wang <amwang@redhat.com>
#
export IN_KDUMP=1
conf_file="/etc/kdump.conf"
SSH_KEY_LOCATION="/root/.ssh/kdump_id_rsa"
SAVE_PATH=$(grep ^path $conf_file| cut -d' ' -f2)
[ -z "$SAVE_PATH" ] && SAVE_PATH="/var/crash"
extra_modules=""
dracut_args=("--hostonly" "-o" "plymouth dash")
get_persistent_dev() {
local i _tmp _dev
_dev=$(udevadm info --query=name --name="$1" 2>/dev/null)
[ -z "$_dev" ] && {
echo "Kernel dev name of $1 is not found."
exit 1
}
for i in /dev/mapper/* /dev/disk/by-uuid/* /dev/disk/by-id/*; do
_tmp=$(udevadm info --query=name --name="$i" 2>/dev/null)
if [ "$_tmp" = "$_dev" ]; then
echo $i
return
fi
done
echo "Persistent device name of $1 is not found."
exit 1
}
add_dracut_arg() {
while [ $# -gt 0 ];
do
dracut_args+=("$1")
shift
done
}
add_dracut_module() {
add_dracut_arg "--add" "$1"
}
add_dracut_mount() {
add_dracut_arg "--mount" "$1"
}
add_dracut_sshkey() {
add_dracut_arg "--sshkey" "$1"
}
# Generic substring function. If $2 is in $1, return 0.
strstr() { [[ $1 =~ $2 ]]; }
target_is_root() {
local _t
_t=$(findmnt -k -n -r -o TARGET $1|sort|head -1)
[ "$_t" = "/" ]
}
to_mount() {
local _dev=$1 _s _t _o _mntopts _pdev
_s=$(findmnt -k -f -n -r -o SOURCE $_dev)
_t=$(findmnt -k -f -n -r -o TARGET,FSTYPE $_dev)
_o=$(findmnt -k -f -n -r -o OPTIONS $_dev)
[ -z "$_t" -o -z "$_o" ] && return
_o=${_o/#ro/rw} #mount fs target as rw in 2nd kernel
_mntopts="$_t $_o"
#for non-nfs _dev converting to use udev persistent name
if [ -b "$_s" ]; then
_pdev="$(get_persistent_dev $_s)"
else
_pdev=$_dev
fi
echo "$_pdev $_mntopts"
}
to_mount_point() {
echo $(findmnt -k -f -n -r -o TARGET $1)
}
is_readonly_mount() {
local _mnt
_mnt=$(findmnt -k -f -n -r -o OPTIONS $1)
#fs/proc_namespace.c: show_mountinfo():
#seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw");
[[ "$_mnt" =~ ^ro ]]
}
#Function: get_ssh_size
#$1=dump target
get_ssh_size() {
local _opt _out _size
_opt="-i $SSH_KEY_LOCATION -o BatchMode=yes -o StrictHostKeyChecking=yes"
_out=$(ssh -q -n $_opt $1 "df -P $SAVE_PATH")
if [ $? -ne 0 ]; then
echo "checking remote ssh server available size failed."
exit 1
fi
#ssh output removed the line break, so print $11 instead of $4
_size=$(echo -n $_out|tail -1 | awk '{print $11}')
echo -n $_size
}
#mkdir if save path does not exist on dump target filesystem
#$1=dump target
mkdir_save_path() {
local _mnt=$(to_mount_point $1)
local _remount="no"
local _ret
[ ! -d ${_mnt}/$SAVE_PATH ] && {
if is_readonly_mount $1; then
echo "Mounting $1 as read-write for creating dump directory.."
mount -o remount,rw $1
[ $? -ne 0 ] && {
echo "Mounting $1 as read-write failed."
exit 1;
}
_remount="yes"
fi
mkdir -p ${_mnt}/$SAVE_PATH
_ret=$?
[ "$_remount" = "yes" ] && {
echo "Remounting $1 as read-only."
mount -o remount,ro $1 || {
echo "Remounting $1 as read-only failed."
exit 1
}
}
[ $_ret -ne 0 ] && {
echo "Creating ${_mnt}/$SAVE_PATH failed."
exit 1
}
}
}
#Function: get_fs_size
#$1=dump target
get_fs_size() {
local _mnt=$(to_mount_point $1)
echo -n $(df -P "${_mnt}/$SAVE_PATH"|tail -1|awk '{print $4}')
}
#Function: get_raw_size
#$1=dump target
get_raw_size() {
echo -n $(fdisk -s "$1")
}
#Function: check_size
#$1: dump type string ('raw', 'fs', 'ssh')
#$2: dump target
check_size() {
local avail memtotal
memtotal=$(awk '/MemTotal/{print $2}' /proc/meminfo)
case "$1" in
raw)
avail=$(get_raw_size "$2")
;;
ssh)
avail=$(get_ssh_size "$2")
;;
fs)
avail=$(get_fs_size "$2")
;;
*)
return
esac
if [ $avail -lt $memtotal ]; then
echo "Warning: There might not be enough space to save a vmcore."
echo " The size of $2 should be greater than $memtotal kilo bytes."
fi
}
is_ssh_dump_target()
{
grep -q "^ssh.*@" $conf_file
}
is_raw_dump_target()
{
grep -q "^raw" $conf_file
}
# $1: core_collector config value
verify_core_collector() {
if grep -q "^raw" $conf_file && [ "${1%% *}" != "makedumpfile" ]; then
echo "Warning: specifying a non-makedumpfile core collector, you will have to recover the vmcore manually."
fi
if is_ssh_dump_target || is_raw_dump_target; then
if [ "${1%% *}" = "makedumpfile" ]; then
! strstr "$1" "-F" && {
echo "The specified dump target needs makedumpfile \"-F\" option."
exit 1
}
fi
fi
}
add_mount() {
local _mnt=$(to_mount "$1")
if target_is_root "$1"; then
:
elif [ -n "$_mnt" ]; then
add_dracut_mount "$_mnt"
else
return 1
fi
return 0
}
# firstly get right SSH_KEY_LOCATION
keyfile=$(awk '/^sshkey/ {print $2}' $conf_file)
if [ -f "$keyfile" ]; then
# canonicalize the path
SSH_KEY_LOCATION=$(/usr/bin/readlink -m $keyfile)
fi
if [ "$(uname -m)" = "s390x" ]; then
add_dracut_module "znet"
fi
while read config_opt config_val;
do
case "$config_opt" in
extra_modules)
extra_modules="$extra_modules $config_val"
;;
ext[234]|xfs|btrfs|minix|nfs)
if [ "$config_opt" = "nfs" ]; then
add_dracut_module "nfs"
fi
add_mount "$config_val"
if [ $? -ne 0 ]; then
echo "Dump target $config_val is probably not mounted."
exit 1
fi
mkdir_save_path $config_val
check_size fs $config_val
;;
raw)
#checking raw disk writable
dd if=$config_val count=1 of=/dev/null > /dev/null 2>&1 || {
echo "Bad raw disk $config_val"
exit 1
}
add_dracut_arg "--device" "$(get_persistent_dev $config_val)"
check_size raw $config_val
;;
ssh)
if strstr "$config_val" "@";
then
check_size ssh $config_val
add_dracut_module "ssh-client"
add_dracut_sshkey "$SSH_KEY_LOCATION"
else
echo "Bad ssh dump target $config_val"
exit 1
fi
;;
net)
echo "net option is not supported anymore, please use nfs|ssh instead."
exit 1
;;
core_collector)
verify_core_collector "$config_val"
;;
blacklist)
add_dracut_arg "--omit-drivers" "$config_val"
;;
*)
if [ -n $(echo $config_opt | grep "^#.*$") ]
then
continue
fi
;;
esac
done < $conf_file
if [ -n "$extra_modules" ]
then
add_dracut_arg "--add-drivers" "$extra_modules"
fi
dracut "${dracut_args[@]}" -M "$@"
_rc=$?
sync
exit $_rc