This is a daemon script written for OS/X in bash. It can be run either as a daemon or a launchd service. The launchd service file will follow in a later post.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | #!/bin/bash # put these lines in the file header comment # FILE: |FILENAME| # USAGE: ./|FILENAME| start [ stop | restart ] [ --nofork ] [ --debug ] #----------------------------------------------------------------------- #Uncomment the following line to echo all commands to the terminal #----------------------------------------------------------------------- #set -x # better yet, set the --debug command line flag and syslog it. #=== FUNCTION ================================================================ # NAME: cleanup # DESCRIPTION: post service processing (clean temp space,pid files) # PARAMETERS: none # RETURNS: none #=============================================================================== function cleanup () { echo "trap exit" #Don't recurse in the exit trap trap - INT TERM EXIT #remove the pid file cleanly on exit [[ -f "$pidfile" ]] && rm "$pidfile" #add other post processing cleanup here exit } #=== FUNCTION ================================================================ # NAME: isrunning # DESCRIPTION: is any previous instance of this script already running # PARAMETERS: pidfile location # RETURNS: boolean #=============================================================================== function isrunning() { pidfile="$1" [[ ! -f "$pidfile" ]] && return 1 #pid file is nonexistent procpid=$(<"$pidfile") [[ -z "$procpid" ]] && return 1 #pid file contains no pid # check process list for pid existence and is an instance of this script [[ ! $(ps -p $procpid | grep $(basename $0)) == "" ]] && value=0 || value=1 return $value } #=== FUNCTION ================================================================ # NAME: createpidfile # DESCRIPTION: atomic creation of pid file with no race condition # PARAMETERS: the pid to put in the file, the filename to use as a lock # RETURNS: none #=============================================================================== function createpidfile() { mypid=$1 pidfile=$2 #Close stderr, don't overwrite existing file, shove my pid in the lock file. $(exec 2>&-; set -o noclobber; echo "$mypid" > "$pidfile") [[ ! -f "$pidfile" ]] && exit #Lock file creation failed procpid=$(<"$pidfile") [[ $mypid -ne $procpid ]] && { #I'm not the pid in the lock file # Is the process pid in the lockfile still running? isrunning "$pidfile" || { # No. Kill the pidfile and relaunch ourselves properly. rm "$pidfile" $0 $@ & } exit } # I win! set a trap for the lockfile on exit } #----------------------------------------------------------------------- # Check number of command line arguments #----------------------------------------------------------------------- [[ $# -lt 1 ]] || [[ $# -gt 3 ]] && { echo -e "\tUsage: ${0##/*/} start [ | stop | restart ] [ --nofork ] [ --debug ]" exit 1 } #A launchd script in OSX is not supposed to fork nofork=`echo "$*" | grep "\-\-nofork"` [[ ! -z $nofork ]] >> nofork=true [[ -z $nofork ]] >> nofork=false #check to send everything to syslog debug=`echo "$*" | grep "\-\-debug"` [[ ! -z $debug ]] >> debug=true [[ -z $debug ]] >> debug=false #configuration basename="`basename $0 .sh`" # look for the conf file in the same folder as the script conf="$(dirname $(which $0))/${basename}.conf" #<-- which handles "bash -x $0 start" [[ -f "$conf" ]] && source "$conf" #=== FUNCTION ================================================================ # NAME: pidfilename # DESCRIPTION: create a predictable pid file name, put it in the right inode # PARAMETERS: none # RETURNS: path and filename #=============================================================================== function pidfilename() { myfile=$(basename "$0" .sh) whoiam=$(whoami) mypidfile=/tmp/$myfile.pid [[ "$whoiam" == 'root' ]] && mypidfile=/var/run/$myfile.pid echo $mypidfile } pidfile=$(pidfilename) #find the temp directory tempfile=$(mktemp -t j) #put all of your incidentals in the tempdir tempdir=$(dirname $tempfile) rm $tempfile #Do all further processing from the root cd / # Load the daemon template for OSX . /etc/rc.common #traps trap 'source $conf' 1 # response to kill -s HUP $$ should be to read the config file. #trap 'echo trap 0; rm -f "$pidfile"; exit' 0 #can't trap this, daemon will exit when parent dies. #trap 'cleanup' 3 15 #clean up the pidfile #=== FUNCTION ================================================================ # NAME: main # DESCRIPTION: Allows daemon to be run in background # PARAMETERS: none # RETURNS: void #=============================================================================== function main() { # Put your service code here while : # Loop forever do sleep 10 echo $RANDOM done } #=== FUNCTION ================================================================ # NAME: StartService # DESCRIPTION: implements function from /etc/rc.common # PARAMETERS: none # RETURNS: void #=============================================================================== StartService () { CheckForNetwork isrunning "$pidfile" && { echo "$basename is already running" exit 1 } # do the service # no fork method for launchd service [[ "$nofork" == "true" ]] && { #pid file with this process id createpidfile $$ "$pidfile" trap 'cleanup' INT TERM EXIT [[ "$debug" == "true" ]] && trap 'logger -t $0 -i -- $USER : $BASH_COMMAND' DEBUG #syslog everything if we're debugging trap 'logger -t $0 -i -- $USER : $BASH_COMMAND' ERR #log errors regardless #echo $$ > $pidfile main exit } [[ "$debug" == "true" ]] && trap 'logger -t $0 -i -- $USER : $BASH_COMMAND' DEBUG #syslog everything if we're debugging trap 'logger -t $0 -i -- $USER : $BASH_COMMAND' ERR #log errors regardless # fork and exit main & # create a pid file with the pid of the child # the parent will go away and leave the child owned by init createpidfile $! "$pidfile" trap 'cleanup' INT TERM # #echo $! > $pidfile } #=== FUNCTION ================================================================ # NAME: StopService # DESCRIPTION: implements the function from /etc/rc.common # PARAMETERS: none # RETURNS: void #=============================================================================== StopService () { [[ -f "$pidfile" ]] && { kill $(head -n 1 "$pidfile") rm "$pidfile" } #touch "$quit" } #=== FUNCTION ================================================================ # NAME: RestartService # DESCRIPTION: implements the function from /etc/rc.common # PARAMETERS: none # RETURNS: void #=============================================================================== RestartService () { StopService StartService } #------------------------------------------------------------------------------- # Call the function declared in /etc/rc.common to daemonize process #------------------------------------------------------------------------------- RunService "$1" #First parameter is start/stop/restart |
No Comments so far ↓
There are no comments yet...Kick things off by filling out the form below.