#!/bin/sh
# ============================================================================
#
# This file is part of the 'Entware-ng' package
# 
# This program is free software; you can redistribute it and/or modify it 
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# Author: Mijzelf <Mijzelf@live.com>
#
# ============================================================================
PKG_NAME="Entware-ng"
THIS_SCRIPT="Entware-ng"
PKG_FIRMWARE=4

############################################################
## Check if we are in upgradig mode. From the point of view of the package
## an upgrade is a uninstall followed by a install. So if you want to preserve
## something over an upgrade, you have to detect it somehow
##
## Function sets PKG_UPGRADE > 0 when upgrading, 
## and PKG_UPGRADE=0 when not
############################################################
IsUpgrading()
{
	PKG_UPGRADING=0
	local dir=
	for dir in "/usr/local/zy_pkgs/" "/i-data/.system/zy-pkgs/"
	do
		local logfile=${dir}tmp/zypkg.log
		[ ! -f ${logfile} ] && continue

		local lastupdate=` grep "Upgrade Mode" ${logfile} | tail -n 1 | grep "\[${PKG_NAME}\]" | awk -v OFS=' ' '{print $1, $2}' `

	        [ "${lastupdate}" = "" ] && return 1

		local since1970=` TZ=GMT date -d "${lastupdate}" +%s `
		local now=`date +%s `
		local ago=""
		let ago=now-since1970
		[ $ago -eq 0 ] && ago=1
		[ 300 -gt $ago ] && PKG_UPGRADING=$ago && return 0

		return 1
	done

	# We shouldn't be here
	return 1
}

#############################################################
## Internal function of Log. Find parent, and print cmdline of process 
#############################################################
FindParent()
{
	local id=${1}
	[ $id -eq 1 ] && return # process 1 is the root of all processes

	local ppid=` grep PPid /proc/$id/status | awk '{ print $2 }' `
	FindParent $ppid

	local cmdline=` cat /proc/$id/cmdline | tr '\0' ' ' `
	echo ${id}${INDENT}${cmdline}
	INDENT="${INDENT}*"
}

#############################################################
## Write some useful log to /tmp/.log. -if it exists
#############################################################
Log() 
{
	[ ! -f /tmp/${PKG_NAME}.log ] && return

	if [ "$1" = "bare" ] ; then
 		shift
		echo "${THIS_SCRIPT}: $@" >>/tmp/${PKG_NAME}.log
		return
	fi

	exec 3>&1 ; exec 4>&2 ; exec >>/tmp/${PKG_NAME}.log 2>/dev/null
	echo "#######################################"
	echo "## Script: ${THIS_SCRIPT}"
	echo "#######################################"
	echo -e "\tTime: ` date +%T `"
	[ "$1" != "" ] && echo -e "\tMessage: $@"
	echo -e "\tCall stack"
	INDENT="*"
	local tmpfile=/tmp/$$.${PKG_NAME}
	FindParent $$ >$tmpfile
	unset INDENT
	local line
	while read line
	do
	    echo -e "\t\t${line}" | tr '*' '\t'
	done <$tmpfile
	rm $tmpfile
	echo -e "\tCurdir: ` pwd `"
	[ -h $0 ] && echo -e "\tSymlink: $0 is a symlink to ` readlink $0 `"
	echo -e "\tEnvironment"
	printenv >$tmpfile
	while read line 
	do
	    echo -e "\t\t${line}"
	done <$tmpfile
	rm $tmpfile
	exec 2>&4 ; exec 4>&- ; exec 1>&3 ; exec 3>&-
}

######################################
## Find the IP address of the box
FrameworkGetIPAddress()
{
	# Detect interfaces
	local interfaces=` ifconfig | grep -e "^egiga" -e "^bond" -e "^eth" | cut -d ' ' -f 1 `

	# And find the IP (v4) address
	for interface in $interfaces
	do
		local address=` ifconfig ${interface} | grep "inet addr" | tr -s ' ' `
		if [ "${address}" != "" ] ; then
			echo ${address} | cut -d ' ' -f 2 | cut -d ':' -f 2
			return
		fi
	done
	hostname # What else?
}

#####################################
## Echo the URL of the package
FrameworkGetLink()
{
	# Do we have a webinterface at all?
	[ ! -d ${PKG_ROOT}/gui/${PKG_NAME}/ ] && exit 0

	local address=` FrameworkGetIPAddress `

	# Seach for configured ports
	local ports=
	for directory in /etc/pkg_service_conf /etc/service_conf
	do
		[ ! -d ${directory} ] && continue

		ports=` grep "^Listen" ${directory}/httpd_zld*.conf | awk '{ print $2 }' `
		ports="$ports ` grep "^<VirtualHost" ${directory}/httpd_zld*.conf | cut -d ':' -f 2 | cut -d '>' -f 1 `"
		ports=` echo $ports | tr -s ' ' | tr ' ' '\n' | sort | uniq | grep -v 8082 `
		break
	done

	for port in $ports
	do
		# Find out if it's https:
		protocol=http
		defaultport=80
		grep -i "^<VirtualHost.*${port}" -A 50 ${directory}/httpd_zld*.conf >/tmp/.$$.${PKG_NAME}

		while read line
		do
			if echo $line | grep -i "^</VirtualHost" >/dev/null
			then
				break
			fi

			if echo $line | grep -i "SSLEngine *On" >/dev/null
			then
				protocol=https
				defaultport=443
			fi
		done </tmp/.$$.${PKG_NAME}
		rm /tmp/.$$.${PKG_NAME}

		[ ${defaultport} -eq 443 ] && continue # Package manager crashes on https :$


		[ $port -eq $defaultport ] && port="" || port=":${port}"

		local url="${protocol}://${address}${port}/pkg/${PKG_NAME}/"

		echo  $url
		# We can only output a single url
		return
	done
}

######################################
## Status get and set
FrameworkStatus()
{
	local pkg_config_file="${PKG_ROOT}/config/${PKG_NAME}/config"
	if [ "get" = "$1" ] ; then
		if [ ! -f ${pkg_config_file} ] ; then
			FrameworkStatus set Disabled
		fi
		cat ${pkg_config_file}
		return
	elif [ "set" = "$1" ] ; then
		mkdir -p ` dirname ${pkg_config_file} `
		
		echo $2 >${pkg_config_file}
	fi
}

################################################
## Run or stop the package
FrameworkRun()
{
	if [ $1 -eq 1 ] ; then
		# Startup
		STATUS=` FrameworkStatus get `
		[ "$STATUS" != "Enabled" ] && return	# We're not enabled

		# Do we have a webinterface?
		if [ -d ${PKG_ROOT}/gui/${PKG_NAME}/ ] ; then
			# Aparently 
			for httpdconf in /etc/pkg_service_conf/httpd_package2.conf
			do
				[ ! -f ${httpdconf} ] && continue
				
				local service_conf=` dirname $httpdconf `

				echo Alias /pkg/${PKG_NAME}/ ${PKG_ROOT}/gui/${PKG_NAME}/ >${service_conf}/${PKG_NAME}.conf
				if ! grep ${PKG_NAME}.conf ${httpdconf} >/dev/null
				then
					sed -i "1iInclude ${service_conf}/${PKG_NAME}.conf" ${httpdconf}
				fi

				# Let the package manager restart the server
				touch /tmp/restart_httpd
				break
			done

		fi

		[ ! -f /lib/ld-linux.so.3 -a -f /lib/ld-linux-armhf.so.3 ] && ln -s ld-linux-armhf.so.3 /lib/ld-linux.so.3 

		Startup
		return
	fi

	Shutdown
	
	for httpdconf in /etc/pkg_service_conf/httpd_package2.conf
	do
		[ ! -f ${httpdconf} ] && continue
		grep -v ${PKG_NAME}.conf ${httpdconf} >/tmp/$$.httpd.conf
		mv /tmp/$$.httpd.conf ${httpdconf}
		touch /tmp/restart_httpd
	break
	done

}

FrameworkVersion()
{
	local controlfile=${PKG_ROOT}/zypkg_conf/info/${PKG_NAME}.control
	local version=$( grep "^Version:" ${controlfile} | awk -F"zypkg" '{print $2}' )
	exit $version
}

FrameworkParseParams()
{
	case $1 in
		getlink)
			FrameworkGetLink
			;;
		status)
			FrameworkStatus get
			;;
		enable)
			FrameworkStatus set Enabled 
			FrameworkRun 1
			;;
		disable)
			FrameworkRun 0
			FrameworkStatus set Disabled 
			;;
		startup)
			FrameworkRun 1
			;;
		shutdown)
			FrameworkRun 0
			;;
		version)
			FrameworkVersion
			;;
	esac
}

Log

PKG_ROOT="/usr/local/zy-pkgs"


# ========================================
# function RotateLogfile
# Arguments: directory logfile
# Rotates logfile, compresses old versions
# ========================================
RotateLogfile()
{
    logpath=$1

    oldlog=${logpath}.9.gz
    if [ -r ${oldlog} ] ; then
        echo rm ${oldlog}
        rm ${oldlog}
    fi

    for nr in 8 7 6 5 4 3 2 1
    do
        oldlog=${logpath}.${nr}.gz
        if [ -r ${oldlog} ] ; then
	    newnr=`expr $nr + 1`
	    newlog=${logpath}.${newnr}.gz
	    echo mv ${oldlog} ${newlog}
	    mv ${oldlog} ${newlog}
	fi
    done
    
    if [ -r ${logpath} ] ; then
	cat ${logpath} | gzip -c >${oldlog}
	rm ${logpath}
    fi
}

# =========================================
# function FilterLogfile
# 
# Is placed in stdout to create a pretty logfile
# with timestamps and indents
#=========================================
FilterLogfile()
{
        local logfile=$1
	local pipe=$2
	local tempfile=$3

	if [ -f $logfile ] ; then
	    exec >>$logfile
	    echo "Reopened logfile at $( date )"
	else
	    exec >$logfile
	    echo "Opened logfile at $( date )"
	fi
    
	if [ "$tempfile" != "" ] ; then
	    echo "Flushing memory buffer"
	    while read line 
	    do
		echo "    ${line}"
	    done <$tempfile
	    rm $tempfile
	    echo "Flushing done"
	fi
    
	local indent=""
    
	while read line 
	do
		if [ "${line:0:3}" = "+++" ] ; then
			case "${line:3}" in
				Indent*)
					if [ "${line:9:1}" = "+" ] ; then
						indent="    $indent"
					else
						indent="${indent:4}"
					fi
					;;
				Move*)
					local moveto=${line:8}
					echo "[$( date +"%T" )] Move logfile from ${logfile} to ${moveto}"
					mkdir -p $( dirname ${moveto} )
					[ -f ${moveto} ] && RotateLogfile ${moveto} 
					exec 1>&-
					mv ${logfile} ${moveto}
					[ $? -eq 0 ] && logfile=${moveto} || echo Move failed. >>${logfile} 
					exec 1>>${logfile}
					;;
				Append*)
					local appendto=${line:10}
					echo "[$( date +"%T" )] Append logfile ${logfile} to ${appendto}"
					mkdir -p $( dirname ${appendto} )
					exec 1>&-
					cat ${logfile} >>${appendto}
					if [ $? -eq 0 ] ; then
					    rm ${logfile}
					    logfile=${appendto}
					else
					    echo Append failed. >>${logfile} 
					fi
					exec 1>>${logfile}
					
			esac
			
			continue
		fi
	
		echo "[$( date +"%T" )] ${indent}${line}"
		
	done <$pipe

	echo Closed logfile at $( date )
	rm $pipe
	exit 0
}

#===============================================
# function OpenLogfile
#
# Open or close a logfile. An open logfile is routed
# through FilterLogfile
#===============================================
OpenLogfile()
{
	[ "$1" = "" ] && return

	if [ "$1" = "-" ] ; then
		exec 1>&3
		exec 3>&-
		exec 2>&4
		exec 4>&-
		rm /tmp/Entware-ng*.pipe
		return
	fi

	mkdir -p $( dirname ${1} )

	exec 3>&1
	exec 4>&2

	if [ "$2" != "" ] ; then
		# First opening
		exec 2>&1 1>>$2
		RotateLogfile $1
	fi

	local pipe=/tmp/Entware-ng.$$.pipe
	mknod ${pipe} p

	filter=FilterLogfile
	[ "${3}" != "" ] && filter="${3} filter"
	
	${filter} ${1} $pipe ${2} 3>&- 4>&- &
	
	exec 1>${pipe} 2>&1
}

PKG_OLDKERNEL=0

Install()
{
	for folder in usr bin etc/init.d lib/opkg sbin share tmp var/lock var/run
	do
		if [ -d "/opt/$folder" ]
		then
			echo "Warning: Folder /opt/$folder exists!"
			echo "Warning: If something goes wrong please clean /opt folder and try again."
		else
			mkdir -p /opt/$folder
		fi
	done

	echo "Info: Opkg package manager deployment..."
	local CURARCH="armv5"
	
	if [ ${PKG_OLDKERNEL} -eq 0 ] ; then
		# ArmV7 on oldkernel should use Armv5 old kernel libs
		# Didn't compile the Armv7 variants
	
		if uname -a | grep armv7 >/dev/null
		then
			CURARCH="armv7"
		fi
	fi
	
	local DLOADER="ld-linux.so.3"
	local URL=http://pkg.entware.net/binaries/$CURARCH/installer
	local MIJZELF_URL=http://downloads.zyxel.nas-central.org/Users/Mijzelf/Entware-ng/binaries/${CURARCH}
	
	wget $URL/opkg -O /opt/bin/opkg
	chmod +x /opt/bin/opkg
	wget $URL/opkg.conf -O /opt/etc/opkg.conf
	wget $URL/libgcc_s.so.1 -O /opt/lib/libgcc_s.so.1

	local OKV=""
	if [ $PKG_OLDKERNEL -eq 1 ] ; then
		URL=${MIJZELF_URL}/installer
		OKV="-2.6.24"
	fi
	
	wget $URL/ld-2.22.so${OKV} -O /opt/lib/ld-2.22.so
	wget $URL/libc-2.22.so${OKV} -O /opt/lib/libc-2.22.so
		
	cd /opt/lib
	chmod +x ld-2.22.so
	ln -s ld-2.22.so $DLOADER
	ln -s libc-2.22.so libc.so.6
	
	echo "Info: Basic packages installation..."
	sed -i "2isrc/gz Mijzelf ${MIJZELF_URL}" /opt/etc/opkg.conf
	/opt/bin/opkg update
	
	[ $PKG_OLDKERNEL -eq 1 ] && /opt/bin/opkg install kernel-2.6.24-support
	/opt/bin/opkg install libc
	[ -x /opt/sbin/kernel-2.6.24-support.sh ] && /opt/sbin/kernel-2.6.24-support.sh
	/opt/bin/opkg install libpthread
	[ -x /opt/sbin/kernel-2.6.24-support.sh ] && /opt/sbin/kernel-2.6.24-support.sh
	/opt/bin/opkg install entware-opt

	# entware-opt overwrites our 2.6.24 support, so restore it
	[ -x /opt/sbin/kernel-2.6.24-support.sh ] && /opt/sbin/kernel-2.6.24-support.sh

	/opt/bin/opkg install profile-hook
	
	if [ ! -f /opt/usr/lib/locale/locale-archive ]
	then
    		wget http://pkg.entware.net/binaries/other/locale-archive -O /opt/usr/lib/locale/locale-archive
	fi

	echo "Info: Congratulations!"
	echo "Info: If there are no errors above then Entware-ng was successfully initialized."
	echo "Info: Found a Bug? Please report at https://github.com/Entware-ng/Entware-ng/issues"
}

Startup()
{
	local optdir=${PKG_ROOT}/opt
	local tmplog=/tmp/${PKG_NAME}.$$.log
	echo "Starting up" >$tmplog

	if [ -x ${optdir}/redirect.sh ] ; then
		local alternate=$( ${optdir}/redirect.sh )
		if [ -d ${alternate} ] ; then
			optdir=${alternate}
			echo "/opt redirected to ${optdir}" >>$tmplog
		fi
	fi

	mkdir -p ${optdir}/var/log
	OpenLogfile ${optdir}/var/log/Entware-ng.log $tmplog

	[ -h /opt ] && rm /opt
	[ -d /opt ] && echo "FATAL: /opt is a directory" && OpenLogfile "-" && exit 0
	[ -f /opt ] && mv /opt "/opt.$( date )"
	
	echo "Create symlink /opt -> ${optdir}"
	ln -s ${optdir} /opt

	local starter=/opt/etc/init.d/rc.unslung

	if [ ! -f ${starter} ] ; then
		echo "${starter} is not available, start installer"
		echo "+++Indent+"
		mkdir -p ${optdir}
		chmod 755 ${optdir}
		Install
		if [ $? -ne 0 ] ; then
		    	OpenLogfile -
			return
		fi
		echo "+++Indent-"
	fi
			
	[ -x /opt/sbin/kernel-2.6.24-support.sh ] && /opt/sbin/kernel-2.6.24-support.sh

	echo "Execute ${starter} start"
	echo "+++Indent+"
	${starter} start	
	echo "+++Indent-"
	echo "Done ${starter} start"
    	OpenLogfile -
}

Shutdown()
{
	OpenLogfile /opt/var/log/Entware-ng.log
	
	local starter=/opt/etc/init.d/rc.unslung
	echo "Execute ${starter} stop"
	echo "+++Indent+"
	${starter} stop
	echo "+++Indent-"
	echo "Done ${starter} stop"

	OpenLogfile -
}


FrameworkParseParams "$@"

exit 0
