3
# fixproc [-min n] [-max n] [-check | -kill | -restart | -exist | -fix] proc ...
10
# 4 fix failed if fix is defined as kill or restart, then
11
# cannot kill or cannot restart is return instead
15
# Fixes a process named "proc" by performing the specified action. The
16
# actions can be check, kill, restart, exist, or fix. The action is specified
17
# on the command line or is read from a default database, which describes
18
# the default action to take for each process. The database format and
19
# the meaning of each action are described below.
25
# cmd /a/b/name args required
26
# min number optional, defaults to 1
27
# max number optional, defaults to 1
29
# check {null, exist, shell} optional, defaults to exist if not defined
30
# [shell command shell commands needed only if check=shell
33
# end_shell] keyword end_shell marks end of shell commands
34
# fix {kill, restart, shell} required
35
# [shell command shell commands needed only if fix=shell
38
# end_shell] keyword end_shell marks end of shell commands
40
# Blank lines and lines beginning with "#" are ignored.
46
# cmd nice /home/kong/z/test1 > /dev/null &
50
# nice /home/kong/z/test1 > /dev/null &
56
# There are 5 possible actions: kill, restart, fix, exist, check. Fix is
57
# defined to be the kill action, the restart action, or a series of shell
58
# commands. Check is optionally defined in the database. If check is not
59
# defined, it defaults to exist.
61
# If the action is specified on the cmd line, it is executed regardless of
62
# check. The commands executed for each action type is as follow:
66
# kill process, wait 5 seconds, kill -9 if still exist
68
# return "cannot kill"
74
# if kill returned "cannot kill"
75
# return "cannot kill"
76
# restart by issuing cmd to shell
82
# return "cannot restart"
90
# execute shell commands
94
# if check defined as null
95
# return "fixproc error"
99
# return (execute exist)
100
# return "check failed"
103
# if proc exists in ps && (min <= num. of processes <= max)
106
# return "check failed"
109
# If the action is not specified on the cmd line, the default action is the
110
# fix action defined in the database. Fix is only executed if check fails:
113
# if check is not defined as null
117
# execute action defined for fix
119
# return "fixproc error"
122
# If proc is not specified on the command line, return "fixproc error."
123
# Multiple proc's can be defined on the cmd line. When an error occurs
124
# when multiple proc's are specified, the first error encountered halts the
127
# For check shell scripts, any non-zero exit code means the check has failed.
130
# Timothy Kong 3/1995
132
$database_file = '/local/etc/fixproc.conf';
134
$debug = 0; # specify debug level using -dN
135
# currently defined: -d1
138
$check_failed_error = 1;
139
$cannot_restart_error = 2;
140
$cannot_kill_error = 3;
141
$cannot_fix_error = 4;
146
$cmd_line_action = '';
155
$shell_header = "#!/bin/sh\n";
156
$shell_end_marker = 'shell_end_marker';
160
# &dump_database(); # debug only
162
# change the default min. and max. number of processes allowed
165
for $name ( keys (%min) )
172
for $name ( keys (%max) )
178
# work on one process at a time
179
for $proc ( @proc_list )
181
$error_code = &work_on_proc ($proc);
183
############# uncomment next line when fully working ############
184
# exit $error_code if ($error_code);
186
die "error_code = $error_code\n" if ($error_code);
190
# create an executable shell script file
193
local ($file) = pop (@_);
194
local ($i) = pop (@_);
196
printf (stderr "create_sh_script\n") if ($debug > 0);
199
open (file, ">"."$file") || die "$0: cannot open $file\n";
200
while ( $shell_lines[$i] ne $shell_end_marker )
202
printf (file "%s", $shell_lines[$i]);
206
system "chmod +x $file";
213
local ($proc) = pop(@_);
215
printf (stderr "do_fix\n") if ($debug > 0);
217
if ($fix{$proc} eq '')
220
die "$0: internal error 4\n";
222
if ($fix{$proc} eq 'kill')
224
return &do_kill ($proc);
226
elsif ($fix{$proc} eq 'restart')
228
return &do_restart ($proc);
232
# it must be "shell", so execute the shell script defined in database
234
local ($tmpfile) = "/tmp/fix_$$";
236
&create_sh_script ($fix{$proc}, $tmpfile);
238
# return code is number divided by 256
239
$error_code = (system "$tmpfile") / 256;
240
system "rm $tmpfile";
241
return ($fix_failed_error) if ($error_code != 0);
243
return &do_exist ($proc);
250
local ($proc) = pop(@_);
252
printf (stderr "do_check\n") if ($debug > 0);
254
if ($check{$proc} eq '')
257
die "$0: internal error 2\n";
260
if ($check{$proc} ne 'exist')
262
# if not "exist", then it must be "shell", so execute the shell script
263
# defined in database
265
local ($tmpfile) = "/tmp/check_$$";
267
&create_sh_script ($check{$proc}, $tmpfile);
269
# return code is number divided by 256
270
$error_code = (system "$tmpfile") / 256;
271
system "rm $tmpfile";
272
return ($check_failed_error) if ($error_code != 0);
274
# check passed, continue
276
return &do_exist ($proc);
282
local ($proc) = pop(@_);
284
printf (stderr "do_exist\n") if ($debug > 0);
286
# do ps, check to see if min <= no. of processes <= max
288
open (command, "/bin/ps -e | /bin/grep $proc | /bin/wc -l |")
289
|| die "$0: can't run ps-grep-wc command\n";
290
$proc_count = <command>;
291
if (($proc_count < $min{$proc}) || ($proc_count > $max{$proc}))
293
return $check_failed_error;
301
local ($proc) = pop(@_);
302
local ($second_kill_needed);
304
printf (stderr "do_kill\n") if ($debug > 0);
308
open (command, "/bin/ps -e | /bin/grep $proc |")
309
|| die "$0: can't run ps-grep-awk command\n";
312
# match the first field of ps -e
314
/^\s*(\d+)\s/ || die "$0: can't match ps -e output\n";
318
# if process still exist, try kill -9
321
open (command, "/bin/ps -e | /bin/grep $proc |")
322
|| die "$0: can't run ps-grep-awk command\n";
323
$second_kill_needed = 0;
326
# match the first field of ps -e
328
/^\s*(\d+)\s/ || die "$0: can't match ps -e output\n";
330
$second_kill_needed = 1;
332
return ($no_error) if ($second_kill_needed == 0);
334
# see if kill -9 worked
337
open (command, "/bin/ps -e | /bin/grep $proc |")
338
|| die "$0: can't run ps-grep-awk command\n";
340
{ # a process still exist, return error
341
return $cannot_kill_error;
343
return $no_error; # good, all dead
349
local ($proc) = pop(@_);
352
printf (stderr "do_restart\n") if ($debug > 0);
354
$error_code = &do_kill ($proc);
355
return $error_code if ($error_code != $no_error);
356
die "$0: internal error 3\n" if ($cmd{$proc} eq '');
357
system "$cmd{$proc}";
359
if ($check{$proc} ne 'null')
361
return $no_error if (&do_check($proc) == $no_error);
362
return $cannot_restart_error;
369
local ($proc) = pop(@_);
372
printf (stderr "work_on_proc\n") if ($debug > 0);
374
if ($cmd_line_action eq '')
376
# perform action from database
378
if ($check{$proc} ne 'null')
380
$error_code = &do_check ($proc);
381
if ($error_code != $check_failed_error)
386
return &do_fix ($proc);
390
# perform action from command line
392
$error_code = $no_error;
393
if ($cmd_line_action eq 'kill')
395
$error_code = &do_kill ($proc);
397
elsif ($cmd_line_action eq 'restart')
399
$error_code = &do_restart ($proc);
401
elsif ($cmd_line_action eq 'fix')
403
$error_code = &do_fix ($proc);
405
elsif ($cmd_line_action eq 'check')
407
if ( $check{$proc} eq 'null' )
411
$error_code = &do_check ($proc);
413
elsif ($cmd_line_action eq 'exist')
415
$error_code = &do_exist ($proc);
420
die "$0: internal error 1\n";
430
for $name (keys(%cmd))
432
printf ("name\t%s\n", $name);
433
printf ("cmd\t%s\n", $cmd{$name});
434
printf ("min\t%s\n", $min{$name});
435
printf ("max\t%s\n", $max{$name});
436
if ( $check{$name} =~ /[0-9]+/ )
438
printf ("check\tshell\n");
440
while ( $shell_lines[$i] ne $shell_end_marker )
442
printf ("%s", $shell_lines[$i]);
448
printf ("check\t%s\n", $check{$name});
450
if ( $fix{$name} =~ /[0-9]+/ )
452
printf ("fix\tshell\n");
454
while ( $shell_lines[$i] ne $shell_end_marker )
456
printf ("%s", $shell_lines[$i]);
462
printf ("fix\t%s\n", $fix{$name});
471
local ($in_check_shell_lines) = 0;
472
local ($in_fix_shell_lines) = 0;
478
open (db, $database_file) || die 'cannot open database file $database_file\n';
481
if ((! /\S/) || (/^[ \t]*#.*$/))
483
# ignore blank lines or lines beginning with "#"
485
elsif ($in_check_shell_lines)
487
if ( /^\s*end_shell\s*$/ )
489
$in_check_shell_lines = 0;
490
push (@shell_lines, $shell_end_marker);
494
push (@shell_lines, $_);
497
elsif ($in_fix_shell_lines)
499
if ( /^\s*end_shell\s*$/ )
501
$in_fix_shell_lines = 0;
502
push (@shell_lines, $shell_end_marker);
506
push (@shell_lines, $_);
511
if ( ! /^\s*(\S+)\s+(\S.*)\s*$/ )
514
die "$0: syntax error in database\n$_";
520
&finish_db_entry($name);
523
elsif ($str1 eq 'cmd')
526
die "$0: cmd specified before name in database\n$_\n"
528
die "$0: cmd specified multiple times for $name in database\n"
529
if ($cmd{$name} ne '');
532
elsif ($str1 eq 'min')
535
die "$0: min specified before name in database\n$_\n"
537
die "$0: min specified multiple times in database\n$_\n"
538
if ($min{$name} ne '');
539
die "$0: non-numeric min value in database\n$_\n"
540
if ( ! ($str2 =~ /[0-9]+/ ));
543
elsif ($str1 eq 'max')
546
die "$0: max specified before name in database\n$_\n"
548
die "$0: max specified multiple times in database\n$_\n"
549
if ($max{$name} ne '');
550
die "$0: non-numeric max value in database\n$_\n"
551
if ( ! ($str2 =~ /[0-9]+/ ));
554
elsif ($str1 eq 'check')
557
die "$0: check specified before name in database\n$_\n"
559
die "$0: check specified multiple times in database\n$_\n"
560
if ($check{$name} ne '');
561
if ( $str2 eq 'shell' )
563
# if $check{$name} is a number, it is a pointer into
564
# $shell_lines[] where the shell commands are kept
565
$shell_lines[$#shell_lines+1] = $shell_header;
566
$check{$name} = $#shell_lines;
567
$in_check_shell_lines = 1;
571
$check{$name} = $str2;
574
elsif ($str1 eq 'fix')
577
die "$0: fix specified before name in database\n$_\n"
579
die "$0: fix specified multiple times in database\n$_\n"
580
if ($fix{$name} ne '');
581
if ( $str2 eq 'shell' )
583
# if $fix{$name} is a number, it is a pointer into
584
# $shell_lines[] where the shell commands are kept
585
$shell_lines[$#shell_lines+1] = $shell_header;
586
$fix{$name} = $#shell_lines;
587
$in_fix_shell_lines = 1;
596
&finish_db_entry($name);
602
local ($name) = pop(@_);
607
die "$0: fix not defined for $name in database\n"
608
if ($fix{$name} eq '');
609
die "$0: cmd not defined for $name in database\n"
610
if ($cmd{$name} eq '');
611
$check{$name} = 'exist' if ($check{$name} eq '');
612
$max{$name} = 1 if ($max{$name} eq '');
613
$min{$name} = 1 if ($min{$name} eq '');
622
local ($action_arg_count) = 0;
624
while ( $i <= $#ARGV )
627
if (($arg eq '-min') || ($arg eq '-max'))
629
if (($i == $#ARGV - 1) || ($ARGV[$i+1] =~ /\D/)) # \D is non-numeric
632
die "$0: numeric arg missing after -min or -max\n";
644
elsif ($arg eq '-kill')
646
$cmd_line_action = 'kill';
650
elsif ($arg eq '-check')
652
$cmd_line_action = 'check';
656
elsif ($arg eq '-restart')
658
$cmd_line_action = 'restart';
662
elsif ($arg eq '-exist')
664
$cmd_line_action = 'exist';
668
elsif ($arg eq '-fix')
670
$cmd_line_action = 'fix';
674
elsif ($arg =~ /-d(\d)$/)
682
die "$0: unknown switch $arg\n";
686
push (@proc_list, $arg);
691
die "$0: no process specified\n" if ($#proc_list == -1);
692
die "$0: more than one action specified\n" if ($action_arg_count > 1);