Wednesday, December 12, 2007

Creating a Generic Init Script Template

I should begin today's post by apologizing, both for my recent fascination with the Creative Commons licensing system (I can't explain why I like the logo so much ;) and for the fact that what we're going to create here today isn't a template in the conventional sense. It's actually more like a script to create init scripts. All depends in how you look at it, I guess.

I have to write enough of these that I don't generally bother with making my life easier. I'll just take the last script I wrote and use a few vi editor tricks to substitute this and that and be done with it. However, if this was something I had to do on a massive scale on an initial build, I think I might like to have a little bit of help. And help, as they say, is always available for those who help themselves.

The following script is written to create straight sh init scripts. I wrote it this ways since Solaris' sh, Linux sh (really bash for the most part) and the posix shell all port almost exactly and I wanted to be able to do this on any platform. With that in mind, I made the init script location and link locations variables as well, since Solaris keeps things in /etc/init.d, HP-UX keeps them in /sbin/init.d and various other flavors of *nix keep them in various other places. My hope is that this will be usable by anyone on any remotely-posix-compliant system; and then maybe even for users of systems that aren't!

If you're interested in reading more about the init script, I'll be doing future posts in greater detail, almost definitely. You can also check out these previous postings (parts 1, 2 and 3) regarding init scripts if you'd like to learn a little bit about some simple ways to manage them without "losing track" (something Solaris can do to you with its rc hard-links).

Hope this helps you out. When I find the time, I'll post an addendum to this (referring back to it) using getopts for the command line processing. For now, this "template" assumes a strict command line parlance and won't swagger unless you rewrite some parts yourself. There's no error checking either because this has become another monster post (perhaps I'll do a completely separate post on error checking so I don't have to keep explaining that). I tried to keep this as generic as possible :)


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/sh
#
# Simple Init Script Creator
# 2007 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#
# Usage: ./programName init_dir rc3_dir
# rc0_dir script_name program_name
# fully_qualified_program_name
# common_bin_directory start_options
# stop_options
#
# This script assumes that all listed
# variables have values, except for the last
# 2 (start options and stop_options - both
# should be surround by double quotes if
# spaces exist - If either of these do not
# exist, use the text string " " (double
# quoted space) to fill that option's
# place on the command line.
#
###########################################

trap 'rm -f ${init_dir}/${script_name} ${rc3_dir}/${script_name} ${rc0_dir}/${script_name} ${script_name}' 1 2 3 9 15

# Examples follow for all command line arguments
init_dir=$1 # /etc/init.d
rc3_dir=$2 # /etc/rc3.d
rc0_dir=$3 # /etc/rc0.d
script_name=$4 # WhateverYouWannaCallIt
program_name=$5 # apachectl
fully_qualified_program_name=$6 # /usr/local/sbin/apachectl
common_bin_directory=$7 # /usr/bin
start_options=$8 # "-f /usr/local/etc/httpd.conf" or " "
stop_options=$9 # "-k stop" or " "

cat <<- EOM >>$script_name

#!/bin/sh

#
# ${program_name} init script
# Usage: $script_name [start|stop]
#

case \$1 in
'start')
echo
echo Starting ${program_name}....
echo
${fully_qualified_program_name} ${start_options} >/dev/null 2>&1 &
${program_name}_running=\`${common_bin_directory}/ps -ef|${common_bin_directory}/grep "${fully_qualified_program_name}"|${common_bin_directory}/grep -v grep|${common_bin_directory}/awk '{print \$2}'\`
if [ "\$${program_name}_running" == "" ]
then
echo "${program_name} failed to start. Please check"
echo "application logs for further detail"
else
echo "${program_name} started successfully"
fi
;;
'stop')
echo
echo Stopping ${program_name}....
echo
if [ "$stop_options" != " " ]
then
${fully_qualified_program_name} ${stop_options} >/dev/null 2>&1 &
fi
${program_name}_walking=\`${common_bin_directory}/ps -ef|${common_bin_directory}/grep "${fully_qualified_program_name}"|${common_bin_directory}/grep -v grep|${common_bin_directory}/awk '{print \$2}'\`
if [ "\$${program_name}_walking" == "" ]
then
echo "${program_name} does not appear to be running."
echo "Process not found. Not shut down."
else
counter=5
dead="alive"
echo "Shutting ${program_name} down."
echo "${fully_qualified_program_name} - pid ${program_name}_walking - stopping."
while [ \$counter -gt 0 ]
do
${program_name}_still_walking=\`${common_bin_directory}/ps -ef|${common_bin_directory}/grep "${fully_qualified_program_name}"|${common_bin_directory}/grep -v grep|${common_bin_directory}/awk '{print \$2}'\`
if [ "\$${program_name}_still_walking" != "" ]
then
echo "killing pid \$${program_name}_still_walking "
${common_bin_directory}/kill \$${program_name}_still_walking >/dev/null 2>&1
counter=\`expr \$counter - 1\`
sleep 1
else
dead="dead"
echo "dead"
counter=0
fi
done
if [ \$dead = "alive" ]
then
echo "Could not kill process after 5 attempts."
echo "Process ${program_name}_walking still active."
${common_bin_directory}/ps -ef|${common_bin_directory}/grep "${fully_qualified_program_name}"|${common_bin_directory}/grep -v grep
fi
fi
;;
*)
echo "Usage: \$0 [start|stop]"
;;
esac
EOM

${common_bin_directory}/chmod 750 ${script_name};
${common_bin_directory}/cp ${script_name} ${init_dir}/${script_name}
${common_bin_directory}/ln -s ${init_dir}/${script_name} ${rc3_dir}/${script_name}
${common_bin_directory}/ln -s ${init_dir}/${script_name} ${rc0_dir}/${script_name}


, Mike