Linux Shell Script example1 (clone disk)


#!/usr/local/bin/bash

# $Yahoo: clone,v 1.60 2000/09/04 08:56:17 filo Exp $

root=256
nic=fxp0
swap=1024
host=
verbose=
verbose_fd=/dev/null
full=
try_nfs=1
nfs_server_default=netapp:/home/freebsd/usr.local
disk_regex="(sd|da|wd|ad)"

command=${0##*/}
tmp_dir=/home/tmp/$command
mnt=$tmp_dir/mnt
nfs_mnt=$tmp_dir/nfs
nfs_dir=$nfs_mnt/FreeBSD/clone
misc_dir=$tmp_dir/misc

physmem=$[`sysctl -n hw.physmem`/1024/1024+64]
if [ $physmem -gt $swap ]; then
  swap=$physmem
fi

# Check to see where the nfs clone images live.
if [ -x /usr/bin/kenv ]; then
  nfs_server=`/usr/bin/kenv build.nfs_server`
  if [ -z "$nfs_server" ]; then
    nfs_server=$nfs_server_default
  fi
else
  nfs_server=$nfs_server_default
fi

usage () {
  echo "usage: $command [-fnv] [-r MB] [-s MB] [-h host] os-version ${disk_type}"
  echo "       $command [-fnv] [-r MB] [-s MB] [-h host] root home ${disk_type}"
  echo "       $command [-fnv] [-r MB] [-s MB] [-h host] dump-dir ${disk_type}"
  echo "       $command [-nv]                            root home dump-dir"
  echo ""
  echo "         -f             full copy - used to create new clone disk"
  echo "         -n             don't look for latest $command via nfs"
  echo "         -v             be verbose"
  echo "         -r MB          size of root partition in MB [$root]"
  echo "         -s MB          size of swap partition in MB [$swap]"
  echo "         -h hostname    hostname for cloned disk"
}

sigint () {
  exit
}

sigexit () {
  trap "" SIGINT
  if [ -z "$verbose" ]; then
    exec > /dev/null 2>&1
  fi
  cleanup
}

cleanup () {
  cd /
  umount ${mnt}/home
  umount ${mnt}
  rmdir ${mnt}
  umount ${nfs_mnt}
  rmdir ${nfs_mnt}
  rm -f $tmp_file_1
  rm -f $tmp_file_2
  rm -f $tmp_file_3
  rm -f $tmp_dir/$command
  rm -rf $misc_dir
  rmdir $tmp_dir
}

trap sigexit EXIT
trap sigint SIGINT

if [ -e $tmp_dir ]; then
  if [ ! -d $tmp_dir ]; then
    echo "error: tmp dir '$tmp_dir' is not a dir"
    exit
  fi
else
  mkdir $tmp_dir 2> /dev/null
fi

for opt in $*; do
  if [ "$opt" = "-n" ]; then
    try_nfs=
  fi
done

if [ -n "$try_nfs" ]; then
  if df | grep $nfs_mnt > /dev/null 2>&1; then
    :
  else
    mkdir $nfs_mnt 2> /dev/null
    mount_nfs -R 1 $nfs_server $nfs_mnt
  fi

if df | grep $nfs_mnt > /dev/null 2>&1; then
    nfs="${nfs_dir}/$command"
    if [ -x "$nfs" ]; then
      sum=$(cksum $0) || exit
      cur_sum=${sum%% *}
      sum=$(cksum $nfs) || exit
      nfs_sum=${sum%% *}
      if [ "$cur_sum" != "$nfs_sum" ]; then
        exec="${tmp_dir}/$command"
        cp -f $nfs $exec || exit
        exec $exec $*
      fi
    fi
  fi
fi

case `uname -r` in
  4.*)
    version=4
    disk_type="da?|ad?"
    conf_dir=/usr/src/etc
    mbr=boot/mbr
    ;;
  3.*)
    version=3
    disk_type="da?|wd?"
    conf_dir=/usr/local/etc
    mbr=boot/mbr
    ;;
  2.2.*)
    version=2.2
    disk_type="sd?|wd?"
    conf_dir=/usr/local/etc
    mbr=usr/mdec/mbr
    ;;
  2.1*)
    version=2.1
    disk_type="sd?|wd?"
    conf_dir=/usr/local/etc
    mbr=usr/mdec/mbr
    ;;
  *)
    echo "error: unsupported machine type `uname -r`"
    exit
    ;;
esac

while getopts "s:h:o:i:r:vfn?" opt; do
  case "$opt" in
    r)
      root=$OPTARG
      ;;
    h)
      host=$OPTARG
      ;;
    n)
      try_nfs=
      ;;
    s)
      swap=$OPTARG
      ;;       
    v)  
      verbose=1
      verbose_fd=/dev/tty
      ;;
    f)
      full=1
      ;;
    \?)
      usage
      exit
      ;;
  esac
done

shift $[OPTIND-1]

if [ $# = 2 ]; then
  case "$1" in
    [1-9]*)
      os=$1; to=$2; shift; shift;
      ;;
    *)
      restore=$1; to=$2; shift; shift;
      ;;
  esac
elif [ $# = 3 ]; then
  root_dir=$1
  home_dir=$2
  if [ -d $3 ]; then
    dump=$3
    full=1
  else
    to=$3
  fi
else
  usage
  exit
fi

if [ -n "$host" ]; then
  ip=`host -t a $host`
  if [ $? != 0 ]; then
    echo "error: host '$host' not found"
    exit
  fi  
  host=`echo $ip | sed -e 's/ .*//'`
  ip=`echo $ip | sed -e 's/.* //'`
else
  host="fixme.yahoo.com"
  ip="1.1.1.1"
fi

if [ -n "$dump" ]; then
  if [ ! -d "$dump" ]; then
    echo "error: the directory '$dump' does not exist"
    exit
  fi
  dump_root_file="${dump}/root.cpio.gz"
  dump_home_file="${dump}/home.cpio.gz"
  dump_users_file="${dump}/users.cpio.gz"
  dump_src_file="${dump}/src.cpio.gz"
  dump_misc_file="${dump}/misc.cpio.gz"
fi

if [ -n "$os" ]; then
  if df | grep $nfs_mnt > /dev/null 2>&1; then
    :
  else
    mkdir $nfs_mnt 2> /dev/null
    mount_nfs -R 1 $nfs_server $nfs_mnt
  fi
  if df | grep $nfs_mnt > /dev/null 2>&1; then
    vers=$(echo $nfs_dir/${os}*) || exit
    restore=${vers##* }
  else
    echo "error: can't find os version $os via nfs"
    exit
  fi
fi

if [ -n "$restore" ]; then
  if [ ! -d "$restore" ]; then
    echo "error: the directory '$restore' does not exist"
    exit
  fi
  dump_root_file="${restore}/root.cpio.gz"
  dump_home_file="${restore}/home.cpio.gz"
  dump_users_file="${restore}/users.cpio.gz"
  dump_src_file="${restore}/src.cpio.gz"
  dump_misc_file="${restore}/misc.cpio.gz"
  if [ ! -e "$dump_root_file" ]; then
    echo "error: the file '$dump_root_file' does not exist"
    exit
  fi
  if [ ! -e "$dump_home_file" ]; then
    echo "error: the file '$dump_home_file' does not exist"
    exit
  fi
  if [ ! -e "$dump_users_file" ]; then
    echo "warning: the file '$dump_users_file' does not exist"
  fi
  if [ ! -e "$dump_src_file" ]; then
    echo "error: the file '$dump_src_file' does not exist"
    exit
  fi
  if [ ! -e "$dump_misc_file" ]; then
    echo "error: the file '$dump_misc_file' does not exist"
    exit
  fi
fi

if [ -n "$root_dir" ]; then
  if [ ! -d "$root_dir" ]; then
    echo "error: the src root-dir '$root_dir' does not exist"
    exit;
  fi
  if [ ! -d "$home_dir" ]; then
    echo "error: the src home-dir '$home_dir' does not exist"
    exit;
  fi
fi

if [ -n "$to" ]; then
  if expr $to : "^[a-z]*[0-9]*$" > /dev/null; then
    to_type=$(expr $to : "^\([a-z]*\)[0-9]*$")
    to_unit=$(expr $to : "^[a-z]*\([0-9]*\)$")
  else
    echo "error: the dst disk '$to' has wrong syntax"
    exit
  fi
  case $to_type in
    sd | da | wd | ad)
      ;;
    *)
      echo "error: the dst disk '$to' has bad type"
      exit
      ;;
  esac
  if grep "^$to" /var/run/dmesg.boot > /dev/null 2>&1; then
    :
  else
    echo "error: the dst drive '$to' was not recognized at boot"
    exit;
  fi
  if df | grep /dev/$to > /dev/null 2>&1; then
    echo "error: the dst disk '$to' is already mounted"
    exit
  fi
  if df | grep ${mnt} > /dev/null 2>&1; then
    echo "error: something is already on ${mnt}"
    exit
  fi
  if [ ! -e /dev/$to -o ! -e /dev/${to}s1a ]; then
    echo "the dst device '/dev/${to}s1a' does not exist"
    echo -n "would you like to create it? (y/n) "
    read answer
    if [ $answer != "y" ]; then
      exit;
    fi
    cd /dev/ || exit
    ./MAKEDEV $to ${to}s1a || exit
  fi

if disklabel -r $to > /dev/null 2>&1; then
    echo -en "==== WARNING - WARNING - WARNING - WARNING ====\n\n!! The contents of /dev/$to will be \033[1mcompletely NUKED\033[0m if you continue !!\n\n==== WARNING - WARNING - WARNING - WARNING ====\n\nAre you sure you want to continue? (y/n) "
    read answer
    echo
  else
    answer=y
  fi

if [ $answer != "y" ]; then
    echo "whew! that was close..."
    exit;
  fi
fi

if [ -n "$verbose" ]; then
  set -xv
fi

if [ $version = 2.1 ]; then
  tmp_file_1=$tmp_dir/$command.$$
  tmp_file_2=$tmp_dir/$command.$$.2
  tmp_file_3=$tmp_dir/$command.$$.3
else
  tmp_file_1=`mktemp $tmp_dir/$command.XXXXXX`
  tmp_file_2=`mktemp $tmp_dir/$command.XXXXXXX`
  tmp_file_3=`mktemp $tmp_dir/$command.XXXXXXX`
fi

if [ -n "$to" ]; then

rev=/home/src/sys/conf/newvers.sh
  misc_prefix=

if [ -n "$restore" ]; then
    mkdir $misc_dir 2> /dev/null
    cd $misc_dir || exit
    zcat $dump_misc_file | cpio -imd --quiet || exit
    rev=$misc_dir$rev
    misc_prefix=$misc_dir
  fi

case `grep ^REVISION $rev` in
    REVISION=\"4*)
      target_version=4
      rc_conf=etc/rc.conf.local
      ssh_host_key=etc/ssh/ssh_host_key
      boot1=boot/boot1
      boot2=boot/boot2
      mbr=boot/mbr
      fdisk_mbr=${misc_prefix}/$mbr
      ;;
    REVISION=\"3*)
      target_version=3
      rc_conf=etc/rc.conf.local
      ssh_host_key=etc/ssh_host_key
      boot1=boot/boot1
      boot2=boot/boot2
      mbr=boot/mbr
      fdisk_mbr=${misc_prefix}/$mbr
      ;;
    REVISION=\"2.2*)
      target_version=2.2
      rc_conf=etc/rc.conf
      ssh_host_key=etc/ssh_host_key
      boot1=usr/mdec/boot1
      boot2=usr/mdec/boot2
      mbr=usr/mdec/mbr
      fdisk_mbr=${misc_prefix}/$mbr
      ;;
    REVISION=\"2.1*)
      target_version=2.1
      rc_conf=etc/sysconfig
      ssh_host_key=etc/ssh_host_key
      boot1=usr/mdec/boot1
      boot2=usr/mdec/boot2
      mbr=usr/mdec/mbr
      fdisk_mbr=${misc_prefix}/$mbr
      ;;
    *)
      echo "error: unsupported target os"
      exit
      ;;
  esac

if df | grep $nfs_mnt > /dev/null 2>&1; then
    conf_dir=$nfs_dir/common/src/etc
  fi

case $to_type in
    sd | da)
      to_TYPE=SCSI
      case $target_version in
        3 | 4)
          target_to_type=da
          ;;
        *)
          target_to_type=sd
          ;;
      esac
      ;;
    wd | ad)
      to_TYPE=ESDI
      case $target_version in
        4)
          target_to_type=ad
          ;;
        *)
          target_to_type=wd
          ;;
      esac
      ;;
    *)
      echo "error: the dst disk '$to' has bad type"
      exit
      ;;
  esac

ed1="perl -i -pe 's/0/1/ if /^(AWRE|ARRE)/'"
  ed8="perl -i -pe 's/0/1/ if /^WCE/'"

if [ $to_type = "sd" ]; then
    EDITOR=$ed1 scsi -m 1 -P 3 -e -f /dev/r$to
    EDITOR=$ed8 scsi -m 8 -P 3 -e -f /dev/r$to
  elif [ $to_type = "da" ]; then
    EDITOR=$ed1 camcontrol modepage $to -m 1 -P 3 -e
    EDITOR=$ed8 camcontrol modepage $to -m 8 -P 3 -e
  fi

dd if=/dev/zero of=/dev/r$to count=128 > $verbose_fd 2>&1 || exit

disklabel -r -w $to auto || exit
  disklabel -r $to | grep sectors/unit > /dev/null || exit

heads=255
  spt=63
  sectors=$(expr "$(disklabel -r $to | grep sectors/unit)" : '^sectors/unit: \(.*\)')
  usable_sectors=$[$sectors - $spt]
  cylinders=$[$sectors/$heads/$spt]
  usable_cylinders=$[$usable_sectors / $heads / $spt]
  if [ $usable_cylinders -gt 1023 ]; then
    usable_cylinders=1023
  fi

if [ $version = 2.1 ]; then
    first_partition=0
  else
    first_partition=1
  fi

cat << EOF > $tmp_file_1 || exit
y
$cylinders
$heads
$spt
y
y
165
$spt
$usable_sectors
y
0
1
1
$usable_cylinders
$[$heads-1]
$[$spt]
y
y
0
0
0
y
0
0
0
0
0
0
y
y
0
0
0
y
0
0
0
0
0
0
y
y
0
0
0
y
0
0
0
0
0
0
y
y
$first_partition
y
y
EOF

if [ $version "<" 3 ]; then
    fdisk -i /dev/$to < $tmp_file_1 > $verbose_fd 2>&1 || exit
  else
    fdisk -i -b $fdisk_mbr /dev/$to < $tmp_file_1 > $verbose_fd 2>&1 || exit
  fi

cat > $tmp_file_1 << EOF || exit
type: ${to_TYPE}
disk: ${to}s1
label:
flags:
bytes/sector: 512
sectors/track: 1
tracks/cylinder: 1
sectors/cylinder: 1
cylinders: $usable_sectors
sectors/unit: $usable_sectors
rpm: 10000
interleave: 1
trackskew: 0
cylinderskew: 0
headswitch: 0           # milliseconds
track-to-track seek: 0  # milliseconds
drivedata: 0
8 partitions:
EOF

if [ $version = 2.1 -o $version = 2.2 ]; then
    cat >> $tmp_file_1 << EOF
 a: $[$root*2048] 0 4.2BSD 0 0 0
 b: $[$swap*2048] $[$root*2048] swap
 c: $usable_sectors 0 unused 0 0
 e: $[$usable_sectors-($swap+$root)*2048] $[($swap+$root)*2048] 4.2BSD 0 0 0
EOF
  else
    cat >> $tmp_file_1 << EOF
 a: $[$root*2048] 0 4.2BSD 1024 8192 16
 b: $[$swap*2048] $[$root*2048] swap
 c: $usable_sectors 0 unused 0 0
 e: $[$usable_sectors-($swap+$root)*2048] $[($swap+$root)*2048] 4.2BSD 1024 8192 16
EOF
  fi

disklabel -r -R $to $tmp_file_1 || exit
fi

cat /dev/null > $tmp_file_1

if [ -n "$root_dir" ]; then
  cd $root_dir || exit
  find -x . | egrep -v '^./usr/sup/' > $tmp_file_1 || exit
fi

if [ -n "$restore" ]; then
  echo "cloning from ${restore##*/}"
fi

if [ -n "$to" ]; then
  mkdir ${mnt} 2> /dev/null

echo "newfs'ing / ..."
  newfs /dev/${to}s1a > $verbose_fd || exit
  mount -o async /dev/${to}s1a ${mnt} || exit

if [ -n "$restore" ]; then
    cd ${mnt} || exit
    echo "restoring / ..."
    zcat $dump_root_file | cpio -i -m --quiet
  else
    echo "copying / ..."
    cpio -p -m --quiet ${mnt} < $tmp_file_1 || exit
  fi
elif [ -n "$dump" ]; then
  echo "dumping / ..."
  cpio -o --quiet --format crc < $tmp_file_1 | gzip -c > $dump_root_file
  cpio -o --quiet --format crc << EOF | gzip -c > $dump_misc_file
$mbr
home/src/sys/conf/newvers.sh
EOF
fi

#
# newfs /home
#

if [ -n "$to" ]; then
  echo "newfs'ing /home ..."
  newfs -i 2048 /dev/r${to}s1e > $verbose_fd || exit

if [ $version "<" 3  -o $target_version "<" 3 ]; then
    :
  else
    tunefs -n enable /dev/r${to}s1e > $verbose_fd 2>&1 || exit
  fi

mount -o async /dev/${to}s1e ${mnt}/home || exit
fi

#
# copy /home
#

cat > $tmp_file_1 << EOF || exit
src
obj
tmp
EOF

cat /dev/null > $tmp_file_2 || exit
cat /dev/null > $tmp_file_3 || exit

if [ -n "$home_dir" ]; then
  cd $home_dir || exit

for d in *; do
    case $d in
      "src" | "graveyard" | "backup" | "obj" | "tmp")
        ;;
      "var")
        find -x $d | egrep -v '^var/log/.*\.(gz|[0-9])' | egrep -v '^var/(crash|mail|backups|account|run|db)/' >> $tmp_file_1
        ;;
      *)
        if id $d > /dev/null; then
          find -x $d >> $tmp_file_3
        else
          find -x $d >> $tmp_file_1
        fi
        ;;
    esac
  done

find -x src/sys | egrep -v '^src/sys/compile/' >> $tmp_file_1

if [ -n "$full" ]; then
    find -x src | egrep -v '^src/sys/' > $tmp_file_2
  else
    cat /dev/null > $tmp_file_2
  fi
fi

if [ -n "$to" ]; then
  if [ -n "$restore" ]; then
    cd ${mnt}/home || exit
    echo "restoring /home ..."
    zcat $dump_home_file | cpio -im --quiet
    if [ -e $dump_users_file ]; then
      echo "restoring /home (users) ..."
      zcat $dump_users_file | cpio -im --quiet
    fi
    if [ -n "$full" ]; then
      echo "restoring /home/src ..."
      zcat $dump_src_file | cpio -im --quiet
    fi
  else
    echo "copying /home ..."
    cat $tmp_file_1 $tmp_file_2 $tmp_file_3 | cpio -p -m --quiet ${mnt}/home || exit
  fi
elif [ -n "$dump" ]; then
  echo "dumping /home ..."
  cpio -o --quiet --format crc < $tmp_file_1 | gzip -c > $dump_home_file
  echo "dumping /home (users) ..."
  cpio -o --quiet --format crc < $tmp_file_3 | gzip -c > $dump_users_file
  echo "dumping /home/src ..."
  cpio -o --quiet --format crc < $tmp_file_2 | gzip -c > $dump_src_file
fi

if [ -n "$to" ]; then
  disklabel -B -b ${mnt}/$boot1 -s ${mnt}/$boot2 $to || exit

cd ${mnt}/home/var/log
  rm -f *.gz *.st *.[0-9]
  for f in *; do
    cat /dev/null > $f
  done

rm -f ${mnt}/home/var/crash/*
  rm -f ${mnt}/home/var/account/*

rm -f ${mnt}/${ssh_host_key}{,.pub} || exit

if [ $target_version = 2.2 ]; then
    perl -i -pe "s/:$disk_regex/:$target_to_type/" ${mnt}/boot.config || exit
  fi

perl -i -pe "s/dev\/$disk_regex/dev\/$target_to_type/" ${mnt}/etc/fstab || exit
  perl -i -pe "s/^dumpdev=\S*/dumpdev=\"\/dev\/${target_to_type}0s1b\"/" ${mnt}/${rc_conf} || exit

if [ -n "$host" ]; then
    perl -i -pe "s/^hostname=\S*/hostname=\"$host\"/" ${mnt}/${rc_conf} || exit

if [ -x $conf_dir/bin/getnet ]; then
      net=`$conf_dir/bin/getnet -f $conf_dir/netmasks -c $ip | sed -e 's/\//-/'`
    else
      net="${ip%.*}.0-24"
    fi
    if [ ! -d "$conf_dir/conf/net/$net" ]; then
      net=`echo $net | sed -e 's/-.*$//'`
      if [ ! -d "$conf_dir/conf/net/$net" ]; then
        net=`echo $net | sed -e 's/\.0$//'`
      fi
    fi

if [ -d "$conf_dir/conf/net/$net" ]; then
      octet=`expr $ip : '^.*\.\([0-9]*\)$'`

if [ -x $conf_dir/bin/getnet ]; then
        netmask=`$conf_dir/bin/getnet -f $conf_dir/netmasks -h $ip`
        netmask=${netmask#* }
      else
        netmask="0xffffff00"
      fi

file="$conf_dir/conf/net/$net/defaultrouter"
      if [ -f $file.0 ]; then
        i=1
        while [ -f $file.$i ]; do
          i=$[i+1]
        done
        mod=$[$octet % $i]
        defaultrouter=`cat $file.$mod`
      elif [ -f $file ]; then
        defaultrouter=`cat $file`
      else
        defaultrouter="$c.1"
      fi

file="${mnt}/etc/start_if.$nic"
      cat /dev/null > $file || exit
      if [ $target_version = 2.1 ]; then
        echo "ifconfig \$1 $ip netmask $netmask link0 link1 link2" >> $file
      else
        echo "ifconfig \$ifn $ip netmask $netmask" >> $file
        echo "ifconfig \$ifn media 100basetx mediaopt full-duplex" >> $file
      fi
      echo "route add default $defaultrouter" >> $file

file="$conf_dir/conf/net/$net/resolv.conf"
      if [ -f $file.0 ]; then
        i=1
        while [ -f $file.$i ]; do
          i=$[i+1]
        done
        mod=$[$octet % $i]
        file="$file.$mod"
      fi
      if [ -f $file ]; then
        install -c -o root -g wheel -m 644 $file ${mnt}/etc/resolv.conf || exit
      fi

if [ -e $conf_dir/conf/net/$net/loghost ]; then
        loghost=`cat $conf_dir/conf/net/$net/loghost`
        perl -i -pe "s/\@\S+/\@$loghost/" ${mnt}/etc/syslog.conf || exit
      fi

install -c -o root -g wheel -m 644 $conf_dir/conf/net/$net/ntp.conf ${mnt}/etc/ || exit
      install -c -o root -g wheel -m 644 $conf_dir/conf/net/$net/hosts.allow ${mnt}/etc/ || exit
      if [ $target_version "<" 3 ]; then
        perl -i -ne 'print if /\$Yahoo/; next if /^\s*#/; next if /deny/i; s/\s*:\s*allow[ \t]*//; print' ${mnt}/etc/hosts.allow || exit
      fi
    fi
  fi

if [ -n "$verbose" ]; then
    df
  fi

cleanup

ed8="perl -i -pe 's/1/0/ if /^WCE/'"

if [ $to_type = "sd" ]; then
    EDITOR=$ed8 scsi -m 8 -P 3 -e -f /dev/r$to
  elif [ $to_type = "da" ]; then
    EDITOR=$ed8 camcontrol modepage $to -m 8 -P 3 -e
  fi
fi

set +xv
echo
echo "success"

Labels: cheatsheet, linux.