aboutsummaryrefslogtreecommitdiffstats
path: root/chapter07/functions.xml
blob: e10c1ab576413315fbacb0637eb060fd9ea866dd (plain)
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
<sect1 id="ch07-functions">
<title>Creating the functions script</title>
<?dbhtml filename="functions.html" dir="chapter07"?>

<para>Create the <filename>/etc/init.d/functions</filename> script by running
the following command:</para>

<para><screen><userinput>cat &gt; /etc/init.d/functions &lt;&lt; "EOF"</userinput>
#!/bin/sh
# Begin /etc/init.d/functions

#
# Set a few variables that influence the text that's printed on the
# screen. The SET_COL variable starts the text in the column number 
# decided by the COL and WCOL section (as defined by the COL 
# variable). NORMAL prints text in normal mode.
# SUCCESS prints text in a green colour and FAILURE prints text in a red
# colour
#

# If COLUMNS hasn't been set yet (bash sets it but not when called as
# sh), do it ourself

	if [ -z "$COLUMNS" ]
    	then
        	# Get the console device if we don't have it already
		# This is ok by the FHS as there is a fallback if
		# /usr/bin/tty isn't available, for example at bootup.
        	test -x /usr/bin/tty &amp;&amp; CONSOLE=`/usr/bin/tty`
        	test -z "$CONSOLE" &amp;&amp; CONSOLE=/dev/console

    		# Get the console size (rows columns)
        	SIZE=$(stty size &lt; $CONSOLE)
 
    		# Strip off the rows leaving the columns
      		COLUMNS=${SIZE#*\ }
	fi
 
COL=$[$COLUMNS - 10]
WCOL=$[$COLUMNS - 30]
SET_COL="echo -en \\033[${COL}G"
SET_WCOL="echo -en \\033[${WCOL}G"
NORMAL="echo -en \\033[0;39m"
SUCCESS="echo -en \\033[1;32m"
WARNING="echo -en \\033[1;33m"
FAILURE="echo -en \\033[1;31m"

#
# The evaluate_retval function evaluates the return value of the process
# that was run just before this function was called. If the return value
# was 0, indicating success, the print_status function is called with
# the 'success' parameter. Otherwise the print_status function is called
# with the failure parameter.
#

evaluate_retval()
{
        if [ $? = 0 ]
        then
                print_status success
        else
                print_status failure
        fi
}

#
# The print_status prints [  OK  ] or [FAILED] to the screen. OK appears
# in the colour defined by the SUCCESS variable and FAILED appears in
# the colour defined by the FAILURE variable. Both are printed starting
# in the column defined by the COL variable.
#

print_status()
{

#
# If no parameters are given to the print_status function, print usage
# information.
#

        if [ $# = 0 ]
        then
                echo "Usage: print_status {success|failure}"
                return 1
        fi

        case "$1" in
                success)
                        $SET_COL
                        echo -n "[  "
                        $SUCCESS
                        echo -n "OK"
                        $NORMAL
                        echo "  ]"
                        ;;
                warning)
                        $SET_COL
                        echo -n "[ "
                        $WARNING
                        echo -n "ATTN"
                        $NORMAL
                        echo " ]"
                        ;;
                failure)
                        $SET_COL
                        echo -n "["
                        $FAILURE
                        echo -n "FAILED"
                        $NORMAL
                        echo "]"
                        ;;
        esac

}

#
# The loadproc function starts a process (often a daemon) with
# proper error checking
#

loadproc()
{

#
# If no parameters are given to the print_status function, print usage
# information.
#

        if [ $# = 0 ]
        then
                echo "Usage: loadproc {program}"
                exit 1
        fi
#
# Find the basename of the first parameter (the daemon's name without
# the path
# that was provided so /usr/sbin/syslogd becomes plain 'syslogd' after
# basename ran)
#

        base=$(/usr/bin/basename $1)
#
# the pidlist variable will contains the output of the pidof command.
# pidof will try to find the PID's that belong to a certain string;
# $base in this case
#

        pidlist=$(/bin/pidof -o $$ -o $PPID -o %PPID -x $base)

        pid=""

        for apid in $pidlist
        do
                if [ -d /proc/$apid ]
                then
                        pid="$pid $apid"
                fi
        done
#
# If the $pid variable contains anything (from the previous for loop) it
# means the daemon is already running
#

        if [ ! -n "$pid" ]
        then
#
# Empty $pid variable means it's not running, so we run "$@" (all
# parameters giving to this function from the script) and then check the
# return value
#

                "$@"
                evaluate_retval
        else
#
# The variable $pid was not empty, meaning it was already running. We'll
# print [ ATTN ] now
#

                $SET_WCOL
                echo -n "Already running"
                print_status warning
        fi

}

#
# The killproc function kills a process with proper error checking
#

killproc()
{

#
# If no parameters are given to the print_status function, print usage
# information.
#

        if [ $# = 0 ]
        then
                echo "Usage: killproc {program} [signal]"
                exit 1
        fi

#
# Find the basename of the first parameter (the daemon's name without
# the path
# that was provided so /usr/sbin/syslogd becomes plain 'syslogd' after
# basename ran)
#

        base=$(/usr/bin/basename $1)

#
# Check if we gave a signal to kill the process with (like -HUP, -TERM,
# -KILL, etc) to this function (the second parameter). If no second
# parameter was provided set the nolevel variable. Else set the
# killlevel variable to the value of $2 (the second parameter)
#

        if [ "$2" != "" ]
        then
                killlevel=-$2
        else
                nolevel=1
        fi

#
# the pidlist variable will contains the output of the pidof command.
# pidof will try to find the PID's that belong to a certain string;
# $base in this case
#

        pidlist=$(/bin/pidof -o $$ -o $PPID -o %PPID -x $base)

        pid=""

        for apid in $pidlist
        do
                if [ -d /proc/$apid ]
                then
                        pid="$pid $apid"
                fi
        done

#
# If $pid contains something from the previous for loop it means one or
# more PID's were found that belongs to the processes to be killed
#

        if [ -n "$pid" ]
        then

#
# If no kill level was specified we'll try -TERM first and then sleep
# for 2 seconds to allow the kill to be completed
#

                if [ "$nolevel" = 1 ]
                then
                        /bin/kill -TERM $pid

#
# If after -TERM the PID still exists we'll wait 2 seconds before
# trying to kill it with -KILL. If the PID still exist after that, wait
# two more seconds. If the PIDs still exist by then it's safe to assume
# that we cannot kill these PIDs.
#

                        if /bin/ps h $pid &gt;/dev/null 2&gt;&amp;1
                        then
                                /usr/bin/sleep 2
                                if /bin/ps h $pid &gt; /dev/null 2&gt;&amp;1
                                then
                                        /bin/kill -KILL $pid
                                        if /bin/ps h $pid &gt; /dev/null 2&gt;&amp;1
                                        then
                                                /usr/bin/sleep 2
                                        fi
                                fi
                        fi
                        /bin/ps h $pid &gt;/dev/null 2&gt;&amp;1
                        if [ $? = 0 ]
                        then
#
# If after the -KILL it still exists it can't be killed for some reason
# and we'll print [FAILED]
#

                                print_status failure
                        else

#
# It was killed, remove possible stale PID file in /var/run and 
# print [  OK  ]
#

                                /bin/rm -f /var/run/$base.pid
                                print_status success
                        fi
                else

#
# A kill level was provided. Kill with the provided kill level and wait
# for 2 seconds to allow the kill to be completed
#

                        /bin/kill $killlevel $pid
                        if /bin/ps h $pid &gt; /dev/null 2&gt;&amp;1
                        then
                                /usr/bin/sleep 2
                        fi
                        /bin/ps h $pid &gt;/dev/null 2&gt;&amp;1
                        if [ $? = 0 ]
                        then

#
# If ps' return value is 0 it means it ran ok which indicates that the
# PID still exists. This means the process wasn't killed properly with
# the signal provided. Print [FAILED]
#

                                print_status failure
                        else

#
# If the return value was 1 or higher it means the PID didn't exist
# anymore which means it was killed successfully. Remove possible stale
# PID file and print [  OK  ]
#

                                /bin/rm -f /var/run/$base.pid
                                print_status success
                        fi
                fi
        else

#
# The PID didn't exist so we can't attempt to kill it. Print [ ATTN ]
#

                $SET_WCOL
                echo -n "Not running"
                print_status warning
        fi
}

#
# The reloadproc functions sends a signal to a daemon telling it to
# reload it's configuration file. This is almost identical to the
# killproc function with the exception that it won't try to kill it with
# a -KILL signal (aka -9)
#

reloadproc()
{

#
# If no parameters are given to the print_status function, print usage
# information.
#

        if [ $# = 0 ]
        then
                echo "Usage: reloadproc {program} [signal]"
                exit 1
        fi

#
# Find the basename of the first parameter (the daemon's name without
# the path that was provided so /usr/sbin/syslogd becomes plain 'syslogd' 
# after basename ran)
#

        base=$(/usr/bin/basename $1)

#
# Check if we gave a signal to send to the process (like -HUP)
# to this function (the second parameter). If no second
# parameter was provided set the nolevel variable. Else set the
# killlevel variable to the value of $2 (the second parameter)
#

        if [ -n "$2" ]
        then
                killlevel=-$2
        else
                nolevel=1
        fi

#
# the pidlist variable will contains the output of the pidof command.
# pidof will try to find the PID's that belong to a certain string;
# $base in this case
#

        pidlist=$(/bin/pidof -o $$ -o $PPID -o %PPID -x $base)

        pid=""

        for apid in $pidlist
        do
                if [ -d /proc/$apid ]
                then
                        pid="$pid $apid"
                fi
        done

#
# If $pid contains something from the previous for loop it means one or
# more PID's were found that belongs to the processes to be reloaded
#

        if [ -n "$pid" ]
        then

#
# If nolevel was set we will use the default reload signal SIGHUP.
#

                if [ "$nolevel" = 1 ]
                then
                        /bin/kill -SIGHUP $pid
                        evaluate_retval
                else

#
# Else we will use the provided signal
#

                        /bin/kill $killlevel $pid
                        evaluate_retval
                fi
        else

#
# If $pid is empty no PID's have been found that belong to the process.
# Print [ ATTN ]
#

                $SET_WCOL
                echo -n "Not running"
                print_status warning
        fi
}

#
# The statusproc function will try to find out if a process is running
# or not
#

statusproc()
{

#
# If no parameters are given to the print_status function, print usage
# information.
#

        if [ $# = 0 ]
        then
                echo "Usage: status {program}"
                return 1
        fi

#
# $pid will contain a list of PID's that belong to a process
#

        pid=$(/bin/pidof -o $$ -o $PPID -o %PPID -x $1)
        if [ -n "$pid" ]
        then

#
# If $pid contains something, the process is running, print the contents
# of the $pid variable
#

                echo "$1 running with Process ID $pid"
                return 0
        fi

#
# If $pid doesn't contain it check if a PID file exists and inform the
# user about this stale file.
#

        if [ -f /var/run/$1.pid ]
        then
                pid=$(/usr/bin/head -1 /var/run/$1.pid)
                if [ -n "$pid" ]
                then
                        echo "$1 not running but /var/run/$1.pid exists"
                        return 1
                fi
        else
                echo "$1 is not running"
        fi

}

# End /etc/init.d/functions
<userinput>EOF</userinput></screen></para>

</sect1>