#!/bin/sh
#
# 	$Source: /home/bs/src/bootcd/backupcvs/bootcd/bootcd/bootcdwrite,v $
#       $Id: bootcdwrite,v 1.83 2011-03-03 15:38:33 bs Exp $
#    author: Bernd Schumacher
#     start: long time ago
#     topic: build cd image
#
#

chng_opts()
{
  O="$(echo " $1 " | sed "s/[[:blank:]]\+/ /g")"
  C="$(echo " $2 " | sed "s/[[:blank:]]\+/ /g")"
  CNOT="$(echo "$C" |
    sed -e "s/!//g" -e "s/ [^ -]\+//g" -e "s/^ //" -e "s/ $//")"
  CADD="$(echo "$C"| sed -e "s/ ![^ ]\+//g" -e "s/^ //" -e "s/ $//")"
# echo "DEBUG O=<$O>" >&2
# echo "DEBUG C=<$C>" >&2
# echo "DEBUG CNOT=<$CNOT>" >&2
# echo "DEBUG CADD=<$CADD>" >&2

  for i in $CNOT; do 
#   echo "DEBUG i=<$i>" >&2
    O="$(echo "$O" | sed "s/ $i [^-]*/ /g")"
#   echo "DEBUG O=<$O>" >&2
  done
  O="$(echo "$O"| sed -e "s/^ //" -e "s/ $//")"
# echo "DEBUG O=<$O>" >&2
  echo "$O $CADD"
}
#echo "test: chng_opts \"-one -two 2 -three drei -four\" \"!-three !-one -two -five 5\"" >&2
#echo "expect: -four -two -five 5" >&2
#echo "result: $(chng_opts "-one -two 2 -three drei -four" "!-three !-one -two -five 5")" >&2
#echo "test: chng_opts \"--one --two 7 --three 8\" \"--three 9\""
#echo "result: $(chng_opts "--one --two 7 --three 8" "--three 9")"
#echo "test: chng_opts \"-a -b\" \"\""
#echo "result: $(chng_opts "-a -b" "")"
#exit 0

isoneword()
{
  [ $# -eq 1 ] && return 0
  return 1
}
#for i in "a b" "a" "a
#b"; do
#if isoneword "$i"; then echo "<$i> ok"; else echo "<$i> nok"; fi
#done
#exit 1

cleanup()
{
  echo "--- Cleanup ---" | tee -a $ERRLOG

  # Be sure that VAR and SRCDISK have no spaces 
  # to not accidently remove anything (for example VAR="/ /var")
  if ! isoneword "$VAR"; then
    echo "Error in VAR <$VAR>" >&2
    exit 1
  fi

  if ! isoneword "$SRCDISK"; then
    echo "Error in SRCDISK <$SRCDISK>" >&2
    exit 1
  fi

  rm -f "$VAR/cdimage"
  rm -rf "$VAR/input_dir"
  rm -rf "$VAR/compressed_dir"
  umount "$VAR/mnt" 2>/dev/null
  [ -d $VAR/mnt ] && rmdir "$VAR/mnt"

  # do not use "rm -r $VAR"
  rm -f "$ERRLOG.tmp"
  rm -rf "$CHANGES" 
  [ -d $VAR -a ! -f $VAR/cdimage.iso ] && rmdir "$VAR"
}

oneline()
{
  if [ $# -gt 0 ]; then
    echo "$*"
  else
    cat
  fi | awk '{printf("%s ",$1)} END {printf("\n")}' | sed "s/ *$//"
}

# df_file - How much free space has the filesystem on which file $1 resides ?
df_file()
{
  df -k -P | awk '{printf("%s %s\n",$4,$6)}' |
  while read size filesys
  do
    if [ "`echo $1 | grep ^$filesys`" ]; then
      namelen=`echo $filesys | wc -c` 
      echo "$namelen $filesys $size"
    fi
  done |
  sort -n | tail -1 | awk '{print $3}'
}
#df_file /home/bianca/daten
#exit 0

# ex_proc - exclude SRCDI/proc 
#         - exclude SRCDI/sys (kernel 2.6.x)
ex_proc()
{
  if [ $# -gt 0 ]; then
    for i in $*; do
      if [ "$(realpath $i)" = "$SRCDISK" ]; then
        find $SRCDISK -maxdepth 1 | 
          grep -v -e "^$SRCDISK$" -e "^$SRCDI/proc$" -e "^$SRCDI/sys$" -e "^$SRCDI/run$"
      else
        realpath $i
      fi
    done | oneline
  fi
}
#SRCDISK="/"; SRCDI=""
#echo "SRCDISK=/; ex_proc / -> /home /etc /bin ... (without /proc and /sys)"
#ex_proc /
#echo "SRCDISK=/; ex_proc /tmp /etc -> /tmp /etc"
#ex_proc /tmp /etc
#exit 0

# du_dir - How much space do given dirs need togehter
du_dir()
{
  if [ $# -gt 0 ]; then
    LIST1="$(for i in $(realpath $*); do echo $i; done | sort)"
    LAST=""; LIST2=""
    for i in $LIST1; do
      if [ "$LAST" ]; then
        if [ "$LAST" = "/" ]; then 
          [ "$(echo "$i" | grep "^/")" ] && i=""
        else
          [ "$(echo "$i" | grep "^$LAST\>")" ] && i=""
        fi
      fi
      if [ "$i" ]; then
        LIST2="$LIST2 $i"
        LAST="$i"
      fi
    done
    LIST3=$(ex_proc "$LIST2")
    echo "du -klsc $LIST3" >> $ERRLOG
    du -klsc $LIST3 | tee -a $ERRLOG | tail -1 | awk '{print $1}'
  fi
}
#ERRLOG=/var/log/errlog
#echo "du_dir /etc; du_dir /tmp; du_dir /etc /tmp -> A + B = C"
#du_dir /etc; du_dir /tmp; du_dir /etc /tmp
#exit 0
#echo "du_dir /etc; du_dir /etc /etc/network -> A = B"
#du_dir /etc; du_dir /etc /etc/network
#exit 0

trapfunc()
{
  echo "trap" >> $ERRLOG
  trap "" 0 2 # Ignore Traps
  cleanup
  exit 1
}


mk_grep()
{
  if [ $# -gt 0 ]; then
    echo "$*" | 
    sed 's/\(^\| \)*\([^ ]*\)/-e ^\2 /g' | 	# Insert all "-e"
    sed "s/[[:space:]]*$//" |			# Delete trailing spaces
    sed "s/^/grep -v /"				# Insert "grep -v"
  else
    echo "cat"
  fi
}
#echo "mk_grep /usr/lib /usr/share -> grep -v -e ^/usr/lib\> -e ^/usr/share\>"
#echo "<$(mk_grep /usr/lib /usr/share)>"
#echo "mk_grep "" -> cat"
#echo "<$(mk_grep "")>"
#exit 0
#
#t=$(mk_grep /x)
#echo "t=<$t>"
#echo "a/x/b: $(echo "a/x/b" | $t)"
#echo "/xb: $(echo "/xb" | $t)"
#echo "/x/b: $(echo "/xb" | $t)"
#exit 0

# chnglist [-add_ro] [-no_mnt] <MNT> <LIST>
#   -add_ro = add ".ro" to directory following <MNT>
#   -no_mnt = path without <MNT>
#   -rel    = start without /
chnglist()
{
  ADD_RO=""
  NO_MNT=""
  REL=""
  OPT="1"
  while [ "$OPT" ]; do
    if [ "$1" = "-no_mnt" ]; then
      NO_MNT="1"
      shift
    elif [ "$1" = "-add_ro" ]; then
      ADD_RO="1"
      shift
    elif [ "$1" = "-rel" ]; then
      REL="1"
      shift
    else
      OPT=""
    fi
  done
  [ $# -ne 2 ] && err "Internal Error calling Function chnglist"
    
  S="$(echo "$1" | sed "s|/\+|/|g")" # change // to / 
  [ "$S" = "/" ] && S=""
  echo " $2" | 
  sed "s|/\+|/|g" | # change // to /
  if [ "$ADD_RO" ]; then
    if [ "$NO_MNT" ]; then
      sed "s|[[:space:]]$S/\([^/]*\)\>| \1.ro|g" | sed "s/[[:space:]]*//"
    else
      sed "s|[[:space:]]$S\(/[^/]*\)\>| $S\1.ro|g" | sed "s/[[:space:]]*//"
    fi
  else
    if [ "$NO_MNT" ]; then
      sed "s|[[:space:]]$S/\([^/]*\)\>| \1|g"
    else
      cat
    fi
  fi |  
  sed 's|[^[:graph:]]/\+\([[:graph:]]\+\)| \1|g' | # without leading /
  if [ "$REL" ]; then
    cat 
  else
    sed 's|\([[:graph:]]\+\)|/\1|g'
  fi |
  sed "s/[[:space:]]*//" | # remove leading space
  sed "s|/\+|/|g" # change // to /
}
#echo 'chnglist -add_ro "/" "/etc/a /etc/b /root" -> /etc.ro/a /etc/.ro/b /root.ro'
#echo "  <$(chnglist -add_ro "/" "/etc/a /etc/b /root")>"
#echo 'chnglist -add_ro "/mnt" "/mnt/etc/a /mnt/root" -> /mnt/etc.ro/a /mnt/root.ro'
#echo "  <$(chnglist -add_ro "/mnt" "/mnt/etc/a /mnt/root")>"
#echo 'chnglist -add_ro -no_mnt "/" "/home/a /root" -> /home.ro/a /root.ro'
#echo "  <$(chnglist -add_ro -no_mnt "/" "/home/a /root")>"
#echo 'chnglist -add_ro -no_mnt "/mnt" "/mnt/home/b /mnt/root" -> /home.ro/b /root.ro'
#echo "  <$(chnglist -add_ro -no_mnt "/mnt" "/mnt/home/b /mnt/root")>"
#echo 'chnglist -no_mnt "/" "/etc/a ///etc/b /root" -> /etc/a /etc/b /root'
#echo "  <$(chnglist -no_mnt "/" "/etc/a ///etc/b /root")>"
#echo 'chnglist -no_mnt "/mnt" "/mnt/etc/a /mnt/root" -> /etc/a /root'
#echo "  <$(chnglist -no_mnt "/mnt" "/mnt/etc/a /mnt/root")>"
#echo 'chnglist -rel -no_mnt "/" "/etc/a /etc/b /root" -> etc/a etc/b root'
#echo "  <$(chnglist -rel -no_mnt "/" "/etc/a /etc/b /root")>"
#echo 'chnglist -no_mnt -rel "/mnt" "/mnt/etc/a /mnt/root" -> etc/a root'
#echo "  <$(chnglist -no_mnt -rel "/mnt" "/mnt/etc/a /mnt/root")>"
#echo 'chnglist -add_ro "/////" "/etc/a /////etc/b /root" -> /etc.ro/a /etc/.ro/b /root.ro'
#echo "  <$(chnglist -add_ro "/////" "/etc/a /////etc/b /root")>"
#exit 0

# function: do_isolinux -- configure isolinux bootloader
do_isolinux()
{
  local kname=""
  local initrd="" 
  local append=""
  local infofile="kinfo.txt"
  local ctrlL=""
  local blue="09"
  local green="0a"
  local yellow="0e"
  local white="0f"
  local back="07"
  local graphics=""
  local text=""
  local version=""

  run mkdir /$CHANGES/isolinux

  # ilsolinux package may not be available in wheezy
  # first try the new location of isolinux.bin file as we see it in jessie
  stdout "^please install package isolinux if available$"
  run "if [ -f /usr/lib/ISOLINUX/isolinux.bin ]; then
         # jessie 
         cp /usr/lib/ISOLINUX/isolinux.bin /$CHANGES/isolinux
       else
         # wheezy
         echo "please install package isolinux if available"
         cp /usr/lib/syslinux/isolinux.bin /$CHANGES/isolinux
       fi"

  # Version 5.00 and higher of isolinux require an additional module to be 
  # loaded/parsed, specifically ldlinux.c32 (BIOS), ldlinux.e32 (EFI32) or 
  # ldlinux.e64 (EFI64). The chosen module may also depend on additional 
  # library modules such as libcom32.c32, libutil.c32, libmenu.c32, libgpl.c32,
  # and liblua.c32. 
  [ -f /usr/lib/syslinux/modules/bios/ldlinux.c32 ] &&
    run cp /usr/lib/syslinux/modules/bios/ldlinux.c32 /$CHANGES/isolinux
 
  # copy isolinux configuration
  run cp $CONFDIR/isolinux.cfg $CHANGES/isolinux/isolinux.cfg

  cat <<END >/$CHANGES/isolinux/$infofile
${ctrlL}
${yellow} Informations about the available kernels:
 -----------------------------------------${back}

END

  # copy all kernels
  # we must change the name, because isolinux does name mangling for
  # the dos 8.3 filename format !!!!
  for i in "" $(set | sed -n "s/^KERNEL\([[:digit:]]\+\)=.*/\1/p"); do
     [ ! "$(eval echo \$KERNEL$i 2>/dev/null)" ] && continue
     [ ! -e "$(eval echo \$KERNEL$i)" ] && err "Can't find kernel \"$(eval echo \$KERNEL$i)\" !"
     echo "add kernel $(eval echo \$KERNEL$i)" >>$ERRLOG
     run cp $(eval echo \$KERNEL$i) /$CHANGES/isolinux/vmlinuz$i
     initrd=""
     if [ "$(eval echo \$INITRD$i 2>/dev/null)" ]; then 
       [ ! -e "$(eval echo \$INITRD$i)" ] && err "Can't find initrd \"$(eval echo \$INITRD$i)\" !"
       run cp $(eval echo \$INITRD$i) /$CHANGES/isolinux/initrd$i
       initrd="initrd=/isolinux/initrd$i"
     fi

     klabel=$(eval echo linux$i) 
     [ "$(eval echo \$KLABEL$i 2>/dev/null)" ] && klabel=$(eval echo \$KLABEL$i)
     append=""
     [ "$(eval echo \$APPEND$i 2>/dev/null)" ] && append=$(eval echo \$APPEND$i)

     cat <<END >>/$CHANGES/isolinux/isolinux.cfg
# KERNEL$i: $(eval echo \$KERNEL$i) $(eval echo \$INITRD$i)
label $klabel
  kernel /isolinux/vmlinuz$i
  append $initrd root=$CDDEV1 bootcd=$BOOTCDMODPROBE $append
END

     cat <<END >>/$CHANGES/isolinux/$infofile
Pressing ${white}<RETURN>${back} or Entering ${white}$klabel${back} uses kernel
${white}$(eval basename \$KERNEL$i)${back} and expands to:
/isolinux/vmlinuz initrd=/isolinux/initrd root=auto bootcd=$BOOTCDMODPROBE $APPEND

END
  done

  # only for the first kernel
  for i in $CDDEVR; do
    # KERNEL$i
    echo "label $(basename $i)"
    echo "  kernel /isolinux/vmlinuz"
    [ "$INITRD" ] && echo "  append initrd=/isolinux/initrd root=$i bootcd=$BOOTCDMODPROBE $APPEND"
  done >>$CHANGES/isolinux/isolinux.cfg

  add_display
  add_credits
}

# function: add_display -- add display text and help
add_display()
{
  local addhelp=""
  local ctrlL=""
  local white="0f"
  local back="07"

  # configure help pages for the boot prompt
  if [ "$DISPLAY" ]; then 

    cat <<END >>/$CHANGES/isolinux/isolinux.cfg

# display config
display display.txt
F0 credits.txt
F1 display.txt
END

    for i in $(seq 2 9); do
       [ ! "$(eval echo \$DISPLAY$i 2>/dev/null)" ] && continue
       if [ "$(eval echo \$DISPLAY$i)" = "kernelinfo" ]; then
         echo "F${i} $infofile"  >>/$CHANGES/isolinux/isolinux.cfg
         addhelp="yes"
         continue
       fi
       [ ! -e "$(eval echo \$DISPLAY$i)" ] && err "Can't find file \"$(eval echo \$DISPLAY$i)\""
       run cp $(eval echo \$DISPLAY$i) /$CHANGES/isolinux/display$i
       echo "F${i} display${i}" >>/$CHANGES/isolinux/isolinux.cfg        
       addhelp="yes"
    done

    # add display file
    ( [ "$addhelp" ] && echo "${ctrlL}${white}Use function keys F1-F10 to get informations!${back}"
      echo ""
      cat $DISPLAY
    ) >/$CHANGES/isolinux/display.txt
  fi
}


# function: add_credits -- add the credit file to isolinux
add_credits()
{
  local ctrlL=""
  local blue="09"
  local green="0a"
  local yellow="0e"
  local white="0f"
  local back="07"
  local graphics=""
  local text=""
  local version=""
  local creditfile=/$CHANGES/isolinux/credits.txt

  version=$(dpkg-query -W -f='${Version}' bootcd 2>/dev/null)
  [ ! "$version" ] && version=$(zcat /usr/share/doc/bootcd/changelog.gz |head -1 2>/dev/null |sed -e "s|.*(\(.*\)).*|\1|")

  # create credits file
  # ${graphics}tt.lss
  cat <<END >> $creditfile
${ctrlL} 
${yellow} bootcd version ${version}${back}

${white} Thanks to all developers and testers for usefull hints (see changelog.gz): ${back}

END

  # add all users
  if [ -e "/usr/share/doc/bootcd/changelog.gz" ]; then 
    echo $(count=1; a=""; zcat /usr/share/doc/bootcd/changelog.gz |
    sed -ne "s|.*[[:space:]]\+\([^[:space:]]\+\)[[:space:]]\+\([^[:space:]]\+\)[[:space:]]*\(.*<.*@.*>\).*|\1 \2 \3|p" | 
    sort | 
    while read i; do 
      if [ "$a" = "" ]; then 
        a=$i
        continue;
      fi
      if [ "$(echo $i| cut -d" " -f2)" = "$(echo $a| cut -d" " -f2)" ]; then 
        count=$(expr $count + 1); 
      else 
        echo "$count $a"; 
        count=1; 
        a=$i; 
      fi
    done |
    sort -n -r | head -50 |
    sed -e "s|\([^[:space:]]*\)[[:space:]]*\(.*\)|\2(\1);|") >> $creditfile
  else
    echo "Bernd Schumacher <Bernd.Schumacher@hpe.com> " >> $creditfile
  fi
  echo "" >> $creditfile
}


# function: compress_dir <files not to be compressed> -- compress files
compress_dir()
{
  # if $EXCLUDE and $MKISOFS equals -x /home/bs
  # then ZFTREEX will become: -e "s|\x00/home/bs\>[^\x00]*||g"
  if [ "$EXCLUDE" -o "$MKISO_NOT" ]; then
    ZFTREEEX="$(echo $EXCLUDE $MKISO_NOT | 
      sed "s|-x[[:space:]]\+\([^[:space:]]\+\)|-e \"s\|\\\\x00\1\\\\>[^\\\\x00]*\|\|g\"|g")"
  fi

  echo "--- Building input_dir for compression ---" | tee -a $ERRLOG
  # ignore output, if we try to link instead copy, to save disk space,
  # but it does not work most of the time
  ignore "^cpio: cannot link .* to .*: Invalid cross-device link$"
  stdout "^cpio: File selinux/poicy grew"
  run "cd $SRCDISK; rm -rf $VAR/input_dir; mkdir $VAR/input_dir; 
    find $(ex_proc $SRCDISK) -print0 | 
    sed -e \"s|^|\\x00|\" | # all files do start and end with \x00 now
    sed -e \"s|\\x00$VAR[^\\x00]*||g\" |
    sed -e \"s|\\x00$ERRLOG[^\\x00]*||g\" |
    sed -e \"s|\\x00$SRCDI/tmp[^\\x00]*||g\" $ZFTREEEX |
    sed -e \"s|\\x00$SRCDI/|\\x00|g\" |
    sed -e \"s|^\\x00||\" | # first file does not start with \x00 now
    cpio --null --quiet -pldum $VAR/input_dir/"

  run "cd $CHANGES; find . -print0 | cpio --null --quiet -pldum $VAR/input_dir/"

  # save files that should not be compressed
  for i in $*; do
    run "mkdir -p $VAR/nocompress_dir/$(dirname $i)"
    run "mv $VAR/input_dir/$i $VAR/nocompress_dir/$i"
  done

  # compress files
  MAX_NUM_THREADS=$(lscpu -p | grep -v "#" | wc -l)
  echo "--- Compressing input_dir to compressed_dir (using $MAX_NUM_THREADS threads) ---" | tee -a $ERRLOG
  run "rm -rf $VAR/compressed_dir; mkzftree -p $MAX_NUM_THREADS $VAR/input_dir $VAR/compressed_dir"

  # copy not compressed files
  for i in $*; do
    run "mv $VAR/nocompress_dir/$i $VAR/compressed_dir/$i"
  done
   
  run rm -rf $VAR/nocompress_dir
  run rm -r $VAR/input_dir
}

mkisofs_ignore()
{
  stdout "Warning: using transparent compression"
  stdout "The resulting filesystem can only be transparently"
  stdout "On other operating systems you need to call"
  stdout "mkzftree by hand to decompress the files"
  ignore "^Using .* for"
  ignore "^Total "
  ignore "estimate finish"
  ignore "^Path table size"
  ignore "^Max brk space used"
  ignore "^$"
  stdout "^Size of boot image is"
  stdout "extents written"
  stdout "Unable to open directory .*/dev/pts"
  stdout "Unknown file type (unallocated) .*/\.\. - ignoring and continuing."
  stdout "Warning: Creating ISO-9660:1999 (version 2) filesystem."
  stdout "Warning: ISO-9660 filenames longer than 31 may cause buffer overflows in the OS."
}

# cdimage_compressed_isolinux <files not to be compressed>
cdimage_compressed_isolinux()
{
  compress_dir isolinux $*
  mkisofs_ignore
  MKISOFS_OPTS="-z -R -b isolinux/isolinux.bin -c isolinux/boot.cat \
    -no-emul-boot -boot-load-size 4 -boot-info-table -o $VAR/cdimage"
  MKISOFS_OPTS="$(chng_opts "$MKISOFS_OPTS" "$MKISOFS_CHNG")"
  MKISOFS_OPTS="$MKISOFS_OPTS $VAR/compressed_dir"
  echo "cdimage_compressed_isolinux=<$MKISOFS $MKISOFS_OPTS>" >>$ERRLOG
  run $MKISOFS $MKISOFS_OPTS
  run rm -r $VAR/compressed_dir
}

CONFDIR="/etc/bootcd"
ONLY_FLOPPY=""
DEVELOPE=""
SCRIPT=""
while [ $# -gt 0 ]; do
  if [ "$1" = "-only_floppy" ]; then
    shift
    ONLY_FLOPPY="yes"
  elif [ "$1" = "-c" -a $# -gt 1 ]; then
    CONFDIR=$2
    shift 2
  elif [ "$1" = "-d" ]; then
    DEVELOPE=1
    shift
  elif [ "$1" = "-s" ]; then
    SCRIPT="$1"
    shift
  else
    echo "Usage: bootcdwrite [-only_floppy] [-c <config directory>] [-s]"
    echo "  use man bootcdwrite to get help"
    echo "  and see $CONFDIR/bootcdwrite.conf"
    exit 1
  fi
done

if [ "`whoami`" != "root" ]; then
  echo "You have to run bootcdwrite as root"
  exit 1
fi

if [ ! -f $CONFDIR/bootcdwrite.conf  ]; then
  echo "No file $CONFDIR/bootcdwrite.conf" >&2
  exit 1
fi

CONFVARS="SRCDISK KERNEL APPEND NOT_TO_CD SSHHOSTKEY \
ERRLOG VAR DO_CHECK CDDEV DISPLAY FLOPPY_RUNTIME_DEV BOOTFLOPPY \
BOOT_ONLY_WITH_FLOPPY CLEAN_VAR INITRD \
TO_FSTAB TYP DISABLE_CRON MKISOFS_CHNG NOTCOMPRESSED BOOTCDMODPROBE \
UDEV_FIXNET"

OBSOLETE="BLANKING CDSCSI CDSPEED FLOPPY_CREATE_DEV ISO_ONLY NOT_TO_RAM FASTBOOT DEVFS"

unset $CONFVARS
. $CONFDIR/bootcdwrite.conf


# add SRCDISK to variables
if [ "$SRCDISK" ]; then
  [ "$SRCDISK" = "/" ] && s="" || s="$SRCDISK" 
  for v in DISPLAY DISABLE_CRON NOT_TO_CD $(for i in "" $(set | sed -n "s/^KERNEL\([[:digit:]]\+\)=.*/\1/p"); do echo KERNEL$i INITRD$i; done); do
    n=""
    for i in $(eval echo \$$v); do
      if [ "$(echo "$i" | cut -c1-1)" != "/" ]; then
        [ "$n" ] && n=$(echo "$n $s/$i") || n="$s/$i"
      else
        [ "$n" ] && n=$(echo "$n $i") || n="$i"
      fi
    done 
    eval $v="\$n"
  done   
fi

mkdir -p $VAR

if [ -f ./bootcd-run.lib -a "$DEVELOPE" ]; then
  . ./bootcd-run.lib
else
  . /usr/share/bootcd/bootcd-run.lib
fi

if [ -f ./bootcd-check.lib -a "$DEVELOPE" ]; then
  . ./bootcd-check.lib
else
  . /usr/share/bootcd/bootcd-check.lib
fi


if [ "$(set | grep ^ERRLOG=)" ]; then
  date "+--- $0 %d.%m.%Y ---" > $ERRLOG
  echo "To see full output: tail -f $ERRLOG" | tee -a $ERRLOG
fi

find_mkisofs

for i in $CONFVARS; do
  [ "`set | grep ^$i=`" ] || err "$i is not set in $CONFDIR/bootcdwrite.conf"
done

PROBLEM="is set in $CONFDIR/bootcdwrite.conf, but is obsolete.
It will be ignored." 
for i in $OBSOLETE; do
  [ "`set | grep ^$i=`" ] && warn "$i $PROBLEM"
done
  

check_config
warn_user
# by din
trap trapfunc 0 2
cleanup

check_locatedb
# We have to get the sizes (get_sizes) before before the final 
# check (check_sizes), because some variables with the value "auto"
# need the information to become either "yes" or "no".
get_sizes
check_file_rc
check_compress
check_cdfiles
check_kernel
check_initrd
check_sizes

echo "--- Building Modifications ---" | tee -a $ERRLOG
run mkdir -p $VAR/mnt $CHANGES/proc $CHANGES/sys $CHANGES/run $CHANGES/tmp
run chmod 777 $CHANGES/tmp
run chmod o+t $CHANGES/tmp

if [ "$CLEAN_VAR" = "yes" -a ! "$ONLY_FLOPPY" ]; then
  run apt-get clean # to clear some diskspace in /var 
fi

# Make sure /etc/securetty accepts devices not seen in /dev
run mkdir -p $CHANGES/etc
run "cp $SRCDI/etc/securetty $CHANGES/etc"
run "echo \"# added by bootcdwrite BEGIN\" >> $CHANGES/etc/securetty"
run "echo \"/dev/console\" >> $CHANGES/etc/securetty"
run "echo \"# added by bootcdwrite END\" >> $CHANGES/etc/securetty"

# Disable persistent-net-rules
for i in z25_persistent-net.rules 70-persistent-net.rules; do
  if [ "$UDEV_FIXNET" = "yes" -a -e "$SRCDI/etc/udev/rules.d/$i" ]; then
    run mkdir -p $CHANGES/etc/udev/rules.d/
    run "sed \"s/^\([^#]\+.*\)/#\1 # disabled by bootcdwrite/\" \
      $SRCDI/etc/udev/rules.d/$i > $CHANGES/etc/udev/rules.d/$i"
  fi
done

run mkdir -p $CHANGES/usr/bin $CHANGES/etc/bootcd $CHANGES/usr/share/bootcd
mkdir -p $CHANGES/etc/init.d
run mkdir -p $CHANGES/usr/bin $CHANGES/etc/bootcd $CHANGES/usr/share/bootcd
run cp /usr/share/bootcd/bootcd2disk $CHANGES/usr/bin/
[ -e "/usr/share/bootcd/bootcdmk2diskconf" ] && run cp /usr/share/bootcd/bootcdmk2diskconf $CHANGES/usr/bin/
[ -e "/usr/share/bootcd/bootcdbackup" ] && run cp /usr/share/bootcd/bootcdbackup $CHANGES/usr/bin/
run cp /usr/share/bootcd/bootcdflopcp $CHANGES/usr/bin/
run "cat /etc/init.d/bootcd |
  sed \"s|^\(BOOT_ONLY_WITH_FLOPPY=\).*$|\1$BOOT_ONLY_WITH_FLOPPY|\" |
  sed \"s|^FLOPPY=.*$|FLOPPY=$FLOPPY_RUNTIME_DEV|\" |
  cat >$CHANGES/etc/init.d/bootcd"
run "chmod 755 $CHANGES/etc/init.d/bootcd"
run cp /usr/share/bootcd/bootcd2disk.conf $CHANGES/etc/bootcd/
run cp /usr/share/bootcd/bootcd-run.lib $CHANGES/usr/share/bootcd/
run cp /usr/share/bootcd/bootcd2disk.lib $CHANGES/usr/share/bootcd/

if [ -d $SRCDI/dev/.static/dev -a -x $SRCDI/etc/init.d/udev ]; then
  # -- udev --
  # The filesystem has static device files in /dev.
  # But tmpfs is mounted over /dev and hides the static device files.
  # The static device files are mounted again in /dev/.static/dev/.
  # This means bootcd has only to copy /dev/.static/dev as /dev, but
  # this directory does not contain the subdir .static, so we create it.
  run mkdir -p $CHANGES/dev/.static
  run chown root:root $CHANGES/dev/.static
  run chmod 700 $CHANGES/dev/.static
fi

# appending .no_run_on_bootcd disables the files in DISABLE_CRON for run-parts
# also set a link to /bin/true to "overwrite" the original file
for f in $DISABLE_CRON; do
  if [ -f $f ]; then
    CHANGESCRON=$(chnglist -add_ro -no_mnt "$SRCDISK" "$f")
    run install -p -D $f $CHANGES/$CHANGESCRON.no_run_on_bootcd
    run ln -s /bin/true $CHANGES/$CHANGESCRON
  fi
done

(
echo "KERNEL=$REL_KERNEL"
echo "INITRD=$REL_INITRD"
echo "DISABLE_CRON=\"$(chnglist -no_mnt "$SRCDISK" "$DISABLE_CRON")\""
) >$CHANGES/etc/bootcd/thisbootcd.conf

run "cat <<END > $CHANGES/etc/fstab
$CDDEV1 / iso9660 defaults,rw 0 0
#proc /proc proc defaults 0 0
$TO_FSTAB
END"

if [ ! "$ONLY_FLOPPY" ]; then
  if [ "$SSHHOSTKEY" = "yes" ]; then
    # each CD gets a unique hostkey"

    # create_host_keys will only recreate keys, if they already exist.
    # So keys will be touched in new dir, if they existed in old dir.
    for i in ssh_host_key ssh_host_rsa_key ssh_host_dsa_key
    do
      if [ -f $SRCDI/etc/ssh/$i ]; then
        run mkdir -p $CHANGES/etc/ssh
	      touch $CHANGES/etc/ssh/$i
      fi
    done

    create_host_keys $CHANGES/etc/ssh

  elif [ "$SSHHOSTKEY" != "no" ]; then
    warn 'SSHHOSTKEY is not defined as "yes" or "no".' \
         'It will be treated as "no".'
  fi

fi

do_isolinux

# only create fastboot file, if there are no additional mount points
if [ ! "$TO_FSTAB" ]; then
	run touch $CHANGES/fastboot
fi

# only call the function, if it is defined
doit=$(egrep "^[[:space:]]*(function)*[[:space:]]*extra_changes" $CONFDIR/bootcdwrite.conf)
if [ ! -z "$doit" ]; then
  echo "--- do function extra_changes ---" | tee -a $ERRLOG
  extra_changes
fi

if [ ! "$ONLY_FLOPPY" ]; then

  echo "--- Creating CD-Image ---" | tee -a $ERRLOG
  
  MKISO_NOT=""
  if [ "$NOT_TO_CD" != "" ]; then
    MKISO_NOT=`echo "$NOT_TO_CD" | sed "s/\(^\| \)*\([^ ]*\)/-x \2 /g"`
    echo "NOT_TO_CD arguments for $MKISOFS = <$MKISO_NOT>" >>$ERRLOG
  fi
  
  # Are there Files in $SRCDI that we have in $CHANGES too
  # If so we have to exclude them
  EXCLUDE=""
  for i in `(cd $CHANGES; find . ! -type d)`; do
                                 # i=./etc.ro/mtab
    j=`echo $i|sed "s|^\.||"`    # j=/etc.ro/mtab
    k=`echo $j|sed "s|\.ro/|/|"` # k=/etc/mtab
    if [ -f $SRCDI$k ]; then
      EXCLUDE="$EXCLUDE -x $SRCDI$k"
    fi
  done

  # since mkisofs 1.13 and genisoimage we have to use the option -graft-points
  if [ "$(basename "$MKISOFS")" = "genisoimage" ]; then
    GRAFTPOINTS="-graft-points"
  else
    GRAFTPOINTS=`$MKISOFS --version | head -1 | awk '{if($2>1.12) {print "-graft-points"}}'`
  fi
  echo "MKISOFS=<$MKISOFS> GRAFTPOINTS=<$GRAFTPOINTS>" >>$ERRLOG

  # Exclude .udev directory
  if [ -d $SRCDI/dev/.udev ]; then 
    MKISO_NOT="${MKISO_NOT}-x $SRCDI/dev/.udev "
    echo "NOT_TO_CD arguments with .udev for $MKISOFS = <$MKISO_NOT>" >>$ERRLOG
  fi

  cdimage_compressed_isolinux $NOTCOMPRESSED
  
  echo "--- Testing CD-Image ---" | tee -a $ERRLOG
  run mount $VAR/cdimage $VAR/mnt -o ro -o loop -t iso9660
  ignore ".*"
  run ls -l $VAR/mnt
  run umount $VAR/mnt
  losetup -d /dev/loop0 2>/dev/null
  
  mv $VAR/cdimage $VAR/cdimage.iso
fi

[ -e "/$CHANGES/cdboot.img" ] && cp /$CHANGES/cdboot.img $VAR/floppy.img

echo "work is done... find images in \"$VAR\" now!"
echo

