#
#script daemon and logging support by nohup
#
#TODO: replace shell scripting by LUA?
#
export LANG=C
export PATH=${PATH}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
#
export SCRIPTLOGFILE=''
#
export ALLARGS="$@"
#
export SCRIPTPID="$$"
#
export SCRIPTTAG="$0"
#
export SCRIPTSELFT="$0"
#
export SCRIPTMARK="$(echo "$SCRIPTSELFT" | tr '/-' '_')"
#
export DAEMONED
#
if [ -z "$TARGETARCH" ]
	then
	TARGETARCH=$(cat /proc/xiaoqiang/model)
fi
#
export TARGETARCH
#
#for debug
#export DAEMONSTDIOFILE="/tmp/daemon/stdio/${SCRIPTMARK}.log"
if [ -z "$DAEMONSTDIOFILE" ]
	then
	DAEMONSTDIOFILE='/dev/null'
fi
export DAEMONSTDIOFILE
#
if [ -z "$DAEMONSYSLOGFILE" ]
	then
	DAEMONSYSLOGFILE='syslog'
	#
	#%##DAEMONSYSLOGFILE=$(cat /etc/config/system 2>/dev/null| grep log_file | awk '{print $3}' | tr -d "'")
	#%##if [ -z "$DAEMONSYSLOGFILE" ]
	#%##then
	#%##	DAEMONSYSLOGFILE='/var/log/messages'
	#%##fi
	#%##basexec mkdir -p $(dirname $DAEMONSYSLOGFILE 2>/dev/null)
fi
#
export DAEMONSYSLOGFILE
#
#ash array support, no lock, no cleanup/gc, use carefully
#
export SCRIPTARRAYDIR="/tmp/arrays/${SCRIPTMARK}/"
#
klogger(){
	local msg="$@"
	test -z "$msg" && return 1
	#echo "$msg"
	echo "$msg" >> /dev/kmsg 2>/dev/null
	return 0
}
logexit(){
	local msg="$@"
	klogger "$msg"
	elog "$msg"
	exit 1
}
basexec(){
	local cmdline="$@"
	test -z "$cmdline" && return 1
	$cmdline
	if [ $? -ne 0 ]
		then
		logexit "ERROR: BASEXEC FAILED: $cmdline, PROC EXITED."
	fi
	return 0
}
#
getdefaultrouteip(){
	echo "$(ip route list | grep '^default via ' | grep -v 'tap' | head -n 1| awk '{print $3}')"
}
getdefaultroutedev(){
	echo "$(ip route list | grep '^default via ' | grep -v 'tap' | head -n 1| awk '{print $5}')"
}
getactivegatewayip(){
	echo "$(ip route list | grep '^default via ' | head -n 1| awk '{print $3}')"
}
getactivegatewaydev(){
	echo "$(ip route list | grep '^default via ' | grep -v 'tap' | head -n 1| awk '{print $5}')"
}
getlanip(){
	echo "`ip route list dev br-lan | head -n1|awk '{print $7}'`"
}
getlanipmask(){
	echo "`ip route list dev br-lan | head -n1|awk '{print $1}'`"
}
lanipwait(){
	lanip='no-ip'
	wcnt=0
	timelimit="$1"
	test -z "$timelimit" && timelimit=30
	lanip=`getlanip`
	#conlog "DEBUG: waiting up to $timelimit seconds for lan ip setup."
	while [ $wcnt -lt $timelimit ]
	do
		lanip=`getlanip`
		if [ -n "$lanip" ]
			then
			break
		fi
		sleep 1
		let wcnt=$wcnt+1
	done
	#
	if [ -z "$lanip" ]
		then
		if [ $timelimit -le 0 ]
			then
			return 1
		fi
		dlog "ERROR: probe lan ip failed: $(/sbin/ifconfig br-lan 2>&1)"
		/sbin/ifconfig | grep -q '^br-lan'
		if [ $? -ne 0 ]
			then
			dlog "WARNING: network interface br-lan no exist."
		fi
		dlog "ERROR: lan ip no configured after $timelimit seconds."
		return 1
	fi
	if [ $timelimit -le 0 ]
		then
		return 0
	fi
	dlog "LAN ip config: $lanip"
	return 0
}
iptexec(){
	local exitcode
	local execline
	local capfile
	local execnt
	execline="$@"
	test -z "$execline" && return 0
	basexec mkdir -p /tmp/logexec/
	capfile="/tmp/logexec/log.$$.$(date -u +%s)"
	exitcode=0
	for execnt in 1 2 3 4 5 6
	do
		$execline > $capfile 2>&1
		exitcode=$?
		if [ $exitcode -ne 0 ]
		then
			cat $capfile 2>/dev/null | grep -iq 'Resource temporarily unavailable'
			if [ $? -ne 0 ]
				then
				break
			else
				sleep 1
			fi
		else
			break
		fi
	done
	if [ $exitcode -ne 0 ]
		then
		dlog "iptexec final: exitcode $exitcode, $execline"
		cat $capfile 2>/dev/null | pipelog dlog
	fi
	rm -f $capfile
	return $exitcode
}
iptsexec(){
	local exitcode
	local execline
	local capfile
	local execnt
	execline="$@"
	test -z "$execline" && return 0
	basexec mkdir -p /tmp/logexec/
	capfile="/tmp/logexec/log.$$.$(date -u +%s)"
	exitcode=0
	for execnt in 1 2 3 4 5 6
	do
		$execline > $capfile 2>&1
		exitcode=$?
		if [ $exitcode -ne 0 ]
		then
			cat $capfile 2>/dev/null | grep -iq 'Resource temporarily unavailable'
			if [ $? -ne 0 ]
				then
				break
			else
				sleep 1
			fi
		else
			break
		fi
	done
	rm -f $capfile
	return $exitcode
}
iptnewchain(){
	local exitcode
	local execline
	local capfile
	local execnt
	execline="$@"
	test -z "$execline" && return 0
	execline="iptables $execline"
	basexec mkdir -p /tmp/logexec/
	capfile="/tmp/logexec/log.$$.$(date -u +%s)"
	exitcode=0
	for execnt in 1 2 3 4 5 6
	do
		$execline > $capfile 2>&1
		exitcode=$?
		if [ $exitcode -ne 0 ]
		then
			#
			cat $capfile 2>/dev/null | grep -iq 'Chain already exists'
			test $? -eq 0 && exitcode=0 && break
			cat $capfile 2>/dev/null | grep -iq 'Resource temporarily unavailable'
			if [ $? -ne 0 ]
				then
				break
			else
				sleep 1
			fi
		else
			break
		fi
	done
	if [ $exitcode -ne 0 ]
		then
		dlog "iptnewchain final: exitcode $exitcode, $execline"
		cat $capfile 2>/dev/null | pipelog dlog
	fi
	rm -f $capfile
	return $exitcode
}
iptremoverule(){
	local exitcode
	local execline
	local capfile
	local execnt
	execline="$@"
	test -z "$execline" && return 0
	execline="iptables $execline"
	basexec mkdir -p /tmp/logexec/
	capfile="/tmp/logexec/log.$$.$(date -u +%s)"
	exitcode=0
	for execnt in 1 2 3 4 5 6 7 8 9 0
	do
		$execline > $capfile 2>&1
		exitcode=$?
		#delete more
		test $exitcode -eq 0 && continue

		cat $capfile 2>/dev/null | grep -iq 'No chain/target/match by that name'
		test $? -eq 0 && exitcode=0 && break

		cat $capfile 2>/dev/null | grep -iq 'Resource temporarily unavailable'
		test $? -ne 0 && break
		#
		#iptables v1.4.10: Couldn't load target `lanuploadtraffic':File not found
		#
		cat $capfile 2>/dev/null | grep -iq 'File not found'
		test $? -ne 0 && exitcode=0 && break

		#other errors
		sleep 1
	done
	if [ $exitcode -ne 0 ]
		then
		dlog "iptremoverule final: exitcode $exitcode, $execline"
		cat $capfile 2>/dev/null | pipelog dlog
	fi
	rm -f $capfile
	return $exitcode
}
#
iptremoveall(){
	iptremoverule $@
	return $?
}
#
killpid(){
	local onepid ksig
	onepid=$1
	ksig=$2
	if [ -z "$onepid" ]
	then
		return 0
	fi
	test -z "$ksig" && ksig=15
	#
	if [ $onepid -le 100 ]
	then
		return 0
	fi
	timelimit=5
	wcnt=0
	while [ : ]
	do
		if [ "$ksig" = '0' ]
			then
			kill -${ksig} $onepid 2>/dev/null
			return $?
		fi
		kill -${ksig} $onepid 2>/dev/null
		test $? -ne 0 && return 0
		let wcnt=$wcnt+1
		test $wcnt -gt $timelimit && break
		sleep 1
	done
	kill -9 $onepid 2>/dev/null
	test $? -eq 0 && return 1
	return 0
	#
}
killpidfile(){
	local pidfile
	pidfile=$1
	if [ -z "$pidfile" ]
	then
		return 0
	fi
	if [ ! -s "$pidfile" ]
	then
		return 0
	fi
	killpid "$(cat $pidfile 2>/dev/null)" "$2"
	return $?
}
#
waitpidfile(){
	local timeout pidfile show
	timeout=$2
	pidfile=$1
	show=$3
	test -z "$pidfile" && dlog "WARNING: waitpidfile, need arg pidfile." && return 0
	test -z "$timeout" && timeout=90
	let timeout=$timeout+1-1 2>/dev/null
	test $? -ne 0 -a "$timeout" != '0' && dlog "WARNING: waitpidfile, invalid arg timeout: $timeout" && return 0
	test ! -s "$pidfile" && return 0
	lckpid=$(cat "$pidfile" 2>/dev/null)
	if [ -n "$show" -a $timeout -gt 0 ]
		then
		dlog ""
		dlog ""
		dlog "WARNING: waiting $timeout seconds for pidfile $pidfile($lckpid) ..."
		dlog ""
		dlog ""
	fi
	wcnt=0
	while [ : ]
	do
		lckpid="`cat "$pidfile" 2>/dev/null`"
		test -z "$lckpid" && return 0
		kill -0 "$lckpid" 2>/dev/null
		if [ $? -ne 0 ]
			then
			return 0
		fi
		let wcnt=$wcnt+1
		test $wcnt -lt $timeout || break
		sleep 1
	done
	if [ $timeout -gt 0 ]
		then
		echo ""
		echo ""
		echo "WARNING: waiting timeout after $timeout seconds for $pidfile($lckpid) ..."
		echo ""
		echo ""
	fi
	return 1
}
waitbootcheck(){
	local timeout
	timeout=$1
	waitpidfile '/tmp/bootcheck.lock' "$timeout"
	return $?
}
isipaddress(){
	echo "$@"|grep -q '^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}$'
	return $?
}
isnumber(){
	local chknum
	test "$@" = '0' && return 0
	let chknum=$@+1-1 2>/dev/null
	return $?
}
addroute(){
	#return 0 for ok, will output error msg
	local routeline oneop opok errstr
	routeline="$@"
	test -z "$routeline" && dlog "ERROR: empty arg for addroute." && return 1
	opok=1
	for oneadd in 1 2 3 4 5
	do
		errstr=$(route add $routeline 2>&1)
		if [ -n "$errstr" ]
			then
			echo $errstr | grep -q 'File exists'
			if [ $? -eq 0 ]
				then
				opok=0
			else
				echo "$errstr"
			fi
		fi
		break
	done
	return $opok
}
ipaddradd(){
	local ipmask ipdev exitcode
	ipmask=$1
	ipdev=$2
	exitcode=0
	test -z "$ipdev" && return 1
	ip addr add ${ipmask} dev $ipdev > /tmp/$$.ipaddradd.log 2>&1
	if [ $? -ne 0 ]
		then
		cat /tmp/$$.ipaddradd.log 2>/dev/null | grep -i -q 'File exists'
		exitcode=$?
	fi
	rm -f /tmp/$$.ipaddradd.log
	return $exitcode
}
ipaddrdel(){
	local ipmask ipdev exitcode
	ipmask=$1
	ipdev=$2
	test -z "$ipdev" && return 1
	exitcode=0
	ip addr del ${ipmask} dev $ipdev > /dev/null 2>&1
	return $exitcode
}
delroute(){
	#return 0 for ok, will output error msg
	local routeline oneop opok errstr
	routeline="$@"
	test -z "$routeline" && dlog "ERROR: empty arg for delroute." && return 1
	opok=1
	for oneadd in 1 2 3 4 5
	do
		errstr=$(route del $routeline 2>&1)
		if [ -n "$errstr" ]
			then
			echo $errstr | grep -q 'No such process'
			if [ $? -eq 0 ]
				then
				opok=0
			else
				echo "$errstr"
			fi
			break
		fi
	done
	return $opok
}
#
strcut1() {
	local onestr onepart onecnt outstr
	onestr="$@"
	onecnt=0
	outstr=''
	for onepart in $onestr
	do
		let onecnt=$onecnt+1
		test $onecnt -le 1 && continue
		if [ -z "$outstr" ]
			then
			outstr="$onepart"
		else
			outstr="$outstr $onepart"
		fi
	done
	echo "$outstr"
	return 0
}
#
strcut2() {
	local onestr onepart onecnt outstr
	onestr="$@"
	onecnt=0
	outstr=''
	for onepart in $onestr
	do
		let onecnt=$onecnt+1
		test $onecnt -le 2 && continue
		if [ -z "$outstr" ]
			then
			outstr="$onepart"
		else
			outstr="$outstr $onepart"
		fi
	done
	echo "$outstr"
	return 0
}
#
strcut3() {
	local onestr onepart onecnt outstr
	onestr="$@"
	onecnt=0
	outstr=''
	for onepart in $onestr
	do
		let onecnt=$onecnt+1
		test $onecnt -le 3 && continue
		if [ -z "$outstr" ]
			then
			outstr="$onepart"
		else
			outstr="$outstr $onepart"
		fi
	done
	echo "$outstr"
	return 0
}
#
strcut4() {
	local onestr onepart onecnt outstr
	onestr="$@"
	onecnt=0
	outstr=''
	for onepart in $onestr
	do
		let onecnt=$onecnt+1
		test $onecnt -le 4 && continue
		if [ -z "$outstr" ]
			then
			outstr="$onepart"
		else
			outstr="$outstr $onepart"
		fi
	done
	echo "$outstr"
	return 0
}
#
stringmatchstart(){
	#return 0 for ok
	local cmplist rawstr cmpcnt cmppos rawpos cmplen rawlen onecmp oneraw
	cmplist=$1
	test -z "$cmplist" && return 0
	rawstr=$(tailspacepos 2 $@)
	cmplen=${#cmplist}
	rawlen=${#rawstr}
	if [ $rawlen -lt $cmplen ]
		then
		#dlog "stringmatchstart: $cmplist is no match len $rawstr // $rawlen -lt $cmplen : $@"
		return 1
	fi
	if [ "${rawstr:0:$cmplen}" !=  "$cmplist" ]
		then
		#dlog "stringmatchstart: $cmplist is no match start $rawstr // $rawlen -lt $cmplen : $@"
		return 1
	fi
	#dlog "stringmatchstart: $cmplist is match start $rawstr : $@"
	return 0
}
pipematchstart(){
	local chkstr oneline
	chkstr="$1"
	while read oneline
	do
		stringmatchstart "X$chkstr" "X$oneline"
		test $? -eq 0 && echo "$oneline"
	done
}
#echo val for match
getspacepos(){
	local pos rawargs chkcnt
	pos=$1
	rawargs=$@
	test -z "$pos" && return 1
	let pos=$pos+1 2>/dev/null
	if [ $? -ne 0 ]
	then
		return 1
	fi
	#dlog "DEBUG: getspacepos rawargs: $rawargs, pos=$pos"
	chkcnt=0
	for oneflag in $rawargs
	do
		let chkcnt=$chkcnt+1
		test $chkcnt -eq 1 && continue
		if [ $chkcnt -eq $pos ]
			then
			echo "$oneflag"
			#dlog "DEBUG: getspacepos ret rawargs: $rawargs, pos=$pos => $oneflag"
			return 0
		fi
	done
	return 0
}
#
pipegetspacepos(){
	local chkstr oneline
	chkstr="$1"
	while read oneline
	do
		getspacepos "$chkstr" "$oneline"
	done
}
#echo val for match
tailspacepos(){
	#return string after pos
	local pos rawargs chkcnt tailstr
	pos=$1
	rawargs=$@
	test -z "$pos" && return 1
	let pos=$pos+1-1 2>/dev/null
	if [ $? -ne 0 ]
	then
		return 1
	fi
	#dlog "DEBUG: tailspacepos rawargs: $rawargs, pos=$pos"
	chkcnt=0
	for oneflag in $rawargs
	do
		let chkcnt=$chkcnt+1
		test $chkcnt -eq 1 && continue
		if [ $chkcnt -le $pos ]
			then
			continue
		fi
		if [ -z "$tailstr" ]
		then
			tailstr="$oneflag"
		else
			tailstr="$tailstr $oneflag"
		fi
		#dlog "DEBUG: tailspacepos rawargs: $rawargs, pos=$pos => $oneflag, tailstr=$tailstr"
	done
	echo "$tailstr"
	return 0
}
##
#stringtrim()
#	| sed 's/^ *//g'
#}
##
#This will remove all spaces ...
#echo " test test test " | tr -d ' '
#
#This will remove trailing spaces...
#
#echo " test test test " | sed 's/ *$//g'
#which results in
#
# test test test
#This will remove leading spaces...
#
#echo " test test test " | sed 's/^ *//g'
#which results in
#
#test test test
#This will remove both trailing and leading spaces
#
#echo " test test test " | sed -e 's/^ *//g' -e 's/ *$//g'
#which results in
#
#test test test
#
charlistinclude(){
	#return 0 for ok
	local cmplist rawstr cmpcnt cmppos rawpos cmplen rawlen onecmp oneraw
	cmplist=$1
	test -z "$cmplist" && return 0
	rawstr=$@
	cmplen=${#cmplist}
	rawlen=${#rawstr}
	cmpcnt=0
	cmppos=0
	rawpos=0
	while [ $cmppos -lt $cmplen ]
	do
		onecmp=${cmplist:$cmppos:1}
		let rawpos=$cmplen+1
		while [ $rawpos -lt $rawlen ]
		do
			oneraw=${rawstr:$rawpos:1}
			#dlog "charlistinclude: '$onecmp' vs '$oneraw' // '$rawstr'"
			if [ "$onecmp" = "$oneraw" ]
				then
				let cmpcnt=$cmpcnt+1
				break
			fi
			let rawpos=$rawpos+1
		done
		let cmppos=$cmppos+1
	done
	if [ $cmpcnt -lt $cmplen ]
		then
		#dlog "charlistinclude: '$cmplist' is $cmpcnt / $cmplen nomatch '$rawstr' // '$@'"
		return 1
	else
		#dlog "charlistinclude: '$cmplist' is $cmpcnt / $cmplen match '$rawstr' // '$@'"
		return 0
	fi
}
charlistlimit(){
	#return 0 for ok
	local cmplist rawstr cmpcnt cmppos rawpos cmplen rawlen onecmp oneraw
	cmplist=$1
	test -z "$cmplist" && return 0
	rawstr=$(tailspacepos 2 $@)
	cmplen=${#cmplist}
	rawlen=${#rawstr}
	cmpcnt=0
	rawpos=0
	while [ $rawpos -lt $rawlen ]
	do
		oneraw=${rawstr:$rawpos:1}
		cmppos=0
		while [ $cmppos -lt $cmplen ]
		do
			onecmp=${cmplist:$cmppos:1}
			if [ "$onecmp" != "$oneraw" ]
				then
				dlog "charlistlimit: $cmplist is nolimit $rawstr // $onecmp != $oneraw : $@"
				return 1
			fi
			let cmppos=$cmppos+1
		done
		let rawpos=$rawpos+1
	done
	dlog "charlistlimit: $cmplist is limit $rawstr : $@"
	return 0
}
charlistdel(){
	#return 0 for ok
	local cmplist rawstr cmpcnt cmppos rawpos cmplen rawlen onecmp oneraw outstr
	cmplist=$1
	test -z "$cmplist" && return 0
	rawstr=$@
	cmplen=${#cmplist}
	rawlen=${#rawstr}
	cmpcnt=0
	rawpos=0
	let rawpos=$cmplen+1
	outstr=''
	while [ $rawpos -lt $rawlen ]
	do
		oneraw=${rawstr:$rawpos:1}
		cmppos=0
		isinclude=0
		while [ $cmppos -lt $cmplen ]
		do
			onecmp=${cmplist:$cmppos:1}
			if [ "$onecmp" = "$oneraw" ]
				then
				#dlog "charlistdel: skipped $onecmp vs $oneraw"
				isinclude=1
				break
			fi
			let cmppos=$cmppos+1
		done
		let rawpos=$rawpos+1
		test $isinclude -ne 0 && continue
		if [ -z "$outstr" ]
			then
			outstr=$oneraw
		else
			outstr=${outstr}${oneraw}
		fi
	done
	#dlog "charlistdel: $cmplist del from $rawstr => $outstr // $@"
	echo "$outstr"
	return 0
}
#TODO: replace grep
#tr -d '[a-zA-Z0-9-_.]'
validAlphaNum(){
	#check input, return 0 for ok
	local invalidstr
	invalidstr=$(echo "$@" | tr -d '[a-zA-Z0-9-_.]')
	if [ -z "$invalidstr" ]
		then
		#dlog "validAlphaNum: $@ -> true [0-9A-Za-z:-]"
		return 0
	else
		#dlog "validAlphaNum: $@ -> false [0-9A-Za-z:-]"
		return 1
	fi
}
validAlphaNum3(){
	#return 0 for ok
	local checkstr checklen onechar validstr validlen onevalid isincluded
	checkstr="$@"
	test -z "$checkstr" && return 1
	validstr='01234567890abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ:-_.'
	#
	checklen=${#checkstr}
	while [ : ]
	do
		let checklen=$checklen-1
		test $checklen -ge 0 || break
		onechar=${checkstr:$checklen:1}
		validlen=${#validstr}
		isincluded=0
		while [ : ]
		do
			let validlen=$validlen-1
			test $validlen -ge 0 || break
			onevalid=${validstr:$validlen:1}
			if [ "$onechar" = "$onevalid" ]
				then
				isincluded=1
				#echo "DEBUG: '$onechar' included in $validstr"
				break
			fi
		done
		if [ $isincluded -eq 0 ]
			then
			#echo "DEBUG: '$onechar' NOT included in $validstr"
			return 1
		fi
	done
	#echo "DEBUG: '$checkstr' all included in $validstr"
	return 0
}
validAlphaNum2(){
	#check input, return 0 for ok
	#TODO: remove grep
	echo "$@" | grep -q '^[0-9A-Za-z:-_\.]\+$'
	if [ $? -eq 0 ]
		then
		#dlog "validAlphaNum: $@ -> true [0-9A-Za-z:-]"
		return 0
	else
		#dlog "validAlphaNum: $@ -> false [0-9A-Za-z:-]"
		return 1
	fi
}
#set or update
arrfastset(){
	#$1 arrname, $2 key $3-... value
	local arrname arrkey arrvalue arrdir
	arrname="$1"
	arrkey="$2"
	test -z "$arrkey" && return 1
	test -z "$SCRIPTARRAYDIR" && return 1
	arrvalue=$(strcut2 "$@")
	test -z "$arrvalue" && return 1
	arrdir="${SCRIPTARRAYDIR}/${arrname}/"
	#dlog "ARRAY DEBUG: set, dir: $arrdir, name: $arrname, key:$arrkey, vaule: $arrvalue"
	basexec mkdir -p $arrdir && echo "$arrvalue" > "$arrdir$arrkey"  2>/dev/null
	test -$? -ne 0 && logexit "ERROR: arrfastset save to file $arrdir$arrkey failed."
	return 0
}
arrset(){
	#$1 arrname, $2 key $3-... value
	local arrname arrkey arrvalue arrdir
	arrname="$1"
	arrkey="$2"
	test -z "$arrkey" && return 1
	test -z "$SCRIPTARRAYDIR" && return 1
	validAlphaNum $arrname || return 1
	validAlphaNum $arrkey || return 1
	arrfastset $@
	return $?
}
#del
arrfastdel(){
	#$1 arrname, $2 key 
	local arrname arrkey arrvalue arrdir
	arrname="$1"
	arrkey="$2"
	test -z "$arrkey" && return 1
	test -z "$SCRIPTARRAYDIR" && return 1
	arrdir="${SCRIPTARRAYDIR}/${arrname}/"
	#dlog "ARRAY DEBUG: del, dir: $arrdir, name: $arrname, key:$arrkey, vaule: $arrvalue"
	rm -f "$arrdir$arrkey"
	return $?
}
#del
arrdel(){
	#$1 arrname, $2 key 
	local arrname arrkey arrvalue arrdir
	arrname="$1"
	arrkey="$2"
	test -z "$arrkey" && return 1
	test -z "$SCRIPTARRAYDIR" && return 1
	validAlphaNum $arrname || return 1
	validAlphaNum $arrkey || return 1
	arrfastdel $@
	return $?
}
#del all
arrdelall(){
	#$1 arrname, $2 key
	local arrname arrkey arrvalue arrdir
	arrname="$1"
	test -z "$arrname" && return 1
	test -z "$SCRIPTARRAYDIR" && return 1
	validAlphaNum $arrname || return 1
	arrdir="${SCRIPTARRAYDIR}/${arrname}/"
	rm -rf "$arrdir"
	return $?
}
#key list all
arrkeylist(){
	#$1 arrname, $2 key
	local arrname arrkey arrvalue arrdir allkeys
	arrname="$1"
	test -z "$arrname" && return 1
	test -z "$SCRIPTARRAYDIR" && return 1
	validAlphaNum $arrname || return 1
	arrdir="${SCRIPTARRAYDIR}/${arrname}/"
	allkeys=''
	#if [ "$arrname" = 'mactrafficdata' ]
	#	then
	#	dlog "DEBUG: arr name: $arrname"
	#	dlog "DEBUG: arr  dir: $arrdir"
	#	dlog "DEBUG: arr  cmd: ls -A $arrdir 2>&1"
	#	ls -A $arrdir 2>&1 | pipelog dlog
	#fi
	for arrkey in $(ls -A $arrdir 2>/dev/null)
	do
		test -d "$arrdir$arrkey" && continue
		if [ -z "$allkeys" ]
			then
			allkeys="$arrkey"
		else
			allkeys="$allkeys $arrkey"
		fi
	done
	#if [ "$arrname" = 'mactrafficdata' ]
	#	then
	#	dlog "DEBUG: key list: $allkeys"
	#fi
	echo "$allkeys"
	return 0
}
arrkeys(){
	arrkeylist $@
}
arrfastgetfile(){
	local onekey arrname
	arrname="$1"
	onekey="$2"
	test -z "$onekey" && return 1
	test -z "$SCRIPTARRAYDIR" && return 1
	arrdir="${SCRIPTARRAYDIR}/${arrname}/"
	#dlog "ARRAY DEBUG: arrfastgetfile, dir: $arrdir, name: $arrname, key:$arrkey, vaule: $arrvalue"
	echo "$arrdir$onekey"
}
arrdump(){
	local dumpkeys onekey arrname
	arrname="$1"
	test -z "$arrname" && return 1
	test -z "$SCRIPTARRAYDIR" && return 1
	dumpkeys=$(arrkeys $@)
	dlog "ARRAY DUMP:"
	dlog "ARRAY NAME: $arrname"
	dlog "ARRAY KEYS: $dumpkeys"
	for onekey in $dumpkeys
	do
		dlog "$onekey $(arrfastgetfile $arrname $onekey) => $(arrfastget $arrname $onekey)"
	done
	dlog "ARRAY DUMP: ---"
}
arrkeydump(){
	local onekey arrname
	arrname="$1"
	onekey="$2"
	test -z "$onekey" && return 1
	test -z "$SCRIPTARRAYDIR" && return 1
	dlog "ARRAY KEYS DUMP:"
	dlog "ARRAY NAME: $arrname"
	dlog "ARRAY KEYS: $onekey"
	dlog "ARRAY  VAL: $(arrfastget $arrname $onekey)"
	dlog "ARRAY KEYS DUMP: --- $(arrfastgetfile $arrname $onekey)"
}
#get
arrfastget(){
	#$1 arrname, $2 key
	local arrname arrkey arrvalue arrdir
	arrname="$1"
	arrkey="$2"
	test -z "$arrname" && return 1
	test -z "$SCRIPTARRAYDIR" && return 1
	arrdir="${SCRIPTARRAYDIR}/${arrname}/"
	test ! -f "$arrdir$arrkey" && return 1
	read arrvalue < $arrdir$arrkey 2>/dev/null
	#dlog "ARRAY DEBUG: get, dir: $arrdir, name: $arrname, key:$arrkey, vaule: $arrvalue"
	echo "$arrvalue"
	return 0
}
#
#get
arrget(){
	#$1 arrname, $2 key
	local arrname arrkey arrvalue arrdir
	arrname="$1"
	arrkey="$2"
	test -z "$arrname" && return 1
	test -z "$SCRIPTARRAYDIR" && return 1
	validAlphaNum $arrname || return 1
	validAlphaNum $arrkey || return 1
	arrfastget $@
	return $?
}
#
#check exist
arrcheck(){
	#return 0 for exist
	#$1 arrname, $2 key
	local arrname arrkey arrvalue arrdir
	arrname="$1"
	arrkey="$2"
	test -z "$arrname" && return 1
	test -z "$SCRIPTARRAYDIR" && return 1
	#validAlphaNum $arrname || return 1
	#validAlphaNum $arrkey || return 1
	arrdir="${SCRIPTARRAYDIR}/${arrname}/"
	test ! -f "$arrdir$arrkey" && return 1
	return 0
}
#
flog(){
	msg="$@"
	test -z "$msg" && return 0
	DATE="`date`"
	test -n "$SCRIPTLOGFILE" && echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> $SCRIPTLOGFILE 2>/dev/null
	return 0
}
#
dlog(){
	local msg
	msg="$@"
	test -z "$msg" && return 0
	DATE="`date`"
	if [ -z "$DAEMONSYSLOGFILE" -o "$DAEMONSYSLOGFILE" = 'syslog' ]
		then
		msg=$(echo "$msg" | sed -e 's#^-#_#')
		/usr/bin/logger -t "${SCRIPTTAG}[${SCRIPTPID}]" "$msg"
	else
		echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> $DAEMONSYSLOGFILE 2>/dev/null
	fi
	test -n "$SCRIPTLOGFILE" && echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> $SCRIPTLOGFILE 2>/dev/null
	return 0
}
#
elog(){
	msg="$@"
	test -z "$msg" && return 0
	DATE="`date`"
	if [ -z "$DAEMONSYSLOGFILE" -o "$DAEMONSYSLOGFILE" = 'syslog' ]
		then
		msg=$(echo "$msg" | sed -e 's#^-#_#')
		/usr/bin/logger -t "${SCRIPTTAG}[${SCRIPTPID}]" "$msg"
	else
		echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> $DAEMONSYSLOGFILE 2>/dev/null
	fi
	test -n "$SCRIPTLOGFILE" && echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> $SCRIPTLOGFILE 2>/dev/null
	echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> /proc/$$/fd/2 2>/dev/null
	return 0
}
#
conlog(){
	msg="$@"
	test -z "$msg" && return 0
	DATE="`date`"
	if [ -z "$DAEMONSYSLOGFILE" -o "$DAEMONSYSLOGFILE" = 'syslog' ]
		then
		msg=$(echo "$msg" | sed -e 's#^-#_#')
		/usr/bin/logger -t "${SCRIPTTAG}[${SCRIPTPID}]" "$msg"
	else
		echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> $DAEMONSYSLOGFILE 2>/dev/null
	fi
	echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> /dev/console 2>/dev/null
	test -n "$SCRIPTLOGFILE" && echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> $SCRIPTLOGFILE 2>/dev/null
	return 0
}
#
conelog(){
	msg="$@"
	test -z "$msg" && return 0
	DATE="`date`"
	if [ -z "$DAEMONSYSLOGFILE" -o "$DAEMONSYSLOGFILE" = 'syslog' ]
		then
		msg=$(echo "$msg" | sed -e 's#^-#_#')
		/usr/bin/logger -t "${SCRIPTTAG}[${SCRIPTPID}]" "$msg"
	else
		echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> $DAEMONSYSLOGFILE 2>/dev/null
	fi
	echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> /dev/console 2>/dev/null
	test -n "$SCRIPTLOGFILE" && echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> $SCRIPTLOGFILE 2>/dev/null
	echo "$DATE ${SCRIPTTAG}[${SCRIPTPID}]: $msg" >> /proc/$$/fd/2 2>/dev/null
	return 0
}
#TODO: fix line length limit
pipelog(){
	logfun="$@"
	if [ -z "$logfun" ]
		then
		dlog "ERROR: pipelog fun arg no defined."
		return 1
	fi
	type -t $logfun >/dev/null 2>&1
	if [ $? -ne 0 ]
		then
		dlog "ERROR: pipelog fun $logfun no defined."
		return 1
	fi
	while read onelogline
	do
		$logfun "$onelogline"
	done
}
#TODO: fix line length limit
lpipelog(){
	logfun="$@"
	if [ -z "$logfun" ]
		then
		dlog "ERROR: pipelog fun arg no defined."
		return 1
	fi
	type -t $logfun >/dev/null 2>&1
	if [ $? -ne 0 ]
		then
		dlog "ERROR: pipelog fun $logfun no defined."
		return 1
	fi
	while [ : ]
	do
		while read onelogline
		do
			$logfun "$onelogline"
		done
		sleep 3
	done
}
slog(){
	#usage: slog uuid dlog "msg"
	local logmark logfun logmsg logstat
	logmark="$1"
	logfun="$2"
	logmsg="$@"
	if [ -z "$logfun" ]
		then
		dlog "ERROR: slog fun arg no defined."
		return 1
	fi
	if [ "$logfun" = 'release' ]
		then
		arrfastset slogmark $logmark 0
		return 0
	fi
	type -t $logfun >/dev/null 2>&1
	if [ $? -ne 0 ]
		then
		dlog "ERROR: pipelog fun $logfun no defined."
		return 1
	fi
	logstat=$(arrfastget slogmark $logmark)
	#dlog "slog arrfastget slogmark $logmark = $logstat"
	if [ "$logstat" = '1' ]
		then
		#already mark
		return 0
	fi
	arrfastset slogmark $logmark 1
	logmsg=$(echo "$logmsg" | sed -e "s/^$logmark //"|sed -e "s/^$logfun //")
	$logfun "$logmsg"
	return 0
}
#echo val for match
getoptval(){
	pos=$1
	#logger "ALLARGS: $ALLARGS, pos=$pos"
	test -z "$pos" && return 1
	let pos=$pos+1-1 2>/dev/null
	if [ $? -ne 0 ]
	then
		return 0
	fi
	chkcnt=0
	for oneflag in $ALLARGS
	do
		echo "$oneflag" | grep -q '^-'
		if [ $? -eq 0 ]
		then
			continue
		fi
		let chkcnt=$chkcnt+1
		if [ $chkcnt -eq $pos ]
		then
			echo "$oneflag"
			#logger "ALLARGS: $ALLARGS, pos=$pos, oneflag=$oneflag"
			return 1
		fi
	done
	return 0
}

strippath() {
	stmsg="$@"
	newstr="${stmsg}${stmsg}"
	while [ : ]
	do
		newstr=`echo "${stmsg}" | sed -e 's/\/\//\//g'`
		if [ "${newstr}" != "${stmsg}" -a -n "${newstr}" ]
		then
			stmsg="${newstr}"
		else
			break;
		fi
	done
	echo "${newstr}"
}

slaprtrim() {
	onexcu=`strippath $@`
	onexcu=`echo ${onexcu} |  sed -e 's/\/$//'`
	echo $onexcu
}

slapltrim() {
	onexcu=`strippath $@`
	onexcu=`echo ${onexcu} |  sed -e 's/\/$//'`
	echo $onexcu
}
#
argmatch(){
	#1 for match
	local chk
	chk="$@"
	test -z "$chk" && echo 0 && return 0
	for onechk in $chk
	do
	   for onearg in $ALLARGS
	   do
	   	if [ "$onechk" = "$onearg" ]
	   		then
	   		echo 1
	   		return 1
	   	fi
	   done
	done
	echo 0
	return 0
}
#
setlogfile(){
	newlogfile="$1"
	test -z "$newlogfile" && return 0
	echo "" > $newlogfile 2>/dev/null
	if [ $? -ne 0 ]
		then
		conlog "ERROR: can not write to logfile $newlogfile"
		return 0
	fi
	SCRIPTLOGFILE="$newlogfile"
}
#
linecat(){
	local catfiles onefile oneline
	catfiles="$@"
	for onefile in $catfiles
	do
		if [ ! -f "$onefile" ]
			then
			#dlog "WARNING: linecat, file no found: $onefile"
			continue
		fi
		while read oneline
		do
			echo "$oneline"
		done < $onefile
	done
}
dlogexec(){
	local exitcode
	local execline
	local capfile
	execline="$@"
	test -z "$execline" && return 0
	capfile="/tmp/logexec/log.$$.$(date -u +%s)"
	basexec mkdir -p /tmp/logexec/
	$execline > $capfile 2>&1
	exitcode=$?
	dlog "logexec: exitcode $exitcode, $execline"
	cat $capfile 2>/dev/null | pipelog dlog
	rm -f $capfile
	return $exitcode
}
#
dlogselftexec(){
	local exitcode
	local execline
	local capfile
	execline="$SCRIPTSELFT"
	test -z "$execline" && return 0
	execline="$execline selftexec"
	test "$(argmatch selftexec)" = '1' && return 0
	capfile="/tmp/logexec/log.$$.$(date -u +%s)"
	basexec mkdir -p /tmp/logexec/
	$execline > $capfile 2>&1
	exitcode=$?
	dlog "logexec: exitcode $exitcode, $execline"
	cat $capfile 2>/dev/null | pipelog dlog
	rm -f $capfile
	exit $exitcode
}
#
echoexec(){
	local exitcode
	local execline
	local capfile
	execline="$@"
	test -z "$execline" && return 0
	capfile="/tmp/logexec/log.$$.$(date -u +%s)"
	basexec mkdir -p /tmp/logexec/
	$execline > $capfile 2>&1
	exitcode=$?
	if [ $exitcode -ne 0 ]
		then
		dlog "logexec: exitcode $exitcode, $execline"
	fi
	cat $capfile
	rm -f $capfile
	return $exitcode
}
#
echoelogexec(){
	local exitcode
	local execline
	local capfile
	execline="$@"
	test -z "$execline" && return 0
	capfile="/tmp/logexec/log.$$.$(date -u +%s)"
	basexec mkdir -p /tmp/logexec/
	$execline > $capfile 2>&1
	exitcode=$?
	cat $capfile 2>/dev/null | pipelog elog
	if [ $exitcode -ne 0 ]
		then
		elog "logexec: exitcode $exitcode, $execline"
	fi
	rm -f $capfile
	return $exitcode
}
echoconlogexec(){
	local exitcode
	local execline
	local capfile
	execline="$@"
	test -z "$execline" && return 0
	capfile="/tmp/logexec/log.$$.$(date -u +%s)"
	basexec mkdir -p /tmp/logexec/
	$execline > $capfile 2>&1
	exitcode=$?
	cat $capfile 2>/dev/null | tee | pipelog conlog
	if [ $exitcode -ne 0 ]
		then
		conlog "logexec: exitcode $exitcode, $execline"
	fi
	rm -f $capfile
	return $exitcode
}
#
echodlogexec(){
	local exitcode
	local execline
	local capfile
	execline="$@"
	test -z "$execline" && return 0
	capfile="/tmp/logexec/log.$$.$(date -u +%s)"
	basexec mkdir -p /tmp/logexec/
	$execline > $capfile 2>&1
	exitcode=$?
	cat $capfile 2>/dev/null | tee | pipelog dlog
	if [ $exitcode -ne 0 ]
		then
		dlog "logexec: exitcode $exitcode, $execline"
	fi
	rm -f $capfile
	return $exitcode
}
#
logexec(){
	local exitcode
	local execline
	local capfile
	execline="$@"
	test -z "$execline" && return 0
	basexec mkdir -p /tmp/logexec/
	capfile="/tmp/logexec/log.$$.$(date -u +%s)"
	$execline > $capfile 2>&1
	exitcode=$?
	if [ $exitcode -ne 0 ]
	then
		dlog "logexec: exitcode $exitcode, $execline"
		cat $capfile 2>/dev/null | pipelog dlog
	fi
	rm -f $capfile
	return $exitcode
}
#
setexitmark(){
	#
	setpid="$1"
	if [ -z "$setpid" ]
		then
		setpid=$SCRIPTPID
	fi
	#
	if [ -z "$SCRIPTLOCK" ]
	then
		SCRIPTLOCK=$SCRIPTMARK
	fi
	validAlphaNum "${SCRIPTLOCK}"
	if [ $? -ne 0 ]
		then
		conlog "ERROR: invalid SCRIPTLOCK(${SCRIPTLOCK}) for daemon setexitmark."
		exit 1
	fi
	arrset run exit_${SCRIPTLOCK} "$setpid"
	#dlog "set proc $$ lock, exit $?, $SCRIPTSELFT // $setpid => ${SCRIPTARRAYDIR}/run/lock"
	#dlog "set proc $$ lock ret: $(arrget run lock)"
	if [ $? -ne 0 ]
		then
		conlog "ERROR: create daemon exitmark($setpid) failed."
		exit 1
	fi
	#
}
#
getexitmark(){
	#
	if [ -z "$SCRIPTLOCK" ]
	then
		SCRIPTLOCK=$SCRIPTMARK
	fi
	validAlphaNum "${SCRIPTLOCK}"
	if [ $? -ne 0 ]
		then
		conlog "ERROR: invalid SCRIPTLOCK(${SCRIPTLOCK}) for daemon getexitmark."
		exit 1
	fi
	echo "$(arrfastget run exit_${SCRIPTLOCK})"
	return 0
}
#
delexitmark(){
	#
	if [ -z "$SCRIPTLOCK" ]
	then
		SCRIPTLOCK=$SCRIPTMARK
	fi
	validAlphaNum "${SCRIPTLOCK}"
	if [ $? -ne 0 ]
		then
		conlog "ERROR: invalid SCRIPTLOCK(${SCRIPTLOCK}) for daemon delexitmark."
		exit 1
	fi
	arrfastdel run exit_${SCRIPTLOCK}
	return $?
}
#
getlockedprocpid(){
	if [ -z "$SCRIPTLOCK" ]
	then
		SCRIPTLOCK=$SCRIPTMARK
	fi
	validAlphaNum "${SCRIPTLOCK}"
	if [ $? -ne 0 ]
		then
		conlog "ERROR: invalid SCRIPTLOCK(${SCRIPTLOCK}) for daemon lock."
		exit 1
	fi
	lockedpid="$(arrget run lock_${SCRIPTLOCK})"
	test "${PROC_LOCK_DEBUG}" = 'TRUE' && dlog "DEBUG: getlockedprocpid: arrget run lock_${SCRIPTLOCK} => $lockedpid"
	echo "$lockedpid"
	return 0
}
releaselockedprocpid(){
	if [ -z "$SCRIPTLOCK" ]
	then
		SCRIPTLOCK=$SCRIPTMARK
	fi
	validAlphaNum "${SCRIPTLOCK}"
	if [ $? -ne 0 ]
		then
		conlog "ERROR: invalid SCRIPTLOCK(${SCRIPTLOCK}) for daemon unlock."
		exit 1
	fi
	setexitmark
	lockedpid="$(arrget run lock_${SCRIPTLOCK})"
	#test "${PROC_LOCK_DEBUG}" = 'TRUE' && dlog "DEBUG: releaselockedprocpid: arrget run lock_${SCRIPTLOCK} => $lockedpid"
	dlog "DEBUG: releaselockedprocpid: arrget run lock_${SCRIPTLOCK} => $lockedpid"
	arrdel run "lock_${SCRIPTLOCK}"
	return $?
}
setproclock(){
	#
	setpid="$1"
	if [ -z "$setpid" ]
		then
		setpid=$SCRIPTPID
	fi
	test -z "$setpid" && return 0
	let setpid=$setpid+1-1 2>/dev/null
	test $? -ne 0 && return 1
	#
	if [ -z "$SCRIPTLOCK" ]
	then
		SCRIPTLOCK=$SCRIPTMARK
	fi
	validAlphaNum "${SCRIPTLOCK}"
	if [ $? -ne 0 ]
		then
		conlog "ERROR: invalid SCRIPTLOCK(${SCRIPTLOCK}) for daemon lock."
		exit 1
	fi
	arrset run lock_${SCRIPTLOCK} "$setpid"
	#dlog "set proc $$ lock, exit $?, $SCRIPTSELFT // $setpid => ${SCRIPTARRAYDIR}/run/lock"
	#dlog "set proc $$ lock ret: $(arrget run lock)"
	if [ $? -ne 0 ]
		then
		elog "ERROR: create daemon lock failed: arrset run lock_${SCRIPTLOCK} $setpid"
		exit 1
	else
		test "${PROC_LOCK_DEBUG}" = 'TRUE' && dlog "DEBUG: setproclocked: arrset run lock_${SCRIPTLOCK} => $setpid"
	fi
	#
}
checkproclock(){
	local waitlck
	local replaceproc
	#
	#check lock, return 0 for no locked, 1 for locked
	#
	test -z "$SCRIPTPID" && SCRIPTPID=$$
	test -z "$SCRIPTSELFT" && SCRIPTSELFT=$0
	#
	waitlck="$1"
	replaceproc="$2"
	test -z "$waitlck" && waitlck=1
	let waitlck=$waitlck+1-1 2>/dev/null
	if [ $? -ne 0 ]
		then
		waitlck=1
	fi
	test $waitlck -le 0 && waitlck=0
	#
	wcnt=0
	#SCRIPTLOCK will effect in getlockedprocpid
	lckpid=$(getlockedprocpid)
	if [ "$lckpid" = "$SCRIPTPID" ]
		then
		#it's me
		test "${PROC_LOCK_DEBUG}" = 'TRUE' && dlog "DEBUG: checkproclock, no locked, myself: $SCRIPTPID"
		return 0
	fi
	if [ -z "$lckpid" ]
		then
		test "${PROC_LOCK_DEBUG}" = 'TRUE' && dlog "DEBUG: checkproclock, no locked, lockpid no exist."
		return 0
	fi
	kill -0 "$lckpid" 2>/dev/null
	if [ $? -ne 0 ]
		then
		#no running
		test "${PROC_LOCK_DEBUG}" = 'TRUE' && dlog "DEBUG: checkproclock, no locked, $lckpid no running."
		return 0
	fi
	if [ "$replaceproc" = 'replaceproc' ]
		then
		dlog "WARNING: try to replace old proc ${lckpid}"
		killpid $lckpid
	fi
	if [ $waitlck -gt 1 ]
		then
		dlog "INFO: proclock waiting $lckpid, timeout $waitlck"
	fi
	running=0
	while [ : ]
	do
		running=0
		lckpid=$(getlockedprocpid)
		if [ -n "$lckpid" ]
			then
			kill -0 "$lckpid" 2>/dev/null
			if [ $? -ne 0 ]
				then
				#no running
				break
			else
				running=1
			fi
		else
			break
		fi
		let wcnt=$wcnt+1
		test $wcnt -ge $waitlck && break
		sleep 1
	done
	#
	if [ $waitlck -gt 1 ]
		then
		if [ $running -ne 0 ]
			then
			dlog "WARNING: pid lock waiting $lckpid timeout after $wcnt seconds."
		else
			dlog "INFO: pid lock waiting $lckpid finish after $wcnt seconds."
		fi
	else
		test "${PROC_LOCK_DEBUG}" = 'TRUE' && dlog "DEBUG: checkproclock, no locked, max wait $waitlck seconds, esp $wcnt seconds, pid $lckpid"
	fi
	#test -n "$lckpid" && dlog "DEBUG: checkproclock, $waitlck seconds, waiting for $lckpid running=$running, after $wcnt seconds."
	return $running
}
#
procgodaemon(){
	#no lock set/check
	if [ `echo "$SCRIPTSELFT"|grep -c '^/'` -eq 0 ]
		then
		elog "ERROR: script must start by absolute path."
		exit 1
	fi
	#
	#check lock
	#
	checkproclock 1
	if [ $? -ne 0 ]
		then
		test "$1" = 'fixme' && dlog "FIXME: already running, pid $(getlockedprocpid))" && exit 1
		exit 0
	#else
	#	elog "INFO: no running"
	fi
	#
	delexitmark
	#
	DAEMONED=''
	if [ `argmatch blocking daemon status checkconf` -eq 0 -a -x "$SCRIPTSELFT" ]
		then
		#
		if [ -z "$SCRIPTNICE" ]
		then
			SCRIPTNICE=10
		fi
		let SCRIPTNICE=$SCRIPTNICE+1-1 2>/dev/null
		if [ $? -ne 0 ]
			then
			SCRIPTNICE=10
		fi
		setproclock
		basexec mkdir -p /tmp/daemon/stdio/
		touch $DAEMONSTDIOFILE
		if [ $? -ne 0 ]
			then
			elog "ERROR: create STDIO file failed: touch $DAEMONSTDIOFILE $(tuch $DAEMONSTDIOFILE 2>&1)"
			exit 1
		fi
		#fifofile="/tmp/daemon/${SCRIPTMARK}.fifo"
		#rm -f $fifofile
		#mkfifo $fifofile
		#if [ $? -ne 0 ]
		#	then
		#	elog "ERROR: create FIFO pipe failed: mkfifo $fifofile $(mkfifo $fifofile 2>&1)"
		#	exit 1
		#fi
		#nohup cat $fifofile 2>&1 < /dev/null | pipelog dlog &
		#pipepid=$!

		#dlog "DEBUG: pipelog pid: $pipepid"
		#disable msg: nohup: ignoring input by cat /dev/zero
		#nice -n $SCRIPTNICE nohup $SCRIPTSELFT $ALLARGS daemon >> $fifofile 2>&1 < /dev/zero &
		SCRIPTTITLE=$(echo "$SCRIPTTITLE"|tr '/\- ' '_')
		nice -n $SCRIPTNICE nohup $SCRIPTSELFT $ALLARGS daemon "$SCRIPTTITLE" >> $DAEMONSTDIOFILE 2>&1 < /dev/zero &
		runcode=$?
		daemonedpid=$!
		#
		if [ $runcode -ne 0 ]
			then
			elog "ERROR: execute // $SCRIPTSELFT $ALLARGS daemon // failed:"
			elog "ERROR: got invalid exitcode: $runcode"
			exit 1
		fi
		if [ -z "$daemonedpid" ]; then
			elog "ERROR: execute // $SCRIPTSELFT $ALLARGS daemon // failed:"
			elog "ERROR: got invalid pid: $daemonedpid"
			exit 1
		fi
		test "${PROC_LOCK_DEBUG}" = 'TRUE' && dlog "DEBUG: setproclock for daemon: $daemonedpid"
		setproclock "$daemonedpid"
		test "${PROC_LOCK_DEBUG}" = 'TRUE' && dlog "DEBUG: running background: $daemonedpid"
		exit 0
	else
		#already daemon
		# trap daemon only
		trap daemonexit SIGTERM SIGINT
		DAEMONED='yes'
		export PROC_LOCK_DEBUG='FALSE'
	fi
	setproclock "$SCRIPTPID"
	#
}
export SCRIPTWARNED=0
waitcleanup(){
	test $SCRIPTWARNED -eq 0 && elog "INFO: waiting for cleanup ..."
	let SCRIPTWARNED=$SCRIPTWARNED+1
	sleep 1
	test $SCRIPTWARNED -ge 10 && exit 0
}
daemonexit(){
	delexitmark
	trap waitcleanup SIGTERM SIGINT
	SCRIPTWARNED=0
	dlog "INFO: exiting ..."
	type -t daemonstop >/dev/null 2>&1
	if [ $? -eq 0 ]
		then
		dlog "INFO: cleanup befor exit ..."
		daemonstop 2>&1 | pipelog dlog
	fi
	dlog "INFO: exited."
	exit 0
}
daemonexited(){
	local exitcode=$1
	test -z "$exitcode" && exitcode=0
	#like daemonexit
	type -t daemonpostexit >/dev/null 2>&1
	if [ $? -eq 0 ]
		then
		dlog "INFO: post exit ..."
		daemonpostexit 2>&1 | pipelog dlog
	fi
	exit $exitcode
}
proc_ctl(){
	if [ "$1" = 'restart' -o "$1" = 'reload' ]
		then
		trap - SIGTERM SIGINT SIGQUIT
		narg=`echo $@ | sed -e 's/restart//g'|sed -e 's/reload//g'|sed -e 's/  / /g'`
		$0 stop $narg >/dev/null 2>&1
		sleep 1
		$0 start $narg 2>&1
		exit $?
	fi
	#
	if [ "$1" = 'status' ]
		then
		#return 0 for running
		trap - SIGTERM SIGINT SIGQUIT
		lckpid=$(getlockedprocpid)
		if [ -n "$lckpid" ]
			then
			kill -0 "$lckpid" 2>/dev/null
			if [ $? -eq 0 ]
				then
				# running
				test "${PROC_LOCK_DEBUG}" = 'TRUE' && dlog "DEBUG: check proc lock status, running, pid: $lckpid"
				test "$2" != 'mute' && elog "INFO: running, pid: $lckpid"
				exit 0
			else
				test "${PROC_LOCK_DEBUG}" = 'TRUE' && dlog "DEBUG: check proc lock status, no running, pid: $lckpid"
			fi
		else
			test "${PROC_LOCK_DEBUG}" = 'TRUE' && dlog "DEBUG: check proc lock status, no lockpid"
		fi
		test "$2" != 'mute' && elog "INFO: no running."
		exit 1
	fi
	if [ "$1" = 'stop' -o "$1" = 'kill' ]
		then
		#
		ctlop="$1"
		#
		killsig=15
		#
		trap - SIGTERM SIGINT SIGQUIT
		lckpid=$(getlockedprocpid)
		if [ -n "$lckpid" ]
			then
			kill -0 "$lckpid" 2>/dev/null
			if [ $? -ne 0 ]
				then
				#no running
				daemonexited 0
			fi
			#
			setexitmark
			#
			#conlog "WARNING: PROC_CALLER=$PROC_CALLER"
			#
			#/etc/init.d/rcS K shutdown
			#
			#/etc/init.d/rcS S boot
			#
			kill -$killsig "$lckpid" 2>/dev/null
			if [ $? -ne 0 ]
				then
				elog "ERROR: stop pid $lckpid failed."
				exit 1
			else
				if [ "$PROC_CALLER" = "/etc/init.d/rcS K shutdown" ]
					then
					# export PROC_CALLER='/etc/init.d/rcS K shutdown'
					dlog "WARNING: fast $ctlop for system shutdown($PROC_CALLER)."
					releaselockedprocpid
					dlog "WARNING: kill all sleep for system shutdown($PROC_CALLER)."
					killall sleep
					daemonexited 0
				fi
				wcnt=0
				waitlimit=120
				while [ : ]
				do
					lckpid=$(getlockedprocpid)
					test -z "$lckpid" && break
					if [ "$ctlop" = 'kill' ]
						then
						kill -9 "$lckpid" 2>/dev/null
					else
						sleep 1
					fi
					kill -0 "$lckpid" 2>/dev/null || break
					let wcnt=$wcnt+1
					test $wcnt -ge $waitlimit && break
				done
				kill -0 "$lckpid" 2>/dev/null
				if [ $? -ne 0 ]
					then
					elog "INFO: $ctlop pid $lckpid ok."
				else
					elog "ERROR: waiting for pid $lckpid exit timeout after $waitlimit seconds, KILLED."
					kill -9 "$lckpid" 2>/dev/null
				fi
			fi
		fi
		daemonexited 0
	fi
}
procdaemon(){
	#check lock
	#daemon
	proc_ctl $ALLARGS
	#set lock
	if [ "$DAEMONBYPASS" != 'yes' ]
		then
		#
		procgodaemon $ALLARGS
		#
	#else
	#	dlog "daemon: bypass $SCRIPTSELFT $ALLARGS"
	fi
}

runintimeusage(){
	echo "USAGE: runintimeusage <timeout> <command>"
}
runintime(){

	timeout=$1
	cmdline=$@
	test -z "$timeout" && return 0

	let timeout=$timeout+1-1 2>/dev/null
	test $? -ne 0 && runintimeusage && echo "ERROR: timeout($timeout) should be 1 - 120" && return 1
	test $timeout -gt 120 -o $timeout -le 0 && runintimeusage && echo "ERROR: timeout($timeout) should be 1 - 120" && return 1
	cmdline=$(echo $cmdline | sed -e "s/$timeout //")
	if [ -z "$cmdline" ]
	then
		runintimeusage
		echo "ERROR: command arg not found."
		return 1
	fi
	#echo "DEBUG: running /$cmdline/$timeout ..."

	nowts=$(date +%s)
	doid=`echo "$nowts/$cmdline/$timeout"|md5sum|awk '{print $1}'`
	dofile="/tmp/`basename $0`.$$.$doid.tmp"

	touch $dofile
	$cmdline > $dofile 2>&1 &
	runcode=$?
	lookpid=$!

	wcnt=0
	addlist=''
	while [ $wcnt -le $timeout ]
	do
		kill -0 $lookpid 2>/dev/null
		if [ $? -ne 0 ]
		then
			#it exited
			break
		fi
		let wcnt=$wcnt+1
		sleep 1
	done

	kill $lookpid 2>/dev/null
	linecat $dofile
	rm -f $dofile
	return $runcode
#
}
find_mtd_part() {
		local PART="$(grep "\"$1\"" /proc/mtd | awk -F: '{print $1}')"
		local PREFIX=/dev/mtdblock

		PART="${PART##mtd}"
		[ -d /dev/mtdblock ] && PREFIX=/dev/mtdblock/
		echo "${PART:+$PREFIX$PART}"
}
#
getmtdbyname() {
	find_mtd_part $@
}
#
overlaymountdir(){
	local showmnt
	local ovldir
	showmnt="$1"
	#
	#check ' /tmp/overlay-disabled' first
	#
	ovldir=`df | grep ' /tmp/overlay-disabled$'|awk '{print $6}'`
	if [ -z "$ovldir" ]
	then
		ovldir=`df | grep ' /overlay$'|awk '{print $6}'`
	fi
	if [ -z "$ovldir" ]
		then
		#
		if [ -n "$showmnt" ]
			then
			conlog "ERROR: overlay no mounted."
			conlog "---"
			conlog "INFO: current mount table:"
			conlog "---"
			#
			df | while read oneline
			do
				conlog "$oneline"
			done
			#
		fi
		#
		return 1
	fi
	if [ -n "$showmnt" ]
		then
		conlog "INFO: overlay mounted: $ovldir"
		df 2>&1 | while read oneline
		do
			conlog "$oneline"
		done
	fi
	echo "$ovldir"
	return 0
}
getoverlaydir(){
	local showmnt
	showmnt="$1"
	local ovldir
	#
	#check ' /tmp/overlay-disabled' first
	#
	ovldir=$(overlaymountdir $@)
	if [ -n "$ovldir" ]
		then
		echo "$ovldir"
		return 0
	fi
	#
	#waiting for overlay mount
	#
	conlog "---"
	conlog "INFO: waiting for overlay mounted, up to 60 seconds."
	conlog "---"
	#
	ovldir=''
	wcnt=0
	while [ $wcnt -le 60 ]
	do
		ovldir=$(overlaymountdir)
		if [ -n "$ovldir" ]
			then
			break
		fi
		let wcnt=$wcnt+1
		sleep 1
	done
	#
	if [ -z "$ovldir" ]
		then
		conlog "ERROR: waiting for overlay mounted failed after 60 seconds."
		return 1
	fi
	if [ -n "$showmnt" ]
		then
		conlog "INFO: overlay mounted: ${ovldir}"
		df | while read oneline
		do
			conlog "$oneline"
		done
	fi
	echo "$ovldir"
	return 0
}
#
ipalivecheck(){
	local chkip mute pingret arpret
	chkip="$1"
	mute="$2"
	#
	test -z "$chkip" && return 1
	#
	#check ip with ping and arp
	#
	/usr/bin/arp -d $chkip 2>/dev/null
	for fcnt in 1 2 3 4 5 6 7 8 9 10
	do
		pingret=`ping -c 1 -w 1 $chkip | grep ': seq='|grep -c ' time='`
		arpret=`/usr/bin/arp -n | grep -v '00:00:00:00:00:00'|grep -v 'incomplete'|grep "^$chkip"`
		if [ $pingret -gt 0 -o -n "$arpret" ]
			then
			break
		fi
	done
	if [ $pingret -le 0 -a -z "$arpret" ]
			then
			test "$mute" = '0' && dlog "WARNING: $chkip unreachable."
			return 1
	#else
	#	dlog "DEBUG: $chkip alive: $arpret"
	fi
	return 0
}
iplocalcheck(){
	#return 0 for ok,
	local chkip mute arpret mark
	chkip="$1"
	mute="$2"
	mark="$3"
	test -z "$mark"&&mark='local'
	#
	test -z "$chkip" && return 1
	#
	#check ip with ping and arp
	#
	####niclist="`ifconfig | grep 'Link encap:' | awk '{print $1}'`"
	#####
	####for onenic in $niclist
	####do
	####	#check p-to-p
	####	ifconfig $onenic 2>/dev/null | grep -i 'inet'|awk -F':' '{print $3}'|awk '{print $1}'|grep -q "$chkip"
	####	if [ $? -eq 0 ]
	####		then
	####		#p-to-p link: inet addr:10.0.109.10  P-t-P:10.0.109.254  Mask:255.255.255.255
	####		return 0
	####	fi
	####done
	#

	#p-to-p link: inet addr:10.0.109.10  P-t-P:10.0.109.254  Mask:255.255.255.255
	ifconfig | grep -q "P-t-P:$chkip "
	if [ $? -eq 0 ]
		then
		return 0
	fi

	#my local ip is false
	ifconfig | grep -q "inet addr:$chkip "
	if [ $? -eq 0 ]
		then
		return 1
	fi

	#
	#check ether
	/usr/bin/arp -d $chkip 2>/dev/null
	for fcnt in 1 2 3 4
	do
		ping -c 1 -w 1 $chkip >/dev/null 2>&1
		arpret=`/usr/bin/arp -n | grep -v '00:00:00:00:00:00'|grep -v 'incomplete'|grep "^$chkip"`
		if [ -n "$arpret" ]
			then
			break
		fi
	done
	if [ -z "$arpret" ]
			then
			test "$mute" = '0' && dlog "WARNING: $chkip unreachable in ${mark}."
			return 1
	#else
	#	dlog "DEBUG: $chkip reachable in ${mark}: $arpret"
	fi
	return 0
}

iplocalethercheck(){
	iplocalcheck $1 $2 'local ethernet'
	return $?
}
#
ipconfictcheck(){
	local chklist chknics onenic nicmac chkip cmpnic dupmac isconfict lannet wannet
	isconfict=0
	chklist="$@"
	test -z "$chklist" && chklist='eth0.2 br-lan'
	for onenic in $chklist
	do
		nicmac=$(ifconfig eth0.2|grep 'HWaddr '|awk '{print $5}')
		chkip=$(/sbin/ifconfig $onenic 2>/dev/null | grep 'inet addr:' | awk -F'inet addr:' '{print $2}'| awk '{print $1}')
		chknics="$onenic"
		for cmpnic in $chknics
		do
			dupmac=$(/usr/bin/arping -D -f -b -c 1 -w 1 -s 0.0.0.0 -I $cmpnic $chkip 2>&1 | grep 'reply from ' | tr -d '[]' | awk -F"$chkip " '{print $2}'|awk '{print $1}')
			if [ -n "$dupmac" ]
			then
				test "$(arrfastget ipconfict ${nicmac}-${onenic}-${chkip}-${cmpnic})" != "1" && dlog "WARNING: IP of ${onenic}/${nicmac} $chkip confict with mac $dupmac at $cmpnic"
				arrfastset ipconfict ${nicmac}-${onenic}-${chkip}-${cmpnic} 1
				let isconfict=$isconfict+1
			else
				test "$(arrfastget ipconfict ${nicmac}-${onenic}-${chkip}-${cmpnic})" = "1" && dlog "INFO: IP confict of ${onenic}/${nicmac} $chkip at ${cmpnic} is gone."
				arrfastset ipconfict ${nicmac}-${onenic}-${chkip}-${cmpnic} 0
			fi
		done
	done
	wannet=$(ip route list dev eth0.2 2>/dev/null| awk '/scope/{print$1}'|head -n1|pipegetspacepos 1)
	test -z "$wannet" && return $isconfict
	lannet=$(ip route list dev br-lan 2>/dev/null| awk '/scope/{print$1}'|head -n1|pipegetspacepos 1)
	if [ "$lannet" = "$wannet" ]
		then
		let isconfict=$isconfict+1
		test "$(arrfastget ipconfict laneqwan)" != "1" && dlog "WARNING: wan network $wannet confict with lan network $lannet"
		arrfastset ipconfict laneqwan 1
	else
		test "$(arrfastget ipconfict laneqwan)" = "1" && dlog "INFO: wan network $wannet confict with lan network $lannet is gone."
		arrfastset ipconfict laneqwan 0
	fi
	return $isconfict
}
ipconfictcheck2(){
	local chklist onenic nicmac chkip cmpnic dupmac isconfict lannet wannet
	isconfict=0
	chklist="$@"
	test -z "$chklist" && chklist='eth0.2 br-lan'
	for onenic in $chklist
	do
		nicmac=$(ifconfig eth0.2|grep 'HWaddr '|awk '{print $5}')
		chkip=$(/sbin/ifconfig $onenic 2>/dev/null | grep 'inet addr:' | awk -F'inet addr:' '{print $2}'| awk '{print $1}')
		for cmpnic in $chklist
		do
			dupmac=$(/usr/bin/arping -D -f -b -c 1 -w 1 -s 0.0.0.0 -I $cmpnic $chkip 2>&1 | grep 'reply from ' | tr -d '[]' | awk -F"$chkip " '{print $2}'|awk '{print $1}')
			if [ -n "$dupmac" ]
			then
				test "$(arrfastget ipconfict ${nicmac}-${onenic}-${chkip}-${cmpnic})" != "1" && dlog "WARNING: IP of ${onenic}/${nicmac} $chkip confict with mac $dupmac at $cmpnic"
				arrfastset ipconfict ${nicmac}-${onenic}-${chkip}-${cmpnic} 1
				let isconfict=$isconfict+1
			else
				test "$(arrfastget ipconfict ${nicmac}-${onenic}-${chkip}-${cmpnic})" = "1" && dlog "INFO: IP confict of ${onenic}/${nicmac} $chkip at ${cmpnic} is gone."
				arrfastset ipconfict ${nicmac}-${onenic}-${chkip}-${cmpnic} 0
			fi
		done
	done
	wannet=$(ip route list dev eth0.2 2>/dev/null| head -n1|pipegetspacepos 1)
	test -z "$wannet" && return $isconfict
	lannet=$(ip route list dev br-lan | head -n1|pipegetspacepos 1)
	if [ "$lannet" = "$wannet" ]
		then
		let isconfict=$isconfict+1
		test "$(arrfastget ipconfict laneqwan)" != "1" && dlog "WARNING: wan network $wannet confict with lan network $lannet"
		arrfastset ipconfict laneqwan 1
	else
		test "$(arrfastget ipconfict laneqwan)" = "1" && dlog "INFO: wan network $wannet confict with lan network $lannet is gone."
		arrfastset ipconfict laneqwan 0
	fi
	return $isconfict
}
#
#2013-11-27 21:18:29.000000000
#+%Y-%m-%d-%H:%M:%S
#
timestamp2date(){
	local onets="$1"
	test -z "$onets" && return 1
	echo "$(date -u -D '%s' -d "$onets" +%Y.%m.%d-%H:%M:%S)"
	return $?
}
rrd2timestamp(){
	local onets="$@"
	local cnvts
	test -z "$onets" && return 1
	onets="$(echo $onets | tr ' ' '-')"
	cnvts="$(date -u +'%s' -d "$onets" -D '%Y-%m-%d-%H:%M:%S')"
	test -z "$cnvts" && return 1
	echo "$cnvts"
	return 0
}
setclock2timestamp(){
	local onets="$1"
	test -z "$onets" && return 1
	tsstr="$(timestamp2date $onets)"
	test -z "$tsstr" && return 1
	date -s "$tsstr"
	return $?
}
#
basexec mkdir -p /tmp/daemon/ && basexec mkdir -p $SCRIPTARRAYDIR
if [ $? -ne 0 ]
	then
	conlog "ERROR: lib.scripthelper.sh create directory /tmp/daemon/ and $SCRIPTARRAYDIR failed: $(basexec mkdir -p /tmp/daemon/ 2>&1) $(basexec mkdir -p $SCRIPTARRAYDIR 2>&1)"
	exit 1
fi
#
#trap daemonexit SIGTERM SIGINT SIGFPE SIGSTP
#trap daemonexit SIGTERM SIGINT
#
trap - SIGTERM SIGINT SIGFPE SIGQUIT
#
##
