Livecd-make

From ElphelWiki
Revision as of 10:03, 29 December 2007 by Polto (talk | contribs) (Reverted edit of ZelelTricb, changed back to last version by 198.60.22.24)
Jump to: navigation, search
#!/bin/sh
# Make a clone from existed knoppix live-cd or dvd

NOFORK=false;
[ -z $REFRESH ] && export REFRESH=true;
[ -z $PHASE ] && export PHASE=10
[ -z "$BEST" ] && export BEST=-b
[ -z $NOSKIPDEBS ] && export NOSKIPDEBS=true;
[ -z $PAUSE ] && export PAUSE=false;
[ -z $DVD ] && export DVD=false;
while true ; do
  case $1 in
    -d) NOFORK=true ;;
    '') if $NOFORK ; then break ; fi
        on_exit() {
	  rm -f CDMAKE$$.tmp
	}
	trap on_exit 0 1 2 3 15
        mkfifo CDMAKE$$.tmp
	tee livecd-make.log <CDMAKE$$.tmp &
	if ! $0 -d 2>CDMAKE$$.tmp ; then
	  echo "WAS ERRORS! See report in livecd-make.log"
	fi
	exit 0 ;;
    unpack) PHASE=1 ;;
    remove) PHASE=2 ;;
    update) PHASE=3 ;;
    patch) PHASE=4 ;;
    quick) BEST=' ' ;;
    dvd) DVD=true ;;
    pause) PAUSE=true ;;
    no-update) NOSKIPDEBS=false ;;
    no-refresh) REFRESH=false; ;;
    *) echo "Usage: $0 [-d] [no-refresh] [no-upate] [quick] [unpack|remove|update|patch]
	unpack	- stop after unpack source distro into ''./new/''
	remove	- stop after remove packages
	update  - stop after install new packages
	patch - stop after patches and scripts
	pause - wait CR after each phase
	quick  - not use ''best'' compression
	dvd - make dvd image - not delete most packages and split root, quick is recommended
	no-update - do not remove & install packages
	no-refresh	- do not remove old ''./new/'' & unpack 
	-d	- do not redirect stderr to logfile"
       exit 1 ;;
  esac
  shift
done

read CDVER DATE < version

date >&2

query() {
    set +x
    echo -n "$1 [$2] " >&2
    read answer
    if [ -z $answer ] ; then answer=$2 ; fi
    set -x
}

set -e -x # Exit if any command fails, print command before execute

if type dialog ; then
gauge() {
    set +x
    lim=$1
    x=1
    while read j ; do 
	echo $(( x++ * 100 / lim )) ; 
    done | dialog --gauge "$2" 8 50
}
elif [ -n "$DISPLAY" ] && type Xdialog ; then
gauge() {
    set +x
    lim=$1
    x=1
    while read j ; do 
	echo $(( x++ * 100 / lim )) ; 
    done | Xdialog --gauge "$2" 8 50
}
else 
gauge() {
    set +x
    #echo $2
    lim=$1
    x=1
    [ -z $COLUMNS ] && COLUMNS=80
    while read j ; do
	echo -ne "\33[2K $(( x++ * 100 / lim ))% ${j:0:$((COLUMNS-5))}\r";
    done
    echo -ne "\33[2K"
}
fi

CSRC=SRC/KNOPPIX/KNOPPIX
UCSRC=KNOPPIX.iso
if [ -b /dev/cdrom ] ; then
  CDROM=/dev/cdrom
  CDRW="0,0,0"
elif [ -b /dev/cdroms/cdrom0 ] ; then
  CDROM=/dev/cdroms/cdrom0
  CDRW=`readlink -f $CDROM`
  CDRW=${CDRW%cd}generic
fi

not_empty() {
  test -n "$1" &&  test -L "$1" -o -e "$1"
}

# Mount knoppix CD or image

if ! [ -s $CSRC ]; then
  query "Knoppix CD or image location" "$CDROM"
  SRC="$answer"
  if ! [ -b $SRC ] ; then LOOP=",loop" ; fi
  [ -d SRC ] || mkdir SRC
  mount -o ro$LOOP $SRC SRC
else
  echo "Comressed image found"
fi
RTSRCZ=( SRC/boot/isolinux/minirt*.gz )

query "Enter default language" us
lang=$answer

if ! [ -s newcd/KNOPPIX/KNOPPIX ] || ! not_empty newcd/boot/isolinux/minirt* ; then

  if ! not_empty new/initrd*/* && not_empty bkinitrd/*/* ; then
    rm -rf new/initrd*/
    mv -f bkinitrd/* new  
  fi
  if ! grep -q "$CDVER" new/etc/knoppix-version 2> /dev/null || ! not_empty new/initrd*/*  ; then
    if [ $PHASE -gt 3 ] ; then
      # test for virtual memory size
      vmemsz=$( expr $( cat /proc/meminfo | grep '[mp]Free' | sed -e 's/.*: *//' -e 's/ k.*/ +/' ) 0 )
      if [ $vmemsz -lt 1200000 ] ; then
        echo "$vmemsz kB free virtual memory detected
	This script needs 1.2GB of memory or swap space to build the CD image.
	If you have enough free space on your hard drive you may 
	safely answer \"yes\" to the following question."
	query "Do you want to use 1.2GB of your disk space for the temporary swap file" yes
	case $answer in
	    [Yy]*)
	    dd if=/dev/zero of=swapfile bs=1M count=1200
	    mkswap swapfile
	    swapon swapfile
	esac
      else
	echo "$vmemsz kB free virtual memory - OK"
      fi
    fi
    # first try to use cloop module
    # Mount inner iso image
    for i in "" 2 3 4 5 ; do
     if ! not_empty UCSRC$i/new/* ; then
      insmod cloop >& /dev/null || true
       test -e $CSRC$i || continue
       [ -d UCSRC$i/new ] || mkdir -p UCSRC$i/new
       if ! ( [ -b /dev/cloop/0 ] &&
	losetup /dev/cloop/$((i+0)) $CSRC$i && mount /dev/cloop/$((i+0)) UCSRC$i/new ) ; then
        # Uncompress inner iso image
        if ! [ -s $UCSRC$i ] ; then
          echo Uncompress image $i...
          extract_compressed_fs $CSRC$i 2>&1 > $UCSRC$i  | 
	    gauge $(( `ls -s $CSRC$i | sed 's/[^0-9 ].*//'` / 23 )) "Uncompress inner image $i..."
        else
          echo "Uncompressed image found"
        fi
        mount -o ro,loop $UCSRC$i UCSRC$i/new
       fi
     else
      echo "Uncompressed image seems to be already mounted"
     fi
    done
    
    read verison j < UCSRC/new/etc/knoppix-version
    KVERS=( `echo UCSRC/new/lib/modules/*.*.* | sed -e 's![^ ]*/!-!g'` )
    
    if [ -d new ] ; then
      umount new/usr/src/debs new/proc || true
      umount new || true
      $REFRESH && rm -rfv new | gauge 135369 "Remove old directory for extracting files"
    fi
    
    if ! [ -d new ]; then
      for i in "" 2 3 4 5 ; do
        [ -e UCSRC$i/new ] || continue
        echo Extract files from the inner image $i
        cp -v -a -u UCSRC$i/new . 2>&1 | gauge 126000 "Extract files from the inner image $i"
      done
    fi

    #Uncompress initrd
    echo "Extract initrd image(s)"
    [ -d RT ] || mkdir RT
    umount RT || true
    for i in "${RTSRCZ[@]}" ; do
      rdimg=${i/*\//}
      rdimg=${rdimg/.gz/}
      gzip -d < $i > $rdimg.orig
      mount -o loop $rdimg.orig RT
      rddir=new/${rdimg/minirt/initrd}
      [ -e $rddir/linuxrc ] && continue
      [ -d $rddir ] && rmdir $rddir
      cp -a RT $rddir
      umount RT
    done

    [ $PHASE -lt 2 ] && exit
    $PAUSE && echo "KNOPPIX root file system unpacked to directory 'new'.
    Next phase deletes some packages and files. Press Enter to continue" && read j
    
#-------------   Modify Live CD --------------
    read j j HOSTKVERS j < /proc/version
    TMPMOD=false
remove() {
    if [ -s $2 ] ; then
	echo "$1 $2"
	eval "local -a lst=( $(cat $2) )"
	[ -z $lst ] && return 0
	chroot new sh -c "$3 ${lst[*]}" || true
    fi
}
update() {
    [ -s "$debs/${1##[^0-9]*}apt-get-list" ] && if chroot . apt-get install `cat $debs/${1##[^0-9]*}apt-get-list` ; then
	true
    else
	case $? in 100)
	    chroot . apt-get -f install
	    chroot . apt-get install `cat $debs/${1##[^0-9]*}apt-get-list`
	    ;;
	*) echo $? ; false
	esac	    
    fi
    aliens=( $debs/$1*.{rpm,tar.gz,tgz} )
    [ -z $aliens ] || chroot . alien "${aliens[@]}"
    local -a lst=( $debs/$1*.deb *.deb )
    [ -s "$lst" ] || return 0
    chroot . dpkg -i --force-overwrite ${lst[@]}
    rm *.deb || true
}
if $NOSKIPDEBS ; then
    if ! [ -d new/lib/modules/$HOSTKVERS ] ; then
        # for buggy packets
        cp -a /lib/modules/$HOSTKVERS new/lib/modules/
	TMPMOD=true
    fi
    if $DVD; then
	remove "Remove packages listed in" debs/00remove-debs-DVD "dpkg -P"
	remove "Remove files listed in" debs/00remove-files-DVD "rm -rf"
    else
	remove "Remove packages listed in" debs/00remove-debs "dpkg -P"
	remove "Remove files listed in" debs/00remove-files "rm -rf"
    fi
    $TMPMOD && rm -rf new/lib/modules/$HOSTKVERS
    
    [ $PHASE -lt 3 ] && exit
    $PAUSE && echo "Some packages and files listed in debs/00remove* are deleted.
     Next phase installs new packages and deletes listed in debs/zzremove*.
     Press Enter to continue" && read j
    
    echo Install new packages
    cd new
    mkdir -p usr/src/debs
    touch etc/fstab
    shopt -s nullglob
    debs=usr/src/debs
    mount --bind ../debs $debs
    mv etc/resolv.conf etc/resolv.conf.orig
    cp /etc/resolv.conf etc/resolv.conf
    if ! chroot . apt-get update -u ; then
	query "Continue" yes
	case $answer in
	    [Yy]*) ;;
	    *) exit 1
	esac
    fi
    
    update 00
    update 01
    update 02
    update '0[^0-2]'
    update '[^0]'
    
    chroot . apt-get -f install -u
    chroot . apt-get clean
    mv etc/resolv.conf.orig etc/resolv.conf
    
    umount usr/src/debs
    rmdir usr/src/debs

    cd ..
    
    NEWKVERS=( `echo new/lib/modules/*.*.* | sed -e 's![^ ]*/!-!g'` )

    if $DVD; then
	remove "Remove packages listed in" debs/zzremove-debs-DVD "dpkg -P"
        remove "Remove files listed in" debs/zzremove-files-DVD "rm -rf"
    else
	remove "Remove packages listed in" debs/zzremove-debs "dpkg -P"
        remove "Remove files listed in" debs/zzremove-files "rm -rf"
    fi
    COLUMNS=140 chroot new dpkg -l > packages.txt

    rm new/etc/fstab || true

fi # $NOSKIPDEBS

    [ $PHASE -lt 4 ] && exit
    $PAUSE && echo "All package add/remove operations is complete
     Next phase try and apply patches placed in 'patches' directory.
     Press Enter to continue" && read j
    
    echo Test patches
    mkdir -p patches-results
    cd new
    set +x
    st=()
    errors=false
    n=0
    for i in ../patches/* ; do
      if [ -d $i ] ; then
       st[$n]=true
      elif [ -x $i ] ; then
        if ! $i --dry-run >& ../patches-results/${i/*\//}-exec; then
	  st[$n]=true
	  errors=true
	else
	  mv ../patches-results/${i/*\//}-exec ../patches-results/${i/*\//}-exec-OK
	fi
      else case "$i" in *.tar.bz2) st[$n]="tar -xjf" ;;
      *)
        if patch -f -p0 --dry-run -i $i >& ../patches-results/${i/*\//}-p0 ; then
         st[$n]="patch -f -p0 -i"
	 mv ../patches-results/${i/*\//}-p0 ../patches-results/${i/*\//}-p0-OK
        elif patch -f -p1 --dry-run -i $i >& ../patches-results/${i/*\//}-p1 ; then
         st[$n]="patch -f -p1 -i"
	 rm ../patches-results/${i/*\//}-p0
	 mv ../patches-results/${i/*\//}-p1 ../patches-results/${i/*\//}-p1-OK
        else
         st[$n]=true
	 errors=true
        fi
      esac fi
      let ++n
    done
    n=0
    echo "Tests results" >&2
    for i in ../patches/* ; do
      echo -ne " ${i/*\//} \t " >&2
      case "${st[$n]}" in
        true) echo ERROR >&2 ;;
        tar*) echo "OK (tar)" >&2 ;;
        *-p0" "*) echo "OK (patch -p0)" >&2 ;;
        *-p1" "*) echo "OK (patch -p1)" >&2 ;;
        '') echo "OK (executable)" >&2 ;;
      esac
      let ++n
    done
    if $errors ; then
      query "Some patches are not applyable, see messages in directory 'patches-results'
Do You want to continue without failed pathes" no
      case "$answer" in [yY]*) ;; *) 
        echo "You may rerun script after corrections with next parameters:
no-update no-refresh"
        exit 1 ;
      esac
    else
      echo "All patches OK">&2
    fi

    echo Applay patches to root file system
    set -x
    n=0
    for i in ../patches/* ; do
      ${st[$n]} $i
      let ++n
    done
    echo Update menus
    #order files in directory
    mkdir etc/menu-methods.new
    mv etc/menu-methods/* etc/menu-methods.new/
    rmdir etc/menu-methods
    mv etc/menu-methods.new etc/menu-methods
    chroot . update-menus -v
    
    echo Update modules in initrd
    
    if [ -x initrd/modules/cloop.ko ] ; then
      SUF=ko
    else
      SUF=o
    fi
    (find initrd/modules -name '*.'$SUF ; cat <<-EOF ;) | while read i ; do
    initrd/modules/floppy.$SUF
    initrd/modules/scsi/usb-ehci.$SUF
    initrd/modules/scsi/usb-uhci.$SUF
    initrd/modules/scsi/usb-ohci.$SUF
    initrd/modules/scsi/usbcore.$SUF
    initrd/modules/scsi/usb_hcd.$SUF
EOF
        b=${i/*\//}
        j=( `find lib/modules/ -name "$b" -or -name "${b/.o/.ko}"` )
	if [ -s "$j" ]; then
	    # [ "$j" -nt "$i" ] && 
	    cp -avf "$j" "$i"
	else
	    b="${b/usb-/}"
	    b="${b/.o/-hcd.o}"
	    j=( `find lib/modules/ -name "$b" -or -name "${b/.o/.ko}"` )
	    if [ -s "$j" ]; then
		cp -avf "$j" "$i"
	    else
	        rm -fv $i
	    fi
	fi
    done
    
    DEFKERNEL=`readlink vmlinuz`
    ln -sf ../vmlinuz boot/vmlinuz
    ln -sf System.map-${DEFKERNEL##*-} boot/System.map
    KH=( usr/src/kernel-headers-* )
    ln -sf ${KH##*/} usr/src/kernel-headers
    echo Update dynamic library cache
    chroot . ldconfig
    echo Update molule dependencies
    for i in boot/System.map-* ; do
      [ -d lib/modules/${i##*-} ] && chroot . depmod -ae -F /$i ${i##*-}
    done
    echo Remove backups
    find . -name '*.orig'  -o -name '*~' | xargs rm -fv

    echo  "$verison-$CDVER $DATE"  > etc/knoppix-version
    cd ..
    rm -rf split?/

  else
    echo Patched Knoppix found
  fi # grep -q "$CDVER" ...
  
  umount UCSRC*/new RT || true
  for i in 0 1 2 3 4 5 ; do
    losetup -d /dev/cloop/$i || true
  done
  rmmod cloop || true

  [ $PHASE -lt 5 ] && exit
  $PAUSE && echo "All changes are complete
     Next phase make new comressed file system image.
     Press Enter to continue" && read j

  echo Make new compressed file system image...
  rm -rf new/.rr_moved $UCSRC*
  if ! not_empty new/inird*/* ; then
    rm -rf bkinitrd
    mkdir -p bkinitrd
    for i in new/initrd* ; do
      mv $i bkinitrd
      mkdir $i
    done
  fi
  umount new/proc || true
  rm -rf new/tmp/*
  
  if $DVD && ! not_empty split?/* ; then
    echo Split the file system ...
    cd new
    du -s opt/* usr/lib/* usr/share/* usr/* * | ../smartsplit.pl 4128768 > ../split-plan
    ##! Names in * must not contain space!
    for i in 0 1 2 3 4 5 6 7 ; do
	files=$( grep ^$i < ../split-plan | cut -d ' ' -f 4- )
	test -z "$files" && break;
	rm -rf ../split$i
	mkdir ../split$i
	cp -al --parents $files ../split$i
    done
    cd ..    
  fi
  mkdir -p newcd/KNOPPIX
  if $DVD; then
    for i in split? ; do
      KN=${i/split/KNOPPIX}
      KN=${KN/0/}
      mkisofs -quiet -hide-rr-moved -R $i |
      create_compressed_fs - $BEST 65536 2>&1 > newcd/KNOPPIX/$KN | gauge 60600 "Make new compressed file system image..."
    done
  else
    mkisofs -quiet -hide-rr-moved -R -U -sort iso-order -pad -x '/inird*/*' new |
    create_compressed_fs - $BEST 65536 2>&1 > newcd/KNOPPIX/KNOPPIX | gauge 30300 "Make new compressed file system image..."
  fi
  rm -rf new/initrd*
  mv bkinitrd/* new
  
else
  echo New compressed file system image found
fi # [ -s newcd/KNOPPIX/KNOPPIX ] ...

echo "Make new initrd"
mkdir -p newcd/boot/isolinux
for i in new/initrd*/ ; do
   DSIZE=`du -s $i`
   OUT=newcd/boot/isolinux/minirt${i##*initrd}
   OUT=${OUT%/}
   dd if=/dev/zero of=$OUT count=$(( ${DSIZE%%[^0-9]*} + 4000 )) bs=1k
   INODES=`ls -R $i | wc -l`
   mke2fs -Fv -N $(( INODES + 6000 )) -m 0 $OUT
   mount -o loop $OUT RT
   rm -rf RT/lost+found
   cp -va $i/* RT/
   umount RT
   gzip -9 $OUT
done
cp -f new/boot/vmlinuz newcd/boot/isolinux/linux
if which rdev; then RDEV=rdev; else RDEV=new/usr/sbin/rdev; fi
$RDEV newcd/boot/isolinux/linux /dev/ram3
umount RT UCSRC*/new new || true
#rm -rf new

echo Make CD image ...

mkdir -p newcd/KNOPPIX/ newcd/m23
touch newcd/KNOPPIX/KNOPPIX2 newcd/m23image.bz2 newcd/mdk.tb2 newcd/m23.tb2\
      newcd/m23/m23_0.4.99_halfBaked-pre3_knoppix.iso
cp -auv SRC/* newcd/
$DVD || rm -rf newcd/*m23* newcd/mdk* newcd/books \
       newcd/boot/isolinux/*m23*
find newcd/KNOPPIX -size 0 | xargs rm -f

i="
s/^KBDMAP german.kbd/#&/"
case "$lang" in de) i="" ;; esac
sed -e "s/lang=[a-z]\+/lang=$lang/$i" SRC/boot/isolinux/isolinux.cfg > newcd/boot/isolinux/isolinux.cfg
umount SRC || true
mkisofs -pad -l -r -J -m Demos -m LinuxTag -m Talks -V "$CDVER" -no-emul-boot \
-boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin \
-c boot/isolinux/boot.cat -hide-rr-moved -o knoppix-$CDVER.iso newcd $FNAME

#rm -rf  KNOPPIX isolinux.cfg isolinux.bin SRC UCSRC* minirt24.gz

echo New CD image in knoppix-$CDVER.iso

query "Do You want to record new CD" no
case "$answer" in
    [yY]*)
    echo "cdrecord -v speed=50 dev=$CDRW driveropts=burnfree -eject knoppix-$CDVER.iso"
    cdrecord -v speed=50 dev=$CDRW driveropts=burnfree -eject knoppix-$CDVER.iso
esac