#!/bin/sh
#
# php-fcgi      This shell script starts and stops PHP FastCGI processes.
#
# chkconfig:   345 80 30
# description: PHP is an interpreted language used within web pages
# processname: php.fcgi
# pidfile:  /var/run/php-fcgi.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Source php-fcgi configureation.
. /etc/sysconfig/php-fcgi

# Check that networking is up.
if is_yes "${NETWORKING}"; then
	if [ ! -f /var/lock/subsys/network -a "$1" != stop -a "$1" != status ]; then
		msg_network_down "PHP FastCGI"
		exit 1
	fi
else
	exit 0
fi

if [ -z "$PHP_FCGI_CHILDREN" ]; then
	PHP_FCGI_CHILDREN=5
fi
if [ -z "$PHP_FCGI_BINARY" ]; then
	PHP_FCGI_BINARY=/usr/bin/php.fcgi
fi

is_ipv4() {
	echo "$1" | LC_ALL=C grep -Eq '^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$'
}

is_numeric() {
	echo "$1" | LC_ALL=C grep -Eq '^[0-9]+$'
}

checkconfig() {
	local prog=${0##*/}

	if [ ! -x "$PHP_FCGI_BINARY" ]; then
		echo >&2 "$prog: PHP FCGI binary '$PHP_FCGI_BINARY' doesn't exist"
		exit 1
	fi

	if [ -n "$SPAWN_PORT" -a -n "$SPAWN_SOCKET" ]; then
		echo >&2 "$prog: port and socket can not be used simulatenously"
		exit 1
	fi

	if [ -n "$SPAWN_ADDR" -a -z "$SPAWN_PORT" ]; then
		echo >&2 "$prog: bind address specified but no port"
		exit 1
	fi

	if [ -n "$SPAWN_ADDR" ] && ! is_ipv4 "$SPAWN_ADDR"; then
		echo >&2 "$prog: bind address not valid ipv4 address: '$SPAWN_ADDR'"
		exit 1
	fi

	if [ -n "$SPAWN_PORT" ] && ! is_numeric "$SPAWN_PORT"; then
		echo >&2 "$prog: spawn port not numeric: $SPAWN_PORT"
		exit 1
	fi

	if [ -n "$FCGI_WEB_SERVER_ADDRS" ]; then
		local a err ifs=$IFS
		IFS=,
		for a in $FCGI_WEB_SERVER_ADDRS; do
			if ! is_ipv4 $a; then
				echo >&2 "$prog: not an ipv4 address: $a"
				err=1
			fi
		done
		IFS=$ifs
		if [ "$err" = 1 ]; then
			echo >&2 "$prog: FCGI_WEB_SERVER_ADDRS must be comma separated list of ips"
			exit 1
		fi
	fi
}

# Spawns FCGI process.

# Sets $RETVAL
# Creates subsys lock.
fcgi_spawn() {
	export PHP_FCGI_MAX_REQUESTS
	export FCGI_WEB_SERVER_ADDRS
	local args

	# user/group
	args="$args ${SPAWN_UID:+-u $SPAWN_UID}"
	args="$args ${SPAWN_GID:+-g $SPAWN_GID}"

	# bind address
	args="$args ${SPAWN_ADDR:+-a $SPAWN_ADDR}"
	args="$args ${SPAWN_PORT:+-p $SPAWN_PORT}"
	args="$args ${SPAWN_SOCKET:+-s $SPAWN_SOCKET}"
	args="$args $SPAWNARGS"

	# set umask the same way daemon() does.
	[ -z "$DEFAULT_SERVICE_UMASK" ] && DEFAULT_SERVICE_UMASK=022
	umask ${SERVICE_UMASK:-$DEFAULT_SERVICE_UMASK}

	env -i PATH=$PATH /usr/sbin/spawn-fcgi -P /var/run/php-fcgi.pid $args -C $PHP_FCGI_CHILDREN -- $PHP_FCGI_BINARY > /dev/null
	RETVAL=$?

	if [ $RETVAL -eq 0 ]; then
		ok
	   	touch /var/lock/subsys/php-fcgi
	else
		fail
	fi

}

# Stops FCGI.
#
# Removes lockfile.
# RETVAL is not set
fcgi_stop() {
	killproc --pidfile php-fcgi.pid ${PHP_FCGI_BINARY##*/}
	rm -f /var/lock/subsys/php-fcgi >/dev/null 2>&1
}

start() {
	# Start daemons.
	if [ ! -f /var/lock/subsys/php-fcgi ]; then
		msg_starting "PHP FastCGI"
		fcgi_spawn
	else
		msg_already_running "PHP FastCGI"
	fi
}

stop() {
	# Stop daemons.
	if [ -f /var/lock/subsys/php-fcgi ]; then
		msg_stopping "PHP FastCGI"
		fcgi_stop
	else
		msg_not_running "PHP FastCGI"
	fi
}

restart() {
	local stop socket oldpid newpid

	# we need to know about stopping before we start
	if [ -f /var/lock/subsys/php-fcgi ]; then
		stop=1
		read oldpid 2>/dev/null </var/run/php-fcgi.pid
	fi

	# so if we're using local sockets, we can create the new processes before
	# stopping old ones, thus causing almost no downtime during restart
	if [ "$SPAWN_SOCKET" ]; then
		socket="$SPAWN_SOCKET"
		SPAWN_SOCKET=$(TMPDIR= mktemp -p ${SPAWN_SOCKET%/*} ${SPAWN_SOCKET##*/}.XXXXXX) || exit 1
		[ "$SPAWN_UID" ] && chown $SPAWN_UID $SPAWN_SOCKET
		[ "$SPAWN_GID" ] && chgrp $SPAWN_GID $SPAWN_SOCKET

		msg_starting "PHP FastCGI (new)"
		fcgi_spawn
		if [ $RETVAL = 0 ]; then
			# on success switch the socket and we can kill the old processes
			mv -f "$SPAWN_SOCKET" "$socket"

			# to prevent killing the newly spawned process we restore pid of old fcgi
			read newpid 2>/dev/null </var/run/php-fcgi.pid
			echo "$oldpid" > /var/run/php-fcgi.pid
		fi
	fi

	# Stop daemons.
	if [ "$stop" = 1 ]; then
		msg_stopping "PHP FastCGI (old)"
		fcgi_stop
		if [ -n "$newpid" ]; then
			echo "$newpid" > /var/run/php-fcgi.pid
			touch /var/lock/subsys/php-fcgi
		fi
	fi

	# if we used socket, the new process was started before killing old one
	if [ -z "$SPAWN_SOCKET" ]; then
		msg_starting "PHP FastCGI (new)"
		fcgi_spawn
	fi
}

RETVAL=0
# See how we were called.
case "$1" in
start)
	checkconfig
	start
	;;
stop)
	stop
	;;
restart|force-reload)
	checkconfig
	restart
	;;
status)
	status php-fcgi $PHP_FCGI_BINARY
	RETVAL=$?
	echo "Configured settings:"
	echo " PHP_FCGI_CHILDREN=$PHP_FCGI_CHILDREN"
	echo " FCGI_WEB_SERVER_ADDRS=$FCGI_WEB_SERVER_ADDRS"
	echo " PHP_FCGI_MAX_REQUESTS=$PHP_FCGI_MAX_REQUESTS"
	read pid 2>/dev/null </var/run/php-fcgi.pid
	if [ -f "/proc/$pid/environ" ]; then
		echo "Running settings:"
		tr '\0' '\n' < /proc/$pid/environ | awk -F= '
			$1 == "PHP_FCGI_CHILDREN" { print " "$0 }
			$1 == "FCGI_WEB_SERVER_ADDRS" { print " "$0 }
			$1 == "PHP_FCGI_MAX_REQUESTS" { print " "$0 }
		'
	fi
	;;
*)
	msg_usage "$0 {start|stop|restart|force-reload|status}"
	exit 3
esac

exit $RETVAL
