#!/bin/bash

# TODO:
# adjust coredump: /proc/sys/kernel/core_pattern
# at the moment it is just 'core'
# TODO:
# crashreboot with reason?
# TODO:
# ulimit -c unlimited?
# -> see crashs of userland, e.g.:
  # root@touch2:/home/tasso# /etc/rc.local function time_setup
  # tasso: [5063] 23.Oct'15-11:54.18 / up: 645sec: startup: root: /etc/rc.local: mac is: '2a:40:5d:44:6b:01'
  # tasso: [5063] 23.Oct'15-11:54.18 / up: 645sec: startup: root: /etc/rc.local: enforced mac: 2a:40:5d:44:6b:01
  # tasso: [5063] 23.Oct'15-11:54.18 / up: 645sec: startup: root: /etc/rc.local: maybe resulting IP: '172.17.34.112' HOSTNAME: 'touch2'
  # tasso: [5063] 23.Oct'15-11:54.18 / up: 646sec: startup: root: /etc/rc.local: [OK] no real NTP available: 172.17.34.65
  # tasso: [5063] 23.Oct'15-11:54.19 / up: 646sec: startup: root: /etc/rc.local: run 1/60: time maybe still not correct: Fri Oct 23 11:54:19 CEST 2015, using server '172.17.34.65'
  # tasso: [5063] 23.Oct'15-11:54.27 / up: 654sec: startup: root: /etc/rc.local: 23 Oct 11:54:27 ntpdate[5111]: adjust time server 172.17.34.65 offset 0.006303 sec/etc/rc.local: line 330:  5136 Segmentation fault      chown tasso:tasso "$file"
  # tasso: [5063] 23.Oct'15-11:54.27 / up: 654sec: startup: root: /etc/rc.local: time now: Fri Oct 23 11:54:27 CEST 2015



# todo: mkimage after every boot if needed -> oops=panic panic=10
### boot.script openwrt?:
# fatload mmc 0:1 0x80000000 openwrt-omap4-zImage
# setenv bootargs vram=32M fixrtc mem=1G@0x80000000 root=/dev/mmcblk0p2 rootfstype=ext4 console=ttyO2,115200n8 rootwait
# bootm 0x80000000
### boot.script on kasse1:
# setenv initrd_high "0xffffffff"
# setenv fdt_high "0xffffffff"
# setenv bootcmd "fatload mmc 0:1 0x80200000 uImage; fatload mmc 0:1 0x81600000 uInitrd; fatload mmc 0:1 0x815f0000 board.dtb; bootm 0x80200000 0x81600000 0x815f0000"
# setenv bootargs "console=tty0 console=ttyO2,115200n8  root=UUID=97be0310-8f48-4898-a3de-689f5323a5e1 rootwait ro fixrtc nocompcache vram=48M omapfb.vram=0:24M oops=panic panic=10 quiet loglevel=0 console=ttyO2"
# boot
###
#       mkimage -A arm -T script -C none -n "My Boot.scr" -d boot.script boot.scr
# todo: mark every reboot (normal/unknown reason) 

### todo: reboot when interfaces/mac has changed

# from scratch:
# google: 'linaro pandaboard.img.bz2 -android'
# -> http://releases.linaro.org/14.02/ubuntu/panda
# -> https://launchpad.net/linaro-dev-platform/+milestone/14.03
### dd if=image of=/dev/sdX
# partition vergroessern:
### fdisk /dev/sdX
# 'p' = print  - look sector START of partition 2
# 'd' = delete - partition 2
# 'n' = new    - partition 2
# enter START + 4G = gigabyte
# 'w' = write
### sudo e2fsck -f /dev/sdb2
### sudo resize2fs /dev/sdb2 4G
# boot card, maybe replace u-boot + MLO (new memory)
# connect via serial console
### adduser tasso
# wget setup to /etc/rc.local
### chmod +x /etc/rc.local
### /etc/rc.local (and answer some questions)



# todo:
# checksum fuer jpg-bilder
# abhängigkeit kasse1 weg von event
# ethernetsteckdose eventwand
# monitore abschalten bei fehler:
#  - export DISPLAY=0:0
#  - abschalten: xset +dpms; xset dpms force standby
#  - wieder einschalten: xset -dpms
#  - aktuelle werte abzeigen: xset -q

# handlungsanweisung an:
# "GNM Haustechnik" <manfred.meiselbach@klassik-stiftung.de>
# 03643/545-324 Meiselbach
# 03643/545-368 Kaufmann


# bild fehlerhaft:
# email: online@klassik-stiftung.de
# pruefsumme fuer jpeg oder anderes verfahren
#
# wenn zeitserver nicht erreichbar:
# email, schwarzes bild + mini-hinweistext + wenn wieder geht:
# email versenden
#
# email: lombego: vorschlag wie preufsumme eingebaut wird, cc: schaefer + seyfarth
# herr nocken
#
# hinweis auf uebliche textauszecihnungen (auch touchWerther)


# root@kasse2:/home/tasso# wget -O - http://172.17.40.8:3000/view/kasse
# --2013-12-13 10:12:01--  http://172.17.40.8:3000/view/kasse
# Connecting to 172.17.40.8:3000... failed: Connection refused.

# tasso@kasse1:~$ wget -O - http://localhost:3000/view/kasse
# --2013-12-13 10:13:43--  http://localhost:3000/view/kasse
# Resolving localhost (localhost)... ::1, 127.0.0.1
# Connecting to localhost (localhost)|::1|:3000... failed: Connection refused.
# Connecting to localhost (localhost)|127.0.0.1|:3000... failed: Connection refused.

# -> check if wget $URL works, if not -> pkill midori


# touchMedien: add default route always


# touchMSR/touchMEDIEN:
# - firefox
# - soundplayer zum testen
# - USB2USB-network (auf MedienTouch) + treiber
#   - change bigbrother-mac to Schaefer?
# - crontab.tasso: $PATH? - fetch XML every 5 mins
# - ntp: 172.17.8.151
# - dns: 172.17.8.151/152
# - mail: 172.17.8.20 ksw-mail.ads.swkk.de
# - defgw: 172.17.19.1
# - audio on panda: http://delog.wordpress.com/2011/07/06/audio-on-pandaboard/
#   (comment from rob April 3, 2013 at 2:22 pm)

# monitor: video-server from touch1/touch2
# echo -e "login root fm1204\nport list 1ii1\nquit" | netcat -w 1 172.17.34.66 1234


# TODO:
# - free discspace -> monitoring
# - wenn ICH per ssh irgendwo drauf bin, soll kein internet-kram gemacht werden
#   ich brauch die leitung fuer mich alleine, jeder soll exklusiv fragen/bekommen/abgeben internet
# - ask4internet: 1 min
# - erlaube fuer IP xy ODER 'komm wieder in X min'
# - nach 60 sec, regel loeschen
#   - bei ssh-login: hinweis schreiben
#   - fruehs vor 8 uhr = egal, da gehts immer

# sudo /etc/rc.local function ssh_setup copykey




# oracleDB-output posten:
# curl -X POST -T "$file.json" http://localhost:3000/api/oracle
# bla | curl -X POST -T - http://localhost:3000/api/oracle



# # `TASSO` Setup & Deploy 
#
# Kick it off: 
# - Get script: `curl "https://static.ars.is/tasso/master/setup_gnm2012_panda_generic.sh" > /etc/rc.local && chmod +x /etc/rc.local`
# - Start testing: `/etc/rc.local test dhcp`
# - or automate it with `scripts/deploy2-step2.sh`
#
# ## ToDo-list:
#
# - fixme event5of5/lightdm: https://bugs.launchpad.net/ubuntu/+source/lightdm/+bug/951404
# - run ntpd: http://lists.debian.org/debian-user/2002/12/msg04091.html
# - when clock was set/had a jump: refresh browser
# - ??? kasse2: cronjob: git pull 
# - try checkout/pull from kasse2, fallback to tarball on disc
# - run iodined early (before software_install) and not twice in this case
# - internal pubkey exchange-function()
# - check if mustache/make changed someting: refresh browser
# - update hostfile to know each other
# - extend log() for flag/bool: ok/err and log in different logfiles
# - extend log() for flag/bool: start/ready
# - only event1 will fetch + build .json: all others download json from there (during make mustache)
# - dmesg |grep DataBufferErr | wc -l -> 2 = OK. manchmal >1000
#
# ### 'pre-deploy' to-do:
#
# - please call this script in /etc/rc.local (run as superuser)
#   and start it manually for the first time, because
#   some things are interactive then...
#
# - in `/etc/lightdm/lightdm.conf`:
#
# `````
# [SeatDefaults]
# greeter-session=unity-greeter
# user-session=openbox
# autologin-user=tasso
# `````
#
# - apt-cache sichern/restore
#
#
# ## Manual
#
# ### script update/-load
#
# upload this script to update-server via:
#
# `````
# SRC="Desktop/bittorf_wireless/kunden/elektro-schaefer/projekt_gnm2012/setup_gnm2012_panda_generic.sh"
# scp $SRC root@intercity-vpn.de:/var/www/files
# `````
#
# ### data update -> or just upload to intercity-vpn.de, see update_this_script()
### for updating the data-archive in "/home/tasso/tasso.tgz" do:
#
# mkdir /tmp/tasso_tarball && cd /tmp/tasso_tarball
# git clone --depth 1 '/home/user/software/tasso'
# tar -cvzf tasso.tgz tasso
# scp tasso.tgz $dest
# cd ~ && rm -fR /tmp/tasso_tarball
#
# or:
# scp tasso.tgz root@intercity-vpn.de:/var/www
#
#
# ### share to all boards **from** kasse2:
#
# `````
# (user tasso); for I in 2 3 4 5 6 7 8; do scp /home/tasso/tasso.tgz 172.17.40.${I}:; done	# all
# su; for I in 3 4 5 7 6; do ssh 172.17.40.${I}; done				# event left...right
# /etc/rc.local function update_this_script; /etc/rc.local
# /etc/rc.local function update_this_script; /etc/rc.local function git_checkout; /etc/rc.local function software force
# `````
#
# ### resolution (`xrandr`)
#
# for testing with a fix resolution do: (put in .xsession for permanent changes)
#
# `````
# xrandr --verbose
# xrandr -d 0:0 --newmode 1366x768 85.500 1366 1494 1624 1798 768 770 776 795 +hsync -vsync
# xrandr -d 0:0 --addmode HDMI-1 1366x768
# xrandr -d 0:0 --size 1366x768
# xrandr -d 0:0	-q		# lists modes: active mode has an asterisk ("*")
#
# MYMODE="$( gtf 800 480 60 | grep Modeline | sed s/Modeline\ // | tr -d '"' )"
# output: '800x480_60.00  29.58  800 816 896 992  480 481 484 497  -HSync +Vsync'
# adding a new mode '800x480_60.00'
# xrandr -d 0:0 --newmode $MYMODE
# xrandr -d 0:0 --addmode default "800x480_60.00"
# xrandr -d 0:0 --output default --mode 800x480_50.00
### xrandr -d 0:0 --size "800x480_60.00"
# `````
#

# # Script: ARGUMENTS and VARIABLES

mkdir '/tmp/FIRSTCALL' 2>/dev/null && {		# /tmp = tmpfs (fresh after reboot)
	UNIXTIME_NOW="$( date +%s )"
	UNIXTIME_MAX="$( date +%s -r '/home/tasso/reboot.txt' )"

	if [ $UNIXTIME_NOW -gt ${UNIXTIME_MAX:-0} ]; then
		# internal clock is working
		date -s @$UNIXTIME_NOW
	else
		# cold boot or strange crash
		date -s @$(( $UNIXTIME_MAX + 30 ))
	fi

	tail -n1 '/home/tasso/reboot.txt' | grep -q ': started'$ && {
		# normally there was a 'reason' written during myreboot()
		echo "$( date ): unknown reason" >>'/home/tasso/reboot.txt'
	}

	read UP REST <'/proc/uptime'
	echo "$( date ): up: $UP sec: started" >>'/home/tasso/reboot.txt'
}

myreboot()
{
	local message="$1"

	read UP REST <'/proc/uptime'
	echo "$( date ): up: $UP sec: going down, reason: '$message'" >>'/home/tasso/reboot.txt'
	/sbin/reboot

	exit 1
}

ARG1="$1"		# <hostname> OR keyword 'function'
ARG2="$2"		# <ip> OR 'dhcp' OR <function-name|list> OR 'function update_this_script'

HOSTNAME="$ARG1"
IP="$ARG2"		# can be 'dhcp'

FAKEGW="172.17.40.8"		# kasse1

if [ "$HOSTNAME" = 'touchMSR' ]; then
	CENTRAL_GATEWAY='172.17.19.1'
else
	CENTRAL_GATEWAY='172.17.40.1'
fi

TIMESERVER="172.17.8.151"
DNSSERVER="$TIMESERVER"

case "$( hostname )" in
	touch1|touch2)
		TIMESERVER='172.17.34.65'	# videoserver
	;;
esac

SMTPSERVER="172.17.8.20"
ORACLE="172.17.8.73"
HOME="/home/tasso"
ETHERDEV='eth0'

# Script: FUNCTIONS

mac()
{
	local enforced="/home/tasso/MAC"
	local out="$( ip link show dev "$ETHERDEV" | sed -n "s|^.*link/ether \([a-f0-9:]*\).*|\1|p" )"

	# e.g. 00:24:7e:12:72:f3
	log "mac is: '$out'"

	if [ -e "$enforced" ]; then
		read out <"$enforced"
		log "enforced mac: $out"
		MAC_ENFORCED="$out"
	else
		# e.g. linaro-14.02 does not remeber the mac
		echo "$out" >"$enforced"
	fi

	echo "$out"
}

log()
{
	local message="$1"
	local prio="$2"			# nothing or "alert"
	local file="/tmp/mylog.txt"
	local file_ever="/home/tasso/everlog.txt"

	local date_and_uptime="$( date "+%d.%b'%y-%H:%M.%S" ) / up: $( cut -d'.' -f1 /proc/uptime)sec:"
	local message="[$$] $date_and_uptime startup: $(whoami): $0: $message"

	[ "$prio" = "alert" ] && {
		message="ALERT: $message"
		echo "$message" >>"$file_ever"
	}

	logger -s "$message"
	echo "$message" >>"$file"

	chown tasso:tasso "$file"
	chmod 777 "$file"
}

has_default_route()
{
	route -n | grep -q ^"0\.0\.0\.0"
}

random_integer()
{
	local max="${1:-100}"
	local line
	local seed="$( dd if=/dev/urandom bs=2 count=1 2>&- | hexdump | if read line; then echo 0x${line#* }; fi )"
  # " the line above is correct but confuses TextMate syntax higlighting :/
  # bonus point if you see why; and why the above line fixes it.
	echo "$(( $seed % $max ))"	# e.g. 0x28b9 % 300 = 225
}

is_good_kernel()
{
	case "$( uname -r )" in
		'3.4.0-2-linaro-lt-omap')
			return 0
		;;
		'3.14.0-1-linaro-omap')
			return 0
		;;
		'3.14'*)
			return 0
		;;
	esac

	case "$( mac )" in
		b8:27:eb:*)		# raspberry_pi
			return 0
		;;
	esac

	return 1
}

wait_for_internet()
{
	[ "$FAKEGW" = "$IP" ] && return 0
	[ "$ARG1" = "function" ] && return 0

	case "$( date +%H )" in
		05|06|07|08)
		;;
		*)
			return 0
		;;
	esac

	I=240
	log "waiting up to $I secs for internet, still early in the morning"

	while true; do {
		sleep 1
		I=$(( $I - 1 ))
		ping -c 1 8.8.8.8 && I=0
		[ $I -eq 0 ] && break
	} done
}

disable_whoopsie()
{
	grep -qi ^"report_crashes=true" "/etc/default/whoopsie" && {
		sed -i 's/true/false/' /etc/default/whoopsie
		killall whoopsie
	}
}

check_ping_to_any_station()		# called every 15mins
{
	local i ip
	local list prefix
	local file_counter='/tmp/ping_counter'
	local counter
	local ip_videoserver='172.17.34.65'
	local ip_watchdog='172.17.34.66'

	case "$HOSTNAME" in
		touchMSR)
			list="40"
			prefix="172.17.19."
		;;
		touch1|touch2|cam*)
			# touch1 | touch2 | wartungslaptop? | webcam-raum214/ausstellung
			list="111 112 113 89"
			prefix="172.17.34."

			good_video()
			{
				if [ -e '/tmp/ERROR_VIDEOSERVER' ]; then
					return 1
				else
					if ping -c1 "$ip_videoserver"; then
						return 0
					else
						return 1
					fi
				fi
			}

			if good_video; then
				log "[OK] server '$ip_videoserver'"
				rm "$file_counter"
			else
				echo -n '#' >>"$file_counter"
				read counter <"$file_counter"
				log "server '$ip_videoserver' unreachable for ${#counter} times"

				[ ${#counter} -ge 5 ] && {
					# after reboot it needs some time to recover / repair HDD
					log "server '$ip_videoserver' unreachable: ${#counter}, rebooting via netio" alert
					echo -e "login root fm1204\nport list 111i\nquit" | netcat -w 1 "$ip_watchdog" 1234
					rm "$file_counter"
				}
			fi
		;;
		*)
			list="dhcp 2 3 4 5 6 7 8 9"
			prefix="172.17.40."
		;;
	esac

	list="$list $list $list $list $list"	# try 5 times

	for i in $list; do {
		ip="${prefix}${i}"
		[ "$ip" = "$IP" ] || {
			[ "$i" = "dhcp" ] && ip="8.8.8.8"	# testnode
			if ping -c1 $ip ; then
				log "good ping to $ip"
				return 0
			else
				log "no ping to $ip (was: '$i')"
			fi
		}
	} done

	case "$( date +%H )" in
		21|22|23|24|00|01|02|03|04|05)
		;;
		*)
			myreboot "no ping possible to $list"
		;;
	esac
}

list()		# show all function-names of this file
{
	sed -n "s|^\([a-zA-Z0-9_]*\)()$|$0 function \1|p" "$0" | sort
}

write_if_needed()
{
	local content="$1"
	local file="$2"

	grep -q ^"$content"$ "$file" || echo "$content" >"$file"
}

hostname()
{
	local name="$1"

	write_if_needed "$name" '/proc/sys/kernel/hostname'
	write_if_needed "$name" '/etc/hostname'
	write_if_needed "127.0.0.1 $name" '/etc/hosts'		# otherwise 'sudo' complains
}

cpu_tweak()
{
	local option="$1"			# e.g. getinfo
	local file='/tmp/cpufreq-info'

	[ -e "$file" ] || {
		/usr/bin/cpufreq-info >"$file"

		# e.g. 'omap2plus'
		set -- $( grep 'driver: ' "$file" | head -n1 )
		echo "$2" >"$file.driver"

		# e.g. '300'
		set -- $( grep 'current CPU frequency is ' "$file" | head -n1 )
		echo "$5" >"$file.freq"

		# e.g. 'ondemand' or 'userspace'
		set -- $( grep 'The governor "' "$file" | head -n1 )
		echo "$3" | cut -d'"' -f2 >"$file.gov"
	}

	[ "$option" = 'getinfo' ] && {
		local freq gov driver
		read freq   <"$file.freq"
		read gov    <"$file.gov"
		read driver <"$file.driver"

		echo "${freq:-noFREQ}.${driver:-noDRIVER}.${gov:-noGOV}"
		return 0
	}

	is_good_kernel && return 0

	[ -e "$file.done" ] || {
		touch "$file.done"

		fgrep -q 'The governor "userspace"' "$file" || {
			log "setting cpu-governor to 'userspace' and fix to 300 MHz"
			/usr/bin/cpufreq-set -r -f 300MHz
			sed -i 's/GOVERNOR="ondemand"/GOVERNOR="userspace"/' /etc/init.d/cpufrequtils
			sed -i 's/MAX_SPEED="0"/MAX_SPEED="300"/' /etc/init.d/cpufrequtils
		}
	}
}

validate_url()
{
	local url="$1"
	[ -z "$url" ] && read url <"/tmp/URL_FIREFOX.txt"	# 2nd line can be a comment

	log "validating: '$url'"
	w3c-validator.py "$url"

	if [ $? -eq 0 ]; then
		log "validated: OK"
	else
		log "error during validating" alert
	fi
}

uptime_in_seconds()
{
	local uptime
	read uptime </proc/uptime
        echo ${uptime%%.*}
}

omap_board()
{
	local file="/tmp/dmesg.boot"
	[ -e "$file" ] || {
		dmesg -c >"$file"
		cp "$file" '/tmp/dmesg.log'
	}

	fgrep "CPU:" "$file" | cut -b 16-
	fgrep "] OMAP" "$file" | cut -b 16-
}

get_onboard_temperature()
{
	return 0

	if [ -e "/opt/vc/bin/vcgencmd" ]; then
		# http://raspberrypi.stackexchange.com/questions/1207/how-to-measure-temperature
		# http://wiki.stocksy.co.uk/wiki/Raspberry_Pi_onboard_temperature_sensors
		# temp=45.5'C -> 45
		/opt/vc/bin/vcgencmd measure_temp | cut -d'=' -f2 | cut -d'.' -f1 | cut -d"'" -f1
	else
		if is_good_kernel; then
			/usr/local/bin/omap4_temp
		else
			log "bad kernel, no output of temperature"
		fi
	fi
}

filesize_mirrored_jpegs()
{
	local size=0
	local file

	for file in /tmp/tasso/events5x/*.jpg; do {
		[ -e "$file" ] && {
			size=$(( $size + $( wc -c <"$file" ) ))
		}
	} done

	echo "$size"
}

monitoring()
{
	local network="gnm"
	local ethernet="$ETHERDEV"
	local hardware
	local mac="$( mac )"; mac="${mac//:/}"

	screenshot "root@intercity-vpn.de:/var/www/networks/$network/settings/${mac}.screenshot.jpg"

	case "$mac" in
		b827eb*)
			hardware="RaspberryPi"
		;;
		*)
			hardware="Pandaboard"
		;;
	esac

	local mygw="$( ip route list exact '0.0.0.0/0' | cut -d' ' -f3 )"
	[ -z "$mygw" ] && return 1

	local mydev="$( ip route list exact '0.0.0.0/0' | head -n1 | cut -d' ' -f5 )"
	local myip="$( ip address show dev $mydev | sed -n "s/^.*inet \(.*\)\/.*/\1/p" )"
	local url="http://intercity-vpn.de/networks/$network/meshrdf"
	local mypubip="$( wget -qO - "http://intercity-vpn.de/scripts/getip/" )"
	local version=$(( $( stat --printf %Y /var/lib/dpkg/status ) / 3600 ))
	local k1="$( sed -n '$=' "/tmp/dmesg.boot" )"
	local k2="$( sed -n '$=' "/tmp/dmesg.log" )"

	local hostname
	read hostname </proc/sys/kernel/hostname

	local ram l
	while read l; do case "$l" in MemTotal:*) set -- $l; ram=$2; break;; esac; done </proc/meminfo

	local uptime=$(( $( uptime_in_seconds ) / 3600 ))

	local load
	read load </proc/loadavg
	load=${load%% *}
	load=${load//./}

	local ssid="$( get_onboard_temperature )"
	if [ -n "$ssid" ]; then
		ssid="$ssid+%c2%b0C"	# space grad celcius
	else
		# EXT4-fs (mmcblk0p2): Remounting filesystem read-only
		if   grep -sq 'Remounting filesystem read-only' '/tmp/dmesg.boot' '/tmp/dmesg.log'; then
			ssid='ReadOnly'
		elif [ -e '/tmp/rootfs_clean' ]; then
			ssid="$( cpu_tweak getinfo )"
		elif e2fsck -n '/dev/mmcblk0p2' | grep -q ^'rootfs: clean'; then
			touch '/tmp/rootfs_clean'
			ssid="$( cpu_tweak getinfo )"
		else
			ssid='FSerr'
		fi
	fi

	local switch="$( [ -e "/sbin/mii-tool" ] && /sbin/mii-tool "$ethernet" )"
	case "$switch" in
		*1000baseT-HD*) switch="c" ;;
		*) switch="-" ;;
	esac

	free_space()
	{
		set -- $( df /dev/mmcblk0p2 | tail -n1 )
		echo $4
	}

	[ $( free_space ) -lt 10000 ] && {
		log "logrotating /home/tasso/everlog.txt"
		gzip --best '/home/tasso/everlog.txt'
		mv '/home/tasso/everlog.txt.gz' "/home/tasso/everlog.txt.gz.$$"
		log "logrotated /home/tasso/everlog.txt" alert
	}

	local file="/home/tasso/tasso.tgz"
	local flash_free="flash.free.kb:$( free_space )"
	local tarball_info="$( stat -c%s "$file" )-$( md5sum "$file" | cut -b 1-8 )"
	local file="$0"
	local script_info="$( stat -c%s "$file" )-$( md5sum "$file" | cut -b 1-8 )"
	local board_info="$( omap_board | md5sum | cut -b 1-8 )"
	local json_hash="$( md5sum /tmp/tasso/events5x/contents/events.json 2>/dev/null | cut -b 1-8 )"
	local fsize="$( filesize_mirrored_jpegs )"
	local colon="%3a"
	local summary="tar${colon}${tarball_info}+script${colon}${script_info}+board${colon}${board_info}+json${colon}${json_hash}+size${colon}${fsize}"
	local node="$( echo "$myip" | cut -d'.' -f4 )"

	url="$url/?local=$( date +%Y%b%d_%Huhr%M )&node=${node}&city=168&mac=${mac}&latlon=&hostname=${hostname}&update=0&wifidrv=&olsrver=&olsrrestartcount=0&olsrrestarttime=&portfw=&optimizenlq=&optimizeneigh=off&txpwr=0&wifimode=ap&channel=1&mrate=auto&hw=${hardware}&frag=&rts=&pfilter=${summary}&gmodeprot=0&gmode=11ng&profile=${network}_ap&noise=-1&rssi=&distance=&version=${version}&reboot=1&up=${uptime}&load=${load}&forwarded=0&essid=${ssid}&bssid=&gw=1&gwnode=1&etx2gw=1&hop2gw=0&neigh=&users=&pubip=${mypubip}&sens=&wifiscan=&v1=$( uname -r )&v2=&s1=${switch}&h1=${ram}&h2=&h4=2&h5=33&h6=4096&h7=337&d0=&d1=&n0=&i0=static&i1=wan&i2=${myip}%2f29&i3=0&i4=0&i5=${mygw}&r0=&w0=wlan0&w1=0&k1=$k1&k2=$k2&services=$flash_free"

	log "${#url} bytes: $url"
	wget -T 30 -qO /dev/null "$url" || log "failing to send monitoring"

	case "$load" in
		0*|10*|11*|12*|13*|14*|15*)
		;;
		*)
			log "too much load: '$load' - rebooting" alert
			[ $( uptime_in_seconds ) -gt 600 ] && myreboot "too much load: '$load'"
		;;
	esac
}

screenshot()
{
	local file="/tmp/screenshot.jpg"
	local upload_destination="$1"
	local exiftime="$( date "+%Y:%m:%d %T.%N" | sed -n 's/^\(.*\...\).*/\1/p' )"
	local unixtime="$( date +%s )"
	local upload

	[ -e "$file" ] || upload="true"

	local hash_old="$( sha1sum "$file" )"

  if ( grep -q 'Debian GNU/Linux wheezy/sid' /etc/issue ); then
    # if we are on a debian/raspbian (Raspberry Pi)
  	export DISPLAY=":0"
  else
  	export DISPLAY="0:0"
  fi

	log "screenshot to '$file'"
	scrot --delay 2 --quality 10 "$file" || {
		which scrot && {
			echo -n "#" >>/tmp/SCROTERR
			case "$( cat /tmp/SCROTERR )" in
				'#####'*)
					[ "$HOSTNAME" = 'stranger' ] || {
						# todo?: apt-get install --reinstall gdm
						myreboot "scrot: REBOOT: giblib error: Can't open X display. It *is* running, yeah?"
					}
				;;
			esac
		}
	}

	chmod 777 "$file"			# so we can remove it to enforce a new shot
	chown tasso:tasso "$file"
	local hash_new="$( sha1sum "$file" )"
	local size="$( stat -c%s "$file" )"
	local size_original="${size:-0}"

	log "screenshot taken: $size bytes"

	case "$size" in
		18002|23676)	# "404 not found" | "background-pattern (no gfx) - 23826??" | couldt not be loaded on kasse2 / same
			hash_old="$hash_new"
			# TODO: if last screenshot was also 18002, then upload=
		;;
		17752|17138|230414|226620)	# grep + "starting_up" | grey only | black? | grey | + maybe 230623 = raster/grau
			hash_old="$hash_new"
		;;
		40254|40463)		# "404 not found"
			[ "$HOSTNAME" = 'touchMedien' ] && hash_old="$hash_new"
		;;
	esac

	which exiftool >/dev/null && {
		rm '/tmp/screenshot.jpg_exiftool'* 2>/dev/null
		exiftool -CreateDate="$exiftime" -comment="UNIXTIME:$unixtime" "$file"
		size="$( stat -c%s "$file" )"
		log "screenshot taken: $size bytes (after exiftool)"
	}

	[ -z "$size" ] && size=0

	if [ "$hash_old" = "$hash_new" -a -e "$file" ]; then
		log "screen did not change on host '$HOSTNAME'"
		case "$HOSTNAME" in
			kasse*)
				[ $size_original -lt 18500 -o $size_original -eq 23676 ] && {
					log "strange: very small file: $size_original bytes" alert
					browser_sendkey 'F5'
				}
			;;
			*)
				case "$( cat "/tmp/URL_FIREFOX.txt" )" in
					*"pudelfallback.html")
					;;
					*)
						refresh_needed()
						{
							case "$size_original" in
								40254|40463)
									[ "$HOSTNAME" = 'touchMedien' ] && return 0
								;;
							esac

							[ "$size_original" = "18002" ] && return 0	# error 404: YES!
							grep -q "pics_only" "$0" && return 1		# pic-only mode: NO!
						}

						refresh_needed && {
							log "error - refreshing browser" alert
							browser_sendkey 'F5'
						}
					;;
				esac
			;;
		esac
	else
		log "screen changed: hashs: '$hash_old' -> '$hash_new'"
	fi

	if [ "$upload" = "true" -a -e "$file" -a -n "$( ip route list exact '0.0.0.0/0' )" ]; then
		[ -n "$upload_destination" ] && {
			[ -e '/tmp/NOPAUSE' ] || {
				local pause="$( random_integer 333 )"
				log "uploading to '$upload_destination' in $pause sec (touch '/tmp/NOPAUSE' to avoid)"
				sleep $pause
			}

			local i=10
			while [ $i -gt 0 ]; do {
				if scp "$file" "$upload_destination"; then
					break
				else
					i=$(( $i - 1 ))
					sleep 10
					[ $i -eq 0 ] && {
						log "screenshot() scp failed" alert
						rm "$file"	# try again next round
					}
				fi
			} done
		}
	else
		log "upload not TRUE"
	fi

	case "$size_original" in
		17138|230414|226620)
			local greyscreens=0
			echo -n "#" >>"/tmp/greyscreen_counter"
			read greyscreens <"/tmp/greyscreen_counter"

			if [ ${#greyscreens} -gt 10 ]; then
				myreboot "rebooting, grey screen: $size_original bytes - counter: $greyscreens"
			else
				log "grey screen: $size_original bytes - counter: $greyscreens - ignoring: hash old/new: $hash_old/$hash_new" alert
			fi
		;;
		*)
			[ -e "/tmp/greyscreen_counter" ] && rm "/tmp/greyscreen_counter"
		;;
	esac

	[ $size_original -eq 18002 ] || {
		[ $size_original -lt 18500 ] && {
			rm "$file"
		}
	}
}

time_setup()
{
	local tz i unixtime unixtime_reference

    # If the time zone is NOT set correctly, 
    read tz </etc/timezone
    [ "$tz" = "Europe/Berlin" ] || {
        # we set the time zone.
        echo "Europe/Berlin" > /etc/timezone
        dpkg-reconfigure --frontend noninteractive tzdata
    }

	[ -e "/usr/sbin/ntpdate" ] || {
		log "cannot setup time, missing /usr/sbin/ntpdate"
		return 0
	}

	case "$HOSTNAME" in
		touch1|touch2)
			log "[OK] no real NTP available: $TIMESERVER"
			local UNIXTIME="$( wget  -qO - 'http://172.17.34.109/cgi-bin-tool.sh?OPT=unixtime' )"
			[ -n "$UNIXTIME" ] && {
				TIMESTRING="$( date -d @$UNIXTIME )"
				date --set "$TIMESTRING"
			}
		;;
	esac

	unixtime_reference="$( date +%s -r '/home/tasso/reboot.txt' )"

	while [ ${unixtime:-0} -lt $unixtime_reference ]; do {
		pidof ntpd >/dev/null && {
			log "stopping ntpd - we dont need it"
			/etc/init.d/ntp stop
		}

		i=$(( ${i:-0} + 1 ))
		log "run $i/60: time maybe still not correct: $( date ), using server '$TIMESERVER'"
		log "$( /usr/sbin/ntpdate $TIMESERVER )"
		test $i -eq 1 || sleep 10
		[ $i -gt 60 ] && break
		unixtime="$( date +%s )"
	} done

	[ -e '/tmp/ntp_was_set' ] || {
		touch '/tmp/ntp_was_set'
		read UP REST <'/proc/uptime'
		echo "$( date ): up: $UP sec: set time: started" >>'/home/tasso/reboot.txt'
	}

	case "$HOSTNAME" in
		'tagebuchbeamer')
			set_url_tagebuchbeamer 'check' || {
				log "time_setup: day changed, killing midori" alert
				set_url_tagebuchbeamer
				pidof midori >/dev/null && pkill midori
			}
		;;
	esac

	log "time now: $( date )"
}

ssh_setup()
{
	local option="$1"
	local file="/$( whoami )/.ssh/id_rsa.pub"
	local server="root@intercity-vpn.de"

    # Check if a ssh key exist already (pre-deployed machines should have the master key).
	if [ -e "$file" ]; then
		log "ssh already setup"
	else
		log "generating keys"
		ssh-keygen -t rsa -b 2048
		option="copykey"
	fi

	[ "$option" = "copykey" ] && {
#		ssh-copy-id -i "$file" "-p 22 $server"

		log "copy '$file' to '$server' :/tmp/authorized_keys.gnm.$HOSTNAME"
		scp "$file" ${server}:/tmp/authorized_keys.gnm.$HOSTNAME

		log "now do on server:"
		log "cat /tmp/authorized_keys.gnm.* >>~/.ssh/authorized_keys.gnm"
		log "rm /tmp/authorized_keys.gnm.*"
		log "/var/www/scripts/apply_pubkeys_from_network-registrator_to_auth_keys.sh join"

		echo
		echo "please press enter, to go further and make sure"
		echo "if git is needed you copy our id to the deploy-keys:"
		echo
		cat "$file"
		echo
		read dummy
	}
}

network()
{
	local ip="$1"
	local defgw
	local file="/etc/network/interfaces"
	local i=20

    # while true; do {
    #     i=$(( $i - 1 )); [ $i -eq 0 ] && break
    #     ip address show dev eth0 | fgrep -q "inet " || {
    #         log "no ip, restart ifs, $i loops left"
    #         /etc/init.d/networking restart
    #         sleep 10
    #     }
    # } done

	mac >/dev/null		# maybe get $MAC_ENFORCED

	[ -n "$ip" ] && {
		echo  >"$file" "# interfaces(5) file used by ifup(8) and ifdown(8)"
		echo >>"$file"
		echo >>"$file" "auto lo"
		echo >>"$file" "iface lo inet loopback"
		echo >>"$file"
		echo >>"$file" "auto $ETHERDEV"

		if [ "$ip" = "dhcp" ]; then
			echo >>"$file" "iface $ETHERDEV inet dhcp"

			if [ -n "$MAC_ENFORCED" ]; then
				echo >>"$file" "	hwaddress ether $MAC_ENFORCED	# see mac() in $0"
			else
				echo >>"$file" "#	hwaddress ether 01:02:03:04:05:06	# see mac() in $0"
			fi
		else
			echo >>"$file" "iface $ETHERDEV inet static"

			if [ -n "$MAC_ENFORCED" ]; then
				echo >>"$file" "	hwaddress ether $MAC_ENFORCED	# see mac() in $0"
			else
				echo >>"$file" "#	hwaddress ether 01:02:03:04:05:06	# see mac() in $0"
			fi

			echo >>"$file" "	address $ip"

			case "$HOSTNAME" in
				touchMSR)
					echo >>"$file" "	netmask 255.255.255.0"		# = /24
				;;
				touch1|touch2|cam*)
					echo >>"$file" "	netmask 255.255.255.192"	# = /26
				;;
				*)
					echo >>"$file" "	netmask 255.255.255.224"	# = /27
				;;
			esac

			defgw="default via $CENTRAL_GATEWAY dev $ETHERDEV"
			echo >>"$file" "	gateway $CENTRAL_GATEWAY"
		fi
	}

	[ "$ip" = "dhcp" ] || {
		log "enforcing nameserver $DNSSERVER"
		echo  >"/etc/resolv.conf" "domain lan"
		echo >>"/etc/resolv.conf" "search lan"
		echo >>"/etc/resolv.conf" "nameserver $DNSSERVER"
	}

	ifconfig $ETHERDEV up	# kasse-touch-UI/ needs this

	[ -z "$defgw" ] && defgw="$( ip route list exact '0.0.0.0/0' | fgrep " via $CENTRAL_GATEWAY " )"

	[ -n "$defgw" ] && {
		ip route del $defgw
		[ "$FAKEGW" = "$IP" ] || ip route add default via $FAKEGW	# kasse1
		ip route add 89.107.188.71 via "$CENTRAL_GATEWAY"		# klassik-stiftung.de
		ip route add 172.17.8.0/24 via "$CENTRAL_GATEWAY"
	}
}

blacklist_kmodules()
{
	local file="/etc/modprobe.d/blacklist.conf"
	local list module

	# always disable parport?
	# lp parport ppdev

	if is_good_kernel; then
		# 3.14
		list='wl12xx wlcore mac80211 cfg80211 bluetooth 6lowpan_iphc wlcore_sdio'
	else
		list="wl12xx wlcore wlcore_sdio mac80211 cfg80211"
		list="$list omapdce omaprpc rpmsg_resmgr_common omap_rpmsg_resmgr"
		list="$list joydev gpio_keys leds_gpio rpmsg_resmgr"
		list="$list virtio_rpmsg_bus omap_remoteproc remoteproc virtio virtio_ring"
	fi
#						# usbhid: mouse/keyboard
#	list_needed="omapdrm_pvr usbhid"	# omapdrm_pvr: makes problems during unload
#	for module in $list_needed; do {
#		grep -q ^"blacklist $module" "$file" && {
#			sed -i "s/blacklist $module/# blacklist $module/" "$file"
#		}
#	} done

	for module in $list; do {
		grep -q ^"$module " '/proc/modules' && {
			log "unloading $module"
			rmmod $module
		}

		grep -q ^"blacklist $module" "$file" || {
			log "blacklisting '$module'" alert
			echo >>"$file" "# enforced from $0: blacklist_kmodules()"
			echo >>"$file" "blacklist $module"
		}
	} done
}

iodine_daemon()
{
	local session_password='test'

	echo 1 >/proc/sys/net/ipv4/ip_forward
	iptables -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
	iptables -t nat -I POSTROUTING -s '172.17.0.0/16' -j MASQUERADE

	# /sbin/start-stop-daemon --background --chuid root --start --exec /usr/local/bin/dnstun.sh --

	/usr/sbin/iodine -P "$session_password" "$DNSSERVER" bittorf2.mooo.com
	ip route add "$TIMESERVER/32" via "$CENTRAL_GATEWAY"
	ip route del default via "$CENTRAL_GATEWAY"
	ip route add default via 172.30.0.1
}

optimize_getty()
{
	local i file action

	for i in 2 3 4 5 6; do {
		file="/etc/init/tty${i}.conf"
		grep -q ^'# respawn' "$file" || {
			sed -i -e 's/respawn/# respawn/' -e 's/exec/# exec/' "$file"
			action='true'
		}
	} done

	[ -n "$action" ] && killall getty
}

do_sysctl()
{
	for ENTRY in "vm.panic_on_oom=1" "kernel.panic_on_oops=1" "kernel.panic=1"; do {
		/sbin/sysctl -w $ENTRY
		grep -q ^"$ENTRY" "/etc/sysctl.conf" || {
			echo "$ENTRY" >>"/etc/sysctl.conf"
		}
	} done
}

leds_off()
{
	echo -n none > /sys/class/leds/pandaboard::status1/trigger	# default is: always 2x/sec
	echo -n none > /sys/class/leds/pandaboard::status2/trigger	# default is: on sdcard activity
}

browser()	# here we write the 'openbox'-autostartfile
{
	local uri="$1"		# is written to '/tmp/URL_FIREFOX.txt'
	local comment="$2"

	local file='/tmp/autostart.temp'
	local file_ready="$HOME/.config/openbox/autostart"
	local bin hide file
	local ffbin="/usr/bin/firefox -width 1366 -height 768"		# fullscreen?
	local webkitbin="/usr/local/bin/firefox"
	local dirty=
	local ask_for_pid="firefox"

	touch /tmp/FFWAIT
	mkdir -p $( dirname "$file" )

	[ -e '/tmp/FORCEFF' ] && dirty="X"	# enforce firefox?

	if   [ -e "/usr/bin/midori" ]; then
		bin="/usr/bin/midori --execute Fullscreen --app"
		hide="#"
		ask_for_pid="midori"

	elif [ -e "${dirty}${webkitbin}" ]; then
		bin="$webkitbin"
		hide="#"
	else
	#	firefox_value_set "browser.cache.disk.capacity" "50111222"	# 50mb
	#	firefox_value_set "browser.cache.disk.enable" "true"
	#	firefox_value_set "browser.cache.check_doc_frequency" "0"	# Check once per browser session
	#	firefox_value_set "browser.cache.disk.parent_directory" "/tmp/ffcache"
	#	firefox_value_set "browser.cache.memory.capacity" "256000"	# use 256mb RAM in [kilobytes]
		firefox_value_set "dom.max_script_run_time" "0"			# dont complain if it lasts long
		firefox_value_set "browser.sessionstore.resume_from_crash" "false"

		bin="$ffbin"
		hide=
	fi

	log "using binary: '$bin'"

	browser_fallback_page >"$HOME/default.html"
	chown tasso:tasso "$HOME/default.html"

	log "writing URL to /tmp/URL_FIREFOX.txt: '$uri' comment: '$comment'"
	echo  >"/tmp/URL_FIREFOX.txt" "$uri"
	[ -n "$comment" ] && echo >>"/tmp/URL_FIREFOX.txt" "$comment"
	chown tasso:tasso "/tmp/URL_FIREFOX.txt"

	echo  >"$file" "log() { echo \"[\$\$] \$(date)|\$( cut -d'.' -f1 /proc/uptime ) autostart: \$(whoami): \$0: \$1\" >>/tmp/mylog.txt; }"
	# rc.local hangs forever, because of fire_nodejs()
	echo >>"$file" "while [ ! -e /tmp/RCLOCAL_READY ]; do log \"waiting for END of rc.local\"; sleep 5 ; done"
	echo >>"$file"
	echo >>"$file" "while true; do {"
	echo >>"$file" "	log \"s1: kill $ask_for_pid\"; pkill $ask_for_pid"
	echo >>"$file" "$hide	mkdir -p /tmp/browserhome/.mozilla"
	echo >>"$file" "$hide	rm -fR /home/tasso/.mozilla"
	echo >>"$file" "$hide	ln -s /tmp/browserhome/.mozilla /home/tasso/.mozilla"
	echo >>"$file" "$hide 	$0 function firefox_value_set dom.max_script_run_time 0"
	echo >>"$file" "$hide 	$0 function firefox_value_set browser.sessionstore.resume_from_crash false"
	echo >>"$file" "	URL=; read URL </tmp/URL_FIREFOX.txt"
	echo >>"$file" "	URL=\${URL:-file://$HOME/default.html}"
	echo >>"$file" "	log \"s2: using url: \$URL\""
	echo >>"$file" "	[ -e /tmp/FFWAIT ] || pidof $ask_for_pid >/dev/null || {"
	echo >>"$file" "		log \"s3: starting browser\" alert"
	echo >>"$file" "		$bin \$URL &"
	echo >>"$file" "$hide		log \"s4: browser started, waiting 60s\""
	echo >>"$file" "$hide		sleep 60; $0 function browser_sendkey \"F11 F5\""
	echo >>"$file" "$hide		log \"s5: send key F11 + F5\""
	echo >>"$file" "	}"
	echo >>"$file" "$hide	$0 function firefox_value_set dom.max_script_run_time 0"
	echo >>"$file" "$hide	$0 function firefox_value_set browser.sessionstore.resume_from_crash false"
	echo >>"$file" "	sleep 5; renice 10 \$( pidof $ask_for_pid )"
	echo >>"$file" "	while pidof $ask_for_pid >/dev/null; do sleep 5; done"
	echo >>"$file" "	log \"s6: $ask_for_pid was stopped\" alert"
	echo >>"$file" "	$0 function make_mustache"
	echo >>"$file" "	rm /tmp/screenshot.jpg"
	echo >>"$file" "$hide	rm $( firefox_settings_dir )/sessionstore.*"
	echo >>"$file" "} done"

	mv "$file" "$file_ready"
	chown tasso:tasso "$file"
	chmod 777 "$file"

	rm /tmp/FFWAIT
}

browser_pudel_page()
{
	local id="$( echo "$HOSTNAME" | cut -d't' -f2 | cut -d'o' -f1 )"	# event4of5 -> 4

	cat <<EOF
<html><head><title>GNM.events</title><style>
body {
  background-image: url('fb${id}.jpg');
  background-position: 0 0;
  background-repeat: no-repeat;
}
</style>
</head>
<body id='ndebug'>&nbsp;</body></html>
EOF
}

browser_fallback_page()
{
	set -- $( ip address show dev "$ETHERDEV" | fgrep "inet6 " )
	local ipv6="$2"

	cat <<EOF
<html><head><title>GNM</title></head><body bgcolor='#2e2e2e'>
<br><br>
<h2>Goethe National Museum</h2>
<h3>starting up device '$HOSTNAME'</h3>
<small>MAC: $( mac )</small>
<small>IPv6: $ipv6</small>
<small>IPv4: $IP</small>
</body></html>
EOF
}

real_firefox_is_active()
{
	grep -sq "#" "$HOME/.config/openbox/autostart"
}

browser_sendkey()
{
	local list_keys="$1"		# e.g. F5 F11
	local window_id name key

	case "$list_keys" in
		*"F5"*)
			make_mustache
		;;
	esac

	pidof midori >/dev/null && {
		log "detected midori, killing" alert
		pkill midori
		return 0
	}

	export DISPLAY="0:0"

	window_id="$( xdotool search --name "warning" )"
	[ -n "$window_id" ] && {
		log "need to send escape key, a warning message needs me" alert
		xdotool windowactivate --sync $window_id
		xdotool key --clearmodifiers "Escape"
		[ "$list_keys" = "Escape" ] && return 0
		sleep 10
	}

	for name in "firefox" "Mozilla Firefox" "webkit"; do {
		log "checking for window '$name' on display '$DISPLAY'"
		for window_id in $( xdotool search --name "$name" ); do {
			xdotool windowactivate --sync $window_id
			for key in $list_keys; do {
				real_firefox_is_active || kill -s USR1 $(pidof firefox)
				log "trying to send '$key' to window-ID '$window_id'"
				xdotool key --clearmodifiers "$key"
			} done
			break	# only first window
		} done
		[ -n "$window_id" ] && break
	} done

	log "it should have refreshed content from /tmp/URL_FIREFOX.txt -> '$( cat /tmp/URL_FIREFOX.txt )'" alert
}

firefox_settings_file()
{
	echo "$( firefox_settings_dir )/prefs.js"
}

firefox_settings_dir()
{
	# e.g. .../pka7p94k.default/...
	find $HOME/.mozilla/firefox/*.default -type d | head -n 1
}

firefox_value_set()	# http://kb.mozillazine.org/About:config_entries
{
	local var="$1"
	local value="$2"
	local file
	local newline="user_pref(\"$var\", $value);"

	end_ff()
	{
		pidof firefox >/dev/null && pkill firefox
		while pidof firefox >/dev/null; do {
			log "waiting for end of firefox"
		} done
		log "firefox has ended"
	}

	file="$( firefox_settings_file )"
#	chown root:root "$file"
#	chmod 744 "$file"

	  if fgrep -q "$newline" "$file"; then
		log "var '$var' already OK (= '$value')"
	elif grep -q "$var" $file; then
		end_ff
		log "change var '$var' to '$value' in file: '$file'"
		sed -i "/$var/s/^.*/$newline/" "$file"
	else
		end_ff
		log "adding var '$var' to file: '$file'"
		echo "$newline" >>"$file"
	fi

#	chown root:root "$file"
#	chmod 744 "$file"		# only root can modify, all others readonly
}

optimize_fstab()	# http://wiki.ubuntuusers.de/Tuning
{
	local file="/etc/fstab"
	local root="$( mount | grep mmc | head -n1 )"		# /dev/mmcblk0p2 on / type ext4 (rw)
	local fs="$(  echo "$root" | cut -d' ' -f5 )"
	local dev="$( echo "$root" | cut -d' ' -f1 )"

	# http://unix.stackexchange.com/questions/34300/what-is-in-fsck-section-in-fstab
	local do_fscheck=1

	grep -q ^"# v2" "$file" || {
		echo  >"$file" "tmpfs	/tmp		tmpfs	defaults			0	0"
		echo >>"$file" "tmpfs	/var/log	tmpfs	defaults			0	0"
		echo >>"$file" "$dev	/	$fs	noatime,errors=remount-ro	0	$do_fscheck"
		echo >>"$file" "# v2"
	}

	# autorepair: http://askubuntu.com/questions/151025/how-can-i-make-fsck-run-non-interactively-at-boot-time
	grep -q ^'FSCKFIX=no' '/etc/default/rcS' && {
		sed -i 's/FSCKFIX=no/FSCKFIX=yes/' '/etc/default/rcS'
	}
}

install_fonts()		# https://wiki.ubuntu.com/Fonts#Manually
{
	local fdir="$HOME/.fonts"		# /usr/share/fonts
	local file

	log "installing fonts"

	mkdir -p "$fdir"

	find $GITDIR -type f -name *.ttf |
	 while read file; do {
		[ -e "$fdir/$( basename "$file" )" ] || {
			log "installing font '$file' to '$fdir'"
			cp "$file" "$fdir"
			log "generating fontcache"
			fc-cache -f -v
			chown -R tasso:tasso "$fdir"
		}
	} done
}

software()
{
	local option="$1"
	local package aptok list file
	local software_ready="/tmp/software_fully_installed"
	local lockfile="/tmp/SOFTWARE_INSTALL"
	local error url
	local myhome

	[ $( uptime_in_seconds ) -lt 180 ] && {
		log "no software install during first 3 minutes"
		return 0
	}

	[ "$option" = "force" ] && rm "$software_ready"

	[ -e "$software_ready" ] && {
		log "software fully installed (marked via '$software_ready')"
		return 0
	}

	has_default_route || {
		log "software() no default router, abort"
		return 0
	}

	if [ -e "$lockfile" ]; then
		log "exit for preventing double run: '$lockfile'"
		return 1
	else
		touch "$lockfile"
	fi

	file="/usr/local/bin/jq"
	[ -e "$file" ] || {
		url="http://stedolan.github.com/jq/download/source/jq.tgz"
		url='http://stedolan.github.io/jq/download/source/jq-1.3.tar.gz'
		if wget -T 30 -O "/tmp/jq.tgz" "$url"; then
			cd /tmp
			tar xzf "jq.tgz"
			cd /tmp/stedolan-jq-* || cd /tmp/jq-*
			./configure

			if make; then
				mv jq "$file"
				chmod +x "$file"
			else
				error=1
			fi
		else
			error=1
		fi

		rm -fR /tmp/stedolan-jq-*
		rm -f "/tmp/jq.tgz"
	}

	file="/usr/local/bin/w3c-validator.py"
	[ -e "$file" ] || {
		log "installing w3c-validator.py"
		url="https://raw.github.com/srackham/w3c-validator/master/w3c-validator.py"
		wget -T 30 -O "$file" "$url" || error=1
		chmod +x "$file"
	}

	file="/usr/local/bin/omap4_temp"
	[ -e "$file" ] || {
		log "installing omap4_temp"
		url="http://intercity-vpn.de/files/omap4_temp"
		wget -T 30 -O "$file" "$url" || error=1
		chmod +x "$file"
	}

	install_apt_if_missing()
	{
		dpkg >/dev/null -s "$1" || {
			[ "$aptok" = "true" ] || apt-get update && aptok="true"
			log "installing: apt: $1" alert

			# autocorrect install errors
			dpkg --configure -a
			apt-get install -y --force-yes "$1" || error=1
		}
	}

	install_npm_if_missing()
	{
		local name="$( echo "$1" | cut -d'@' -f1 )"

		[ -e "$HOME/.npm/$name" ] && return 0

		[ -n "$NPM" ] || {
			log "npm: building index for the first time"
			npm list >/dev/null	# build the index?
			NPM=1
		}

		npm list | fgrep -q " ${1}@" || {
			log "installing: npm: $1"
			npm config set registry http://registry.npmjs.org/	# force http NOT https
			npm install --verbose --global "$1" || error=1
			npm link "$name" || error=1
		}
	}

	# force NPM-stuff reinstall:
	# rm -fR "/home/tasso/.npm" "/root/.npm" "/usr/local/lib/node_modules"

	# is 'lightdm' and 'rungetty' needed?

	list="
		openssh-server
		build-essential
		u-boot-tools
		nodm
		xinit
		cpufrequtils
		cron
		curl
		git
		git-core
		iodine
		iptables
		iputils-ping
		lighttpd
		lsof
		make
		midori
		net-tools
		ntpdate
		openbox
		python-xdg
		scrot
		screen
		vim
		x11vnc
		xdotool
		imagemagick
		libimage-exiftool-perl
		dnsutils
		nodejs-latest
		npm
		npm:mustache
		npm:less
		npm:punch"

	myhome="$HOME"
	HOME=/root
	for package in $list; do {
		log "checking need for software-package: $package"
		cpu_tweak

        # Not needed anymore, node_modules are in git
		case "$package" in
			nodejs-latest)
				case "$HOSTNAME" in
					kasse1)
					;;
					*)
						continue
					;;
				esac

				# e.g. output: 'v0.6.12' or 'v0.11.8-pre'

				remove_nodejs()
				{
					dpkg -l nodejs && apt-get -y remove nodejs
					dpkg -l node   && apt-get -y remove node
				}

				node --version | fgrep -q '0.6.' && {
					remove_nodejs
				}

				if   [ -e "/home/tasso/node_10.20.0-1_armhf.deb" ]; then
					dpkg -l node | fgrep -q 'node-js-master' || {
						remove_nodejs
						dpkg -i "/home/tasso/node_10.20.0-1_armhf.deb"
					}
				elif [ -e '/home/tasso/node_latest_armhf.deb' ]; then
					dpkg -l node | fgrep -q '0.10.26-1' || {
						# https://github.com/nathanjohnson320/node_arm
						# always from: http://node-arm.herokuapp.com/node_latest_armhf.deb
						remove_nodejs
						dpkg -i '/home/tasso/node_latest_armhf.deb'
					}
				else
					# selfcompile and build above package:
					# https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager
					install_apt_if_missing 'python'
					install_apt_if_missing 'g++'
					install_apt_if_missing 'make'
					install_apt_if_missing 'checkinstall'

					mkdir -p '/tmp/src'
					cd '/tmp/src'
					wget -O 'node-latest.tar.gz' -cN 'http://nodejs.org/dist/v0.10.26/node-v0.10.26.tar.gz'
#					wget -cN 'http://nodejs.org/dist/node-latest.tar.gz'

					tar xzf node-latest.tar.gz && {
						cd node-v*
						./configure
						checkinstall		# fixme! manually change version-number in menu
						cd ..
						rm -fR '/tmp/src'
					}
				fi
			;;
			npm:*)
				package="$( echo "$package" | cut -d':' -f2 )"

				case "$HOSTNAME" in
					Xevent4of5)
						install_npm_if_missing "$package"
					;;
					*)
						log "will not install '$package' on this host '$HOSTNAME'"
					;;
				esac
			;;
			*)
				install_apt_if_missing "$package"
			;;
		esac
	} done
	HOME="$myhome"

    local do_helium=0
    # file="/usr/local/bin/firefox"
    # if [ -e "$file" ]; then
    #     case "$( $file --version )" in
    #         *"20120911"*)
    #             log "helium: we have a good version"
    #         ;;
    #         *)
    #             do_helium=1
    #         ;;
    #     esac
    # else
    #     do_helium=1
    # fi
    
    # Not needed atm
    do_helium=0

    # [ "$do_helium" = 1 ] && {
    #     cd /tmp/tasso/helium-browser
    # 
    #     [ -d "/tmp/cabal" ] || {
    #         log "preparing compile"
    #         rm -fR $HOME/.cabal
    #         mkdir /tmp/cabal
    #         ln -s /tmp/cabal $HOME/.cabal
    #     }
    # 
    #     [ -d "$HOME/.cabal/packages/hackage.haskell.org" ] || {
    #         cabal --verbose update
    #     }
    # 
    #     # cabal install gtk2hs-buildtools
    #     # cabal install webkit
    #     # cabal install
    #     # -> cabal configure
    #     # -> cabal build
    #     # + deps
    #     # + ~/.cabal/bin/Helium
    # 
    #     log "compiling helium-browser"
    #     if cabal install; then
    #         log "cleaning up, moving to $file"
    #         if mv $HOME/.cabal/bin/Helium $file; then
    #             rm -fR /tmp/cabal
    #             pkill firefox
    #         else
    #             error=1
    #         fi
    #     else
    #         error=1
    #     fi
    # }

	if [ -z "$error" ]; then
		touch "$software_ready"		# check after each reboot
	else
		log "error during install/compile"
	fi

	rm "$lockfile"

	pidof mysqld >/dev/null && {
		/etc/init.d/mysql stop
	}
}

git_checkout()
{
	local dir="/tmp"
	local file="$dir/tasso.tgz"
	#local url="http://intercity-vpn.de/tasso.tgz"
	local url="https://static.ars.is/tasso/master.tgz"

	GITDIR="/tmp/tasso"
	log "removing $GITDIR"
	rm -fR $GITDIR

	log "hostname is: $HOSTNAME"

	case "$HOSTNAME" in
		kasse2|test)
			cd $HOME

			if [ -e "$HOME/tasso" ]; then
				log "[!] GIT REPO is ALREADY on disk"
				cd "tasso"
				if git pull -t --force --keep git@git.ars.is:ksw/tasso.git master | grep -q -v 'Already up-to-date.' ; then
					log "git: wow, we have an update"

					cd ..
					rm tasso.tgz
					log "creating new tarball from git-repo"
					tar czf tasso.tgz --exclude .git --exclude "*.log" tasso
					rm -fR $GITDIR
				else
					log "git: Already up-to-date. (or changes are not in master-branch)"
				fi
			else
				log "[!] GIT REPO is NOT on disk"
				log "cloning from git@git.ars.is:ksw/tasso.git"

				if git clone --depth 1 "git@git.ars.is:ksw/tasso.git"; then
					cd tasso
					git pull -t --force --keep git@git.ars.is:ksw/tasso.git master

					log "setting up git-hooks 'setup'"
					sh ./scripts/git-hooks.sh setup
					# simulate a post_checkout just this once
					log "calling git-hook 'post-receive'"
					sh ./scripts/git-hooks.sh post-receive
					log "calling git-hook 'post-checkout'"
					sh ./scripts/git-hooks.sh post-checkout

					cd ..
					rm tasso.tgz
					log "creating new tarball from git-repo"
					tar czf tasso.tgz --exclude .git --exclude "*.log" tasso && {
						rm -fR $GITDIR
					}
				else
					log "cloning from git@git.ars.is:ksw/tasso.git failed" alert
				fi
			fi
		;;
		*)
			log "this is not kasse2|test: no git action"
		;;
	esac

	if [ -e "$GITDIR" ]; then
		log "gitdir $GITDIR already exists"		# unneeded!
	else
		if [ -e "$HOME/tasso.tgz" ]; then
			log "taking archive from permanent storage: $HOME/tasso.tgz"
			cp "$HOME/tasso.tgz" "$file"
		else
			log "fetching tar from production mirror: $url"
			#wget -T 30 -O "$file" "$url"
			curl --retry 10 --retry-max-time 120 --retry-delay 60 --output "$file" "$url"

			log "making copy to permanent storage: $HOME/tasso.tgz"
			cp "$file" "$HOME/tasso.tgz"
		fi

		case "$( tar tvzf "$file" | head -n1 )" in
			*' tasso/')
			;;
			*)
				# git.ars.is doesnt has everything under 'tasso/'
				dir='/tmp/tasso'
				mkdir -p "$dir"
			;;
		esac

		log "untar of '$file', from dir '$dir'"
		cd $dir
		tar xzf "$file" || {
			log "error during untar, removing '$GITDIR'"
			rm -fR "$GITDIR"

			[ -e "$HOME/tasso.tgz" ] && {
				log "removing copy on disc"
				rm "$HOME/tasso.tgz"
				log "fetching from world: $url"
				curl --retry 10 --retry-max-time 120 --retry-delay 60 --output "$file" "$url"
				log "making copy to permanent storage: $HOME/tasso.tgz"
				cp "$file" "$HOME/tasso.tgz"

				log "untar of '$file'"
				tar xzf "$file" || {
					log "untar failed again, needs manual help"
					rm -fR "$GITDIR"
				}
			}
		}

		# fixme! live-patching:
		sed -i 's/(update, 1000)/(update, 10000)/' '/tmp/tasso/werther/public/kasse/kasse.js'

		chown -R tasso:tasso $GITDIR
		chmod -R 777 $GITDIR


	fi

	chown tasso:tasso $HOME/tasso.tgz
	chmod 777 $HOME/tasso.tgz
	rm "$file"
}


setup_base_system_files()
{
    # Setup base system files
    local script="/tmp/tasso/system/setup-system-files.sh"
    [ -e "$script" ] && sh /tmp/tasso/system/setup-system-files.sh
}


prepare_workingdir()
{
	# todo:
	# copy html for this machine to e.g. /tmp/working

	install_fonts
}

update_this_script()
{
    # maybe allow to give an argument like "IC" to fetch from intercity-vpn.de?
    
	local hash1 hash2 url temp

	# scp /etc/rc.local root@intercity-vpn.de:/var/www/files/setup_gnm2012_panda_generic.sh
	url="${1:-http://intercity-vpn.de/files/setup_gnm2012_panda_generic.sh}"
	temp="/tmp/new_script.sh"

	log "checking '$url'"
	curl --insecure --silent --retry 10 --retry-max-time 120 --retry-delay 60 --output "$temp" "$url"
	tail -n1 "$temp" | grep -q ^'exit 0' || {
		log "ERROR in last line: '$( tail -n1 "$temp" )', try yourself: '$url'"
		rm "$temp"
		return 1
	}

	hash1="$( md5sum "$0"    | cut -d' ' -f1 )"
	hash2="$( md5sum "$temp" | cut -d' ' -f1 )"

	if [ "$hash1" = "$hash2" ]; then
		log "no new version"
		rm "$temp"
	else
		log "installing NEW version" alert
		mv "$temp" "$0"
		chmod +x "$0"
	fi

	return 0
}

check_klog()
{
	dmesg -c >>'/tmp/dmesg.log'

	case "$( uname -a )" in
		*"3.4.0-1485"*)
			# Linux HOST 3.4.0-1485-omap4 #2-Ubuntu SMP PREEMPT Thu Jul 12 15:59:41 UTC 2012 armv7l armv7l armv7l GNU/Linux
		;;
		*)
			# Linux HOST 3.4.0-2-linaro-lt-omap #2~ci+121020091603-Ubuntu SMP PREEMPT Sat Oct 20 15:13:41 UTC 20 armv7l armv7l armv7l GNU/Linux
			return 0
		;;
	esac

	# https://bugzilla.redhat.com/show_bug.cgi?id=522602
	[ $( grep 'WARNING:' '/tmp/dmesg.log' | wc -l ) -gt 8 ] && {	# fixme! not more than 2 or 6?
		myreboot "dmesg spammed with WARNING:"			# tcp_recvmsg+0x21c/0x990()
	}

	fgrep -q 'Xorg: page allocation failure:' '/tmp/dmesg.log' && {
		myreboot "dmesg: Xorg: page allocation failure"
	}
}

crontabs()
{
	local file='/tmp/cronjob.tasso.sh'

	cat >"$file" <<EOF
#!/bin/sh
export PATH="$PATH"
export DISPLAY=0:0
xdotool mousemove 0 0 click 1 mousemove 1366 768

[ -d '/tmp/tasso/kasse/public/msr/' ] && {
	cd '/tmp/tasso/kasse/public/msr/'
	./msr.conf.sh 'msr.conf' '/tmp/tasso/kasse/public/msr'
}

case "$HOSTNAME" in
	kasse1)
		pidof node >/dev/null || $0 function fire_nodejs

		PERMDIR='/home/tasso/werther-touch-git'
		WORKING_DIR='/tmp/tasso/werther/data'

		git config --global user.name  | grep -q . || git config --global user.name  "gitbot: $HOSTNAME"
		git config --global user.email | grep -q . || git config --global user.email "info@bittorf-wireless.de"

		cd "\$WORKING_DIR" || exit
		[ -d '.git' ] || {
			if [ -d "\$PERMDIR" ]; then
				# get copy from disk on bootup
				git clone "\$PERMDIR/data"
				cp 'data/'* .		# files
				mv 'data/.git' .	# git-database
				rm -fR data
			else
				# store initial copy to disk
				git init
				git add kasse.json tasso.json tickets.json	# omit 'ticketsBlocked.json'
				git commit -m "initial commit"

				mkdir "\$PERMDIR"
				cd "\$PERMDIR" || exit
				git clone "\$WORKING_DIR"
				# now we have a dir 'data' with the files
			fi
		}

		# TODO:
		# /tmp/tasso/werther/public/kasse/kasse.mustache

		for FILE in kasse.json tasso.json tickets.json; do {
			git add "\$FILE"
			git diff HEAD | grep -q . && {
				git commit -m "autocommit: \$FILE - \$(stat --printf %s \$FILE) bytes"
				# git diff HEAD | grep ^'[+-]' | grep -v ^'--- ' | grep -v ^'+++ '

				cd "\$PERMDIR/data" || exit
				git pull "\$WORKING_DIR"
			}
		} done
	;;
esac
EOF
	chmod +x "$file"
	chown tasso:tasso "$file"

	if [ "$HOSTNAME" = 'kasse1' ]; then
		echo >'/tmp/crontab.tasso' "* * * * * $file"
	else
		echo >'/tmp/crontab.tasso' "*/5 * * * * $file"
	fi

	crontab -u tasso '/tmp/crontab.tasso'


	file="/tmp/cronjob.root.sh"
	cat >"$file" <<EOF
#!/bin/sh

read UP REST </proc/uptime
[ \${UP%.*} -ge 43200 ] && $0 function myreboot "overup: \$UP"		# 12h (6-18Uhr, eigentlich: 5.45 Uhr Start -> 20 Uhr)

case "\$( pidof sshd )" in
	*" "*)
		if [ -e /tmp/GO ]; then
			:
		else
			$0 function log "CRON: no action, somebody is working here - touch /tmp/GO for override" alert
			exit
		fi
	;;
	*)
		pidof sshd >/dev/null || {
			$0 function log "starting lost ssh-daemon" alert
			/etc/init.d/ssh restart
		}
	;;
esac

case "$HOSTNAME" in
	touch1|touch2)
		OLD_VALUE=
		[ -e /tmp/OLD_VALUE_VIDEOSERVER ] && read OLD_VALUE </tmp/OLD_VALUE_VIDEOSERVER
		NEW_VALUE=
		NEW_VALUE="\$( wget -qO - http://172.17.34.65/recording/last_good_unixtime )"
		[ -e /tmp/FORCE_BAD_VIDEO ] && NEW_VALUE=

		html_shows_good_videoserver()
		{
			local URL="\$( cat /tmp/URL_FIREFOX.txt )"
			wget -qO - "\$URL" | fgrep -q 'OK - Videoaufzeichnung'
		}

		# timestamp does not change or is empty:
		if [ "\$OLD_VALUE" = "\$NEW_VALUE" -o -z "\$NEW_VALUE" ]; then
			html_shows_good_videoserver && {
				$0 function log "detecting ERROR_VIDEOSERVER" alert
				touch /tmp/ERROR_VIDEOSERVER	# see good_video()

				cd /tmp/tasso/bigbrother
				./cam_gen_html.sh start
				pkill midori
			}
		else
			echo "\$NEW_VALUE" >/tmp/OLD_VALUE_VIDEOSERVER

			html_shows_good_videoserver || {
				$0 function log "ERROR_VIDEOSERVER ok again" alert
				rm /tmp/ERROR_VIDEOSERVER	# see good_video()

				cd /tmp/tasso/bigbrother
				./cam_gen_html.sh start
				pkill midori
			}
		fi
	;;
	kasse1|touchMSR)
		# should only be active in the morning and evening
		case "\$( date +%H )" in
			08)
#				[ -e /tmp/IODINE_STOPPED ] || {
#					killall iodine && touch /tmp/IODINE_STOPPED
#				}
			;;
			17)
#				pidof iodine || {
#					rm /tmp/IODINE_STOPPED
#					iodine_daemon
#				}
			;;
		esac
	;;
esac

case "\$( date +%H:%M )" in
	*":00")
		rm "/tmp/screenshot.jpg"
	;;
esac

export PATH="$PATH"
if pidof node >/dev/null; then
	touch '/tmp/NODEJS_NEEDED'
else
	[ -e '/tmp/NODEJS_NEEDED' ] && {
		$0 function log "node died, restarting" alert
		$0 function fire_nodejs
		sleep 60
	}
fi

$0 function log CRON:start
$0 function cpu_tweak
$0 function check_klog
$0 function check_ping_to_any_station
pidof omap4_temp && {
	$0 function myreboot "hanging omap4_temp"
}

set -- \$( ps awux | grep rsyslogd | head -n1 )
LOAD=\${3:-0}
LOAD="\$( echo \$LOAD | cut -d'.' -f1 )"

if [ \$LOAD -gt 70 ]; then
	$0 function log "CRON: rsyslogd: KILL: load:\$LOAD + sleep 60" alert
	/etc/init.d/rsyslogd stop
	killall rsyslogd
	killall rsyslog
	sleep 60
else
	$0 function log "CRON: rsyslogd: OK: load:\$LOAD"
fi

set -- \$( ps awux | grep midori | grep tasso | head -n1 )
LOAD=\${3:-0}
LOAD="\$( echo \$LOAD | cut -d'.' -f1 )"

if [ \$LOAD -gt 95 ]; then
	$0 function log "CRON: midori: load:\$LOAD - wait 30sec"
	sleep 30

	set -- \$( ps awux | grep midori | grep tasso | head -n1 )
	LOAD=\${3:-0}
	LOAD="\$( echo \$LOAD | cut -d'.' -f1 )"

	[ \$LOAD -gt 95 ] && {
		if [ -e /tmp/MIDORI_HIGHLOAD ]; then
			$0 function myreboot "CRON: midori: REBOOT: load:\$LOAD"
		else
			touch /tmp/MIDORI_HIGHLOAD
		fi
	}
else
	rm /tmp/MIDORI_HIGHLOAD
	$0 function log "CRON: midori: OK: load:\$LOAD"
fi

case "\$( date +%H )" in
	08|12|17|19)
		$0 function update_this_script
		$0 function blacklist_kmodules
	;;
	07|13|18)
		$0 function software force
	;;
	23)
		$0 function myreboot "latenight, 23"
	;;
esac
$0 function software
$0 function make_mustache
$0 function crontabs
$0 function time_setup

[ -e "/tmp/screenshot.jpg" ] || {
	$0 function log "waiting till sec 05 of next minute, now '\$( date +%S )'"
	while true; do {
		case "\$( date +%S )" in
			05|5)
				# called each 15mins, wait 4 mins after that:
				case "\$( date +%M )" in
					04|19|34|49)
						break
					;;
					*)
						$0 function log "waiting till minute 04|19|34|49 - now \$( date +%M )"
					;;
				esac
			;;
		esac
		sleep 1
	} done
}

$0 function monitoring
$0 function log CRON:ready
EOF

	echo  >"/tmp/crontab.root" "*/15 * * * * $file"
#	echo >>"/tmp/crontab.root" "* * * * * dmesg | grep -q 'BUG: scheduling while atomic:' && ...
#	echo >>"/tmp/crontab.root" "* * * * * dmesg | grep -q 'omapdss DISPC error: FIFO UNDERFLOW on gfx' && /sbin/reboot"

	chmod +x "$file"
	crontab -u root "/tmp/crontab.root"

	log "(maybe) new crontab activated"

#	[ "$FAKEGW" = "$IP" ] && {
#		echo >>"/tmp/crontab.root" "* * * * * "
#	}
}

fire_nodejs()
{
	local file='/tmp/fire_nodejs'
	local pid="$( pidof node )"
	local nodejs_bin='/usr/local/bin/node'			# e.g. 0.26.0
	[ -e "$nodejs_bin" ] || nodejs_bin='/usr/bin/node'	# e.g. 0.6.12

	# what is '/tmp/tasso/werther/bin/werther' ?
	#
	# TODO: /tmp/tasso/werther/node_modules/st/st.js @zeile 66 + zeile 127 _extend
	#root@kasse1:/tmp/tasso/werther# /usr/local/bin/node app.js
	#
	#node.js:201
	#        throw e; // process.nextTick error, or 'error' event on first tick
	#              ^
	#TypeError: Object #<Object> has no method '_extend'
	#    at /tmp/tasso/werther/node_modules/st/st.js:127:31
	#    at Mount.getCacheOptions (/tmp/tasso/werther/node_modules/st/st.js:140:9)
	#    at new Mount (/tmp/tasso/werther/node_modules/st/st.js:98:16)
	#    at st (/tmp/tasso/werther/node_modules/st/st.js:78:11)
	#    at [object Object].static (/tmp/tasso/werther/node_modules/flatiron/lib/flatiron/plugins/static.js:72:46)
	#    at [object Object].<anonymous> (/tmp/tasso/werther/node_modules/flatiron/lib/flatiron/plugins/static.js:85:15)
	#    at [object Object].use (/tmp/tasso/werther/node_modules/flatiron/node_modules/broadway/lib/broadway/app.js:165:31)
	#    at Object.<anonymous> (/tmp/tasso/werther/app.js:17:5)
	#    at Module._compile (module.js:441:26)
	#    at Object..js (module.js:459:10)

	cat >"$file" <<EOF
touch /tmp/NODEJS_NEEDED
cd /tmp/tasso/werther
(while true; do $nodejs_bin app.js; sleep 3; done) &
# later 

# only kill of node when it was up before
[ -n "$pid" ] && pkill midori
EOF

	chmod +x "$file"
	chown tasso:tasso "$file"

	log "[START] $file"
	( $file ) &
	sleep 5
	log "[READY] $file - pid: '$( pidof node )'"
}

disable_unneeded_services()
{
	write_if_needed 'manual' '/etc/init/cups.override'
	write_if_needed 'manual' '/etc/init/gator-daemon.override'

	# disable ssh-agent:
	gconftool-2 --set --type bool /apps/gnome-keyring/daemon-components/ssh false
}

generic_for_all()
{
	local list funcname

	omap_board >/dev/null	# generate dmesg.boot

	log "do_sysctl"
	do_sysctl

	log "hostname: $HOSTNAME"
	hostname "$HOSTNAME"

	log "network: ip: $IP"
	network "$IP"
	wait_for_internet

	list="
		blacklist_kmodules
		optimize_getty
		optimize_fstab
		software
		cpu_tweak
		time_setup
		ssh_setup
		git_checkout
		setup_base_system_files
		prepare_workingdir
		crontabs
		disable_whoopsie
		disable_unneeded_services
		leds_off"

	sleep 10	# give time for ssh-login/change something
	for funcname in $list; do {
		log "entering $funcname()"
		$funcname
	} done
}

make_mustache()
{
	local dir="$1"
	local file="/tmp/WORKING_DIR"
	local process="firefox"
	local pathadd myhome hash1 hash2 file rc

	case "$dir" in
		force)
			process="does_hopefully_not_exist"
			dir=
		;;
		*)
			case "$( cat /tmp/URL_FIREFOX.txt )" in
				*"127.0.0.1"*)
					log "using local webserver, changing files is harmless"
					process="does_hopefully_not_exist"
				;;
			esac
		;;
	esac

	pidof $process >/dev/null && {
		log "firefox runs - no make_mustache()"
		return 0
	}

	if [ -n "$dir" ]; then
		echo "$dir" >"$file"
	else
		[ -e "$file" ] || return 0
		read dir <"$file"
	fi

	pathadd="$( find /usr/local/lib/node_modules -maxdepth 1 -type d )"
	pathadd="$pathadd $( find $HOME/.npm -type d -name bin )"
	pathadd="$pathadd $( find $HOME/.npm -type d -name package )"
	pathadd="$pathadd /usr/local/bin/"

	cd /
	for npmpath in $pathadd; do {
		echo "$PATH" | fgrep -q "$npmpath" || {
#			log "adding '$npmpath' to PATH"
			export PATH="$PATH:$npmpath"
		}
	} done
	log "PATH: $PATH"

	export NODE_PATH="/usr/local/lib/node_modules"
	log "NODE_PATH: $NODE_PATH"
	cd "$dir"

	case "$HOSTNAME" in
		touchMSR)
			mkdir /tmp/tasso/kasse/public/msr
			cp -v /home/tasso/tasso/msr/* /tmp/tasso/kasse/public/msr
			cp -R /home/tasso/msr_new/* /tmp/tasso/kasse/public/msr
			chmod -R 777 /tmp/tasso/kasse/public/msr
			/tmp/cronjob.tasso.sh
		;;
		event*|test)
			file="/tmp/tasso/events5x/contents/events.json"
			hash1="$( md5sum "$file" | cut -d' ' -f1 )"
			log "[START] rebuild_feed_from_ksw.sh: -> $file"

			local event_json_hash="$( grep -q "barrierinfo" "$file" || echo "good" )"
			[ -e "$file" ] || event_json_hash=

			[ "$event_json_hash" = "good" ] || {
				case "$HOSTNAME" in
					event2*|event3*|event4*|event5*)
#						log "fetching from event1: http://172.17.40.3/contents/events.json"
#						sleep 60
#						wget -qO "$file" http://172.17.40.3/contents/events.json || {
							/tmp/tasso/events5x/rebuild_feed_from_ksw.sh "$file" pics_only
#						}
					;;
					*)
						/tmp/tasso/events5x/rebuild_feed_from_ksw.sh "$file" pics_only
					;;
				esac
			}

			log "[READY] rebuild_feed_from_ksw.sh"
		;;
		*)
			file="/tmp/URL_FIREFOX.txt"
			hash1="$( md5sum "$file" | cut -d' ' -f1 )"
		;;
	esac

	log "[START] make clean + make -> mustache/less/punch in $( pwd )"
	[ "$event_json_hash" = "good" ] || {
		myhome="$HOME"
		HOME=/root

		make clean || {
			rc=$?
			log "command 'make clean' in $(pwd) failed with code $rc" alert
		}

		make >>/tmp/mylog.txt || {
			rc=$?
			log "command 'make' in $(pwd) failed with code $rc" alert
		}

		HOME="$myhome"
	}
	log "[READY] make ready"

	log "copy fb* to www-public"
	cp /home/tasso/fb* /tmp/tasso/events5x/public/

	browser_pudel_page >/tmp/tasso/events5x/public/pudelfallback.html

	# ugly hack!
	[ -e '/tmp/tasso/events5x/public/events-nurbilder.html' ] && {
		local i first_good
		local myfile="/tmp/tasso/events5x/public/events-nurbilder.html"
		local url_bad='http://www.klassik-stiftung.de/fileadmin/user_upload/GNM-Banner'
		local url_good='http://127.0.0.1'
		sed -i "s|$url_bad|$url_good|g" "$myfile"

		first_good="$( ls -1 /var/www/[0-9].ok | head -n1 )"	# /var/www/3.ok
		first_good="$( basename "$first_good" )"		# 3.ok
		first_good="$( echo "$first_good" | cut -d'.' -f1 )"	# 3

		for i in 9 8 7 6 5 4 3 2 1; do {
			[ -e "/var/www/$i.ok" ] || {
				log "rollback: cannot found '/var/www/$i.jpg', rewrite to '$first_good'"
				sed -i "s|$url_good/$i|$url_good/$first_good|g" "$myfile"
			}
		} done
	}

	hash2="$( md5sum "$file" | cut -d' ' -f1 )"
	[ "$hash1" = "$hash2" ] || {
		if [ -e "/tmp/BROWSER_WAS_RESTARTED" ]; then
			log "file '$file' changed, refire browser" alert
		else
			log "file '$file' changed, refire browser for the first time after boot"
			touch "/tmp/BROWSER_WAS_RESTARTED"
		fi

		pkill firefox
		pkill midori
	}
}

prepare_local_webserver()
{
	local wwwroot="$1"

	rm -fR /var/www
	mkdir -p /var/log/lighttpd
	chown -R tasso:tasso /var/log/lighttpd
	chmod -R 777 /var/log/lighttpd

	log "linking /var/www to '$wwwroot'"
	ln -s $wwwroot /var/www
	log "linked: $( ls -l /var/www )"
	/etc/init.d/lighttpd restart
	log "linking ready, lighttpd started"
}

diary_text_of_today()
{
	local file='/tmp/tasso/diary/diary.json'
	local day="${1:-$( date +%d )}"
	local month="${2:-$( date +%m )}"
	local jq_bin='/usr/local/bin/jq'
	local marker='/tmp/diary_text_of_today'
	local add_days

	read -r add_days 2>/dev/null <'/tmp/fake_add' || add_days=0

	[ -e "$marker" ] || {
		[ -e "$file" ] || {
			touch "$marker"
			return 0	# fake 'good' on first call/bootup
		}
	}

	if [ -e "$file" ]; then
		log "[OK] query in $file - month='$month' and day='$day' add_days='$add_days'"
		# FIXME! when called from set_url_tagebuchbeamer() we get no output?
		$jq_bin ".diary[] | select(.month == $month) | select(.day == $day)" <"$file" | grep .
	else
		log "[ERR] file missing: '$file'"
		echo "file missing: '$file'"
		return 1
	fi
}

set_url_tagebuchbeamer()
{
	local just_check="$1"

	local day="$(   date +%d )"
	local month="$( date +%m )"
	local comment_realdate="# day=$day month=$month"
	local fake_day fake_month base_url diary_entry add_days

	if [ -n "$just_check" ]; then
		grep ^"$comment_realdate"$ '/tmp/URL_FIREFOX.txt'
	else
		fake_date()
		{
			fake_day="$(   date +%d --date="+$add_days day" )"
			fake_month="$( date +%m --date="+$add_days day" )"
		}

		read -r add_days 2>/dev/null <'/tmp/fake_add' || add_days=0
		fake_date
		while ! diary_entry="$( diary_text_of_today "$fake_day" "$fake_month" )"; do {
			log "no entry for: fake_day: $fake_day fake_month: $fake_month add: $add_days" alert

			[ $add_days -gt 30 ] && break
			add_days=$(( add_days + 1 ))
			echo "$add_days" >'/tmp/fake_add'
			fake_date	# set vars

			sleep 3
		} done

		german_month()
		{
			local fake="$1"
			local mydate

			# error does happen with +0 days - why?
			mydate="$( date '+%B' $fake )" || mydate="$( date '+%B' )"
			log "german_month: fake: '$fake' mydate=$mydate"

			case "$mydate" in
				'January') echo 'Januar' ;;
				'February') echo 'Februar' ;;
				'March') echo 'M&auml;rz' ;;
				'April') echo 'April' ;;
				'May') echo 'Mai' ;;
				'June') echo 'Juni' ;;
				'July') echo 'Juli' ;;
				'August') echo 'August' ;;
				'September') echo 'September' ;;
				'October') echo 'Oktober' ;;
				'November') echo 'November' ;;
				'December') echo 'Dezember' ;;
				*)
					log "[ERR]: fake: '$fake' date: '$( date '+%B' )'"
					echo 'Weihnachten'
				;;
			esac
		}

		# it is OK to omit the year
		# '9. Oktober '
		local datename_good="$( date +%-d ). $( german_month ) "
		local datename_must="$( date +%-d --date="+$add_days day" ). $( german_month --date="+$add_days day" ) "
		local file='/tmp/tasso/diary/diary.json'

		log "diary_entry: $diary_entry"
		log "[OK] fake add_days: $add_days"
		log "[OK] datename_good=$datename_good"
		log "[OK] datename_must=$datename_must"

		if   [ $add_days -eq 0 ]; then
			log "[OK] no need for faking date"
		elif [ -e "$file" ]; then
			log "[OK] faking entry in '$file' - old: $datename_good new: $datename_must" alert
			sed -i "s/$datename_must/$datename_good/" "$file"
		else
			log "cannot fake date, not found: '$file'"
		fi

		base_url='http://127.0.0.1/index.html'
		browser "$base_url#cols=1&day=$fake_day&month=$fake_month" "$comment_realdate"
	fi
}

# # Script: MAIN

# ## Act on Arguments

# Check if we are super user.
[ "$( whoami )" = "root" ] || {
    # If we are NOT super user, check if we can do it without it.
	case "$ARG2" in
		Xmake_mustache|list|browser_sendkey|firefox_value_set|validate_url)
		;;
		*)
        # Exit if we cannot continue withour privileges.
			log "start as root, exit"
			exit 1
		;;
	esac
}

# Set a special time server if we run on dhcp.
[ "$IP" = "dhcp" ] && TIMESERVER="0.openwrt.pool.ntp.org"

# Unset the shell variable before we run the check
unset HOSTNAME

# Set the host name either from an argument
# if [ -n "$HOSTNAME" -a "$HOSTNAME" != "function" ]; then
#     IP="$2"
# # or, if none given, 
# else
    # set the hostname based on MAC address.
	case "$( mac )" in
		2a:40:5d:44:6b:xx) IP="dhcp"; HOSTNAME="test"; TIMESERVER="0.openwrt.pool.ntp.org" ;;

		0e:60:5e:24:3c:0a) IP="172.17.19.48"; HOSTNAME="touchMSR" ;;	# x9   -> Wartung = .49
		0e:60:60:5e:3c:0a) IP="172.17.40.10"; HOSTNAME="touchMedien" ;; # x10

		2a:40:5d:44:6b:01) IP="172.17.34.112"; HOSTNAME="touch2" ;;	# links
		2a:40:fb:77:6a:01) IP="172.17.34.111"; HOSTNAME="touch1" ;;	# rechts

# kasse3 = DrWerche = 172.17.40.11 - VerwaltungsPC / Direktion
# .12 = wartungsPC? -> ip a a 172.17.40.12/27 dev eth2 -> 255.255.255.224
		0a:40:cf:49:6b:01) IP="172.17.40.8"; HOSTNAME="kasse1" ;;	# links
		2a:40:0a:f9:3b:0a) IP="172.17.40.9"; HOSTNAME="kasse2" ;;	# rechts
		2a:40:d3:0a:6b:01) IP="172.17.40.2"; HOSTNAME="tagebuchbeamer" ;;
		2a:40:49:65:6b:01) IP="172.17.40.3"; HOSTNAME="event1of5" ;;
		0a:40:ea:d0:3b:0a) IP="172.17.40.4"; HOSTNAME="event2of5" ;;
		2a:40:8f:5e:6b:01) IP="172.17.40.5"; HOSTNAME="event3of5" ;;
		2a:40:fb:77:6b:01) IP="172.17.40.7"; HOSTNAME="event4of5" ;;
		2e:40:71:c0:6c:0a) IP="172.17.40.6"; HOSTNAME="event5of5" ;;

		2a:40:13:f9:3b:0a) IP="172.17.40.7"; HOSTNAME="event4of5" ;;
		b8:27:eb:8d:bb:f0) IP="dhcp"; HOSTNAME="test" ;;  # RaspberryPi (bunt)
		*) IP='dhcp'; HOSTNAME='stranger'; TIMESERVER="0.openwrt.pool.ntp.org" ;;

		# 2a:40:c1:42:6b:01 = mein alter, der nun 'touchMedien' wird mit Kuehlkoerpern
	esac
# fi

[ "${ARG1}-${ARG2}" = "function-log" ] || log "maybe resulting IP: '$IP' HOSTNAME: '$HOSTNAME'"

# ### Provide Help 
[ "$ARG1" = "help" ] && {
	echo "Usage: $0 help"
	echo "       $0 <hostname> <ip>"
	echo "       $0 function list"
	echo "       $0 function update_this_script"
	echo "       $0 function git_checkout"
	echo "       $0 function browser_sendkey 'F5 F11 Escape'"
	echo "		or use: kill -s USR1 \$(pidof firefox)"
	exit 1
}

# ### Run a function on demand, 
[ "$ARG1" = "function" ] && {
	read HOSTNAME </etc/hostname
    # taking care of the arguments order
	shift
	shift
	$ARG2 "$@"
    # and exiting gracefully. 
	exit 0
}

# ## Run-Always

# ### Generic Tasks

# this can last for a very long time - really needed?
# e.g. on touchMedien) there is /home/tasso/qemu + aboriginal
#
# chown -R tasso:tasso /home/tasso


generic_for_all

# ### Tasks by "Role"

# Test for role by hostname 
case "$HOSTNAME" in
  # - Role: "touchMedien"
  #    * runs TODO: @bittorf ??? 
	touchMedien)
#		if node --version | fgrep -q 'v0.10.26' ; then
#			pidof node >/dev/null || {
#				cd /tmp/tasso/werther
#				# uses the server on kasse1 !!!
				browser "http://172.17.40.8:3000/view/faust"
#			}
#		else
#			browser "http://127.0.0.1/public/kasse.html#holz=1&marmor=0&glow=1&inset=1&holz-lg=0"
#		fi
	;;
    # - Role: "kasse1"
    #    * runs `iodine_daemon`
    #    * generates, serves, shows: web output 'kasse' (public display with prices, info, etc.)
	kasse1)
		iodine_daemon
		fire_nodejs

		# oracleDB / externer Zugriff
		iptables -t nat -I PREROUTING -p tcp --dport 1521 -j DNAT --to-destination $ORACLE
		iptables -t nat -I POSTROUTING -d $ORACLE -j MASQUERADE

		prepare_local_webserver "/tmp/tasso/kasse"
		make_mustache "/tmp/tasso/kasse"

		# FIXME! cron-checks if something has changed...
		[ -d '/home/tasso/git-kasse' ] && {
			cp /home/tasso/git-kasse/* /tmp/tasso/werther/data
		}

		browser "http://localhost:3000/view/kasse#holz=1&marmor=0&glow=1&inset=1&d1=0&d2=true&d3=0"
	;;
    # - Role: "kasse2" or "kasse-*" (for testing)
    #    * generates, serves, shows: web output 'kasse'
	kasse2|kasse-*)
		prepare_local_webserver "/tmp/tasso/kasse"
		make_mustache "/tmp/tasso/kasse"

		if node --version | fgrep -q 'v0.10.26' ; then
			browser "http://172.17.40.8:3000/view/kasse#holz=1&marmor=0&glow=1&inset=1&d1=0&d2=true&d3=0"
		elif [ "$HOSTNAME" = 'kasse2' ]; then
			browser "http://172.17.40.8:3000/view/kasse#holz=1&marmor=0&glow=1&inset=1&d1=0&d2=true&d3=0"
		else
			browser "http://127.0.0.1/public/kasse.html#holz=1&marmor=0&glow=1&inset=1&holz-lg=0"
		fi
	;;
	touchMSR)
		iodine_daemon

		prepare_local_webserver "/tmp/tasso/kasse"
		make_mustache "/tmp/tasso/kasse"

		mkdir /tmp/tasso/kasse/public/msr
		cp -v /home/tasso/tasso/msr/* /tmp/tasso/kasse/public/msr
		cp -v /home/tasso/msr_new/* /tmp/tasso/kasse/public/msr
		chmod 777 /tmp/tasso/kasse/public/msr/*
		/tmp/cronjob.tasso.sh

		browser "http://127.0.0.1/public/msr/menue_gnm5.html"
	;;
    # - Role: "touch1/2"
    #    * serves: website of KSW
	touch1)
		# set date:
		# date --set "Thu, 04 Dec 2012 12:05:00 +0100"
		prepare_local_webserver "/tmp/tasso"
		mkdir /tmp/tasso/bigbrother
		cd /tmp/tasso/bigbrother
		./cam_gen_html.sh start
		browser "http://127.0.0.1/bigbrother/$( ls -1 camera_page:[a-zA-Z]* | head -n1 )"
	;;
	touch2)
		prepare_local_webserver "/tmp/tasso"
		mkdir /tmp/tasso/bigbrother
		cd /tmp/tasso/bigbrother
		./cam_gen_html.sh start
		browser "http://127.0.0.1/bigbrother/$( ls -1 camera_page:[a-zA-Z]* | head -n1 )"
	;;
    # - Role: "tagebuchbeamer"
    #    * serves, shows: web output 'kasse'
	tagebuchbeamer)
		prepare_local_webserver "/tmp/tasso/diary"
		set_url_tagebuchbeamer
	;;
    # - Role: "Events"
    #    * serves, shows: web output 'event5x'
    #    * has subroles for the 5 screens and a test instance
	event*|test|stranger|*)
		prepare_local_webserver "/tmp/tasso/events5x"
		make_mustache "/tmp/tasso/events5x"

		base_event="events-nurbilder.html"	# was: events.html

        # Test for 'event5x'-sub-roles by hostname
		case "$HOSTNAME" in
			event1of5)
				browser "http://127.0.0.1/public/${base_event}#screen1"
				#browser "http://127.0.0.1/public/pudelfallback.html"
			;;
			event2of5)
				browser "http://127.0.0.1/public/${base_event}#screen2"
				#browser "http://127.0.0.1/public/pudelfallback.html"
			;;
			event3of5)
				browser "http://127.0.0.1/public/${base_event}#screen3"
				#browser "http://127.0.0.1/public/pudelfallback.html"
			;;
			event4of5)
				browser "http://127.0.0.1/public/${base_event}#screen4"
				#browser "http://127.0.0.1/public/pudelfallback.html"
			;;
			event5of5)
				browser "http://127.0.0.1/public/${base_event}#screen5"
				#browser "http://127.0.0.1/public/pudelfallback.html"
			;;
			test|stranger|*)
				browser "http://127.0.0.1/public/${base_event}#screen1"
			;;
		esac
	;;
esac

##cpu_tweak
##
##pidof firefox >/dev/null && {
##	log "restarting firefox"
##	pkill firefox
##	sleep 5
##
##	pidof firefox >/dev/null && {
##		log "firefox hangs, rebooting"
##		reboot
##	}
##}

#log "waiting 60sec till firefox runs good - abort with CTRL+C if not needed"
#sleep 60
#[ -n "$( ps ax | grep firefox | fgrep "[firefox] <defunct>" | grep -v "fgrep" )" ] && {
#	log "there is a problem, removing settings-file"
#	pkill firefox
#	rm "$( firefox_settings_file )"
#}
#
#log "ending script"
#

# ## Run CPU tweak
cpu_tweak
log "rc.local / $0 / cpu_tweak ready"

# ## Run dirty hack for Raspberry Pi
if ( grep -q 'Debian GNU/Linux wheezy/sid' /etc/issue ); then
  # if we are on a debian/raspbian (Raspberry Pi)
  cd /var/www
  make >/dev/null
  sleep 15
  killall midori
fi

# the last line is important, it's a marker for 'good download' - so leave it here:
# see update_this_script()
log "rc.local / $0 / READY/EXIT"
touch /tmp/RCLOCAL_READY
exit 0
