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

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 [ "$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
			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]

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


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
    -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"
    -v                display version

Examples:
    sb2-init ARM arm-linux-gcc
    sb2-init -m maemo 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
}


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=$SBOX_INIT_TIME
SBOX_INIT_ID="$SBOX_INIT_ID"

export SBOX_CONFIG_VERSION=5
export SBOX_TARGET_ROOT=$SBOX_TARGET_ROOT
export SBOX_CPU=$ARCH
export SBOX_GCC_TARGET=$GCC_TARGET
export SBOX_CPUTRANSPARENCY_METHOD="$CPUTRANSP"
export SBOX_UNAME_MACHINE=$ARCH

export SBOX_DEFAULT_GCC_PREFIX=$GCC_PREFIX

export SBOX_CROSS_GCC_NAME=cross-gcc
export SBOX_CROSS_GCC_PREFIX_LIST=$GCC_TARGET-:$ARCH-linux-:$GCC_PREFIX
export SBOX_CROSS_GCC_SUBST_PREFIX=$GCC_PREFIX
export SBOX_CROSS_GCC_SPECS_FILE=
export SBOX_CROSS_GCC_DIR=$GCC_PATH
export SBOX_CROSS_GCC_LD_ARGS=
export SBOX_EXTRA_CROSS_COMPILER_ARGS="$SBOX_EXTRA_CROSS_COMPILER_ARGS"
export SBOX_EXTRA_CROSS_COMPILER_STDINC="$SBOX_EXTRA_CROSS_COMPILER_STDINC"
export SBOX_EXTRA_CROSS_LD_ARGS="-rpath-link $SBOX_TARGET_ROOT/usr/lib:$SBOX_TARGET_ROOT/lib"

export DEB_BUILD_ARCH_CPU=$DEBIAN_CPU
export DEB_BUILD_ARCH=$DEBIAN_CPU
export DEB_BUILD_GNU_CPU=$ARCH
export DEB_BUILD_GNU_TYPE=$ARCH-linux-gnu

export DEB_HOST_ARCH_CPU=$DEBIAN_CPU
export DEB_HOST_ARCH=$DEBIAN_CPU
export DEB_HOST_GNU_CPU=$ARCH
export DEB_HOST_GNU_TYPE=$ARCH-linux-gnu

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

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

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

export SBOX_TOOLS_ROOT=$TOOLS_ROOT
export SBOX_REDIR_LD_SO=$REDIR_LD_SO
export SBOX_REDIR_LD_LIBRARY_PATH=$REDIR_LD_LIBRARY_PATH
if [ -n "\$SBOX_TOOLS_ROOT" ]; then
	export 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:\$SBOX_REDIR_LD_LIBRARY_PATH:\$LD_LIBRARY_PATH
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  $REMOTEHOST
  nfs   $LOCALHOST:$SBOX_TARGET_ROOT  /  rw,nolock,noac,tcp
  nfs   $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
}

export SBOX_DIR=$(readlink -f $(dirname $_)/..)

# SBOX_INIT_* variables are used to record who initialized, and when and 
# how sb2 was initialized.
# It is possible to set SBOX_INIT_ID externally (for example, if
# another program is used to initialize the system)
SBOX_INIT_ORIG_ARGS="$*"
SBOX_INIT_TIME=`date +%Y-%m-%d_%H:%M:%S`
if [ -z "$SBOX_INIT_ID" ]
then
	SBOX_INIT_ID="user '$USER'"
fi

REMOTEHOST=
LOCALHOST=

set_as_default=0
with_libtool=1
skip_checks=false

SBOX_EXTRA_CROSS_COMPILER_ARGS=""

if [ -z "$*" ]; then
	usage
fi

while getopts c:C:r:l:m:dhnst:v foo
do
	case $foo in
	(c) CPUTRANSP=$OPTARG ;;
	(r) REMOTEHOST=$OPTARG ;;
	(l) LOCALHOST=$OPTARG ;;
	(d) set_as_default=1 ;;
	(h) usage ;;
	(m) MAPPING_MODE=$OPTARG ;;
	(n) with_libtool=0 ;;
	(s) skip_checks=true ;;
	(t) TOOLS_ROOT=$OPTARG ;;
	(v) version ;;
	(C) SBOX_EXTRA_CROSS_COMPILER_ARGS="$SBOX_EXTRA_CROSS_COMPILER_ARGS $OPTARG " ;;
	(*) usage ;;
	esac
done
shift $(($OPTIND - 1))

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

TARGET=$1
SBOX_TARGET_ROOT=$PWD
GCC=$2

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

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

GCC_FULLPATH=$(which $GCC)
# test that gcc exists and can be executed
if [ $? != 0 ]; then
	echo "$GCC doesn't exist"
	exit 1
fi
GCC_PATH=$(dirname $(which $GCC))
if [ $GCC -v > /dev/null 2>&1 != 0 ]; then
	echo "Invalid compiler specified: $GCC"
	exit 1
fi

GCC_PREFIX=$(basename $GCC | sed 's/-gcc$/-/')
ARCH=$($GCC -dumpmachine | awk -F- '{ print $1 }')
GCC_TARGET=$($GCC -dumpmachine)
DEBIAN_CPU=$ARCH
if [ -z "$CPUTRANSP" ]; then
	CPUTRANSP="qemu-$ARCH"
fi

case "$ARCH" in
	arm*) 
		echo $GCC_TARGET | grep -q -i eabi
		if [ $? == 0 ]; then
			DEBIAN_CPU=armel
		fi
		;;
	ppc*) ;;
	mips*) ;;
	sh*) ;;
	*)
		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 [ -z "$MAPPING_MODE" ]; then
	MAPPING_MODE="simple"
fi

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


if [ ! $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
	set_as_default=1
fi

if [ -n "$TOOLS_ROOT" ]; then
	if [ -e "$TOOLS_ROOT/etc/scratchbox-version" ]; then
		# this is a scratchbox 1.x directory, tread carefully
		# sb1 is not FHS, *sigh*
		REDIR_LD_SO=\$SBOX_TOOLS_ROOT/host_shared/lib/ld-linux.so.2
		REDIR_LD_LIBRARY_PATH=\$SBOX_TOOLS_ROOT/host_shared/lib:$TOOLS_ROOT/tools/lib:\$LD_LIBRARY_PATH
		TOOLS_ROOT=$TOOLS_ROOT/tools
	else
		# assume standard FHS system
		REDIR_LD_SO=
		REDIR_LD_LIBRARY_PATH=\$SBOX_TOOLS_ROOT/usr/local/lib:\$SBOX_TOOLS_ROOT/usr/lib:\$SBOX_TOOLS_ROOT/lib:\$LD_LIBRARY_PATH
	fi
fi

SBOX_EXTRA_CROSS_COMPILER_STDINC="-I/usr/include"
SBOX_EXTRA_CROSS_COMPILER_ARGS="$SBOX_EXTRA_CROSS_COMPILER_ARGS -L$SBOX_TARGET_ROOT/usr/lib -L$SBOX_TARGET_ROOT/lib"

# test if the cross compiler needs to be silenced about /usr/include
# usage
echo "" | $GCC_FULLPATH -E - -Wno-poison-system-directories > /dev/null 2>&1
if [ $? = 0 ] ; then
	SBOX_EXTRA_CROSS_COMPILER_ARGS="$SBOX_EXTRA_CROSS_COMPILER_ARGS -Wno-poison-system-directories"
fi

HOST_GCC_INC=$(echo "#include <stdio.h>" | gcc -M -E - | 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"};')

SBOX_COMPILER_ROOT=$(readlink -f $SBOX_CROSS_GCC_DIR/..)

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

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

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

if [ $with_libtool == 1 ]; then
	$SBOX_DIR/bin/sb2 -t $TARGET $SBOX_DIR/bin/sb2-build-libtool
	printf "\n\n"
	if [ $? == 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
