#!/bin/sh
#
# 	$Source: /cvsroot/bootcd/bootcd/bootcdwrite,v $
#       $Id: bootcdwrite,v 1.59 2006/12/08 15:40:04 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" "$VAR/ram1" "$VAR/ram2"
  [ -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$"
      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

# mk_bootcdram <SRCDISK> <NOT_TO_RAM>
mk_bootcdram()
{
  CHNG=$(chnglist -add_ro -no_mnt "$1" "$2")
  CHNGGREP=$(mk_grep $CHNG)
  cat /usr/share/bootcd/S12bootcdram.sh |
    sed "s|<CHNG>|$CHNG|" |
    sed "s|<CHNGGREP>|$CHNGGREP|" |
    sed "s|<BORDERLINKS>|$BORDERLINKS|"
}
#echo 'mk_bootcdram "/mnt" "/mnt/root /mnt/home/a" -> skript with:'
#echo '...| grep -v -e ^/root.ro -e ^/home.ro/a |...'
#mk_bootcdram "/mnt" "/mnt/root /mnt/home/a"
#exit 0

#echo 'mk_bootcdram "/" "/root /home/a" -> skript with:'
#echo '...| grep -v -e ^/root.ro -e ^/home.ro/a |...'
#mk_bootcdram "/" "/root /home/a"
#exit 0

#echo 'mk_bootcdram "/" "" -> skript with: "...| cat |..." and without "ln -s"'
#mk_bootcdram "/" ""
#exit 0


do_isolinux()
{
  run mkdir /$CHANGES/isolinux
  run cp /usr/lib/syslinux/isolinux.bin /$CHANGES/isolinux
  run cp $KERNEL /$CHANGES/isolinux/vmlinuz
  LILOINITRD=""
  if [ "$INITRD" ]; then 
    run cp $INITRD /$CHANGES/isolinux/initrd
    LILOINITRD="initrd=/isolinux/initrd"
  fi

  run cp $CONFDIR/isolinux.cfg $CHANGES/isolinux/isolinux.cfg
cat <<END >>/$CHANGES/isolinux/isolinux.cfg
label linux
  kernel /isolinux/vmlinuz
  append $LILOINITRD root=$CDDEV1 ramdisk_size=$RAMDISK_SIZE bootcd=$BOOTCDMODPROBE $APPEND
END

  for i in $CDDEVR; do
    echo "label $(basename $i)"
    echo "  kernel /isolinux/vmlinuz"
    echo "  append $LILOINITRD root=$i ramdisk_size=$RAMDISK_SIZE bootcd=$BOOTCDMODPROBE $APPEND"
  done >>$CHANGES/isolinux/isolinux.cfg

  if [ "$DISPLAY" ]; then 

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

    run cp $DISPLAY /$CHANGES/isolinux/display.txt
  fi
}

compress_dir()
{
  if [ "$EXCLUDE" -o "$MKISO_NOT" ]; then
    ZFTREEEX="$(echo $EXCLUDE $MKISO_NOT | 
      sed "s/-x[[:space:]]\+\([^[:space:]]\+\)/-e \"^\1\\\\>\"/g")"
  fi
  echo "--- Building input_dir for compression ---" | tee -a $ERRLOG
  run "cd $SRCDISK; rm -rf $VAR/input_dir; mkdir $VAR/input_dir; 
    find $(ex_proc $SRCDISK) |
    grep -v -e \"^$VAR\\>\" -e \"^$ERRLOG\\>\" -e \"^$SRCDI/tmp\\>\" $ZFTREEEX |
    sed \"s|^$SRCDI/||\" |
    cpio --quiet -pdum $VAR/input_dir/"

  run mv $VAR/input_dir/home $VAR/input_dir/home.ro
  run mv $VAR/input_dir/root $VAR/input_dir/root.ro
  run mv $VAR/input_dir/var $VAR/input_dir/var.ro
  run mv $VAR/input_dir/etc $VAR/input_dir/etc.ro
  run mv $VAR/input_dir/dev $VAR/input_dir/dev.ro
  run "cd $CHANGES; find . | cpio --quiet -pdum $VAR/input_dir/"

  echo "--- Compressing input_dir to compressed_dir ---" | tee -a $ERRLOG
  run "rm -rf $VAR/compressed_dir; mkzftree $VAR/input_dir $VAR/compressed_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) /var/spool/bootcd/telekom/compressed_dir/.. - ignoring and continuing."
}

uncompress_files()
{
  if [ $# -gt 0 ]; then
    for i in $*; do
      F="-F"
      [ -d $VAR/compressed_dir/$i ] && F=""
      run mkzftree -u $F $VAR/compressed_dir/$i $VAR/uncompress.tmp
      run rm -rf $VAR/compressed_dir/$i
      run mv $VAR/uncompress.tmp $VAR/compressed_dir/$i
    done
  fi
}

cdimage_compressed_isolinux()
{
  compress_dir
  uncompress_files 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"
  run mkisofs $MKISOFS_OPTS
  run rm -r $VAR/compressed_dir
}

cdimage_compressed_normal()
{
  compress_dir
  uncompress_files cdboot.img $*
  mkisofs_ignore
  MKISOFS_OPTS="-z -R -b cdboot.img -c cdboot.catalog -o $VAR/cdimage"
  MKISOFS_OPTS="$(chng_opts "$MKISOFS_OPTS" "$MKISOFS_CHNG")"
  MKISOFS_OPTS="$MKISOFS_OPTS $VAR/compressed_dir"
  run mkisofs $MKISOFS_OPTS
  run rm -r $VAR/compressed_dir
}

cdimage_isolinux()
{
  mkisofs_ignore
  MKISOFS_OPTS="$GRAFTPOINTS $MKISO_NOT \
    -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 \
    -x $SRCDI/proc -x $SRCDI/sys -x $VAR -x $ERRLOG \
    -x $SRCDI/etc -x $SRCDI/var -x $SRCDI/tmp \
    -x $SRCDI/dev -x $SRCDI/home -x $SRCDI/root $EXCLUDE \
    /=$SRCDI/ /=$CHANGES \
    /home.ro/=$SRCDI/home /root.ro/=$SRCDI/root /var.ro/=$SRCDI/var \
    /etc.ro/=$SRCDI/etc $MKISODEVFS"
  run mkisofs $MKISOFS_OPTS
}

cdimage_normal()
{
  mkisofs_ignore
  MKISOFS_OPTS="$GRAFTPOINTS $MKISO_NOT \
    -R -b cdboot.img -c cdboot.catalog -o $VAR/cdimage"
  MKISOFS_OPTS="$(chng_opts "$MKISOFS_OPTS" "$MKISOFS_CHNG")"
  MKISOFS_OPTS="$MKISOFS_OPTS \
    -x $SRCDI/proc -x $SRCDI/sys -x $VAR -x $ERRLOG \
    -x $SRCDI/etc -x $SRCDI/var -x $SRCDI/tmp \
    -x $SRCDI/dev -x $SRCDI/home -x $SRCDI/root $EXCLUDE \
    /=$SRCDI/ /=$CHANGES \
    /home.ro/=$SRCDI/home /root.ro/=$SRCDI/root /var.ro/=$SRCDI/var \
    /etc.ro/=$SRCDI/etc $MKISODEVFS"
  run mkisofs $MKISOFS_OPTS
}

# get_border_links
#
# if the following link exists on your host
#   /etc/X11/X -> ../../usr/bin/X11/XFree86
# and bootcd adds the followin link
#   /etc -> /etc/ram1
# then the X points to the non existing path
# /ram1/usr/bin/X11/XFree86
#   
# the call get_border_links /etc would return
# the first part of dangling links that would
# exist on bootcd under /ram1: usr
#
get_border_links()
{
  L=$(cd $1; find . -type l -print0 | xargs -0 /bin/ls -l) 
  #echo "DEBUG all symlinks <$L>" >&2
  L=$(echo "$L"|awk '{printf(" %s %s \n",$(NF-2),$NF)}' )
  #echo "DEBUG symlink target <$L>" >&2
  L=$(echo "$L" |sed "s|\([ /]\)\./|\1|g" )
  #echo "DEBUG rm ./ <$L>" >&2
  T=""; while [ "$T" != "$L" ]; do
    T="$L"
    L=$(echo "$L" | sed "s|\([ /]\)[^/.]\+/\.\./|\1|g" ) 
  done 
  #echo "DEBUG rm <dir>/../ <$L>" >&2
  L=$(echo "$L" | grep " \.\./") 
  #echo "DEBUG <path1> ../<path2> <$L>" >&2
  L=$(echo "$L" |sed "s|\.\./\([^.]\)|../ \1|")
  #echo "DEBUG <path1> ../ <path2>  <$L>" >&2 
  L=$(echo "$L" |sed "s|\([^ ]\) |\1/|")
  #echo "DEBUG <path1>/../ <path2> <$L>" >&2
  T=""; while [ "$T" != "$L" ]; do
    T="$L"
    L=$(echo "$L" | sed "s|\([ /]\)[^/.]\+/\.\./|\1|g" )
  done 
  #echo "DEBUG rm ./ <$L>" >&2
  L=$(echo "$L" | grep "^  "| sed "s/^  //")
  #echo "DEBUG only target <$L>" >&2
  L=$(echo "$L" | sed "s|/.*||" | sort -u)
  #echo "DEBUG target-start <$L>" >&2
  echo "$L"
}
#rm -rf /tmp/t
#mkdir -p /tmp/t/etc/X11
#mkdir -p /tmp/t/usr/bin/X11
#echo "server" >/tmp/t/usr/bin/X11/XFree86 >&2
#(cd /tmp/t/etc/X11; rm -f X; ln -s ../../usr/bin/X11/XFree86 X)
#echo "TEST1 expected=<usr> result=<$(get_border_links /tmp/t/etc)>" >&2
#(cd /tmp/t/etc/X11; rm -f X; ln -s ./.././../usr/./bin/X11/XFree86 X)
#echo "TEST2 expected=<usr> result=<$(get_border_links /tmp/t/etc)>" >&2
#(cd /tmp/t/etc/X11; rm -f X; ln -s /tmp/t/usr/bin/X11/XFree86 X)
#echo "TEST3 expected=<> result=<$(get_border_links /tmp/t/etc)>" >&2
#(cd /tmp/t/etc/X11; rm -f X; ln -s ../../usr/../usr/bin/X11/XFree86 X)
#echo "TEST4 expected=<usr> result=<$(get_border_links /tmp/t/etc)>" >&2
#(cd /tmp/t/etc/X11; rm -f X; ln -s ../../usr/bin/../../usr/bin/X11/XFree86 X)
#echo "TEST5 expected=<usr> result=<$(get_border_links /tmp/t/etc)>" >&2
#(cd /tmp/t/etc/X11; rm -f X; ln -s ../X11 X)
#echo "TEST6 expected=<> result=<$(get_border_links /tmp/t/etc)>" >&2
#(cd /tmp/t/etc/X11; rm -f X; ln -s /../../../usr/bin/X11/XFree86 X)
#echo "TEST7 expected=<> result=<$(get_border_links /tmp/t/etc)>" >&2
#exit 0

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>]"
    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 NOT_TO_RAM SSHHOSTKEY RAMDISK_SIZE \
ERRLOG VAR DO_CHECK CDDEV DISPLAY FASTBOOT FLOPPY_RUNTIME_DEV BOOTFLOPPY \
BOOT_ONLY_WITH_FLOPPY CLEAN_VAR SYSLINUX_SAVE ISOLINUX ARCH INITRD DEVFS 
TO_FSTAB TYP COMPRESS DISABLE_CRON MKISOFS_CHNG NOTCOMPRESSED BOOTCDMODPROBE"

OBSOLETE="BLANKING CDSCSI CDSPEED FLOPPY_CREATE_DEV ISO_ONLY"

unset $CONFVARS
. $CONFDIR/bootcdwrite.conf

# add SRCDISK to variables
if [ "$SRCDISK" ]; then
  [ "$SRCDISK" = "/" ] && s="" || s="$SRCDISK" 
  for v in KERNEL DISPLAY INITRD DISABLE_CRON NOT_TO_CD NOT_TO_RAM; 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

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
trap trapfunc 0 2
cleanup

if [ "$ARCH" = "hppa" ]; then
  PROBLEM="You have defined ARCH=hppa, but /usr/share/bootcd/bootcd-hppa.lib is 
not installed. Please apt-get bootcd-hppa."
  if [ -f ./bootcd-hppa.lib -a "$DEVELOPE" ]; then
    . ./bootcd-hppa.lib
  elif [ -f /usr/share/bootcd/bootcd-hppa.lib ]; then
    . /usr/share/bootcd/bootcd-hppa.lib
  else
    err "$PROBLEM"
  fi

elif [ "$ARCH" = "ia64" ]; then
  PROBLEM="You have defined ARCH=ia64, but /usr/share/bootcd/bootcd-ia64.lib is 
not installed. Please apt-get bootcd-ia64."
  if [ -f ./bootcd-ia64.lib -a "$DEVELOPE" ]; then
    . ./bootcd-ia64.lib
  elif [ -f /usr/share/bootcd/bootcd-ia64.lib ]; then
    . /usr/share/bootcd/bootcd-ia64.lib
  else 
    err "$PROBLEM"
  fi

elif [ "$ARCH" = "i386" ]; then
  PROBLEM="You have defined ARCH=i386, but /usr/share/bootcd/bootcd-i386.lib is 
not installed. Please apt-get bootcd-i386."
  if [ -f ./bootcd-i386.lib -a "$DEVELOPE" ]; then
    . ./bootcd-i386.lib
  elif [ -f /usr/share/bootcd/bootcd-i386.lib ]; then
    . /usr/share/bootcd/bootcd-i386.lib
  else 
    err "$PROBLEM"
  fi
fi

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_not2ram
check_cdfiles
check_kernel
check_initrd
[ "$ARCH" = "hppa" ] && check_hppa
check_sizes

# find border links
BORDERLINKS="$(
  for i in etc home root dev; do
    get_border_links $SRCDISK/$i 
  done | grep -v -e '^etc$' -e '^home$' -e '^root$' -e '^dev$' | sort -u |
  oneline
)"
[ "$BORDERLINKS" ] && echo "found border links: $BORDERLINKS" >>$ERRLOG
  
echo "--- Building Modifications ---" | tee -a $ERRLOG
run mkdir -p $VAR/mnt $CHANGES/proc $CHANGES/sys $CHANGES/ram1 $CHANGES/ram2

# at Boottime /etc -> /ram1/etc -> /etc.ro
for i in etc tmp dev home root; do run ln -sf ../$i.ro $CHANGES/ram1/$i; done
for i in var; do run ln -sf /$i.ro $CHANGES/ram2/$i; done
for i in etc tmp dev home root; do  run ln -sf ram1/$i $CHANGES/$i; done
for i in var; do  run ln -sf /ram2/$i $CHANGES/$i; done

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

# build etc.ro var.ro dev.ro tmp.ro home.ro root.ro
run mkdir $CHANGES/tmp.ro
run chmod 777 $CHANGES/tmp.ro
run mkdir $CHANGES/etc.ro
run chmod 755 $CHANGES/etc.ro
run mkdir $CHANGES/dev.ro
run chmod 755 $CHANGES/dev.ro

run ln -sf /proc/mounts $CHANGES/etc.ro/mtab
mkdir -p $CHANGES/etc.ro/rcS.d
run "mk_bootcdram \"$SRCDISK\" \"$NOT_TO_RAM $LOCATEDB\" >$CHANGES/etc.ro/rcS.d/S12bootcdram.sh"
run "chmod 755 $CHANGES/etc.ro/rcS.d/S12bootcdram.sh"
run mkdir -p $CHANGES/usr/bin $CHANGES/etc.ro/bootcd $CHANGES/usr/share/bootcd
run cp /usr/share/bootcd/bootcd2disk $CHANGES/usr/bin/
run cp /usr/share/bootcd/bootcdflopcp $CHANGES/usr/bin/
run "cat /usr/share/bootcd/S13bootcdflop.sh |
  sed \"s|^\(BOOT_ONLY_WITH_FLOPPY=\).*$|\1$BOOT_ONLY_WITH_FLOPPY|\" |
  sed \"s|^FLOPPY=.*$|FLOPPY=$FLOPPY_RUNTIME_DEV|\" |
  cat >$CHANGES/etc.ro/rcS.d/S13bootcdflop.sh"
run chmod 755 $CHANGES/etc.ro/rcS.d/S13bootcdflop.sh
run cp /usr/share/bootcd/bootcd2disk.conf $CHANGES/etc.ro/bootcd/
run cp /usr/share/bootcd/bootcd-run.lib $CHANGES/usr/share/bootcd/

if [ -d /dev/.static/dev -a -x /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.ro/.static
  run chown root:root $CHANGES/dev.ro/.static
  run chmod 700 $CHANGES/dev.ro/.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")\""
echo "ARCH=$ARCH"
) >$CHANGES/etc.ro/bootcd/thisbootcd.conf

run "cat <<END > $CHANGES/etc.ro/fstab
$CDDEV1 / iso9660 defaults,ro 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.ro/ssh
	touch $CHANGES/etc.ro/ssh/$i
      fi
    done

    create_host_keys $CHANGES/etc.ro/ssh

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

if [ "$ARCH" = "ia64" ]; then
  elilo_ia64
else
  if [ "$ARCH" != "hppa" -a "$ISOLINUX" = "no" ]; then
    do_syslinux
  fi

  if [ "$ISOLINUX" != "no" ]; then
    do_isolinux
  fi
fi

# 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 [ "$FASTBOOT" = "yes" ]; then
  echo "--- Creating /ram[1|2].cpio.gz for FASTBOOT ---" | tee -a $ERRLOG

  run mkdir $VAR/ram1
  mkdir $VAR/ram1/tmp; chmod 1777 $VAR/ram1/tmp
  FG=$(mk_grep $(chnglist -rel -no_mnt "$SRCDISK" "$NOT_TO_RAM $NOT_TO_CD"))
  echo "FG (FASTBOOT GREP) = <$FG>" >>$ERRLOG

  if [ "$DEVFS" = "yes" ]; then 
    CPIODIR="home root etc"
  else
    CPIODIR="home root etc dev"
  fi
  for i in $CPIODIR; do 
    run "cd $SRCDISK; find $i | $FG | cpio --quiet -pdum $VAR/ram1"

    if [ "$i" = "dev" -a -d /dev/.static/dev -a -x /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.
      mv $VAR/ram1/$i $VAR/ram1/$i.tmp
      mv $VAR/ram1/$i.tmp/.static/$i $VAR/ram1/$i
      mv $VAR/ram1/$i.tmp/.static $VAR/ram1/$i
      rm -rf $VAR/ram1/$i.tmp
    fi

    if [ -d $CHANGES/$i.ro ]; then 
      run "cd $CHANGES/$i.ro
           find . | 
	   cut -c3- | grep -v '^$' | 		# ./file -> file
	   $FG | cpio --quiet -pdum $VAR/ram1/$i"
    fi
  done

  ignore "cpio: .*: truncating inode number"
  run "cd $VAR/ram1
       find . |cpio --quiet --format=crc -o |gzip -c -9 >$CHANGES/ram1.cpio.gz"
  run "rm -r $VAR/ram1"
  
  run mkdir $VAR/ram2
  run "cd $SRCDISK
       find var -type d -or -type l | grep -v -e '^var/spool/bootcd' |
         $FG | cpio --quiet -pdum $VAR/ram2"

  ignore "cpio: .*: truncating inode number"
  run "cd $VAR/ram2
       find . |cpio --quiet --format=crc -o |gzip -c -9 >$CHANGES/ram2.cpio.gz"
  run "rm -r $VAR/ram2"

elif [ "$FASTBOOT" != "no" ]; then
  warn 'FASTBOOT is not defined as "yes" or "no".' \
       'It will be treated as "no".'
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 we have to use the option -graft-points
  GRAFTPOINTS=`mkisofs --version | awk '{if($2>1.12) {print "-graft-points"}}'`
  echo "GRAFTPOINTS=<$GRAFTPOINTS>" >>$ERRLOG

  if [ "$DEVFS" = "yes" ]; then
    MKISODEVFS=""
  elif [ -d /dev/.static/dev -a -x /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.
    MKISODEVFS="/dev.ro/=$SRCDI/dev/.static/dev"
  else
    MKISODEVFS="/dev.ro/=$SRCDI/dev"
  fi

  if [ "$COMPRESS" = "no" ]; then
    if [ "$ARCH" = "ia64" ]; then
      cdimage_ia64
    elif [ "$ISOLINUX" = "yes" ]; then
      cdimage_isolinux
    elif [ "$ARCH" = "hppa" ]; then
      cdimage_hppa
    else
      cdimage_normal
    fi
  else
    # NOTCOMPRESSED="$(chnglist -no_mnt "$SRCDISK" "$NOTCOMPRESSED")"
    if [ "$ARCH" = "ia64" ]; then
      cdimage_compressed_ia64 $NOTCOMPRESSED
    elif [ "$ISOLINUX" = "yes" ]; then
      cdimage_compressed_isolinux $NOTCOMPRESSED
    elif [ "$ARCH" = "hppa" ]; then
      cdimage_compressed_hppa $NOTCOMPRESSED
    else
      cdimage_compressed_normal $NOTCOMPRESSED
    fi  
  fi
  
  echo "--- Testing CD-Image ---" | tee -a $ERRLOG
  run mount $VAR/cdimage $VAR/mnt -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!\n"

