#!/bin/sh

[ 0$(id -u 2>/dev/null) -eq 0 ] || exec su -c "$0 $@"

DIALOG=dialog

ddq()
{
	dd $@ 2> /dev/null
}

ddn()
{
	ddq conv=notrunc $@
}

get()
{
	hexdump -v -s $1 -n ${4:-${3:-2}} -e "\"\" 1/${3:-2} \" %u\n\"" "$2"
}

bytes2bin()
{
	for i in $@ ; do
		printf '\\\\x%02X' $((i&255))
	done | xargs echo -en
}

words2bin()
{
	for i in $@ ; do
		printf '\\\\x%02X\\\\x%02X' $((i&255)) $(((i>>8)&255))
	done | xargs echo -en
}

quads2bin()
{
	for i in $@ ; do
		printf '\\\\x%02X\\\\x%02X\\\\x%02X\\\\x%02X' $((i&255)) \
			$(((i>>8)&255)) $(((i>>16)&255)) $(((i>>24)&255))
	done | xargs echo -en
}

gettazboot()
{
	echo -e "\nCreating $(basename $1) ..."
	gotcdfile linld.com
	S=$(($(stat -c %s $file)+12))
	P=$(((S+511)/512))
	E=$((4096-(32*P)))
	words2bin 0x5A4D $((S%512)) $P 0 2 $E -1 -16 \
			-2 0 256 -16 28 0x6C53 0x5469 0x7A61 > $1
	dd if=$file bs=1 count=$(($(stat -c %s $file)-1)) >> $1 2> /dev/null
	echo -en '@tazboot.cmd\0' >> $1
}

maybe64()
{
	echo -n $1
	grep -q ' lm ' /proc/cpuinfo && [ -s ${1}64 ] && echo 64
}

size()
{
	stat -c %s "$1"
}

sectcnt()
{
	[ ! -b "$1" ] && echo $(($(size "$1")/512)) ||
	cat /sys/block/${1#/dev/}/size
}

uncpio()
{
	i=$1                                                    
	[ $0 = /init.exe ] && i=$(maybe64 $i)
	[ -s "$i" ] || return
	echo -en "\n Extracting $(basename $i) ..."
	case $(get 0 $i) in
	*35615)	( zcat || gunzip ) ;;
	*14333) unxz ;;
	*\ 93)	unlzma ;;
	*)	cat ;;
	esac < $i | ( cd ${2:-/} ; cpio -idmu > /dev/null 2>&1 )
}

xdotwait=dotwait
dotwait()
{
	echo -n "${1:-Install filesystem}.."
	echo -n > /tmp/wait
	[ "$REQUEST_URI" ] && return
	while [ -e /tmp/wait ]; do
		echo -n "." > /dev/${tty0:-tty}
		sleep 1
	done &
}

getuuid()
{
	dev=$(mount | sed "/ $(echo $mnt | sed 's|/|\\/|g') /!d;s/ .*//;s|/dev/||;q")
	[ "$dev" ] &&
	blkid | sed "/$dev:/!d;s/.* UUID=.\\([^ ]*\\)\".*/\\1/" ||
	echo "/dev/hda1"
}

tazusbinitfs()
{
	PAD=$(($(size $1) % 4))
	[ $PAD -ne 0 ] && ddq if=/dev/zero bs=1 count=$((4 - PAD)) >> $1
	mkdir -p /tmp/fs$$/etc /tmp/fs$$/lib /tmp/fs$$/home
	cp -a /etc/locale.conf /etc/locale.conf /tmp/fs$$/etc 2> /dev/null
	cat > /tmp/fs$$/init1 <<EOT
#!/bin/sh
sed -i 's|sbin/init|init2|' /init
exec /init
EOT
	cat > /tmp/fs$$/init2 <<EOT
#!/bin/sh

mount -t proc /proc /proc
for i in /lib/modules/*.ko* ; do insmod \$i 2> /dev/null ; done; sleep 2
v=\$(sed '/\\/home=/!d;s|.*/home=\\([^ ]*\\).*|\\1|' /proc/cmdline /cmdline 2> /dev/null)
mount / -o remount,rw
mkdir /mnt/dos
rm -f /cmdline 2> /dev/null
mount / -o remount,ro
mnt=/mnt/dos/\${v#*/}
dev=\$( (blkid /dev/[sh]d* || blkid) | grep \${v%%/*} | sed 's/:.*//;q')
echo "Mount \$dev in /mnt/dos for \$v..." | tee -a /run/boot.log
mount \$dev /mnt/dos
if [ ! -d /mnt/dos/slitaz ]; then
	umount /mnt/dos 2> /dev/null
	(blkid /dev/[sh]d* || blkid) | while read dev line; do
		case "\$line" in
		*ntfs*|*vfat*|*msdos*) ;;
		*) continue ;;
		esac
		mount \${dev%:} /mnt/dos
		[ -d /mnt/dos/slitaz ] && break
		umount /mnt/dos
	done
fi
$([ "$2" ] || echo '# ')mount.posixovl -F \$mnt -- -oallow_other -odefault_permissions -osuid
mount --bind \$mnt /home
mount -o size=0,ro -t tmpfs tmpfs \$mnt
umount /proc
exec /sbin/init
EOT
	chmod 755 /tmp/fs$$/init?
	ln -s /sqfs/bin/gzip /bin 2> /dev/null
	( cd /tmp/fs$$ ; find * | cpio -o -H newc ) | gzip -9 >> $1
	rm -rf /tmp/fs$$
}

mkinitrd()
{
	echo -en "\nCreating $(basename $1) "
	fs=/tmp/fs$$
	for i in bin lib dev proc tmp mnt etc ; do
		mkdir -p $fs/$i
	done
	for i in /dev/null /dev/tty /dev/tty[012] /dev/fuse /dev/[hs]d* \
			/dev/console ; do
		cp -a $2$i $fs/dev/
	done
	for i in /bin/busybox $(which mount.posixovl) $(which blkid) \
		 $(which ntfs-3g); do
		cp $(LD_TRACE_LOADED_OBJECTS=1 /lib/ld*.so $i | \
		sed 's|.*=> \(.*/lib/l[^ ]*\).*|\1|;/^\//!d') $fs/lib
		cp $i $fs/bin
	done
	cp -a /sqfs/lib/ld-* /tmp/fs/lib 2> /dev/null ||
	cp -a /lib/ld-* $fs/lib
	for i in $(busybox | sed '/Current/,$!d'); do
		[ -e $fs/bin/${i%,} ] || ln -s busybox $fs/bin/${i%,}
	done
	ln -s /proc/mounts $fs/etc/mtab
	sed 's/ .*//' /proc/modules | while read mod ; do
		find /lib/modules/ | grep $mod.ko | \
			sed 's|.*|cp & $fs/lib|' | sh
	done
	cat > $fs/init <<EOT
#!/bin/sh

arg()
{
	grep -q \$1 /proc/cmdline &&
	val="\$(sed "s/.*\$1=\\([^ ]*\\).*/\\1/" < /proc/cmdline)" &&
	echo "\$2 \$val"
}

mount -t proc /proc /proc
  arg debug "shell" && debug=true && set -x
for i in /lib/*.ko* ; do insmod \$i 2> /dev/null ; done; sleep 2
arg mount "Mount device"
dsk=\$( (blkid /dev/[sh]d* || blkid) | grep \$val | sed 's/:.*//;q')
mount \$dsk /mnt || mount.ntfs \$dsk /mnt
arg subroot "Change root to directory"
if [ -d /mnt/\$val ]; then
	umount /mnt 2> /dev/null
	(blkid /dev/[sh]d* || blkid) | while read dev line; do
		case "\$line" in
		*ntfs*|*vfat*|*msdos*) ;;
		*) continue ;;
		esac
		mount \${dev%:} /mnt
		[ -d /mnt/\$val ] && break
		umount /mnt
	done
fi

$([ "$3" ] || echo -n '# ')mount.posixovl -F /mnt/\$val -- -oallow_other -odefault_permissions -osuid
mount --bind /mnt /mnt/\$val/mnt/dos
mount -o size=0,ro -t tmpfs tmpfs /mnt/\$val/mnt/dos/\$val
LDSO=\$(ls /mnt/\$val/lib/ld-* | sed q)
export LD_LIBRARY_PATH=\$val/lib:\$val/usr/lib:/lib
  [ "$debug" = "true" ] && sh
umount /proc
exec /bin/switch_root /mnt \${LDSO#/mnt/} \$val/usr/sbin/chroot \$val /sbin/init
EOT
	chmod +x $fs/init
	( cd $fs ; find * | cpio -o -H newc ) | lzma e $1 -si 2> /dev/null
	rm -rf $fs /tmp/wait
}

ls_r()
{
	ls -r $@ 2> /dev/null || ls $@
}

is_loram()                                                                   
{                                                                            
	[ -s /lib/modules/squashfs.ko* ]                                     
}                                                                            

doinstall()
{
	unset useposixovl
	blkid | grep $(df $mnt | sed '$!d;s/ .*/:/') | \
		grep -qiE "(msdos|vfat|ntfs)" && useposixovl=YES
	case "$mnt" in
	*mkzip*) useposixovl=YES
	esac
	mkdir -p $mnt/slitaz/boot $mnt/slitaz/mnt/dos
	[ "$useposixovl" ] &&
	if ! mount.posixovl -F $mnt/slitaz -- \
		-oallow_other -odefault_permissions -osuid; then
		echo "Can't install SliTaz. Abort."
		sleep 5
		return 1
	fi
	dotwait "Install root filesystem in /slitaz.."
	if [ "$1" ]; then
		ls_r $media/boot/rootfs*gz* | \
		xargs cat > $mnt/slitaz/boot/rootfs.gz
		tazusbinitfs $mnt/slitaz/boot/rootfs.gz $useposixovl
		initrd=rootfs.gz
		extraargs="/home=$(getuuid)/slitaz rdinit=/init1"
	else
		if [ -d $media/fs ]; then                                
                        cp -a $media/fs/. $mnt/slitaz                    
                elif is_loram; then                                            
                        for i in $(ls_r $media/boot/rootfs*); do         
                                losetup -o 124 /dev/loop7 $i                   
                                mount -t squashfs -o ro /dev/loop7 /sqfs/mnt   
                                cp -a /sqfs/mnt/. $mnt/slitaz                  
                                umount /sqfs/mnt                               
                                losetup -d /dev/loop7                          
                        done                                                   
                else
			for i in $(ls_r $media/boot/rootfs*gz*); do
				${uncpio:-uncpio} $i $mnt/slitaz
			done
		fi
		for i in $packages_list; do
			tazpkg get-install $i --root=$mnt/slitaz
		done
		for i in $packages_dir/*.tazpkg; do
			[ -s "$i" ] &&
			tazpkg install $i --root=$mnt/slitaz
		done
		cp -a /etc/locale.conf $mnt/slitaz/etc 2> /dev/null
		cp -a /etc/keymap.conf $mnt/slitaz/etc 2> /dev/null
		mkinitrd $mnt/slitaz/boot/initrd $mnt/slitaz $useposixovl
		initrd=initrd
		extraargs="mount=$(getuuid) subroot=slitaz"
	fi
	echo -en "\nInstall boot files..."
	for i in $media/boot/bzImage* $media/boot/*pxe* \
		$media/boot/plop* \
		$media/boot/isolinux/he* $media/boot/isolinux/opt* \
		$media/README $media/boot/memtest* ; do
		[ -s $i ] && cp $i $mnt/slitaz/boot
	done
	for i in $mnt/slitaz/boot/memtest $mnt/slitaz/boot/*pxe ; do
		[ $(get 0 $i 2> /dev/null || echo 0) -eq 23117 ] &&
		mv $i $i.exe
	done
	bzimage=$(cd $mnt/slitaz/boot ; ls bzImage* | sed q)
	cp /etc/keymap.conf /etc/locale.conf $mnt/slitaz/etc 2> /dev/null
	gettazboot $mnt/slitaz/boot/tazboot.exe	# autoappend 64 suffix
	unix2dos > $mnt/slitaz/boot/tazboot.cmd <<EOT
image=/slitaz/boot/$bzimage
initrd=/slitaz/boot/$initrd
root=/dev/null $extraargs autologin
EOT
	uudecode - <<EOT | gunzip > $mnt/slitaz/boot/slitaz.pif
begin-base64 644 -
H4sIAAAAAAACA8XPxUHGMBTA8X9ecb/glgFwv+FO23zeI+7ucMFhCjZgEEZh
Ctzd4Rf3PFbtQHGLG9BmfmZqdlE/tSmw2LfePzOzWDK0OsQXpPHvFGfZBmL5
f3Zns98NuG1BbTrbWj0OFMypSKfT4kYCurKuRleWlBEth2qUTYFBKjg746pI
2nZaIT/v9vWwbeuqi9fPznLlSPFLLuK22/0lLT09/BDhXgWKO1f9aLKxOObE
EhLuVvO4FksSwaH5qbHpvkle0TyzND82NK+doRVeZgGGbIw0XD2QwV9SnAN/
ACxDxwMAAA==
====
EOT
	unix2dos $mnt/slitaz/boot/he* $mnt/slitaz/boot/opt* \
		$mnt/slitaz/boot/README
	[ -d $mnt/slitaz/usr/sbin -a ! -x $mnt/slitaz/usr/sbin/mount.posixovl ] &&
	cp $(which mount.posixovl) $mnt/slitaz/usr/sbin
	if [ "$useposixovl" ] && grep -qs " $mnt " /proc/mounts &&
	   [ ! -d $mnt/boot/grub ]; then
		mkdir -p $mnt/boot/grub
		echo -en "\nInstall grub in /boot/grub..."
		cp -a /usr/lib/grub/*/* $mnt/boot/grub
		cat > $mnt/boot/grub/menu.lst <<EOT
# /boot/grub/menu.lst: GRUB boot loader configuration.

# By default, boot the first entry.
default 0

# Boot automatically after 8 secs.
timeout 8

title Microsoft Windows
	chainloader +1

EOT
		dev=$(grep " $mnt " /proc/mounts | awk '{ print $1 }')
		base=${dev//[0-9]/}
		dd if=$base bs=32k count=1 of=$mnt/boot/grub/$(basename $base)
		cat > $mnt/boot/grub/uninstall-grub.sh <<EOT
#!/bin/sh

[ -s /boot/grub/$(basename $base) ] &&
dd if=/boot/grub/$(basename $base) of=$base
EOT
		grub-install --no-floppy --root-directory=$mnt $base
	fi
	if [ -s $mnt/boot/grub/menu.lst ] &&
	   ! grep -q /slitaz/boot/$bzimage $mnt/boot/grub/menu.lst; then
		echo -en "\nUpdate /boot/grub/menu.lst..."
		cat >> $mnt/boot/grub/menu.lst <<EOT
title SliTaz GNU/Linux $(cat $mnt/slitaz/etc/slitaz-release)
	kernel /slitaz/boot/$bzimage root=/dev/null $extraargs autologin
	initrd /slitaz/boot/$initrd

EOT
	fi
false &&                                                                          
	[ -s $mnt/boot.ini ] && ! grep -qs tazboot $mnt/boot.ini &&               
	echo "Update boot.ini ..." && unix2dos >> $mnt/boot.ini <<EOT             
C:\\slitaz\\boot\\tazboot.exe="SliTaz"                                                
EOT
false &&                                                                          
	grep -qis menuitem $mnt/config.sys && ! grep -qi tazboot $mnt/config.sys &&
	echo "Update config.sys ..." &&                                            
	sed -i 's/menudefault/menuitem SLITAZ, SliTaz\r\n&/' $mnt/config.sys &&    
	unix2dos >> $mnt/config.sys <<EOT                                          
[SLITAZ]                                                                           
install=\\slitaz\\boot\\tazboot.exe                                                
EOT
	rm -f $tmp/wait
	[ "$useposixovl" ] && umount $mnt/slitaz
	return 0
}

windev()
{
	if [ -b "$1" ]; then
		device=$1
	elif [ "$1" ]; then
		echo "Invalid Linux/Windows partition"
		return 1
	else
		DEV="$(blkid | grep -iE "(msdos|vfat|ntfs|ext[234]|xfs|btrfs)" | sed 's/:.*//;s|/dev/||')"
		[ "$DEV" ] || return
	cat > /tmp/dialog$$ <<EOT
$DIALOG --clear --title " Select your Linux/Windows partition " \
	--menu "\nPlease select the Linux/Windows partition according to its known size.
The data will be kept untouched.\n" 17 70 8 \
	$(for i in $DEV ; do
		label="$(blkid | sed "/$i:/!d;s/.*://;s/[^ ]*UUID=[^ ]* //g;s/LABEL=//")"
		echo -n "/dev/$i \"$(($(cat /sys/block/*/$i/size)/2048))MB $label\" "
	done)
EOT
		exec 3>&1
		[ $? -eq 0 ] || return
		device=$(. /tmp/dialog$$ 2>&1 1>&3)
		exec 3>&-
		rm -f /tmp/dialog$$
	fi
	mnt=/tmp/mnt$$
	mkdir -p $mnt && mount $device $mnt
}

extra_packages()
{
	packages_list=
	packages_dir=
	[ $0 = /init.exe ] && return
	$DIALOG --clear --title " Extra packages " \
		--defaultno --yesno \
"Do you want to add extra packages ?" 7 70
	[ $? -eq 0 ] || return
	[ -s /var/lib/tazpkg/packages.txt ] || tazpkg recharge
	if [ -s $media/boot/vmlinuz-$(uname -r) ]; then
		cat > /tmp/dialog$$ <<EOT
$DIALOG --clear --title " Select the packages " \
	--separate-output \
	--cancel-label "Skip" \
	--checklist "Please select the packages you want to install. Try with the first letter." \
	0 0 0 \\
EOT
		awk -F\| '{ printf "%s \"%s\" off ",$1,$3 }' \
			/var/lib/tazpkg/packages.desc >> /tmp/dialog$$
		sh /tmp/dialog$$ 2> /tmp/dialog.out$$
		[ $? -eq 0 ] && packages_list="$(cat /tmp/dialog.out$$)"
	fi
	cat > /tmp/dialog$$ <<EOT
$DIALOG --clear \
	--title "Please select the directory with every custom package to install." \
	--cancel-label "Skip" --dselect $PWD 13 78
EOT
	sh /tmp/dialog$$ 2> /tmp/dialog.out$$
	[ $? -eq 0 ] && packages_dir="$(cat /tmp/dialog.out$$)"
	rm -f /tmp/dialog$$ /tmp/dialog.out$$
}

_install()
{
	extra_packages
	$DIALOG --clear --title " SliTaz UMSDOS way installation " \
		--yes-label "Install" --yesno \
"\nSliTaz will be installed in the subdirectory \\slitaz of the current
Linux/DOS/Windows partition. You can see your files from /mnt/dos.\n\n
You can start SliTaz with \\slitaz\\boot\\tazboot.exe\n\n
To uninstall SliTaz, you have only to remove this directory.
The file \\boot.ini or \\config.sys may be modified too.\n\n
SliTaz may run slowly on the 'UMSDOS way' installation due to the
posixovl filesystem. The 'TAZUSB way' installation runs faster.\n\n
To do a traditional installation with disk partitioning,
start SliTaz Live with the 'SliTaz RAM boot' menu.\n" 19 70
	[ $? -eq 0 ] || return
	doinstall
	[ $0 = /init.exe ] || return 0
	[ -x $mnt/slitaz/sbin/init ] || return 0
	umount -d $media/cdrom
	umount_proc
	exec chroot $mnt/slitaz /sbin/init
}

readtazbootconf()
{
	kernel="$(sed '/^image=/!d;s/.*=//' $mnt/slitaz/boot/tazboot.cmd)"
	initrd="$(sed '/^initrd=/!d;s/.*=//' $mnt/slitaz/boot/tazboot.cmd)"
	cmdline="$(sed '/^image=/d;/^initrd=/d' $mnt/slitaz/boot/tazboot.cmd)"
}

bootinstalled()
{
	[ "$(which kexec)" ] || return
	[ -x $mnt/slitaz$1 ] || return
	[ -s $mnt/slitaz/boot/tazboot.cmd ] || return
	readtazbootconf
	kexec -l $kernel --initrd $initrd --command-line "$cmdline" || return
	umount $mnt
	rm -rf $mnt
	quit "kexec -e"
}

mkzip()
{
	device=
	packages_list=
	packages_dir=
	mnt=/tmp/mkzipmnt$$
	mkdir -p $mnt
	$1 $2 || return
	for i in bootlace.com grubinst.exe grldr ; do
		wget -O $mnt/slitaz/boot/$i http://mirror.slitaz.org/boot/$i
	done
	readtazbootconf
	cat > $mnt/slitaz/boot/menu.lst <<EOT
title SliTaz
	kernel $kernel $cmdline
	initrd $initrd

EOT
	while read file title; do
		file=$(ls $mnt/slitaz/boot/*$file* 2> /dev/null)
		[ -s "$file" ] && cat >> $mnt/slitaz/boot/menu.lst <<EOT
title $title
	kernel ${file#$mnt}

EOT
	done <<EOT
memtest	MemTest
plop	USB boot
pxe	Web boot
EOT
	unix2dos $mnt/slitaz/boot/menu.lst
	unix2dos > $mnt/slitaz/boot/install.txt <<EOT
For DOS users (real mode only):

Start SliTaz with \\slitaz\\boot\\tazboot.exe


For NT/2000/XP users:

1- Move the files grldr and menu.lst into the root directory

C:\\> copy \\slitaz\\boot\\grldr \\
C:\\> copy \\slitaz\\boot\\menu.lst \\

2- Remove boot.ini attributes

C:\\> attrib -r -h -s boot.ini

3- Append the following line to boot.init

C:\\grldr="slitaz"

4- Restore boot.ini attributes

C:\\> attrib +r +h +s boot.ini

See http://diddy.boot-land.net/grub4dos/files/README_GRUB4DOS.txt
and http://xpt.sourceforge.net/techdocs/nix/disk/boot/boot07-GrubForDosInfo/ar01s03.html
EOT
	( cd $mnt ; echo 'See \slitaz\boot\install.txt to launch SliTaz.' | \
	  zip -zr9 $(basename "$ISO" .iso).zip slitaz )
	[ "$(which advzip)" ] &&
	echo "Recompressing $(basename "$ISO" .iso).zip ..." &&
	advzip -z4 $mnt/*.zip
	mv $mnt/*.zip .
	du -h $PWD/$(basename "$ISO" .iso).zip
	umount $mnt
	rm -rf $mnt
}

install()
{
	windev $1 || return
	packages_list=
	packages_dir=
	if [ "$1" ]; then
		doinstall
	else
		_install && bootinstalled /sbin/init
	fi
	umount $mnt
	rm -rf $mnt
}

inst2zip()
{
	if [ "$1" ]; then
		mkzip doinstall
	else
		mkzip _install
	fi
}

_installtaz()
{
	$DIALOG --clear --title " SliTaz TAZUSB way installation " \
		--yes-label "Install" --yesno \
"\nSliTaz will be installed in the subdirectory \\slitaz of the current
Linux/DOS/Windows partition. You can see your files from /mnt/dos.\n\n
You can start SliTaz with \\slitaz\\boot\\tazboot.exe\n\n
To uninstall SliTaz, you have only to remove this directory.
The file \\boot.ini or \\config.sys may be modified too.\n\n
The filesystem is loaded entirely into memory upon boot to
increase responsiveness. Only /home lands on the hard disk.\n\n
To do a traditional installation with disk partitioning,
start SliTaz Live with the 'SliTaz RAM boot' menu.\n" 19 70
	[ $? -eq 0 ] || return
	doinstall tazusblike || return
	[ $0 = /init.exe ] || return
	dotwait
	if [ -d /media/cdrom/fs ]; then
		cp -a /media/cdrom/fs/. /
	else
		for i in $(ls_r /media/cdrom/boot/rootfs*); do
			${uncpio:-uncipo} $i
		done
	fi
	cp /tmp/fs/etc/* /etc 2>/dev/null
	echo "/home=$(getuuid)/slitaz" > /cmdline
	rm -f /tmp/wait
	[ -x /init1 ] || return
	umount -d /media/cdrom
	umount /mnt/slitaz
	rm -f /dev/cdrom
	umount /mnt
	mkdir /mnt/dos
	umount_proc
	exec /init1
}

installtaz()
{
	windev $1 || return
	packages_list=
	packages_dir=
	if [ "$1" ]; then
		doinstall tazusblike
	else
		_installtaz && bootinstalled /boot/bzImage
	fi
	umount $mnt
	rm -rf $mnt
}

insttaz2zip()
{
	if [ "$1" ]; then
		mkzip doinstall tazusblike
	else
		mkzip _installtaz
	fi
}

bootiso()
{
	cd /tmp
	for i in $(ls_r $media/boot/rootfs*gz); do
		i=$(maybe64 $i)
		cat $i
		n=$((4 - ($(size $i) % 4)))
		[ $n -eq 4 ] || dd if=/dev/zero bs=1 count=$n
	done > initrd$$
	cmdline="root=/dev/null autologin lang=$LANG"
	[ -s /etc/keymap.conf ] && cmdline="$cmdline kmap=$(cat /etc/keymap.conf)"
	[ -s /etc/TZ ] && cmdline="$cmdline tz=$(cat /etc/TZ)"
	rm -f cmdline initrd 2> /dev/null
	getcustomconf kexec >/dev/null
	[ -s cmdline ] && cmdline="$cmdline $(cat cmdline)" && rm cmdline
	[ -s initrd ] && cat initrd >> initrd$$ && rm initrd
	kernel=$(maybe64 $media/boot/bzImage)
	. /etc/locale.conf
	kexec -l $kernel --initrd initrd$$ --command-line "$cmdline" &&
	rm -f initrd$$
	quit "kexec -e"
}

tazboot()
{
	if [ -z "$1" ]; then
		$DIALOG --clear --title " SliTaz bootloader for DOS " \
			--yes-label "Install" --yesno \
"\nThe file TAZBOOT.EXE will be created in the top directory. It supports
any linux kernel, multiple initramfs and a kernel command line.\n\n
Usage: tazboot.exe [[@commands]|[image=<bzimage>]
[initrd=<rootfs>[,<rootfs2>...]] cmdline args ...]\n\n
Defaults: tazboot @tazboot.cmd or tazboot image=bzImage auto\n\n\
Examples for tazboot.cmd:\n\n\
  image=boot/bzImage\n\
  initrd=boot/rootfs4.gz,boot/rootfs3.gz,boot/rootfs2.gz,boot/rootfs1.gz\n\
  root=/dev/null autologin\n\n\
  image=\\slitaz\\vmlinuz root=/dev/sda5 ro\n" 0 0
		[ $? -eq 0 ] || return
	fi
	gettazboot tazboot.exe
	du -h $PWD/tazboot.exe
}

md5()
{
	dotwait "Checking files"
	( cd $media ; ${md5sum:-md5sum -c md5sum*} 2>&1 | sort ) > /tmp/data
	unset md5sum
	rm -f /tmp/wait
	if [ "$1" ]; then
		cat /tmp/data
	else
		$DIALOG --clear --title " Checked files " \
			--textbox /tmp/data 0 0
	fi
	rm -f /tmp/data
}

filepos()
{
	dotwait "locate files"
	( cd $media; find * -type f | while read f; do
		printf "%8d  %s\n" $(busybox stat -m "$f" | sed q) "$f"
	done | sort -n ) > /tmp/data
	rm -f /tmp/wait
	if [ "$1" ]; then
		cat /tmp/data
	else
		$DIALOG --clear --title " File start sector " \
			--textbox /tmp/data 0 0
	fi
	rm -f /tmp/data
}

gotcdfile()
{
	for i in "$media/$1" "$media/*/$1" "$media/*/isolinux/$1" ; do
		file=$(ls $i 2> /dev/null | sed q)
		[ -s "$file" ] && break
	done
}

sha()
{
	gotcdfile 'sha*sum*'
	sha=$(basename $file)
	md5sum="${sha%sum*}sum -c ${file#$media/}"
	md5 $@
}

readme()
{
	gotcdfile 'README*'
	if [ "$1" ]; then
		cat $file
	else
		$DIALOG --clear --title " Readme " --textbox $file 0 0
	fi
}

bzimage()
{
	if [ -z "$1" ]; then
		$DIALOG --clear --title " Create linux.exe ? " \
			--yes-label "Install" --yesno \
"\nLinux.exe launches the linux kernel under DOS (in real mode only).
The cmdline arguments are supported except initrd=,
vga= (you can try 'rdev -v') and mem= (partially).
\nExample:\nC:\\> linux.exe root=/dev/hda2 ro panic=60\n" 12 70
		[ $? -eq 0 ] || return
	fi
	cp $(maybe64 $media/boot/bzImage) linux.exe
	du -h $PWD/linux.exe
}

memtest()
{
	if [ -z "$1" ]; then
		$DIALOG --clear --title " Create memtest.exe ? " \
			--yes-label "Install" --yesno \
"\nMemtest86 is a thorough, stand alone memory test for x86 architecture
computers. BIOS based memory tests are a quick, cursory check and often
miss many of the failures that are detected by Memtest86.\n" 0 0
		[ $? -eq 0 ] || return
	fi
	gotcdfile 'memtest*' && cp $file memtest.exe
	du -h $PWD/memtest.exe
}

mkfat12()
{
	[ $(($(get 0 $1) - 0x5A4D)) -eq 0 ] || return
	J=$(($(get 3 $1 1) + 0x02))
	R=$((1 + $(get 497 $1 1) + 1 + ($(get 500 $1)-1)/32))
	[ $R -lt 2500 ] || return
	[ $((($(get 500 $1)-1) & 31)) -lt 30 ] &&
	ddq if=$file bs=32 count=1 seek=$((R*16 - 1)) of=/dev/fd0
	G="18 0 2 0 0 0 0 0"
	[ $J -gt 25 ] || G=""
	F=0
	for i in 1 2 3; do
		F=$((((2880-R-F-F)*3+1023)/1024))
	done
	bytes2bin 0xEB $J 0x90 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 \
		0 2 2 $((R%256)) $((R/256)) 2 64 0 64 11 0xF0 $F 0 \
		$G | ddq bs=1 of=/dev/fd0
	ddq if=/dev/zero bs=512 count=$((4+F+F)) seek=$R of=/dev/fd0
	for i in $R $((R+F)) ; do
		bytes2bin 0xF0 0xFF 0xFF | ddq bs=512 seek=$i of=/dev/fd0
	done
	echo -n $(basename $1) | ddq bs=1 seek=3 count=8 of=/dev/fd0
}

mkfloppy()
{
	dotwait "Create a $(basename $1 .exe) boot floppy"
	ddq if=$1 of=/dev/fd0
	mkfat12 $1
	rm -f /tmp/wait
}

fdmemtest()
{
	if [ -z "$1" ]; then
		$DIALOG --clear --title " Create a Memtest86 boot floppy " \
			--yes-label "Create floppy" --yesno \
"\nMemtest86 is a thorough, stand alone memory test for x86 architecture
computers. BIOS based memory tests are a quick, cursory check and often
miss many of the failures that are detected by Memtest86.\n\n
Please insert a blank disk in floppy drive.\n" 0 0
		[ $? -eq 0 ] || return
	fi
	gotcdfile 'memtest*' && mkfloppy $file
}

pxe()
{
	gotcdfile '?pxe*'
	if [ -z "$1" ]; then
		$DIALOG --clear --title " Create $(basename $file .exe).exe ? " \
			--yes-label "Install" --yesno \
"\nBoot your operating system from the internet and enjoy a full system
working entirely in RAM with speed and stability in mind. The Linux Kernel
and the complete SliTaz compressed root filesystem will be loaded into RAM
from the Web using PXE and HTTP protocols.\n" 0 0
		[ $? -eq 0 ] || return
	fi
	cp $file $(basename $file .exe).exe
	du -h $PWD/$(basename $file .exe).exe
}

fdpxe()
{
	if [ -z "$1" ]; then
		$DIALOG --clear --title " Create a SliTaz Web boot floppy " \
			--yes-label "Create floppy" --yesno \
"\nBoot your operating system from the internet and enjoy a full system
working entirely in RAM with speed and stability in mind. The Linux Kernel
and the complete SliTaz compressed root filesystem will be loaded into RAM
from the Web using PXE and HTTP protocols.\n\n
Please insert a blank disk in floppy drive.\n" 0 0
		[ $? -eq 0 ] || return
	fi
	gotcdfile '?pxe*' && mkfloppy $file
}

plop()
{
	gotcdfile 'plop*'
	if [ -z "$1" ]; then
		$DIALOG --clear --title " Create $(basename $file .exe).exe ? " \
			--yes-label "Install" --yesno \
"\nBoot your operating system from a USB disk without BIOS support.\n" 0 0
		[ $? -eq 0 ] || return
	fi
	cp $file $(basename $file .exe).exe
	du -h $PWD/$(basename $file .exe).exe
}

fdplop()
{
	if [ -z "$1" ]; then
		$DIALOG --clear --title " Create a Plop boot floppy " \
			--yes-label "Create floppy" --yesno \
"\nBoot your operating system from a USB disk without BIOS support.\n\n
Please insert a blank disk in floppy drive.\n" 0 0
		[ $? -eq 0 ] || return
	fi
	gotcdfile 'plop*' && mkfloppy $file
}

menuitem()
{
	[ "$3" ] && shift
	echo -en "\"$1\"	\"$2\""
}

gotposixovl()
{
	mount.posixovl 2>&1 | grep -qi usage && gotcdfile 'rootfs*.gz' &&
	menuitem "$@"
}

gotposixovlzip()
{
	[ "$(which zip)" ] && gotposixovl "$1" "$2"
}

noinit()
{
	[ $0 = /init.exe ] || menuitem "$@"
}

initx()
{
	[ $0 = /init.exe ] && menuitem "$@"
}

xfile()
{
	for i in $1; do
		[ "$(which $i)" ] && menuitem "$@" && break
	done
}

initxfile()
{
	[ $0 = /init.exe ] && xfile "$@"
}

cdfile()
{
	gotcdfile "$1" && menuitem "$@"
}

gottazusb()
{
	gotcdfile 'rootfs*.gz' && xfile tazusb "$@"
}

isbzImage()
{
	[ $(get 514 $file 4) -eq 1400005704 ] &&
	[ $(($(get 529 $file 1) & 1)) -eq 1 ]
}

cdfilex()
{
	gotcdfile "$1" && [ "$(which kexec)" ] && isbzImage && menuitem "$@"
}

cdfilef()
{
	[ -e /sys/block/fd0 ] && cdfile "$@"
}

cdexe()
{
	gotcdfile "$1" &&
	[ $(get 0 $file 2>/dev/null || echo 0) -eq 23117 ] &&
	[ $(get 128 $file 2>/dev/null || echo 0) -ne 10 ] &&
	menuitem "$@"
}

misspkg()
{
	for i in zip kexec-tools posixovl cdrkit cdrkit-isoinfo ; do
		[ -d /var/lib/tazpkg/installed/$i/ ] && continue
		[ "$1" != "install" ] && menuitem "$@" && return
		tazpkg get-install $i
	done
}

noinitmisspkg()
{
	[ $0 = /init.exe ] || misspkg "$@"
}

missing()
{
	misspkg install
}

ishybrid()
{
	[ $(get 510 "$ISO") -eq 43605 ] || return
	C=$((2048*$(get $(((17*2048) + 71)) "$ISO" 4)))
	[ $(get $C "$ISO" 4) -eq 1 ] || return
	[ $(get $((C+30)) "$ISO" 4) -eq $((0x88AA55)) ] || return
	C=$((2048*$(get $((C+40)) "$ISO" 4)))
	[ $(get $((C+64)) "$ISO" 4) -eq 1886961915 ] && menuitem "$@"
}

isiso()
{
	[ $(get 32769 "$ISO" 4) -eq 808469571 ] && menuitem "$@"
}

burnable()
{
	[ "$(sed '/Can wr.*1$/!d' /proc/sys/dev/cdrom/info 2> /dev/null)" ] &&
	menuitem "$@"
}

blankable()
{
	[ "$(sed '/Can wr.*RW.*1$/!d' /proc/sys/dev/cdrom/info 2> /dev/null)" ] &&
	menuitem "$@"
}

burniso()
{
	wodim -v speed=$(fgrep "drive speed" /proc/sys/dev/cdrom/info | cut -f3) \
		-eject -multi "$ISO"
}

blankcd()
{
	wodim -v -blank=fast
}

customsector()
{
	local c=$(echo $(get 32848 "$ISO" 4))
	hascustomconf $((c+16)) && echo $((c+16)) || echo $c
}

xhascustomconf=hascustomconf
hascustomconf()
{
	[ "$(ddq bs=2k skip=${1:-$(customsector)} if="$ISO" | ddq bs=1 count=6)" \
	  = "#!boot" ]
}

gotcustomconf()
{
	hascustomconf && menuitem "$@"
}

hasflavor()
{
	[ -x /usr/bin/tazlito ] && [ -s $(maybe64 $media/boot/bzImage) ] && menuitem "$@"
}

gotisomd5()
{
	[ "$(which md5sum 2> /dev/null)" ] &&
	[ $(get 0 "$ISO") -eq 23117 ] &&
	[ $(get 18 "$ISO") -ne 0 ] && menuitem "$@"
}

read_return()
{
	echo -e "\rPress RETURN to continue."
	read n
}

getcustomconf()
{
	ddq bs=2k skip=$(customsector) if="$ISO" | while read line; do
		case "$line" in
		\#!boot*) ;;
		append=*) echo ${line#append=} > cmdline && ls -l $PWD/cmdline ;;
		initrd:*) cnt=${line#initrd:}
			  { ddq bs=512 count=$((cnt / 512));
			    ddq bs=1 count=$((cnt % 512)); } > initrd &&
			  ls -l $PWD/initrd
			  break ;;
		*)	  break ;;
		esac
	done
	[ "$1" ] || read_return
}

setcustomconf()
{
	msg="$(stat -c '%12s   %.16z   %n' $PWD/cmdline $PWD/initrd 2>/dev/null|sed 'N;s|\n|\\n|')"
	[ "$msg" ] || msg="These files are not found. Your configuration will be cleared.\\n"
	msg="\nUpdate the custom configuration with the files cmdline and initrd\n
in the current directory $PWD. Any missing file is assumed empty.\n\n$msg"
	[ "$1" ] && echo -e "$msg" ||
	$DIALOG --clear --title " Update custom configuration " \
		--yes-label "Update config" --yesno "$msg\n
\nAre you sure to do the update ?\n" 0 0
	[ $? -eq 0 ] || return
	ddq bs=2k seek=$(customsector) of="$ISO" count=0
	if [ "$(ls $PWD/cmdline $PWD/inird 2> /dev/null)" ]; then
		rm -f /tmp/custom$$ 2>/dev/null
		[ -s $PWD/cmdline ] &&
		echo "append=$(cat $PWD/cmdline)" >>/tmp/custom$$
		[ -s $PWD/initrd ] &&
		echo "initrd:$(size $PWD/initrd)" >>/tmp/custom$$ &&
		cat $PWD/initrd >>/tmp/custom$$
		echo "#!boot $(md5sum /tmp/custom$$ | sed 's| .*||')" >>"$ISO"
		cat /tmp/custom$$ >>"$ISO"
		dd if=/dev/zero bs=4k count=1 >>"$ISO"
		rm -f /tmp/custom$$
	fi
}

isomd5()
{
	dotwait "Checking iso image"
	[ "$(ddq if="$ISO" bs=2k skip=16 \
	     count=$(($(get 32848 "$ISO" 4)-16)) | md5sum)" = \
	  "$(ddq if="$ISO" bs=16 count=1 skip=2047 | od -N 16 -t x1 -An | \
	     sed 's/ //g')  -" ] && echo "OK" || echo "ERROR"
	echo -en "\rChecking iso hybrid boot..."
	n=$(($(get 2 "$ISO")-1+($(get 4 "$ISO")-1)*512))
	if [ $n -lt 40000 -a $n -gt 32768 ]; then
		s=$(get 0 "$ISO" 2 $n | awk '{ i+= $0 } END { print i }')
		[ $(((1+s+$(get $((n+1)) "$ISO" 1)) % 65536)) -eq 0 ] &&
		echo "OK" || echo "ERROR"
	fi
	if hascustomconf; then
		echo -en "\rChecking iso custom config..."
		TMP=/tmp/$(basename $0)$$md5
		md5="$(ddq bs=2k skip=$(customsector) if="$ISO" | while read line; do
			case "$line" in
			\#!boot*) echo ${line#*boot } > $TMP ;;
			append=*) echo $line ;;
			initrd:*) echo $line
				  cnt=${line#initrd:}
				  ddq bs=512 count=$((cnt / 512))
				  ddq bs=1 count=$((cnt % 512))
				  break ;;
			*)	  break ;;
			esac
		done | md5sum | cut -c1-32)"
		[ "$md5" = "$(cat $TMP)" ] && echo "OK" || echo "ERROR"
		rm -f $TMP
	fi
	rm -f /tmp/wait
	[ "$1" ] || read_return
}

usbdev()
{
	dotwait "Wait 5 seconds for USB devices"
	sleep 5
	rm -f /tmp/wait
	DEV="$(grep -l 1 /sys/block/*/removable | \
		sed 's|/sys/block/\(.*\)/removable|\1|')"
	[ "$DEV" ] || return
	cat > /tmp/dialog$$ <<EOT
$DIALOG  --clear --title " Select your USB key " \
	--menu "\nPlease select the USB key according to its known size.\n\n" \
	0 0 0 \
	$(for i in $DEV ; do
		grep -qs 1 /sys/block/$i/ro ||
		[ $(cat /sys/block/$i/size) -lt 100 ] ||
		echo -n "/dev/$i \"$(($(cat /sys/block/$i/size)/2048))MB $(cat /sys/block/$i/device/model 2> /dev/null)\" "
	done) \

EOT
	exec 3>&1
	. /tmp/dialog$$ 2>&1 1>&3 2>/tmp/device$$
	retval=$?
	device=$(cat /tmp/device$$)
	rm -f /tmp/dialog$$ /tmp/device$$
	exec 3>&-
	[ $retval -eq 0 ]
}

tazusbmsg()
{
	[ "$(which tazusb 2> /dev/null)" ] || return
	echo "You should choose 'USB key read/write installation' to be
able to save the package updates or your own configuration and data files.\n\n"
}

fixup_gpt()
{
	quads2bin 1 0 $2 0 | ddq bs=1 seek=$((512+24)) of=$1	# my gpt, alt gpt
	quads2bin 0 | ddq bs=1 seek=$((512+88)) of=$device
	quads2bin $(isohybrid --crc32 $1 1024 $(($(get 596 $1 4)*$(get 592 $1 4)))) | \
		ddq bs=1 seek=$((512+88)) of=$1			# CRC32 partitions
	ddn of=$1 if=$1 bs=512 skip=1 seek=$2 count=1
	ddn of=$1 if=$1 bs=512 skip=2 seek=$(($2-1)) count=1
	quads2bin $2 0 1 0 | ddq bs=1 seek=$(($2*512+24)) of=$1	# my gpt, alt gpt
	quads2bin $(($2-1)) 0 | ddq bs=1 seek=$(($2*512+72)) of=$1
	i=$(get 524 $1 4)
	quads2bin 0 | ddq bs=1 seek=$(($2*512+16)) of=$device
	quads2bin $(isohybrid --crc32 $1 $(($2*512)) $i) | \
		ddq bs=1 seek=$(($2*512+16)) of=$1	# CRC32 header
	quads2bin 0 | ddq bs=1 seek=$((512+16)) of=$device
	quads2bin $(isohybrid --crc32 $1 512 $i) | ddq bs=1 seek=$((512+16)) of=$1	# CRC32 header
	partprobe $1
}

usbbootkey()
{
	if [ -b "$1" ]; then
		device=$1
	elif [ "$1" ]; then
		echo "Invalid USB key device"
		return 1
	else
		$DIALOG --clear --title " Create a USB boot key " \
			--yes-label "Continue" --yesno \
"\nThe USB key will be used like a CD-ROM. You will not be able to write
any data on the boot partition.\n\n
An extra FAT32 partition will be created with the remaining free space.\n\n
$(tazusbmsg)Please plug your USB stick in now.\n" 16 70
		[ $? -eq 0 ] || return
		usbdev || return
	fi
	
	# perform dd in progress bar
	max=$(($(sectcnt "$ISO")/2048))
	i=0; while [ $i -le $max ]; do
		ddq if="$ISO" bs=1024k count=1 skip=$i seek=$i of=$device
		echo $(((i*100)/max))
		i=$((i+1))
	done | { [ "$1" ] || dialog --gauge \
		" The ISO image transfer can be long. Please wait..." \
		6 70 0 > /dev/tty 2>&1; }

	# GPT partition + fat32 format for the remaining space
	sectors=$(($(sectcnt $device)-1))
	quads2bin $sectors | ddq bs=1 seek=458 of=$device	# pmbr
	quads2bin $((sectors-2)) 0 | ddq bs=1 seek=$((512+48)) of=$device
	uudecode - <<EOT | gunzip | ddn bs=128 seek=9 of=$device	# basic data partiton
begin-base64 644 -
H4sIAAAAAAACA1u04MLrpzuNXdoPZGzbrjbzOAORwIkhkaGYIZMhmUGBIQXI
LgFiBYYCIFkEZGeCcT5DHkFzAAqvwhqAAAAA
====
EOT
	ddq if=/dev/urandom bs=16 count=1 seek=73 of=$device		# partition uuid
	last=$(sectcnt "$ISO")
	custom=$((4*$(get 32848 $device 4)))
	[ $custom -gt $((last-4)) ] && last=$((custom+4))		# room for cmdline
	quads2bin $last 0 | ddq bs=1 seek=$((1024+128+32)) of=$device	# partition first address
	quads2bin $((sectors-2)) 0 | ddq bs=1 seek=$((1024+128+40)) of=$device	# partition last address
	fixup_gpt $device $sectors
	[ -b ${device}p2 ] && pdev=${device}p2 || pdev=${device}2
	value=$(cat /sys/block/${device#/dev/}/${pdev#/dev/}/size)
	[ ${#value} -gt 7 -a "$(which mkfs.exfat)" ] && value="exfat" || value="fat32"
	if [ -z "$1" ]; then
		echo -n "$DIALOG --clear --title \" Select the filesystem \" \
--radiolist \"\\nPlease select the filesystem type to create.\" 14 70 4" > /tmp/dialog$$
		while read type rem; do
			which mkfs.${type/fat32/vfat} > /dev/null || continue
			echo -n " $type \"$rem" >> /tmp/dialog$$
		done <<EOT
fat32	for a small key"	$([ "$value" = "fat32" ] && echo "on" || echo "off")
exfat	for a large key"	$([ "$value" = "exfat" ] && echo "on" || echo "off")
ntfs	"			off
ext3	for most linux"		off
ext4	"			off
btrfs	for recent linux"	off
xfs
EOT
		exec 3>&1
		value=$(. /tmp/dialog$$ 2>&1 1>&3)
		retval=$?
		exec 3>&-
		rm -f /tmp/dialog$$
	fi
	homedev=/dev/$(basename /sys/block/${device#/dev/}/${pdev#/dev/})
	case "$value" in
	*fat*)	mkfs.${value/fat32/vfat} -n 'SLITAZ HOME' $homedev;;
	*)	mkfs.$value -L 'SLITAZ HOME' $homedev;;
	esac > /dev/null 2>&1

	# update boot/exe crc16
	words2bin 0 | ddq bs=1 seek=18 of=$device
	i=$(($(get 2 $device) - 1 + ($(get 4 $device) - 1)*512))
	i=$(($(od -v -N $i -t u2 -w2 -An $device | \
		awk '{ i+= $0 } END { print (i % 65536) }') \
		+ $(get $((i+1)) $device 1)))
	words2bin $(( (-i -1) & 65535 )) | ddq bs=1 seek=18 of=$device

	[ "$1" ] || $DIALOG --clear --title " Set /home persistent " \
			--yes-label "Continue" --yesno \
"\nThe USB key will run fully in ram. The datas will be lost after each reboot.\n\n
This option will mount /home on the USB key vfat during the boot process.\n\n
Your own data will be saved, but the system stay not upgradable.\n" 16 70
	if [ $? -eq 0 ]; then
		echo -en "$(echo "SliTaz persistent /home" | sed 's|.|&\\0|g')" | ddn bs=8 seek=151 of=$device
		fixup_gpt $device $sectors
		[ "$(ddn bs=512 skip=$custom if=$device | ddn bs=1 count=6)" = "#!boot" ] && return
		mkdir /tmp/mnt$$
		mount $pdev /tmp/mnt$$
		echo -e "keyboard\nlocale\ntimezone" > /tmp/dialog.out$$
		touch /tmp/dialog$$
		if [ -z "$1" ]; then
			cat > /tmp/dialog$$ <<EOT
$DIALOG --clear --title " Select configuration " \
	--separate-output \
	--cancel-label "Skip" \
	--checklist "Please select the configuration to store." \
	0 0 0 \
keyboard "kmap=$(cat /etc/keymap.conf)" on \
locale "lang=${LANG%.UTF*}" on \
timezone "tz=$(cat /etc/TZ)" on \
$([ -s /tmp/mnt$$/boot/rootfs.gz ] || cat <<EOM
network "/etc/network.conf" off \
ssh "/etc/dropbear" off \
password "/etc/passwd /etc/*shadow /etc/group" off \
custom "Your own list of files" off
EOM
)
EOT
			sh /tmp/dialog$$ 2> /tmp/dialog.out$$
			[ $? -eq 0 ] || echo -n "" > /tmp/dialog.out$$
		fi
		data=""; files=""
		while read i ; do
			case "$i" in
			keyboard)	data="${data}kmap=$(cat /etc/keymap.conf) ";;
			locale)		data="${data}lang=${LANG%.UTF*} " ;;
			timezone)	data="${data}tz=$(cat /etc/TZ) " ;;
			network)	files="${files} /etc/network.conf" ;;
			ssh)		files="${files} /etc/dropbear" ;;
			password)	files="${files} /etc/passwd /etc/*shadow /etc/group" ;;
			custom) 	exec 3>&1
					custom="$($DIALOG --clear --title " Custom files " \
				--inputbox "\nEnter the list of files to save:\n" 10 70 2>&1 1>&3)"
					retval=$?
					exec 3>&-
					[ $retval -eq 0 ] && files="${files} $custom" ;;
			esac
		done < /tmp/dialog.out$$
		rm -f /tmp/dialog$$ /tmp/dialog.out$$
		[ "$data" ] && cat <<EOT | ddn bs=512 seek=$custom of=$device
#!boot $(echo "append=$data" | md5sum | sed 's/ .*//')
append=$data
--
EOT
		if [ "$files" ]; then
			mkdir /tmp/mnt$$/boot 2> /dev/null
			find $files | cpio -o -H newc | gzip -9 > /tmp/mnt$$/boot/rootfs.gz
		fi
		umount /tmp/mnt$$
		rm -rf /tmp/mnt$$
	fi
}

usbkey()
{
	$DIALOG --clear --title " Create a SliTaz USB key " \
		--yes-label "Continue" --yesno \
"\nUnlike a hard drive install, the filesystem is kept in a compressed
rootfs.gz. The filesystem is loaded entirely into memory upon boot.
This should increase responsiveness, protect the filesystem against
accidental corruption and reduce read/writes to the USB drive.
Once setup, the tazusb utility can rewrite the root filesystem
with any changes you have made since booting up,
giving the effective benefits of a hard drive install.\n\n
/home is mounted on boot using the UUID of your particular flash drive.
Unlike a device name, the UUID has the benefit of never changing from machine
to machine.\n\n
Please plug your USB stick in now.\n" 19 70
	[ $? -eq 0 ] || return
	usbdev || return
	exec 3>&1
	format=`$DIALOG  --clear \
	--title " Select the filesystem " \
	--radiolist "\nPlease select the filesystem type to create.\n\n\
The filesystem creation will erase all the data in the USB key." 14 70 4 \
		"none"	"Do not erase the USB key" on \
		"ext3"	"Ext3 journaling filesystem" off \
		"ext2"	"Ext2 filesystem" off \
		"fat32"	"Windows FAT32 filesystem" off \
	2>&1 1>&3`
	retval=$?
	exec 3>&-
	[ $retval -eq 0 ] || return
	[ "$format" != "none" ] && tazusb format $device "SliTaz" $format
	tazusb gen-iso2usb "$ISO" $device
}

flavdata()
{
	[ $(get 1024 "$ISO") -eq 35615 ] && n=2 || n=$((1+$(get 417 "$ISO" 1)))
	[ $n -eq 4 ] && n=20
	[ $(get $((n*512)) "$ISO") -eq 35615 ] || n=13
	ddq if="$ISO" bs=512 skip=$n count=20 | zcat 2>/dev/null
}

hasflavinfo()
{
	[ "$(flavdata | ddq bs=1 count=7)" = "0707010" ] && menuitem "$@"
}

showfavinfo()
{
	mkdir -p /tmp/data
	flavdata | ( cd /tmp/data ; cpio -i )
	file=/tmp/data/info
	cat /tmp/data/*desc > $file
	if [ -s /tmp/data/*receipt ]; then
		echo "=== receipt ==="
		cat /tmp/data/*receipt
	fi >> $file
	for i in /tmp/data/*list* ; do
		echo "=== extra ${i#*list} files"
		cat $i
	done >> $file
	if [ "$1" ]; then
		cat $file
	else
		$DIALOG --clear --title " Flavor info " \
			--textbox $file 0 0
	fi
	rm -rf /tmp/data
}

flavor()
{
	name="$(flavdata | cpio -t 2> /dev/null | sed 's/.[a-z]*$//;q')"
	echo "Create ${name:=flavor}.flavor..."
	tazlito iso2flavor "$ISO" $name
	ls -l $name.flavor 2> /dev/null && return
	sleep 5
	[ "$1" ] || read_return
}

parse_isolinux()
{
	awk 'BEGIN { IGNORECASE=1 }
function multi(n)
{
	auto=$n
	for (--n; n < NF; n+=2) {
		s=$n
		if (s ~ /M$/) s = substr(s,0,length(s)-1)
		else s /= 1024
		sizes=int(s) " " sizes
	}
	next
}
{
	if ($1 == "LABEL") {
		label=$2
		if (auto == "") auto=label
	}
	if ($1 == "KERNEL" || $1 == "COM32") kernel[label]=$2
	if ($1 == "INITRD") initrd[label]=$2
	if ($1 == "APPEND") {
		i=2
		if (kernel[label] ~ "ifmem.c32") multi(3)
		if (kernel[label] ~ "c32box.c32") {
			if ($2 == "linux") { kernel[label]=$3; i=4 }
			if ($2 == "ifmem") multi(4)
		}
		if (kernel[label] ~ "ifcpu64.c32") { auto=$4; next }
		while (i <= NF) {
			if ($i ~ "^initrd=") initrd[label]=substr($i,8)
			else cmdline[label]=cmdline[label] " " $i
			i++
		}
	}
}
END {
	print "KERNEL=\"" kernel[auto] "\""
	print "INITRD=\"" initrd[auto] "\""
	print "CMDLINE=\"" substr(cmdline[auto],2) "\""
	print "SIZES=\"" sizes "\""
}'
}

locase()
{
	echo "$1" | tr [A-Z] [a-z]
}

ifmemcode()
{
	uudecode <<EOT
begin-base64 644 -
gUwQIIBmYLkaAGoA4vxmYYnnsRS4IOhmulBBTVPNFWYZwnUM/00QdQMDbQoJ
23Xgg8QUwe0EdQi0iM0VlcHtCkXoAABfvu4Bra+DwAQ4BHYIOa0YAHbyiARm
Ycs=
====
EOT
}

floppyset()
{
	gotcdfile 'isolinux.cfg'
	$0 include $file | parse_isolinux > /tmp/var$$
	. /tmp/var$$
	[ -z "$KERNEL" ] && echo "Can't parse isolinux.cfg" && return
	for i in $media/$KERNEL $(dirname $file)/$KERNEL $media/$(locase $KERNEL) \
		 $(dirname $file)/$(locase $KERNEL); do
		i="$(ls $i* | sed q)"
		[ -n "$i" ] && KERNEL=$i && break
	done
	rm -f /tmp/var$$
	[ $(get 514 $KERNEL 4) -eq 1400005704 ] || return
	n=$(($(get 497 $KERNEL 1)+1))
	ddq bs=512 count=$n if=$KERNEL of=/tmp/fd$$
	uudecode <<EOT | ddn of=/tmp/fd$$
begin-base64 644 -
v8adaACQF4n8FgcxwLk7APOqWx+g8X1AD6H6xXd4XwZXvQAAsQbzpRYfZGaP
R3jGRfg/l1hB6C4BvgACgUwQIIDGRCWb6IYBMfYLN3Q3x0f+P6PoewGwIOhL
ASwYc/lO6FEBPAh0A4gErTk3dPLoNQE8CnXhiHz+Fge/AICJ/oc3tQLzpFuJ
5v9IEMdAFAiTgPMIdfO79AGxBaEVAmaLH2ZLZtPrZkOJRBtmv4AAAABmKfuc
cwIB31dQU1Yx22gAgAfokQBeW4zBtIcWB80VWF/R5wH4EEwfnXfMuQkCv+4B
ix2DBQTTbRB0GAnbdCm0iM0VPQCwcgaIbB+IbS2hGQLrmlNmi1/8ZgFdLi7G
BnB93Fs6XQJyheMWl80T6gAAIJBaOMh2NrAAYM0T+ehyAGFSUCjIdwKwATn4
cgKJ+FC0As0TWlhy2pUB0Y7pANcA1ynXWnRMjOmVOMF11IjIsQEwznXM/sWA
/VB1xbUAYL7hAVPoWwBbifXoOAB1HP4Mi0w1dJNSmM0TuAECzRNa0NQ6Zv51
40VIdd8MIDxidODrjrAxHAO0DrsHAM0QPA1087Miw79sBGTGBaa4DQFkOiV0
Cs0WdPSYzRaO50fDA3QOsA3o0P+sPAB/+MNCIG9yIE5leHQhBw0AFAAAAADq
Ae4=
====
EOT
	pos=$((n*512))
	if [ -n "$CMDLINE" ]; then
		echo -n "$CMDLINE" | ddq bs=512 count=1 conv=sync >> /tmp/fd$$
		bytes2bin $n | ddn bs=1 seek=497 of=/tmp/fd$$
		words2bin $pos | ddn bs=1 seek=34 of=/tmp/fd$$
		[ $(get 518 $KERNEL 4) -ge 514 ] &&
		words2bin 32768 9 | ddn bs=1 seek=552 of=/tmp/fd$$
	fi
	syssize=$(echo $(get 500 /tmp/fd$$ 4))
	ddq bs=512 skip=$n if=$KERNEL | cat - /dev/zero | \
	ddq bs=512 count=$(((syssize+31)/32)) conv=sync >> /tmp/fd$$
	base=$(size /tmp/fd$$)
	len=
	if [ "$INITRD" ]; then
		l=0
		for i in ${INITRD//,/ }; do
			for j in $media/$i $(dirname $KERNEL)/$i $media/$(locase $i) \
				 $(dirname $KERNEL)/$(locase $i); do
				j="$(ls $j* | sed q)"
				[ -n "$j" ] && i=$j && break
			done
			ddq if=$i >> /tmp/fd$$
			l=$((l+$(size $i)))
			r=$((4 - (l % 4)))
			if [ $r -ne 4 ]; then
				ddq if=/dev/zero bs=1 count=$r >> /tmp/fd$$
				l=$((l + r))
			fi
			case "$i:$INITRD" in
				*rootfs.gz:*rootfs.gz,*) continue	# loram
			esac
			len="$len $l"; l=0
		done
		rdadrs=${RDADRS:-$((((syssize*16)+0x1F0000) & -4096))}
		quads2bin $rdadrs | ddn bs=1 seek=536 of=/tmp/fd$$
	fi
	n=$(echo $len | wc -w)
	if [ $((494 - $(get 494 /tmp/fd$$))) -ge $((n * 4)) ]; then
		i=$(($(get 494 /tmp/fd$$)))
		bytes2bin $((i + (n*4) - 256)) | ddn bs=1 \
			seek=496 of=/tmp/fd$$
	else
		i=$((pos + 0x1FC - (n*4)))
		bytes2bin $((i % 256)) $((i / 256)) 252 | ddn bs=1 \
			seek=494 of=/tmp/fd$$
		s=$((i - 2*$(echo "$SIZES" | wc -w)))
		p=$((s - $(ifmemcode | wc -c)))
		ifmemcode | ddn bs=1 seek=$p of=/tmp/fd$$
		words2bin $SIZES | ddn bs=1 seek=$s of=/tmp/fd$$
		bytes2bin 154 $((p%256)) $((p/256)) 0 144 | \
		ddn bs=1 seek=60 of=/tmp/fd$$
	fi
	for r in $len ; do
		quads2bin $r | ddn bs=1 seek=$i of=/tmp/fd$$
		i=$((i + 4))
	done
	split -b 1440k /tmp/fd$$ fd$$
	rm -f /tmp/fd$$
	n=1; i=0; r=0
	set -- $len
	ls fd$$* | while read file ; do
		if [ $i -ge $(($1+base)) ]; then
			base=$(($1+base-i))
			shift
			r=$((r+100)); n=0; i=0
		fi
		ddq of=$file bs=18k seek=80 count=0
		i=$((i+1474560))
		printf "mv %s fd%03d.img\n" $file $((r+n))
		n=$((n+1))
	done | sh
	du -ch $PWD/fd???.img
}

quit()
{
	umount -d $media
	rmdir $media
	${1:-exit}
}

infoiso()
{
	isoinfo -d -i "$ISO" > /tmp/isoinfo$$ 2> /dev/null
	if [ "$(which iso2exe)" ]; then
		echo "----"
		blkid "$ISO" | while read args; do
			set -- $args
			while [ -n "$2" ]; do
				case "$2" in
				*UUID*|PT*) echo $2;;
				esac
				shift
			done
		done
		if ! fdisk -l "$ISO" | grep -q 'valid partition'; then
			fdisk -l "$ISO" | grep heads
			fdisk -l "$ISO" | sed 's/^ *[^ ]* *//;s/  */ /g;$!d'
		fi
		echo "----"
		iso2exe -l "$ISO"
	fi >> /tmp/isoinfo$$
	if [ "$1" ]; then
		cat /tmp/isoinfo$$
	else
		$DIALOG --clear --title " Info ISO " \
			--textbox /tmp/isoinfo$$ 0 0
		files=$(sed '/^custom.*d/!d;s| .*||' /tmp/isoinfo$$)
		if [ "$files" ]; then
			$DIALOG --clear --title " Extract custom files " \
				--defaultno --yesno \
				"Do you want to extract the custom boot files ?\n$files" 7 70
			[ $? -eq 0 ] && for i in $files ; do
				echo "Extract $i ..."
				iso2exe -l "$ISO" $i
			done
		fi
	fi
	rm -f /tmp/isoinfo$$
}

isotitle()
{
	echo "$(blkid "$ISO" | sed 's/.*LABEL="\([^"]*\).*/\1/')  $(stat \
		-c %y $media/.|sed 's/ .*//')  $(basename "$ISO")"
}

	if [ $0 = /init.exe ]; then

case "${ISO##*/}$(getarg mode)" in
*install*|*INSTALL*)	install;;
*live*|*LIVE*)		live;;
*text*|*TEXT*)		text;;
esac
dmesg > /tmp/dmesg

	else

if [ "$1" = "include" ]; then
	[ -s "$2" ] && cd $(dirname "$2") && awk -v exe=$0 \
	'{ if ($1 == "include") system(exe " include " $2); else print }' <"$2"
	exit
fi
ISO="${1:-/dev/null}"
while [ -L "$ISO" ]; do
	media="$(readlink "$ISO")"
	case "$media" in
	/*) ISO="$media" ;;
	*)  ISO="$(dirname "$ISO")/$media" ;;
	esac
done
[ "${ISO:0:1}" != "/" ] && ISO="$(cd $(dirname "$ISO"); echo $PWD/$(basename "$ISO"))"
[ -z "$(isiso 2> /dev/null)" ] && echo "Usage : $0 file.iso" && exit 1
media=/tmp/media$$
mkdir -p $media
mount -o loop,ro "$ISO" $media

if [ "$2" = "list" ]; then
	sed '/^\$(.*") \\/!d;s/^\$(\(.*\)").*/\1"/' $0 | while read line; do
		eval $line
		echo
	done | sed '/^$/d;/"usbkey"/d'
	quit
fi
if grep -q "^$2()" $0; then
	exe=$2
	shift 2
	if [ -n "$(eval $(grep "\"$exe\"" $0 | sed \
		   '/^\$/!d;s/.(\(.*\)[\t ]*".*"[\t ]*".*/\1/'))" ]; then
		isotitle
		grep "\"$exe\"" $0 | sed '/^\$/!d;s/.*"[\t ]*"\(.*\)".*/\1/'
		echo ----
		$exe "$@"
	fi
	quit
fi
	fi

while true; do
	keymap="$(cat /etc/keymap.conf 2>/dev/null)"
	locale="$(sed '/^LANG=/!d;s/.*=//' /etc/locale.conf 2>/dev/null)"
	cat > /tmp/dialog$$ <<EOT
$DIALOG  --clear --title " $(isotitle) " --menu "" 0 0 0 \
$(initxfile tazkeymap	"tazkeymap"	"Select keyboard (${keymap:-none})") \
$(initxfile tazlocale	"tazlocale"	"Select locale (${locale:-none})") \
$(initx			"live"		"Linux RAM boot (full desktop)") \
$(initx			"text"		"Linux RAM boot") \
$(cdfile 'README*'	"readme"	"Show the README file") \
$(gotcustomconf		"getcustomconf"	"Get custom config") \
$(noinit		"setcustomconf"	"Set custom config") \
$(gotisomd5		"isomd5"	"Check the ISO image") \
$(cdfile 'md5sum*'	"md5"		"Check the ISO files") \
$(cdfile 'sha*sum*'	"sha"		"Check the ISO files") \
$(menuitem		"filepos"	"File start sector") \
$(xfile 'isoinfo iso2exe'	"infoiso"	"ISO image info") \
$(cdfilex 'bzImage*'	"bootiso"	"Boot the ISO image") \
$(burnable		"burniso"	"Burn the ISO image") \
$(blankable		"blankcd"	"Blank the CD/DVD") \
$(gotposixovl		"install"	"Hard disk installation (UMSDOS way)") \
$(gotposixovl		"installtaz"	"Hard disk installation (TAZUSB way)") \
$(gotposixovlzip	"inst2zip"	"ZIP installation archive (UMSDOS way)") \
$(gotposixovlzip	"insttaz2zip"	"ZIP installation archive (TAZUSB way)") \
$(gottazusb 		"usbkey"	"USB key read/write installation") \
$(ishybrid		"usbbootkey"	"USB boot key (kernel not upgradable)") \
$(hasflavinfo		"showfavinfo"	"Show flavor extra info") \
$(hasflavor		"flavor"	"Get flavor file") \
$(cdfile isolinux.cfg	"floppyset"	"Boot floppy set") \
$(cdfile linld.com	"tazboot"	"Get tazboot.exe Linux loader for DOS") \
$(cdexe 'bzImage*'	"bzimage"	"Get linux DOS/EXE file") \
$(cdexe 'memtest*'	"memtest"	"Get Memtest86 DOS/EXE file") \
$(cdfilef 'memtest*'	"fdmemtest"	"Create a Memtest86 boot floppy") \
$(cdexe '?pxe*'		"pxe"		"Get SliTaz Web boot DOS/EXE utility") \
$(cdfilef '?pxe*'	"fdpxe"		"Create a SliTaz Web boot floppy") \
$(cdexe 'plop*'		"plop"		"Get USB boot DOS/EXE utility") \
$(cdfilef 'plop*'	"fdplop"	"Create a USB boot floppy") \
$(initxfile reboot	"restart"	"Restart the computer") \
$(initxfile poweroff	"stop"		"Power off") \
$(initx			"bootlog"       "Linux boot messages") \
$(initx			"shell"         "Shell prompt") \
$(noinitmisspkg		"missing"	"Install packages to get more options") \
$(noinit		"quit"		"Quit this utility")
EOT
	exec 3>&1
	value=$(. /tmp/dialog$$ 2>&1 1>&3)
	retval=$?
	exec 3>&-
	rm -f /tmp/dialog$$
	[ $retval -ne 0 ] && [ $0 != /init.exe ] && quit
	$value
done
