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);