4b9c868b8d
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>
303 lines
7.0 KiB
Bash
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
|
|
|