#!/bin/bash
# sb2-init - Copyright (C) 2007 Lauri Leukkunen <lle@rahina.org>
# Licensed under GPL version 2

my_path=$_
if [ $(basename $my_path) != $(basename $0) ]; then
	my_path=$0
	if [ $(basename $my_path) = $my_path ]; then
		my_path=$(which $my_path)
	fi
fi

function log_config_action()
{
	tstamp=`/bin/date '+%Y-%m-%d %H:%M:%S'`
	echo "$tstamp	$*" >>$SBOX_CONFIG_DIR/CONFIG-LOG
}

# Get the original arguments that were specified to sb2-init from
function show_existing_config_info()
{
	has_targets="no"
	echo "Already initialized targets:"
	echo
	for f in $HOME/.scratchbox2/*/sb2.config; do
		if [ -f $f ]; then
			SBOX_CONFIG_VERSION=0
			. $f
			has_targets="yes"
			targetdir=`dirname $f`
			targetname=`basename $targetdir`
			echo "Target $targetname:"
			if [ -d "$SBOX_TARGET_ROOT" ]; then
				if [ "$SBOX_CONFIG_VERSION" -lt 5 ]; then
					echo "(configuration file version too old)"
				else
					echo "configured at $SBOX_INIT_TIME by $SBOX_INIT_ID, with command"
					echo "( cd $SBOX_TARGET_ROOT;"
					echo "sb2-init $SBOX_INIT_ORIG_ARGS )"
				fi
			else
				echo "(out of order - target root directory does not exist)"
			fi
			echo
		fi
	done
	if [ has_targets = "no" ]; then
		echo "none."
	fi
}

function usage()
{
	cat <<EOF
sb2-init - initialize a target root for scratchbox2
Usage:
	sb2-init [OPTION]... [TARGETNAME] [COMPILER] [SECONDARY_COMPILER...]

sb2-init is expected to be run in the directory you want
to use as scratchbox 2 target root.

TARGETNAME is what you want to call this target
COMPILER is of the form $HOME/arm-2006q3/bin/arm-linux-gcc
If more than one compiler is specified, the additional compilers
are available by version number (e.g. if the primary is known as
"gcc" and "gcc-4.1", the secondary may be "gcc-3.4", etc)


Options:
    -c "command"      specify cpu transparency command, for example:
                      "qemu-arm", "sbrsh" or "qemu-arm -m 512"
    -r [hostname]     generate sbrsh config using remote device address
    -l [hostname]     NFS server/localhost address seen by remote device
    -d                set target as default scratchbox2 target
    -m [mapping_mode] use mapping_mode as default
    -h                print this help
    -n                don't build libtool for the target
    -N                don't generate localization files for the target
    -s                skip checks for target root's /usr/include etc.
    -t [tools_dir]    set directory containing the build tools distribution
    -C "options"      add extra options for the compiler, for example:
                      "-fgnu89-inline"
    -A arch           manually override target architecture
    -M arch           manually override machine name (see uname(2)). This
                      defaults to the target architecture (see option -A)
    -v                display version

Examples:
    sb2-init -c qemu-arm ARM arm-linux-gcc
    sb2-init -c qemu-arm -m devel ARM arm-linux-gcc
    sb2-init -sn -c sbrsh armel-debian /path/to/arm-linux-gcc

EOF
	show_existing_config_info
	exit 2
}

function version()
{
	cat $SBOX_DIR/share/scratchbox2/version
	exit 0
}

# Create the old-style configuration file.
# TODO: This system will be replaced by smaller configuration files 
# that live in $SBOX_CONFIG_DIR directory.
function write_target_config()
{
	cat - > $HOME/.scratchbox2/$TARGET/sb2.config <<EOF
# Scratchbox2 configuration file generated by sb2-init.

SBOX_INIT_ORIG_ARGS="$SBOX_INIT_ORIG_ARGS"
SBOX_INIT_TIME=$SB2INIT_INIT_TIME
SBOX_INIT_ID="$SB2INIT_INIT_ID"

SBOX_CONFIG_VERSION=10

SBOX_TARGET_ROOT=$SBOX_TARGET_ROOT

SBOX_CPU=$ARCH
SBOX_CPUTRANSPARENCY_METHOD="$SB2INIT_CPUTRANSP"
SBOX_UNAME_MACHINE=$MACHINE_ARCH

DEB_BUILD_ARCH=$SB2INIT_DEB_BUILD_ARCH
DEB_BUILD_ARCH_CPU=$SB2INIT_DEB_BUILD_ARCH_CPU
DEB_BUILD_ARCH_ABI=$SB2INIT_DEB_BUILD_ARCH_ABI
DEB_BUILD_GNU_CPU=$ARCH
DEB_BUILD_GNU_TYPE=$SB2INIT_DEB_BUILD_GNU_TYPE
DEB_BUILD_GNU_SYSTEM=$SB2INIT_DEB_BUILD_GNU_SYSTEM

DEB_HOST_ARCH=$DEBIAN_CPU
DEB_HOST_ARCH_OS=$SB2INIT_DEB_HOST_ARCH_OS
DEB_HOST_ARCH_CPU=$SB2INIT_DEB_HOST_ARCH_CPU

DEB_HOST_GNU_CPU=$ARCH
DEB_HOST_GNU_TYPE=$SB2INIT_DEB_HOST_GNU_TYPE
DEB_HOST_GNU_SYSTEM=$SB2INIT_DEB_HOST_GNU_SYSTEM

SBOX_HOST_GCC_NAME=host-gcc
SBOX_HOST_GCC_PREFIX_LIST=host-
SBOX_HOST_GCC_SUBST_PREFIX=
SBOX_HOST_GCC_SPECS_FILE=
SBOX_HOST_GCC_DIR=/usr/bin
SBOX_HOST_GCC_LD_ARGS=
SBOX_EXTRA_HOST_COMPILER_ARGS="$HOST_GCC_INC"

SBRSH_CONFIG=$HOME/.scratchbox2/$TARGET/sbrsh.config

if [ -z "\$SBOX_MAPMODE" ]; then
	SBOX_MAPMODE=$MAPPING_MODE
fi

SBOX_TOOLS_ROOT=$SB2INIT_TOOLS_ROOT

if [ -n "\$SBOX_TOOLS_ROOT" ]; then
	LD_LIBRARY_PATH=/usr/local/lib:/usr/lib/:/usr/lib64:/lib:/lib64:\$SBOX_TOOLS_ROOT/usr/lib/libfakeroot:\$SBOX_TOOLS_ROOT/usr/lib64/libfakeroot:\$SBOX_TOOLS_ROOT/usr/lib32/libfakeroot:\$LD_LIBRARY_PATH
else
	# SBOX_TOOLS_ROOT not set, include the fakeroot lib path in any case.
	LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:/usr/lib/libfakeroot:/usr/lib64/libfakeroot:/usr/lib32/libfakeroot
fi
EOF
	echo "Finished writing sb2.config"
}

function write_sbrsh_config()
{
	cat - > $HOME/.scratchbox2/$TARGET/sbrsh.config <<EOF
# sbrsh configuration file generated by sb2-init.

$TARGET  $SB2INIT_REMOTEHOST
  nfs   $SB2INIT_LOCALHOST:$SBOX_TARGET_ROOT  /  rw,nolock,noac,tcp
  nfs   $SB2INIT_LOCALHOST:$HOME  $HOME  rw,nolock,noac,tcp
  bind  /tmp      /tmp
  bind  /proc     /proc
  bind  /sys      /sys
  bind  /dev      /dev
  bind  /dev/pts  /dev/pts
EOF
	echo "Finished writing sbrsh.config"
}

function check_buildroot_sanity()
{
	a_ok=1

	if [ ! -e usr/include/stdio.h ]; then
		echo "no usr/include/stdio.h"
		a_ok=0
	fi

	if [ ! -e lib/libc.so.6 ] && [ ! -e lib/libc.so.0 ]; then
		echo "no lib/libc.so.6 or lib/libc.so.0"
		a_ok=0
	fi

	if [ ! -e usr/lib/libc.so ]; then
		echo "no usr/lib/libc.so"
		a_ok=0
	fi
	
	if [ $a_ok == 1 ]; then
		true
	else
		echo "Your buildroot seems to lack basic essentials like headers 
or c-library. You should probably get either a ready rootfs tarball or
copy the necessary files from your toolchain into place. After doing that
you can re-run this script."
		exit 1
	fi
}

function configure_toolchains()
{
	secondary_compiler=""

	if [ -n "$SB2INIT_ARCH" ]; then
		gccconfig_arch_option="-A $SB2INIT_ARCH"
	else
		gccconfig_arch_option=""
	fi
	for compiler_path in $*; do
		log_config_action "sb2-init: configuring toolchain, compiler $compiler_path"
		$SBOX_SHARE_DIR/scripts/sb2-config-gcc-toolchain \
			-v \
			$secondary_compiler \
			$gccconfig_arch_option \
			-R "$SBOX_TARGET_ROOT" \
			-S "$SBOX_DIR" \
			-t "$TARGET" \
			-m "$MAPPING_MODE" \
			-C "$SB2INIT_SBOX_EXTRA_CROSS_COMPILER_ARGS" \
			-- \
			$compiler_path
		if [ $? != 0 ]; then
			log_config_action "sb2-init: failed to configure $compiler_path"
			echo "Failed to configure $compiler_path"
			exit 1
		fi
		secondary_compiler="-V"
	done
}

if [ -z "$SBOX_DIR" ]; then
	SBOX_DIR=$(readlink -f $(dirname $(readlink -f $my_path))/..)
fi
SBOX_SHARE_DIR=$SBOX_DIR/share/scratchbox2

SBOX_INIT_ORIG_ARGS="$*"

# No parameters => show usage and exit.
if [ -z "$SBOX_INIT_ORIG_ARGS" ]; then
	usage
fi

# Parse parameters (round 1); don't write anything to the config directory yet,
# because a) name of the target is currently unknown, b) there might be 
# errors in the parameters, or c) if the user is just requesting help or
# version and we are not actually going to configure anything.
eval `$SBOX_SHARE_DIR/scripts/sb2-parse-sb2-init-args $SBOX_INIT_ORIG_ARGS`

TARGET=$SB2INIT_TARGET
SBOX_TARGET_ROOT=$SB2INIT_TARGET_ROOT

MAPPING_MODE=$SB2INIT_MAPPING_MODE

# ---------- Check parameters

if [ "$SB2INIT_SHOW_USAGE" == 1 -o "$SB2INIT_ERROR" == 1 ]; then
	usage
fi

if [ "$SB2INIT_SHOW_VERSION" == 1 ]; then
	version
fi

if [ "$SB2INIT_LOCALHOST" ] && [ -z "$SB2INIT_REMOTEHOST" ]; then
	echo "Warning: Local host specified without remote host."
fi

if [ -z "$TARGET" ]; then
	echo "Error: no target given"
	exit 1
fi

if [ -z "$MAPPING_MODE" ]; then
	MAPPING_MODE="simple"
	echo "Info: Mapping mode not specified, using default ($MAPPING_MODE)"
fi

if [ ! -d $SBOX_DIR/share/scratchbox2/lua_scripts/pathmaps/$MAPPING_MODE ]; then
	echo "Invalid mapping mode: $MAPPING_MODE"
	exit 1
fi

# ---------- end of parameter checks

mkdir -p $HOME/.scratchbox2/$TARGET

SBOX_CONFIG_DIR=~/.scratchbox2/$TARGET/sb2.config.d 
if [ ! -d $SBOX_CONFIG_DIR ]; then
        mkdir $SBOX_CONFIG_DIR 
fi
log_config_action "sb2-init $SBOX_INIT_ORIG_ARGS"

# Parse parameters (round 2); store parameters to the config directory.
# "$SBOX_CONFIG_DIR/sb2-init-args" can be overwritten by sb2-init or
# sb2-upgrade-config; the config log should identify who did what..
$SBOX_SHARE_DIR/scripts/sb2-parse-sb2-init-args $SBOX_INIT_ORIG_ARGS \
	>$SBOX_CONFIG_DIR/sb2-init-args

if [ -z "$SB2INIT_COMPILERS" ]; then
	echo "Warning: no compiler given"
	ARCH=$SB2INIT_ARCH
else
	configure_toolchains $SB2INIT_COMPILERS
	# get ARCH from the primary gcc config file
	. $HOME/.scratchbox2/$TARGET/sb2.config.d/gcc.config.sh
	ARCH=$SB2_GCC_INIT_ARCH
fi
echo "sb2-init: Target architecture is '$ARCH'"

if [ -z "$SB2INIT_MACHINE_ARCH" ]; then
	MACHINE_ARCH=$ARCH
else
	# forced by a command-line option.
	MACHINE_ARCH=$SB2INIT_MACHINE_ARCH
	echo "sb2-init: Target machine is '$SB2INIT_MACHINE_ARCH'"
fi

DEBIAN_CPU=$ARCH

HOST_ARCH="$(uname -m)"
if echo "$HOST_ARCH" | grep -q "^i.86*"; then
	HOST_ARCH="i[3456]86"
fi
echo "sb2-init: Host architecture is '$HOST_ARCH'"

case "$ARCH" in
	$HOST_ARCH*) ;;

	arm*) 
		# SBOX_GCC_TARGET from gcc.config.sh..
		if [ -z "$SBOX_GCC_TARGET" ]; then
			DEBIAN_CPU=$ARCH
		else
			echo $SBOX_GCC_TARGET | grep -q -i eabi
			if [ $? == 0 ]; then
				DEBIAN_CPU=armel
			fi
		fi
		DEFAULT_CPUTRANSP="qemu-$ARCH"
		;;

	ppc*)	DEFAULT_CPUTRANSP="qemu-$ARCH" ;;
	mips*)	DEFAULT_CPUTRANSP="qemu-$ARCH" ;;
	sh*)	DEFAULT_CPUTRANSP="qemu-$ARCH" ;;

	# No DEFAULT_CPUTRANSP for any of the x86 architectures:
	i386*) ;;
	i486*) ;;
	i586*) ;;
	i686*) ;;
	amd64*) ;;

	*)
		echo "Unsupported target architecture: '$ARCH'"
		echo "You must add support for it into preload/sb_exec.c"
		echo "and utils/sb2-init"
		exit 1
		;;

esac

if [ "$HOST_ARCH" != "$ARCH" -a -z "$SB2INIT_CPUTRANSP" ]; then
	# Host arch. != target arch, and CPU transparency was not specified...

	if [ -z "$DEFAULT_CPUTRANSP" ]; then
		# ...and there is no default CPU transparency method.
		# This may be an error, or may not be: If one has a 64-bit host,
		# but develops for an 32-bit Intel target, the architecture 
		# strings are different but Qemu is not needed.
		echo "sb2-init: WARNING:"
		echo "sb2-init: *******  Host architecture is different than target architecture,"
		echo "sb2-init: *******  but CPU transparency was not set. This may not be what"
		echo "sb2-init: *******  you want (maybe you should run sb2-init again and"
		echo "sb2-init: *******  specify 'qemu-$ARCH' as the CPU transparency method?)"
	else
		# ...try to use the default CPU transparency.
		_cputransp=$(which $DEFAULT_CPUTRANSP)
		if [ -n "$_cputransp" -a -e "$_cputransp" ]; then
			SB2INIT_CPUTRANSP=$_cputransp
		else
			echo "sb2-init: WARNING:"
			echo "sb2-init: *******  default CPU transparency ($DEFAULT_CPUTRANSP) can not"
			echo "sb2-init: *******  be located or executed. Maybe you should run sb2-init "
			echo "sb2-init: *******  again and specify a working CPU transparency method"
			echo "sb2-init: *******  with the '-c' option?"
		fi
	fi
fi

# defaults for SB2_INIT_DEB_BUILD_GNU_TYPE, SB2_INIT_DEB_HOST_GNU_TYPE, etc,
# and the cross-gcc prefix list:
# these may be changed by sb2rc.$MAPPING_MODE
SB2INIT_DEB_BUILD_ARCH=$DEBIAN_CPU
SB2INIT_DEB_BUILD_ARCH_ABI="gnu"
SB2INIT_DEB_BUILD_GNU_TYPE=$ARCH-linux-gnu
SB2INIT_DEB_BUILD_GNU_SYSTEM=""
SB2INIT_DEB_BUILD_ARCH_CPU=$DEBIAN_CPU

SB2INIT_DEB_HOST_GNU_TYPE=$ARCH-linux-gnu
SB2INIT_DEB_HOST_GNU_SYSTEM=""
SB2INIT_DEB_HOST_ARCH_OS="linux"
SB2INIT_DEB_HOST_ARCH_CPU=$DEBIAN_CPU

# $ARCH has been set, get mode-specific settings..
if [ -f $SBOX_DIR/share/scratchbox2/modeconf/sb2rc.$MAPPING_MODE ]; then
	echo "Reading mode-specific settings.."
	. $SBOX_DIR/share/scratchbox2/modeconf/sb2rc.$MAPPING_MODE "initializing"
fi


if [ ! $SB2INIT_SKIP_CHECKS ]; then
	check_buildroot_sanity
fi

mkdir -p $HOME/.scratchbox2

if [ -z "$(sb2-config -l)" ]; then
	# force this as default anyway as there are no
	# other existing targets
	SB2INIT_SET_AS_DEFAULT=1
fi

if [ -n "$SB2INIT_TOOLS_ROOT" ]; then
	if [ -e "$SB2INIT_TOOLS_ROOT/etc/scratchbox-version" ]; then
		# this is a scratchbox 1.x directory, tread carefully
		# sb1 is not FHS, *sigh*
		SB2INIT_TOOLS_ROOT=$SB2INIT_TOOLS_ROOT/tools
	fi
	# else assume standard FHS system
fi

HOST_GCC_INC=$(echo "#include <stdio.h>" | gcc -M -E - | SBOX_DIR=$SBOX_DIR perl -e 'while(<STDIN>) { $foo{$1} = 1 if m/\/usr([^[:space:]]*\/include)/;}; foreach my $k (keys %foo) {print " -isystem $ENV{SBOX_DIR}/share/scratchbox2/host_usr$k"};')

mkdir -p $HOME/.scratchbox2/$TARGET/bin
write_target_config

if [ -n "$SB2INIT_REMOTEHOST" ]; then
	if [ -z "$SB2INIT_LOCALHOST" ]; then
		SB2INIT_LOCALHOST=$(ip -f inet -o addr \
			| awk -- '/: eth[0-9]/ { print $4; exit }' \
			| cut -d/ -f1)
		echo "Using NFS server address: $SB2INIT_LOCALHOST"
	fi
	write_sbrsh_config
fi

if [ $SB2INIT_SET_AS_DEFAULT == 1 ]; then
	sb2-config -d $TARGET
fi

#
# If target architecture is same as host (currently i386)
# we need to extract localization archive from target and
# place resulting files under ~/.scratchbox2/$SBOX_TARGET/locales.
#
# We do the same check for tools here and generate necessary
# localization files if they are missing.
#
if [ $SB2INIT_WITH_LOCALES == 1 ]; then
	if [ -n "$SB2INIT_TOOLS_ROOT" ]; then
		$SBOX_DIR/bin/sb2 -t $TARGET \
		    $SBOX_DIR/share/scratchbox2/scripts/sb2-generate-locales -T
	fi

	if [ -z "$SB2INIT_CPUTRANSP" ]; then
		$SBOX_DIR/bin/sb2 -t $TARGET \
		    $SBOX_DIR/share/scratchbox2/scripts/sb2-generate-locales
	fi
fi

if [ $SB2INIT_WITH_LIBTOOL == 1 ]; then
	echo "sb2-init: configuring libtool for this target:"
	$SBOX_DIR/bin/sb2 -t $TARGET $SBOX_DIR/bin/sb2-build-libtool
	TEST=$?
	printf "\n\n"
	if [ $TEST == 0 ]; then
		echo "sb2-init completed successfully, have fun!"
	else
		echo "Running $SBOX_DIR/bin/sb2-build-libtool failed"
		echo "You can run this manually later, otherwise your"
		echo "sb2 environment is correctly setup and ready to use"
	fi
fi
