#!/bin/sh
set -u # exit on using unset var

#        name = bootcdmk2diskconf - create bootcd2disk.conf for backup
#       autor = Bernd Schumacher 
#   startdate = 08.05.2007

### BOOTCD-RUN_LIB Placeholder ##############
# bootcd-run.lib
# vim: set filetype=sh :

#     version: $Version: $
#   copyright: Bernd Schumacher <bernd.schumacher@hpe.com> (2007)
#     license: GNU General Public License, version 2
#     comment: use ANSW to change the next point from external
# description: To understand what to do with this library you can download
#              the test programs with wget
#

RUN_INTERACT="no"
LANG=C
LC_ALL=C
IGNORE=""
STDOUT=""

msg()
{
  echo "--- MESSAGE ---" | tee -a $ERRLOG >&2
  echo "$@" | tee -a $ERRLOG >&2
}

set +u
if [ ! "$ERRLOG" ]; then
  ERRLOG=/var/log/bootcd.errlog
  touch "$ERRLOG" >/dev/null 2>&1
  [ $? -ne 0 ] && ERRLOG=/tmp/bootcd.errlog
  msg "ERRLOG was unset. It is set to $ERRLOG now."
fi
set -u

# function dbg prints DEBUG Messages to stderr.
# It is very fast because no if-check has to be done
# functions dbgoff, dbgon, and dbgtoggle switches dbg on or off
dbgoff()
{
   eval "dbg() { :; }"
}

if [ "$(type dbg 2>&1| grep "not found")" ]; then
  dbgoff
fi

dbgon()
{
   eval "dbg() { echo \"DEBUG \$@\" >&2; }"
}

# with option -v dbtoggle is more verbose
dbgtoggle()
{
  if [ "$(dbg 2>&1)" ]; then
    dbgoff
    [ "$1" = "-v" ] && echo "debug off" >&2
  else
    dbgon
    [ "$1" = "-v" ] && echo "debug on" >&2
  fi
}

# function run: run given command and output error
# get: $IGNORE   -- regexp for error messages, generate no output, no question
#                   (set from function ignore)
#      $STDOUT   -- regexp for error messages, only output, no question
#                   (set from function stdout)
#      $ERRORLOG -- write to this file
#
#      $RUN_INTERACT -- "yes" meens run from interactiv
# comment: by default, all errors (stdout, error) generates output and questions 
#
# Attention: do not try to set global variables in a command called by run !!!
#
run()
{
  local ERR C T A
  #echo >&2 "IGNORE $IGNORE"
  #echo >&2 "STDOUT $STDOUT"
  while :
  do

    > $ERRLOG.tmp
    (
      eval "$@" 2>&1
      ERR=$?
      if [ "$ERR" != "0" ]; then
        echo "exit=$ERR"
      fi
    ) |
    if [ "$IGNORE" != "" ]; then
      C="grep -v $IGNORE"
      tee $ERRLOG.tmp | tee -a $ERRLOG | eval "$C"
    else
      tee -a $ERRLOG.tmp | tee -a $ERRLOG
    fi

    T=`cat $ERRLOG.tmp`
    if [ "$IGNORE" != "" ]; then
      C="grep -v $IGNORE"
      T=`echo "$T" | eval "$C"`
    fi
    if [ "$STDOUT" != "" ]; then
      C="grep -v $STDOUT"
      T=`echo "$T" | eval "$C"`
    fi
  
    if [ "$T" != "" ]; then
      A=""
      while [ "$A" != "e" -a "$A" != "r" -a "$A" != "i" -a "$A" != "s" ]
      do
        echo "--- OUTPUT from <$@> ---" | tee -a $ERRLOG
        echo "$T" | tee -a $ERRLOG
        if [ "$RUN_INTERACT" = "yes" ]; then 
          echo -n "--- (e)xit (r)edo (i)gnore (s)witch interactive --- " | tee -a $ERRLOG
        else 
          echo -n "--- (e)xit (r)edo (i)gnore --- " | tee -a $ERRLOG
        fi
        read A 
        # Next line handles EOF from a pipe as "(e)xit"
        [ $? -ne 0 ] && A="e"
        echo "$A" >> $ERRLOG
      done
      if [ "$A" = "e" ]; then
        exit 1
      elif [ "$A" = "i" ]; then
        break
      # switch to interactive mode
      elif [ "$A" = "s" -a "$RUN_INTERACT" = "yes" ]; then
        echo
        echo "switching to interactive mode to point ($ntrctv_ANSW) which failed"
        echo
	ntrctv_ANSW=$(($ntrctv_ANSW-1))
        ntrctv_y=""
        break
      fi
    else
      break
    fi
  
  done
  IGNORE=""
  STDOUT=""
}

# function: build stdout for interactive
# get: $1 -- number
#      $2 -- stdout string
in_stdout()
{
  local nr=$1
  shift 

  eval STDOUT${nr}=\"\$STDOUT${nr} -e \\\"\$@\\\"\"
}

# function: build ignore for interactive
stdout()
{
  STDOUT="$STDOUT -e \"$@\""
}

# function: build ignore for interactive
# get: $1 -- number
#      $2 -- ignore string
in_ignore()
{
  local nr=$1
  shift 

  eval IGNORE${nr}=\"\$IGNORE${nr} -e \\\"\$@\\\"\"
}

## example
#mm=0
#mm=$(($mm+1)); eval IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
#in_ignore $mm "error bla"
#in_ignore $mm "^bluber sumsel .*"
#in_stdout $mm "no error but but a useful comment"
#mm=$(($mm+1)); eval IGNORE${mm}=\"\"
#in_norun $mm
#echo $IGNORE1 -- $IGNORE2
#exit

# function: run interactiv -r without run for this menu point
# get: $1 -- number
# comment: please update norunstring also in interactive!
in_norun()
{
  local norunstring="interactive_without_run"
  local nr=$1

  eval IGNORE${nr}=\"$norunstring\"
  eval STDOUT${nr}=\"$norunstring\"
}


ignore()
{
  IGNORE="$IGNORE -e \"$@\""
}

warn()
{
  if [ $# -gt 0 ]; then
    A=""
    while [ "$A" != "e" -a "$A" != "i" ]
    do
      echo "--- WARNING ---" | tee -a $ERRLOG
      echo "$@" | tee -a $ERRLOG
      echo -n "--- (e)xit (i)gnore --- " | tee -a $ERRLOG
      if [ "$SCRIPT" ]; then
        A="i"
	echo "$A (SCRIPT)"
        echo "$A (SCRIPT)" >> $ERRLOG
        echo
      else
        read A 
        # Next line handles EOF from a pipe as "(e)xit"
        [ $? -ne 0 ] && A="e"
        echo "$A" >> $ERRLOG
      fi
    done
    if [ "$A" = "e" ]; then
      exit 1
    fi
  fi
}

err()
{
  (
  echo "--- FATAL ERROR ---" 
  echo "$@"
  ) |
  if [ "$(set | grep ^ERRLOG=)" ]; then
    tee -a $ERRLOG >&2
  else
    cat >&2
  fi
  exit 1
}

# create_host_keys <DIR>
#   if ssh_host_key, ssh_host_rsa or ... exists in <DIR>
#   then recreate it.
create_host_keys() 
{
  # Now only ssh versions which support Option -t are supported

  F=ssh_host_key
  if [ -f $1/$F ]; then  
    echo "Creating OpenSSH_2 $F" >>$ERRLOG
    run "rm -f $1/$F $1/$F.pub"
    run "ssh-keygen -b 1024 -f $1/$F -N '' -t rsa1 >>$ERRLOG 2>&1"
  fi

  F=ssh_host_rsa_key
  if [ -f $1/$F ]; then  
    echo "Creating OpenSSH_2 $F" >>$ERRLOG
    run "rm -f $1/$F $1/$F.pub"
    run "ssh-keygen -b 1024 -f $1/$F -N '' -t rsa >>$ERRLOG 2>&1"
  fi

  F=ssh_host_dsa_key
  if [ -f $1/$F ]; then  
    echo "Creating OpenSSH_2 $F" >>$ERRLOG
    run "rm -f $1/$F $1/$F.pub"
    run "ssh-keygen -b 1024 -f $1/$F -N '' -t dsa >>$ERRLOG 2>&1"
  fi
}

#      syntax: interactive [-y] [-e] [-h <head>] <functioncall with params> ...
# description: interactive evaluates the listed functioncalls. If the first 
#              argument is not -y an interactive menu will be given. This menu
#              can get a header <head> with -h. An extra evaluation of <head> 
#              and <functioncall with params> can be forced with option -e.
#              The <functioncall with params> can contain the special 
#              character sequences "<-i>" and "<h>". "<-i>" will be translated
#              either to "-i" or to "". This can be toggled with the key "i".
#              
#              -y        --   run without interaction
#              -e        --   evaluate each function call one times more
#              -h <head> --   print <head> as menu head
#              -r        --   run command with "run"
#
# helper functions for "run" (-r given to interactive):
#            in_stdout <number> <string> -- ignore stdout+stderr
#            in_ignore <number> <string> -- ignore stdout+stderr, don't print
#            in_norun <number>           -- run menupoint without run!
#
#
interactive()
{
  local ntrctv_ANSW ntrctv_A="" ntrctv_i ntrctv_y="" ntrctv_t="-i " ntrctv_head="" ntrctv_e="" ntrctv_run="" ntrctv_c
  local ntrctv_cmd
  local norunstring="interactive_without_run"

  # get all options
  while [ $# -ge 1 ]; do
    if [ "$1" = "-y" ]; then
      ntrctv_y="$1"
      ntrctv_t=""
      shift
    elif [ "$1" = "-e" ]; then
      ntrctv_e="$1"
      shift
    elif [ "$1" = "-h" -a $# -gt 2 ]; then
      ntrctv_head="$2"
      shift 2
    elif [ "$1" = "-r" ]; then
      ntrctv_run="yes"
      shift 1
    else
      break
    fi
  done
  
  # read the function calls
  if [ $# -gt 0 ]; then
    ntrctv_ANSW="1"
    while :; do
      if [ ! "$ntrctv_y" ]; then
        # print head 
        if [ "$ntrctv_head" ]; then 
	  ntrctv_c="$ntrctv_head"
          # evaluate the head
          [ "$ntrctv_e" ] && ntrctv_c="$(eval echo "$ntrctv_c")"
          echo "$ntrctv_c"
        fi
        ntrctv_i=1
        # build menu
        while [ $ntrctv_i -le $# ]; do
          ntrctv_c=$(echo "$ntrctv_i $(eval echo "\${$ntrctv_i}")" | sed "s/<-i>[[:space:]]*/$ntrctv_t/g")
          [ "$ntrctv_e" ] && ntrctv_c="$(eval echo "$ntrctv_c")"
          echo "$ntrctv_c"
          ntrctv_i=$(($ntrctv_i+1))
        done
        
        # dbg exists, print flag (do not use declare to be posix konform)
        [ "$(type dbg 2>&1| grep "not found")" ] || echo "d toggle dbg() function on and off"
        # i flag can be toggled 
        [ "$(echo "$*"|grep "<-i>")" ] && echo "i toggle -i flag"
        # menu point "continue"
        [ "$ntrctv_ANSW" != "q" ] && [ $ntrctv_ANSW -lt $# ] && echo "c continue without questions"
        echo "q quit"
        echo -n "? [$ntrctv_ANSW]"
        read ntrctv_A
        # Next line handles EOF from a pipe as "q"
        [ $? -ne 0 ] && ntrctv_A="q"
        [ "$ntrctv_A" -a "$ntrctv_A" != "c" -a "$ntrctv_A" != "i" -a "$ntrctv_A" != "d" ] && ntrctv_ANSW="$ntrctv_A"
      fi
      if [ "$ntrctv_ANSW" = "q" ]; then
        return
      elif [ "$ntrctv_A" = "d" ]; then
        dbgtoggle -v
      elif [ "$ntrctv_A" = "i" ]; then
        [ "$ntrctv_t" ] && ntrctv_t="" || ntrctv_t="-i "
      elif [ "$(echo "$ntrctv_ANSW" | sed 's/[0-9]//g')" ]; then
        ntrctv_ANSW="?"
      elif [ "$ntrctv_ANSW" -ge 1 -a "$ntrctv_ANSW" -le $# ]; then
        [ "$ntrctv_A" = "c" ] && ntrctv_y="-y"
        # build the command and set -i, if needed
        ntrctv_cmd="$(echo "$(eval echo "\${${ntrctv_ANSW}}")" | sed -e "s/<-i>/$ntrctv_t/g")"
        # eval function call again
        [ "$ntrctv_e" ] && ntrctv_cmd="$(eval echo "$ntrctv_cmd")"

        # call function
        if [ "$ntrctv_run" ]; then
          local IGNORE="" STDOUT=""
	  [ "$(set | grep "^IGNORE${ntrctv_ANSW}=")" ] && eval IGNORE=\"\$IGNORE${ntrctv_ANSW}\"
	  [ "$(set | grep "^STDOUT${ntrctv_ANSW}=")" ] && eval STDOUT=\"\$STDOUT${ntrctv_ANSW}\"
          # run is on but run this menu point without run!
          if [ "$IGNORE" = "$STDOUT" -a "$STDOUT" = "$norunstring" ]; then
            eval "$ntrctv_cmd"
          else
            [ "$ntrctv_y" ] && local RUN_INTERACT="yes" || local RUN_INTERACT="no"
            run "$ntrctv_cmd"
          fi
        else
          eval "$ntrctv_cmd"
        fi
        ntrctv_ANSW=$(($ntrctv_ANSW+1))
        [ $ntrctv_ANSW -gt $# ] && ntrctv_ANSW=q
      fi
    done
  fi
}
## examples ... comment out and try it
#
#a() { A="called: a"; [ $# -ge 1 ] && A="$A <$1>"; [ $# -ge 2 ] && A="$A <$2>"; [ $# -ge 3 ] && A="$A <$3>"; [ $# -ge 4 ] && A="$A <$4>"; echo "$A" ;}
#interactive a "a -x # with arg and comment" "a -x \"one two\" # 2 args, one with spaces"
#exit 0
#
#interactive -y a "a -x # with arg and comment" "a -x \"one two\" # 2 args, one with spaces"
#exit 0
#
#interactive "a A" "a B" "a C" "a D" "a E" "a F" "a G" "a H" "a I" "a J" "a K"
#exit 0
#
#f="a \"a -x # with arg and comment\" \"a -x \\\"one two\\\" # 2 args, one with spaces\""
#eval "interactive $f"
#exit 0
#
#interactive # should return without doing anything
#exit 0
#
#interactive "a <-i> A" "a B" "a <-i> C"
#exit 0
#
#f1() { IANAME="$IANAME/f1" interactive -e -h "=== \$IANAME \(opts=-e\) n=\<\$n\> ===" "n=$((n+1))" f1; }
#n=""; IANAME="main" interactive -e -h "=== \$IANAME \(opts=-e\) n=\<\$n\> ===" "n=$(($n+1)" f1
#exit 0
#
#interactive -r "sh -c \"exit 0\"" "echo \"error auf stdout\"" "echo \"error auf stderr\" >&2" "sh -c \"exit 1\""
#exit 0
#
#interactive -y -r "sh -c \"exit 0\"" "echo \"error auf stdout\"" "echo \"error auf stderr\" >&2" "sh -c \"exit 1\""
#exit 0
#


# function: ask_user -- ask user
# get: question = string
#      default  = y|n
# ret: 1 == yes | 0 == no
ask_user()
{
  local quest=$1
  [ "$2" = "y" -o "$2" = "n" ] && local default=$2 || local default=""

  while [ 1 ]; do
    echo  "$quest"
    read a
    # Next line handles EOF from a pipe as "default"
    [ $? -ne 0 ] && a=""
    [ "$a" = "" ] && a=$default
    if [ "$a" = "Y" -o "$a" = "y" -o "$a" = "J" -o "$a" = "j" ]; then
      # echo "yes"
      return 1;
    fi
    if [ "$a" = "N" -o "$a" = "n" ]; then
      # echo "no"
      return 0;
    fi
    echo >&2 "Error: \"$a\" is not a allowed answer!"
  done
}


# function: do_dir -- create directory
# get: $1 -- directory
#      $2 -- permissions (optional)
do_dir()
{
  local dir=$1
  local perm=""; [ $# -ge 2 ] && perm=$2

  if [ -d "$dir" ]; then
    ask_user "Directory \"$dir\" exist's, remove it [Y|n] " "y"
    [ $? = 0 ] && err "Can't work without directory \"$dir\"."
    rm -rf $dir
  fi
  mkdir -p $dir
  [ "$perm" ] && chmod $perm $dir
  echo ""
}


# function: check_tools -- check if tools exist
#           use ./ to search in local directory
# get: $1..$n -- tools
check_tools()
{
  while [ $# -gt 0 ]; do 
    echo -n >&2 " check for \"$1\" ..."
    if [ "$(echo $1 |cut -c1-2)" = "./" ]; then
      [ ! -f "$1" ] && err "Can't find file \"$1\"!"
    else
      [ ! "$(which $1)" ] && err "Can't find tool \"$1\" in PATH!"
    fi
    echo >&2 "ok"
    shift
  done
}

# function: prepare_chroot <workdir> [-i]
# globals: IAHEAD
prepare_chroot()
{
  local workdir="$1"
  local interact=""; [ $# -ge 2 ] && interact="$2"
  local TODO="" mm=0
  if [ "$(env | grep "^IAHEAD=")" ]; then 
    local IAHEAD="$IAHEAD / prepare_chroot"
  else
    local IAHEAD="prepare_chroot"
  fi

  mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
  TODO="$TODO \"mount --bind /dev $workdir/dev\""

  mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
  TODO="$TODO \"mount -t proc none $workdir/proc\""

  mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
  TODO="$TODO \"mount -t sysfs none $workdir/sys\""

  mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
  TODO="$TODO \"mount -t devpts none $workdir/dev/pts\""

  mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
  TODO="$TODO \"chroot $workdir sh -c \\\"[ -f /etc/mtab ] && mv /etc/mtab /etc/mtab.bootcd || rm -f /etc/mtab.bootcd\\\"\""

  mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
  TODO="$TODO \"chroot $workdir sh -c \\\"grep -v -e \\\\\\\"^sunrpc\>\\\\\\\" -e \\\\\\\"^rootfs\>\\\\\\\" /proc/mounts >/etc/mtab\\\"\""

  # we need selinux mounted to install openssh_server without
  # error "chage: Permission denied."
  if [ "$(cat /proc/mounts | grep selinux)" ]; then
    mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
    TODO="$TODO \"mount -t selinuxfs none $workdir/selinux\""
  fi

  [ "$interact" ] && interact="" || interact="-y"
  eval "interactive -h \"=== \$IAHEAD ===\" $interact -r $TODO"
}

# unprepare_chroot <workdir> [-i]
# globals IAHEAD
unprepare_chroot()
{
  local workdir="$1"
  local interact=""; [ $# -ge 2 ] && interact="$2"
  local TODO="" mm=0
  if [ "$(env | grep "^IAHEAD=")" ]; then 
    local IAHEAD="$IAHEAD / unprepare_chroot"
  else
    local IAHEAD="unprepare_chroot"
  fi

  mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
  TODO="$TODO \"chroot $workdir sh -c \\\"[ -f /etc/mtab.bootcd ] && mv /etc/mtab.bootcd /etc/mtab || rm -f /etc/mtab\\\"\""

  if [ "$(cat /proc/mounts | grep selinux)" ]; then
    mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
    TODO="$TODO \"umount $workdir/selinux\""
  fi

  mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
  TODO="$TODO \"umount $workdir/dev/pts\""

  mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
  TODO="$TODO \"umount $workdir/sys\""

  mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
  TODO="$TODO \"umount $workdir/proc\""

  mm=$(($mm+1)); eval local IGNORE${mm}=\"\"; eval local STDOUT${mm}=\"\"
  TODO="$TODO \"umount $workdir/dev\""

  [ "$interact" ] && interact="" || interact="-y"
  eval "interactive -h \"=== \$IAHEAD ===\" $interact -r $TODO"
}
### BOOTCD-RUN_LIB Placeholder ##############

# exclude this filesystems from RIDF (readinfo from df)
RIDF_EXCLUDES="-e ^/dev/shm.*/dev/shm"

# only grep filesystems from fstab
MOUNTGREP='grep -e "^/dev/" -e "^LABEL=" -e "^UUID=" | grep -v -e "\<noauto\>" -e "\<auto\>" -e "\<swap\>"  -e "\<devpts\>" -e "\<sysfs\>" -e "\<tmpfs\>" -e "\<proc\>"'

MNTBOOTCDDISC="mnt/bootcd.disc"

######################## nothing to configure behind this line ###############

# The following parameters are defined in the order listed
PARAMETERS="ERRLOG
DISK0
LVMGRP
LVMVOL
TRYFIRST
SFDISK0
VFAT
EXT2FS
EXT3FS
EXT4FS
SWAP
MOUNT
BIND
UMOUNT
FSTAB
GRUB2
GRUB
GRUBBOOTDISK
GRUBBOOTDIR
GRUBDEVICEMAP
LILO
SSHHOSTKEY
UDEV_FIXNET
IMAGEURL
PARTITIONLABEL"

USAGE="
Usage: bootcdmk2diskconf [-v] [-d]
   -v 	verbose 
   -d   debug
   -s   same; same size for last partition. If this option is not used 
        the last partition will be adjusted to actual disk size.
   -e   exact; exact disks will be used. Normally only the disk order will
        be used.
   -b   This option is needed to create a bootcd2disk.conf that can be 
        used to restore an offline backup.
   -f <fstabdev>
        Not the actual running system is used, but a system described by 
	the fstab that can be found on device <fstabdev>.
	<fstabpath>. example: -f /dev/sde7
"

debug()
{
  if [ "$DEBUG" ]; then
    echo "DEBUG $*" >&2
  fi
}

# label2dev <label>
label2dev()
{
  mount -vnf LABEL=$1 | # -> /ram1/dev/sda1 on /mnt/boot type ext3 (rw)
    awk '{print $1}' | # -> /ram1/dev/sda1
    sed "s|/ram[^/]*||" # /dev/sda1
}

# function: labelsed -- remove labels by real devices
# get: stdin -- stream
labelsed()
{
  local T T1 L j i
  T="$(cat)"
  debug "labelsed INPUT=<$T>"
  L="$(echo "$T" | sed -n "s/.*LABEL=\([^:[:space:]]\+\).*/\1/p" | sort -n)"
  for i in $L; do
    debug "labelsed search for label <$i>"
    j="$(echo "$RILABEL" | grep ":$i$" | awk -F: '{print $1}')"
    debug "labelsed found <$j>"
    T1="$(echo "$T" | sed -e "s|LABEL=$i:|$j:|" -e "s|LABEL=$i$|$j|")"
    T="$T1"
  done
  debug "labelsed OUTPUT=<$T>"
  echo "$T"
}
#echo "   Precondition: RILABEL-Line1=\"/dev/sda1:/\" RILABEL-Line2=\"/dev/sda2:SWAP-sda2\""
#echo "          Input: Line1=\"LABEL=/:/\" Line2=\"LABEL=SWAP-sda2\""
#echo "       Expected: Line1=\"/dev/sda1:/\" Line2=\"/dev/sda2\""
#echo "labelsed Output:"
#echo "LABEL=/:/
#LABEL=SWAP-sda2" | DEBUG="" RILABEL="/dev/sda1:/
#/dev/sda2:SWAP-sda2" labelsed 
#exit 0

# function: uuidsed -- remove uuids by real devices
# get: stdin -- stream
uuidsed()
{
  local O N i j

  O="$(cat)"
  for i in $(echo "$RIUUID" | sed "s/^[^:]\+://"); do
    j="$(echo "$RIUUID" | sed -n "s/:$i$//p")"
    debug "i=<$i> j=<$j>"   
    N="$(echo "$O" | sed "s|$i|UUID!$j|g")"
    O="$N" 
  done   
  echo "$O"
}
#riuuid="/dev/sda1:35096edc-998f-4af8-b971-a5195937492f"
#echo "Precondition: RIUUID=\"$riuuid\""
#inp="UUID=35096edc-998f-4af8-b971-a5195937492f:/boot"
#echo "Input=<$inp> Expected:"
#echo "UUID=UUID!/dev/sda1:/boot Output:"
#echo "$inp" | DEBUG="" RIUUID="/dev/sda1:35096edc-998f-4af8-b971-a5195937492f" uuidsed
#inp="search --no-floppy --fs-uuid --set 35096edc-998f-4af8-b971-a5195937492f:/boot"
#echo "Input=<$inp> Expected:"
#echo "search --no-floppy --fs-uuid --set UUID!/dev/sda1:/boot Output:"
#echo "$inp" | DEBUG="" RIUUID="/dev/sda1:35096edc-998f-4af8-b971-a5195937492f" uuidsed
#exit 0

# rmvg()
rmvg()
{
  T="$(cat)"
  debug "rmvg INPUT=<$T>"
  for i in $CIVG; do
    debug "rmvg $i"
    # i=vg_rh6 would remove /dev/mapper/vg_rh6-lv_swap
    # i=vg00 wourd remove /dev/vg00/lv01
    T1="$(echo "$T" | grep -v -e "/dev/$i\>" -e "/dev/mapper/$i-")"
    T="$T1"
  done
  debug "rmvg OUTPUT=<$T>"
  echo "$T"
}

# function: readinfo -- read informations of disks
readinfo()
{
  MNT=""
  [ $# -gt 0 ] && local MNT="$1"  

  RIFSTAB="$(cat $MNT/etc/fstab)"
  RIGRUB="$(for i in $MNT/boot/grub/menu.lst $MNT/boot/grub/grub.conf $MNT/boot/boot/grub/menu.lst \
    $MNT/boot/boot/grub/grub.conf; do if [ -s $i ]; then cat $i; break; fi; done)"
  RIGRUB2="$(for i in $MNT/boot/grub/grub.cfg $MNT/boot/boot/grub/grub.cfg; do if [ -s $i ]; then cat $i; break; fi; done)"
  RILV="$([ "$(type lvdisplay 2>&1 | grep "not found")" ] || 
    (lvdisplay --ignorelockingfailure --units m -C | tail -n +2 | 
    sed "s/^[[:space:]]*//" | awk '{printf("%s:%s:%d\n",$1,$2,$4)}'))"
  RIPV="$([ "$(pvdisplay --ignorelockingfailure 2>/dev/null)" ] && 
    (pvdisplay --ignorelockingfailure -C | tail -n +2 |
    awk '{printf("%s:%s\n",$1,$2)}'))"
  # read from df
  RIDF="$(df -lPm | grep -e "^/dev/" -e "^LABEL=" | grep -v $RIDF_EXCLUDES |
    awk '{printf("%s:%s\n",$1,$2)}')"
  RILABEL="$(for i in $(echo "$RIFSTAB" | 
    sed -n "s/.*LABEL=\([^[:space:]]\+\).*/\1/p" | sort -n); do
      echo "$(label2dev $i):$i"
    done)"
  # RIUUID="/dev/sda1:35096ed...5492f<RETURN>/dev/sda2:1PTfZ5...ZARL1"
  RIUUID="$(for i in $(echo "$RIFSTAB" | 
    sed -n "s/.*UUID=\([^[:space:]]\+\).*/\1/p" | sort -n); do
      echo "$(blkid -U $i):$i"
    done)"
  RIPARTITION="$(cat /proc/partitions | tail -n +3|
    awk '{printf("/dev/%s:%d\n",$4,$3/1024)}';
    sfdisk -s | grep -v "^total" | 
    awk '{printf("%s%d\n",$1,$2/1024)}') | sort -u)"
}

uuidcut()
{
   sed "s/UUID=UUID!//g"
}

calcinfo()
{
  local i j

  CIVG="$(echo "$RILV" | awk -F: '{print $2}' | sort -u)" 

  CISWAP="$(echo "$RIFSTAB" | grep -e "^/dev/" -e "^LABEL=" -e "^UUID=" | 
    grep "\<swap\>" |awk '{print $1}' | labelsed | uuidsed | uuidcut )"

  CIFS="$(echo "$RIFSTAB"| eval "$MOUNTGREP" | awk '{printf("%s:%s:%s\n",$1,$2,$3)}' | labelsed | uuidsed | uuidcut)"

  # CIPART calculation
  #
  # Exp1: CIFS="/dev/hda2:/:ext4<RETURN>/dev/hda5:/home:ext2" CISWAP="/dev/hda3" RIPV="" 
  #       => CIPART=</dev/hda2<RETURN>/dev/hda3<RETURN>/dev/hda5>
  # Exp2: CIFS="/dev/VolGroup00/LogVol00:/:ext4<RETURN>/dev/sda1:/boot:ext4"
  #       CISWAP="/dev/VolGroup00/LogVol01" RIPV="/dev/sda2:VolGroup00"
  #       => CIPART="/dev/sda1<RETURN>/dev/sda2"
  # Exp3: CIFS="/dev/sda1:/:ext4" CISWAP="/dev/sda2" RIPV="" 
  #       => CIPART="/dev/sda1<RETURN>/dev/sda2"
  # Exp4: CIFS="/dev/VolGroup01/LogVol00:/:ext4<RETURN>/dev/sda1:/boot:ext4"
  #       CISWAP="/dev/VolGroup01/LogVol01" 
  #       RIPV="/dev/sda2:VolGroup01<RETURN>/dev/sdb1:VolGroup01<RETURN>/dev/sdc1:VolGroup01"
  #       => CIPART="/dev/sda1<RETURN>/dev/sda2<RETURN>/dev/sdb1<RETURN>/dev/sdc1"
  #
  # Exp5: CIFS="/dev/mapper/vg_rh6-lv_root:/:ext4<RETURN>/dev/sda1:/boot:ext4" 
  #       CISWAP="/dev/mapper/vg_rh6-lv_swap" 
  #       RIPV="/dev/sda2:vg_rh6<RETURN>/dev/sda2" 
  #       => CIPART="/dev/sda1<RETURN>/dev/sda2"
  #
  # add   space  for dash ;-) 


  CIPART="$( (echo "$CIFS" | awk -F: '{print $1}'; echo "$CISWAP"; 
    echo "$RIPV" | awk -F: '{print $1}') | rmvg | sort -u)"

  # CIDISK calculation
  #
  # Exp1: CIPART=</dev/hda2<RETURN>/dev/hda3<RETURN>/dev/hda5>
  #       CIDISK=</dev/hda:DISK0>
  # Exp2: CIPART=</dev/sda1<RETURN>/dev/sda2>
  #       CIDISK=</dev/sda:DISK0>
  # Exp3: CIPART=</dev/sda1<RETURN>/dev/sda2<RETURN>/dev/sdb1<RETURN>/dev/sdc1> 
  #       CIDISK=</dev/sda:DISK0<RETURN>/dev/sdb:DISK1<RETURN>/dev/sdc:DISK2>
  # Exp4: CIPART=</dev/mapper/3600508b1001c9e14b850ec3afd0d1fccp1<RETURN>
  #               /dev/mapper/3600508b1001c9e14b850ec3afd0d1fccp2<RETURN>
  #               /dev/mapper/nnm-pkg>
  #       CIDISK=</dev/mapper/3600508b1001c9e14b850ec3afd0d1fcc:DISK0<RETURN>
  #               /dev/mapper/nnm-pkg:DISK1>

  CIDISK="$(
    j=0
    for i in $(echo "$CIPART" | sed "s/p*[123456789][[:digit:]]*$//"|uniq); do
      echo "$i:DISK$j"
      j=$(($j+1))
    done
  )"

}

showinfo()
{
  dbg "RIFSTAB=\"$RIFSTAB\""
  dbg "RIGRUB=\"$RIGRUB\""
  dbg "RIGRUB2=\"$RIGRUB2\""
  dbg "RILV=\"$RILV\""
  dbg "RIPV=\"$RIPV\""
  dbg "RIDF=\"$RIDF\""
  dbg "RILABEL=\"$RILABEL\""
  dbg "RIUUID=\"$RIUUID\""
  dbg "RIPARTITION=\"$RIPARTITION\""

  dbg "CIVG=\"$CIVG\""
  dbg "CISWAP=\"$CISWAP\""
  dbg "CIFS=\"$CIFS\""
  dbg "CIPART=\"$CIPART\""
  dbg "CIDISK=\"$CIDISK\""
}

parttrans()
{
  local i dev dsk

  T="$(cat)"
  for i in $CIDISK; do
    # i=/dev/sda:DISK1 -> dev=/dev/sda dsk=DISK1
    dev="$(echo "$i" | awk -F: '{print $1}')"
    dsk="$(echo "$i" | awk -F: '{print $2}')"

    T1="$(echo "$T" | sed "s|${dev}p*\>|$dsk|")"
    T="$(echo "$T1" | sed "s|${dev}p*\([[:digit:]]\+\)|${dsk}P\1|")"
  done
  [ "$T" ] && echo "$T"
}

trans()
{
  echo "$1"  | sed "$PARTTRANS"
}

mapperlv2lv()
{
   T="$1"
   for i in $VG; do
     T1="$(echo "$T" | sed "s|/dev/mapper/$i-|/dev/$i/|")"
     T="$T1"
   done
   echo "$T"
}

template()
{
cat << 'END_OF_BOOTCD2DISK.CONF' | tail -n +2 | head -n -1
### BOOTCD2DISK.CONF Placeholder ##############
ERRLOG=/var/log/bootcd2disk.log

# function do_first
# If you want to do some things first before doing anythin else (e.g. load
# additional modules), you can add this to this function.
#    function do_first() {
#    return
#    }

# To define the disk that will be newly partitioned before copying the cd to it
#   DISK0="/dev/hda"
# If you don't want do partition any disk
#   DISK0=""
# If you want bootcd2disk to find a disk (bootcd tries to use the first disk)
DISK0="auto"

# It is possible to define more disks. The disk number must be increased by 1.
#DISK1="auto"
#DISK2="auto"

# Syntax:
#   LVMGRP="<group> <diskdev> [<diskdev> ...][<vgcreate-cmd>][\n ...]"
#
# Example1:
#   LVMGRP="vg00 DISK0P1
#           vg01 DISK0P2
#           vg02 DISK0P3 DISK0P4"
#   
# Example2 which is the same as Example1 because it used the default schema
#   LVMGRP="vg00 DISK0P1 vgcreate vg00 DISK0P1
#           vg01 DISK0P2 vgcreate vg01 DISK0P2
#           vg02 DISK0P3 vgcreate vg02 DISK0P3 DISK0P4"
#
# hint: Each volume group definition needs a new line! 
#
# Default: 
#   LVMGRP=""
LVMGRP=""

# Syntax:
#   LVMVOL="<volname> <size> <group> [<lvcreate-cmd>][\n ...]"
#
#   size in vgcreate syntax, e.g.: 100 means 100 MByte 
#
# Example1:
#   LVMVOL="lv00 2000 vg00"
#
# Example2 which is the same as Example1 because it used the default schema
#   LVMVOL="lv00 2000 vg00 lvcreate -n lv00 -L 2000 vg00"
#
# Example3 uses striping for the second volume 
#   LVMVOL="lv00 2000 vg00
#           lv01 100 vg00 lvcreate -n lv01 -i 3 -I 8 -L 100 vg00"
#
# hint: Each logical volume definition needs a new line! 
#
# Default: 
#   LVMVOL=""
LVMVOL=""

# If DISK0="auto" is defined, the first disk found will be used. To change
# this order TRYFIRST can be defined for example to use SCSI Disks first:
#   TRYFIRST="/dev/sda /dev/hda"
# Most people will not need this option and will define:
#   TRYFIRST=""
TRYFIRST=""

# If you don't want to repartition anything use:
#   SFDISK0=""
# If you want to specify yourself: see man sfdisk
# If no unit is defined in SFDISK0 MB will be used with sfdisk option "-uM"
#   SFDISK0="
#   ,50
#   ,100,S
#   ;
#   "
# If you want to do it automatically. There will be 3 partitions
# /boot, swap and /. /boot is created first to be sure the bios can load
# the kernel also on very large disks. Sectors will be used as unit
#   SFDISK0="
#   unit: sectors
#   2048,102400,L
#   102401,307201,S
#   307202,+,L
#   "
SFDISK0="auto"

# For each defined DISK<x> there must be one SFDISK<x> Line
# SFDISK1="auto"
# SFDISK2="auto"

# VFAT is normally only needed on ia64 for EFI files.
# Do not run mkdosfs: 
#   VFAT=""
# Create partitions defined in VFATFS with mkdosfs
#   VFAT="/dev/sdb4"
VFAT=""

# Do not not create ext2 filesystems:
#   EXT2FS=""
# Create partitions defined in EXT2FS with mke2fs:
#   EXT2FS="/dev/hda1 
#           /dev/hda3"
# hint: Each device or logical volume definition needs a new line! 
# 
# To create partitions needed automatically:
#   EXT2FS="auto"
# if also EXT3FS="auto" then ext3 will be used if possible
EXT2FS="auto"

# Do not not create ext3 filesystems:
#   EXT3FS=""
# Create partitions defined in EXT3FS with mke2fs -j:
#   EXT3FS="/dev/hda1 
#           /dev/hda3"
# hint: Each device or logical volume definition needs a new line! 
# 
# To create partitions needed automatically:
#   EXT3FS="auto"
# if also EXT4FS="auto" then ext4 will be used if possible
EXT3FS="auto"

# Do not not create ext4 filesystems:
#   EXT4FS=""
# Create partitions defined in EXT4FS as ext4 filesystems:
#   EXT4FS="/dev/hda1 
#           /dev/hda3"
# hint: Each device or logical volume definition needs a new line! 
# 
# To create partitions needed automatically:
#   EXT4FS="auto"
EXT4FS="auto"

# If you don't want to run mkswap use:
#   SWAP=""
# If you want to specify partitions for mkswap:
#   SWAP="/dev/hda2"
# hint: Each swap device definition needs a new line! 
# If you want to automatically use mke2fs:
SWAP="auto"

# If you don't want to mount anything, before copying the cd to /mnt
#   BIND=""
#   MOUNT=""
#   UMOUNT=""
# If you want to mount everything yourself:
#   MOUNT="mount /dev/hda3 /mnt/bootcd.disc; \
#          mkdir /mnt/bootcd.disc/boot; mount /dev/hda1 /mnt/bootcd.disc/boot"
# In a chroot bootcdbackupwizard has to rebind existing mountpoints:
#   BIND="mount --bind / /mnt/bootcd.disc; \
#         mount --bind /boot /mnt/bootcd.disc/boot"
#   UMOUNT="umount /mnt/bootcd.disc/boot; umount /mnt/bootcd.disc"
# If you want to automatically mount:
MOUNT="auto"
BIND="auto"
UMOUNT="auto"

# If you don't want to change the /etc/fstab copied form cd:
#   FSTAB=""
# If You want to define it yourself:
#   FSTAB="
#   /dev/sda1 /boot ext2 defaults 0 1
#   /dev/sda2 none  swap sw 0 0
#   /dev/sda3 /     ext2 defaults,errors=remount-ro 0 1
#   proc      /proc proc defaults 0 0
#   "
# The string DISK0P1 will be automatically changed to <device of the first 
# partition of the first disk>. The string UUID!DISK1P3 will be automacally 
# changed to the <UUID of the third partition of the second disk>.
#
# If You want to do it automatically:
FSTAB="auto"

# If you don't want to use GRUB2:
#   GRUB2=""
# If GRUB2 and GRUB and LILO is defined and installed, GRUB2 will be used
# If GRUB2 is auto grub-mkconfig will be used to create it automatically.
# If you want to define it yourself:
#   GRUB2="
#   set lang=en
#   insmod gettext
#   set timeout=5
#   set menu_color_normal=cyan/blue
#   set menu_color_highlight=white/blue
#   
#   menuentry 'Debian GNU/Linux' --class debian --class gnu-linux --class gnu --class os {
#        insmod ext2
#        set root='(hd0,1)'
#        linux   /\$(basename \$KERNEL) root=DISK0P3 ro
#        initrd  /\$(basename \$INITRD)
#   }
#   "
# Attention grub2 starts counting partitions at 1 and grub1 starts at 0
GRUB2="auto"

# If you don't want to use GRUB:
#   GRUB=""
# If GRUB2 is not installed or defined and GRUB is defined and grub is 
# installed it will be used and
# LILO will be ignored.
# If you want to define it yourself:
#   GRUB="
#   default 0
#   timeout 5
#   color   cyan/blue white/blue
#   title   Debian GNU/Linux
#   root    (hd0,0)
#   kernel  /vmlinuz-2.4.27-2-386 root=/dev/hda3 ro
#   initrd  /initrd.img-2.4.27-2-386
#   savedefault
#   boot
#   "
# If You want to do it automatically:
GRUB="auto"

# Only if you BIOS sees another disk as the first disk you may
# have to change the next line.
GRUBBOOTDISK="hd0"

# If /boot is not the first partition on disk
# we need to know which one it is to install 
# grub properly. Attention: bootcd starts counting with 0 like
# grub1 !
GRUBBOOTDIR="0"

# GRUBDEVICEMAP=auto|no|<value>
# GRUBDEVICEMAP="auto" means, bootcd2disk deletes the original
# device.map, so that it will be auto-created by grub again.
# This should work also when installing on different hardware with
# different disks..
# GRUBDEVICEMAP="no" means bootcd2disk does not change device.map.
# This should work if a bootcd is installed on the original hardware
# Everything else will be used as new value for device.map.
GRUBDEVICEMAP="auto"

# If GRUB is defined and installed LILO will be ignored. 
# If you don't want to change the /etc/lilo.conf copied from cd:
#   LILO=""
# If you want to define it yourself:
#   LILO="
#   boot=DISK0
#   delay=20
#   vga=0
#   image=/vmlinuz
#   root=DISK0P3
#   initrd=/initrd.img
#   label=Linux
#   read-only
#   "
# If You want to do it automatically:
LILO="auto"

# SSHOSTKEY=yes|no
# If you are using ssh it is helpful to have a unique ssh hostkey for
# each PC installed with bootcd2disk. This will be generated with 
#   SSHHOSTKEY="yes"
SSHHOSTKEY=yes

# UDEV_FIXNET=yes|no
# If you are using udev filesystem and install the image on other machines
# you need to set this to "yes" because the network interfaces are hardwired
# in /etc/udev/rules.d/z25_persistent-net.rules (etch) or in 
# /etc/udev/rules.d/70-persistent-net.rules (lenny) and we must remove them.
#   UDEV_FIXNET="yes"
UDEV_FIXNET="yes"

# IMAGEURL="" | IMAGEURL="<url>"
# If bootcd2disk is slow on your system (because of a slow CD/DVD drive or
# the HP ILO virtual CD interface), you can use a image server to get the 
# image from.
# bootcd2disk use the SWAP partition of your upcoming system as temporary
# space and copy the image from the configured image server (IMAGEURL or
# cmdline -url) to this partition and use it as image. 
# The "url" is used with "wget" so all url from wget are possible.
# e.g: http://192.168.100.10/cdimage.iso
# hint: Please use a ip because of failed DNS and you need also the
#       configured ip interface.
# hint: the option may be overwritten from command line (-url)
#  IMAGEURL=""
IMAGEURL=""

# PARTITIONLABEL=""
# If you want the filesystem or swap partitions to have labels you can define
# them here. Example:
#   PARTITIONLABEL="/dev/sda1:/
#   /dev/sda2:SWAP-sda2"
PARTITIONLABEL=""

# function after_copy
# If you want to do some things after copying the files (e.g. remount of
# directories ...), you can add this to this function.
#    function after_copy() {
#    return
#    }

#
# Examples:
#

# IF you only want to copy the cd to an already existing Partition /dev/hda2
# You can now specify:
#   DISK0=""; SFDISK0=""; SWAP=""; FSTAB=""; LILO=""
#   EXTFS2="/dev/hda2"
#   MOUNT="mount /dev/hda2 /mnt/bootcd.disc"
### BOOTCD2DISK.CONF Placeholder ##############
END_OF_BOOTCD2DISK.CONF
}

checktemplate()
{
  USED="$(template | grep "^[^#[:blank:]]" | sed "s/\(.*\)=.*/\1/")"
  if [ "$USED" != "$PARAMETERS" ]; then
    echo "INTERNAL ERROR: <$PARAMETERS> != <$USED>" >&2
    exit 1
  fi
  exit 0
}

printbefore()
{
  ( template 
    cat <<END
LASTLINES="This is just to make printbefore work for the last lines"
END
  ) |
  awk '
    /^'$1'=/ {print B}
    /^[^#]/ && ! /^ *$/ {B=""}
    /^#/ || /^ *$/ { B=sprintf("%s\n%s",B,$0) }
  ' | 
  tail -n +2
}

#x=$(printbefore LVMGRP)
#x=$(printbefore LASTLINES)
#echo "x=<$x>"
#exit 0

# sfdisk4grub2
# change sfdisk created by print2diskconf and
# insert space for MBR before first partition 
sfdisk4grub2()
{
  local line position megabytes sectors a b r

  a="$(cat)"
  # only change primitive configs
  # do not change if unit is already specified
  # do only change if every line start with "," or ";"
  r="
"
  b="unit: sectors$r$r$(
    position=2048
    echo "$a" | while read line; do
      if [ "$line" = "" ]; then
        :
      elif [ $(echo "$line" | grep "^,[[:digit:]]\+$") ]; then
        megabytes="$(echo "$line" | sed "s/^,\([[:digit:]]\+\)$/\1/")"
        sectors="$(($megabytes * 2048))"
        echo "$position,$sectors"
        position="$(($position + $sectors))"
      elif [ "$line" = ",,E" ]; then
        echo "$position,,E"
        position="$(($position + 1))"
      elif [ "$line" = ";" -o "$line" = "0,0" ]; then
        echo "$line"
      else
        echo "sfdisk4grub2: no change because of line=<$line>"
        return
      fi
    done
  )"

  if [ "$(echo "$b" | grep "no change")" ]; then
    dbg "$(echo "$b" | grep "no change")"
    echo "$a"
  else
    echo "$b"
  fi
}
#. ./bootcd-run.lib
#dbgon
#a="$(echo -e ",18026\n,14998\n,1027\n,,E\n;")"
#b="$(echo -e "unit: sectors\n\n2048,36917248\n36919296,30715904\n67635200,2103296\n69738496,,E\n;")"
#c="$(echo "$a" | sfdisk4grub2)"
#[ "$b" = "$c" ] && echo "ok" || echo "Error: output=<$c> expected=<$b>"
#a="$(echo -e "unchangeable")"
#b="$(echo -e "unchangeable")"
#c="$(echo "$a" | sfdisk4grub2)"
#[ "$b" = "$c" ] && echo "ok" || echo "Error: output=<$c> expected=<$b>"
#a="$(echo -e ",101\n;")"
#b="$(echo -e "unit: sectors\n\n2048,206848\n;")"
#c="$(echo "$a" | sfdisk4grub2)"
#[ "$b" = "$c" ] && echo "ok" || echo "Error: output=<$c> expected=<$b>"
#a="$(echo -e ",19711\n,,E\n0,0\n0,0\n;")"
#b="$(echo -e "unit: sectors\n\n2048,40368128\n40370176,,E\n0,0\n0,0\n;")"
#c="$(echo "$a" | sfdisk4grub2)"
#[ "$b" = "$c" ] && echo "ok" || echo "Error: output=<$c> expected=<$b>"
#exit 0

print2diskconf()
{
  cat <<END
# bootcd2disk.conf - automatically created by bootcdmk2diskconf
END

  printbefore ERRLOG
  cat <<END
ERRLOG=/var/log/bootcd2disk.log
END

  printbefore DISK0

  for i in $CIDISK; do 
    # i=/dev/sda:DISK1 -> dev=/dev/sda dsk=DISK1
    dev="$(echo "$i" | awk -F: '{print $1}')"
    dsk="$(echo "$i" | awk -F: '{print $2}')"
    echo "ORIG_$dsk=\"$dev\""
  done

  for i in $CIDISK; do 
    # i=/dev/sda:DISK1 -> dev=/dev/sda dsk=DISK1
    dev="$(echo "$i" | awk -F: '{print $1}')"
    dsk="$(echo "$i" | awk -F: '{print $2}')"
    if [ "$EXACTDISKS" ]; then
      echo "$dsk=\"$dev\""
    else
      echo "$dsk=\"auto\""
    fi
  done

  printbefore LVMGRP
  echo "LVMGRP=\""
  for i in $(echo "$RIPV" | awk -F: '{print $2}' | sort -u); do
    echo "$i$(echo "$RIPV" | grep ":$i$" | awk -F: '{printf(" %s",$1)}' |
      parttrans)"
  done
  echo "\""

  printbefore LVMVOL
  echo "LVMVOL=\""

  for i in $RILV; do
    echo "$(echo "$i" | awk -F: '{printf("%s %s %s\n", $1,$3,$2)}')"
  done
  echo "\""

  printbefore TRYFIRST
  cat <<END
TRYFIRST=""
END

  printbefore SFDISK0
  for i in $CIDISK; do                                 
    # i=/dev/cciss/c0d0:DISK0 -> x=/dev/cciss/c0d0 y=0
    x="$(echo "$i" | awk -F: '{print $1}')"                
    y="$(echo "$i" | awk -F: '{print $2}' | sed "s/DISK//")"  
    echo "SFDISK$y=\""
    # n is number of partition, pn is the size of partition n
    # m and pm are the same info for the following partition
    n=0
    while :; do
      # RIPARTITION="/dev/cciss/c0d0p1:101\n/dev/cciss/c0d0p2:34624" 
      # -> n=1, m=2, pn=101, pm=34624  -> n=2, m=3, pn=34624 pm=
      n=$(($n+1))
      m=$(($n+1))
      pn="$(echo "$RIPARTITION" | grep "^${x}p*${n}:" | awk -F: '{print $2}')"
      if [ ! "$pn" ]; then
        if [ "$n" = "1" ]; then
          pn=0 # if a disk is used as a whole we set size of partition1 to 0
          echo ",0"
          break
        else
          echo "bootcdmk2diskconf: FATAL Unknown Error" >&2
          exit 1
        fi
      fi
      # Extended Partition
      if [ "$pn" -eq 0 -a "$n" -lt 5 ]; then
        echo ",,E"
        n=$(($n+1))
        m=$(($n+1))
        # if there are unsed first four partitions fill them
        while [ $n -lt 5 ]; do
          echo "0,0"
          n=$(($n+1))
          m=$(($n+1))
        done
        pn="$(echo "$RIPARTITION" | grep "^${x}p*${n}:" | awk -F: '{print $2}')"
      fi
      pm="$(echo "$RIPARTITION" | grep "^${x}p*${m}:" | awk -F: '{print $2}')"
      if [ "$pm" ]; then
        echo ",$pn"
      else
        if [ "$SAMESIZE" ]; then
          echo ",$pn"
	else
          echo ";"
        fi
        break
      fi
    done |
    if [ "$RIGRUB2" ]; then
      sfdisk4grub2
    else
      cat 
    fi
    echo "\""
  done

  printbefore VFAT
  cat <<END
VFAT=""
END

  printbefore EXT2FS
  # Catch everything not ext3 and not ext4
  echo "EXT2FS=\""
  echo "$CIFS" | grep -v -e ":ext3" -e ":ext4" | awk -F: '{print $1}' | parttrans
  echo "\""

  printbefore EXT3FS
  echo "EXT3FS=\""
  echo "$CIFS" | grep ":ext3" | awk -F: '{print $1}' | parttrans
  echo "\""

  printbefore EXT4FS
  echo "EXT4FS=\""
  echo "$CIFS" | grep ":ext4" | awk -F: '{print $1}' | parttrans
  echo "\""

  printbefore SWAP
  echo "SWAP=\"$(echo "$CISWAP" | parttrans)\""

  # CIFS="<devpath>:<mountpoint>:<fstyp>\n..."
  # Sort it with length of <mountpoint> for right mount order
  SORTCIFS=$(for i in $CIFS; do
    echo "$(echo "$i" | awk -F: '{print $2}'|wc -c):$i" | sort -n
  done)
  
  printbefore MOUNT

  echo "[ ! \"\$(set |grep \"^BOOTCDMP=\")\" ] && BOOTCDMP=\"/$MNTBOOTCDDISC\""

  echo "MOUNT=\""
  # SORTCIFS="<mountpointlen>:<devpath>:<mountpoint>\n..."
  for i in $SORTCIFS; do
    x="$(echo "$i" | awk -F: '{print $2}')"
    y="$(echo "$i" | awk -F: '{print $3}')"
    echo "mkdir -p \$BOOTCDMP$y; mount $x \$BOOTCDMP$y" | parttrans
  done
  echo "\""

  printbefore BIND

  echo "BIND=\""
  for i in $SORTCIFS; do
    y="$(echo "$i" | awk -F: '{print $3}')"
    echo "mkdir -p \$BOOTCDMP$y; mount --bind $y \$BOOTCDMP$y" | parttrans
  done
  echo "\""

  printbefore UMOUNT
  UMOUNT=""
  echo "UMOUNT=\""
  for i in $(echo "$SORTCIFS" | sort -nr); do
    x="$(echo "$i" | awk -F: '{print $3}')"
    echo "umount \$BOOTCDMP$x"
    UMOUNT="$UMOUNT umount \$BOOTCDMP$x;"
  done
  echo "\""
  
  # Always (even on backup) use "uuidsed", because a disk may be
  # changed at restore time which would make old UUIDs unusable

  printbefore FSTAB
  echo "FSTAB=\""
  echo "$RIFSTAB" | uuidsed | parttrans
  echo "\""
  if [ "$BACKUP" ]; then
    (
    echo " Now the original FSTAB is listed for reference:"
    echo "FSTAB=\""
    echo "$RIFSTAB"
    echo "\""
    ) | sed "s/^/#/"
  fi

  printbefore GRUB2
  echo "GRUB2=\""
  echo "$RIGRUB2" | uuidsed | parttrans
  echo "\""
  if [ "$BACKUP" ]; then
    (
    echo " Now the original GRUB2 is listed for reference:"
    echo "GRUB2=\""
    echo "$RIGRUB2"
    echo "\""
    ) | sed "s/^/#/"
  fi

  printbefore GRUB
  echo "GRUB=\""
  echo "$RIGRUB" | uuidsed | parttrans
  echo "\""
  if [ "$BACKUP" ]; then
    (
    echo " Now the original GRUB is listed for reference:"
    echo "GRUB=\""
    echo "$RIGRUB"
    echo "\""
    ) | sed "s/^/#/"
  fi

  printbefore GRUBBOOTDISK
  cat <<END
GRUBBOOTDISK="hd0"
END

  printbefore GRUBBOOTDIR
  cat <<END
GRUBBOOTDIR="0"
END

  printbefore GRUBDEVICEMAP
  cat <<END
GRUBDEVICEMAP="auto"
END

  printbefore LILO
  cat <<END
LILO=""
END

  printbefore SSHHOSTKEY
  cat <<END
SSHHOSTKEY="unchanged"
# SSHHOSTKEY="unchanged". It is used, as definded in backup.
# But if you want to recreate it, use the following
# line instead:
#SSHHOSTKEY="yes"
END

  printbefore UDEV_FIXNET
  cat <<END
UDEV_FIXNET="no"
END

  printbefore IMAGEURL
  cat <<END
IMAGEURL=""
END

  if [ "$BACKUP" ]; then
    # default directory structure for backup called <name>:
    #   /<name>/cpio00
    #   /etc/bootcd/<name>/bootcd2disk.conf (this file)

    # echo "RESTORECMD=\"(cd /mnt/bootcd.disc; tar xzf /\\\$(basename \\\$CONFDIR)/backup.tgz)\""
    # echo "RESTORECMD=\"(cd /mnt/bootcd.disc; cat \\\$CONFDIR/backup* |gzip -d -c | cpio --null --quiet -idmn)\""
    echo "RESTORECMD=\"(cd \$BOOTCDMP; 
[ -f \\\$ISOLOOPBACK/backup/data/cpio00 ] && (cat \\\$ISOLOOPBACK/backup/data/cpio* |gzip -d -c | cpio --null --quiet -idmn);
[ -f \\\$ISOLOOPBACK/backup/data/star00 ] && (cat \\\$ISOLOOPBACK/backup/data/star* |gzip -d -c | star -U -xattr -x -f - );:
)\"" 
  fi

  printbefore PARTITIONLABEL
  echo "PARTITIONLABEL=\""
  echo "$RILABEL" | parttrans 
  echo "\""

  printbefore LASTLINES
}


SAMESIZE=""
DEBUG=""
EXACTDISKS=""
BACKUP=""
FSTABDEV=""
TESTDATA=""
while [ "$*" ]; do
  if [ "$1" = "-v" ]; then
    dbgon
    shift
  elif [ "$1" = "-d" ]; then
    DEBUG="1"
    shift
  elif [ "$1" = "-s" ]; then
    SAMESIZE="$1"
    shift
  elif [ "$1" = "-e" ]; then
    EXACTDISKS="$1"
    shift
  elif [ "$1" = "-b" ]; then
    BACKUP="$1"
    shift 1
  elif [ "$1" = "-f" ]; then
    FSTABDEV="$2"
    shift 2
  elif [ "$1" = "-t" ]; then
    TESTDATA="$1"
    shift
  elif [ "$1" = "-checktemplate" ]; then
    # Internal Option to check if bootcd2disk.conf fits to this script
    checktemplate
    shift
  else
    echo "$USAGE" >&2
    exit 1
  fi
done

if [ "$TESTDATA" ]; then
  for i in RILV RIPV RIDF RILABEL RIUUID RIPARTITION; do
    if [ ! "`set | grep ^$i=`" ]; then
      echo "TESTDATA $i not defined" >&2
      exit 1 
    fi
  done

elif [ "$FSTABDEV" ]; then

  mkdir -p /$MNTBOOTCDDISC
  if [ "$(/bin/ls /$MNTBOOTCDDISC)" ]; then
    echo "/$MNTBOOTCDDISC is not emply; please empty it, (rm or umount)" >&2
    exit 1
  fi
  mount $FSTABDEV /$MNTBOOTCDDISC
  if [ $? -ne 0 ]; then
    echo "Problem mounting $FSTABDEV /$MNTBOOTCDDISC" >&2
    exit 1
  fi

  if [ ! "$(grep "# bootcdmk2diskconf entries" /etc/fstab)" ]; then
    echo "# bootcdmk2diskconf entries" >>/etc/fstab

    if [ -f /etc/fstab ]; then
      FSTABPATH="/etc/fstab"
    elif [ -f /fstab ]; then
      FSTABPATH="/fstab"
    else
      echo "Can not find fstab" >&2
      exit 1
    fi
    ADDMNT="$(cat /$MNTBOOTCDDISC/$FSTABPATH | eval "$MOUNTGREP" | awk '{$2="/'$MNTBOOTCDDISC'/"$2; print}')"
    dbg "Additional mounts: <$ADDMNT>"
    echo "$ADDMNT" >> /etc/fstab
  fi
  mount -a
  readinfo /$MNTBOOTCDDISC

else
  readinfo
fi

calcinfo
showinfo
print2diskconf


if [ "$FSTABDEV" ]; then

  cp /etc/fstab /etc/fstab.tmp
  cat /etc/fstab.tmp | awk 'BEGIN {p=1} /# bootcdmk2diskconf entries/ {p=0} {if(p) print}' >/etc/fstab
  rm /etc/fstab.tmp

  dbg "Doing umount: <$UMOUNT>"
  eval "$UMOUNT"

  if [ "$(/bin/ls /$MNTBOOTCDDISC)" ]; then
    echo "ERROR: /$MNTBOOTCDDISC is not emply; calculated umount <$UMOUNT> did not work !!!"
    exit 1
  fi

  rmdir -f /$MNTBOOTCDDISC

fi
