| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695 |
- #!/usr/bin/perl
- #
- # fixproc [-min n] [-max n] [-check | -kill | -restart | -exist | -fix] proc ...
- #
- # fixproc exit code:
- # 0 ok
- # 1 check failed
- # 2 cannot restart
- # 3 cannot kill
- # 4 fix failed if fix is defined as kill or restart, then
- # cannot kill or cannot restart is return instead
- # 10 fixproc error
- #
- #
- # Fixes a process named "proc" by performing the specified action. The
- # actions can be check, kill, restart, exist, or fix. The action is specified
- # on the command line or is read from a default database, which describes
- # the default action to take for each process. The database format and
- # the meaning of each action are described below.
- #
- # database format
- # ---------------
- #
- # name foo required
- # cmd /a/b/name args required
- # min number optional, defaults to 1
- # max number optional, defaults to 1
- #
- # check {null, exist, shell} optional, defaults to exist if not defined
- # [shell command shell commands needed only if check=shell
- # ...
- # shell command
- # end_shell] keyword end_shell marks end of shell commands
- # fix {kill, restart, shell} required
- # [shell command shell commands needed only if fix=shell
- # ...
- # shell command
- # end_shell] keyword end_shell marks end of shell commands
- #
- # Blank lines and lines beginning with "#" are ignored.
- #
- #
- # Example:
- #
- # name test1
- # cmd nice /home/kong/z/test1 > /dev/null &
- # max 2
- # fix shell
- # xterm&
- # nice /home/kong/z/test1 > /dev/null &
- # end_shell
- #
- #
- # actions
- # -------
- # There are 5 possible actions: kill, restart, fix, exist, check. Fix is
- # defined to be the kill action, the restart action, or a series of shell
- # commands. Check is optionally defined in the database. If check is not
- # defined, it defaults to exist.
- #
- # If the action is specified on the cmd line, it is executed regardless of
- # check. The commands executed for each action type is as follow:
- #
- # switch action:
- # kill:
- # kill process, wait 5 seconds, kill -9 if still exist
- # if still exist
- # return "cannot kill"
- # else
- # return "ok"
- #
- # restart:
- # execute kill
- # if kill returned "cannot kill"
- # return "cannot kill"
- # restart by issuing cmd to shell
- # if check defined
- # execute check
- # if check succeeds
- # return "ok"
- # else
- # return "cannot restart"
- #
- # fix:
- # if fix=kill
- # execute kill
- # else if fix=restart
- # execute restart
- # else
- # execute shell commands
- # execute check
- #
- # check:
- # if check defined as null
- # return "fixproc error"
- # else
- # execute check
- # if check succeeds
- # return (execute exist)
- # return "check failed"
- #
- # exist:
- # if proc exists in ps && (min <= num. of processes <= max)
- # return "ok"
- # else
- # return "check failed"
- #
- #
- # If the action is not specified on the cmd line, the default action is the
- # fix action defined in the database. Fix is only executed if check fails:
- #
- # if fix defined
- # if check is not defined as null
- # execute check
- # if check succeeds
- # return "ok"
- # execute action defined for fix
- # else
- # return "fixproc error"
- #
- #
- # If proc is not specified on the command line, return "fixproc error."
- # Multiple proc's can be defined on the cmd line. When an error occurs
- # when multiple proc's are specified, the first error encountered halts the
- # script.
- #
- # For check shell scripts, any non-zero exit code means the check has failed.
- #
- #
- # Timothy Kong 3/1995
- use File::Temp qw(tempfile);
- $database_file = '/local/etc/fixproc.conf';
- $debug = 0; # specify debug level using -dN
- # currently defined: -d1
- $no_error = 0;
- $check_failed_error = 1;
- $cannot_restart_error = 2;
- $cannot_kill_error = 3;
- $cannot_fix_error = 4;
- $fixproc_error = 10;
- $min = 1;
- $max = 1;
- $cmd_line_action = '';
- %min = ();
- %max = ();
- %cmd = ();
- %check = ();
- %fix = ();
- $shell_lines = ();
- @proc_list = ();
- $shell_header = "#!/bin/sh\n";
- $shell_end_marker = 'shell_end_marker';
- &read_args();
- &read_database();
- # &dump_database(); # debug only
- # change the default min. and max. number of processes allowed
- if ($min != 1)
- {
- for $name ( keys (%min) )
- {
- $min{$name} = $min;
- }
- }
- if ($max != 1)
- {
- for $name ( keys (%max) )
- {
- $max{$name} = $max;
- }
- }
-
- # work on one process at a time
- for $proc ( @proc_list )
- {
- $error_code = &work_on_proc ($proc);
- ############# uncomment next line when fully working ############
- # exit $error_code if ($error_code);
- die "error_code = $error_code\n" if ($error_code);
- }
- # create an executable shell script file
- sub create_sh_script
- {
- local ($file) = pop (@_);
- local ($fh) = pop (@_);
- local ($i) = pop (@_);
- printf (STDERR "create_sh_script\n") if ($debug > 0);
- $! = $fixproc_error;
- while ( $shell_lines[$i] ne $shell_end_marker )
- {
- printf ($fh "%s", $shell_lines[$i]);
- $i++;
- }
- close ($fh);
- chmod 0755, $file;
- }
- sub do_fix
- {
- local ($proc) = pop(@_);
- printf (STDERR "do_fix\n") if ($debug > 0);
- if ($fix{$proc} eq '')
- {
- $! = $fixproc_error;
- die "$0: internal error 4\n";
- }
- if ($fix{$proc} eq 'kill')
- {
- return &do_kill ($proc);
- }
- elsif ($fix{$proc} eq 'restart')
- {
- return &do_restart ($proc);
- }
- else
- {
- # it must be "shell", so execute the shell script defined in database
- local ($tmpfh, $tmpfile) = tempfile("fix_XXXXXXXX", DIR => "/tmp");
- &create_sh_script ($fix{$proc}, $tmpfh, $tmpfile);
- # return code is number divided by 256
- $error_code = (system "$tmpfile") / 256;
- unlink($tmpfile);
- return ($fix_failed_error) if ($error_code != 0);
- # sleep needed here?
- return &do_exist ($proc);
- }
- }
- sub do_check
- {
- local ($proc) = pop(@_);
- printf (STDERR "do_check\n") if ($debug > 0);
- if ($check{$proc} eq '')
- {
- $! = $fixproc_error;
- die "$0: internal error 2\n";
- }
- if ($check{$proc} ne 'exist')
- {
- # if not "exist", then it must be "shell", so execute the shell script
- # defined in database
- local ($tmpfh, $tmpfile) = tempfile("check_XXXXXXXX", DIR => "/tmp");
- &create_sh_script ($fix{$proc}, $tmpfh, $tmpfile);
- # return code is number divided by 256
- $error_code = (system "$tmpfile") / 256;
- unlink($tmpfile);
- return ($check_failed_error) if ($error_code != 0);
- # check passed, continue
- }
- return &do_exist ($proc);
- }
- sub do_exist
- {
- local ($proc) = pop(@_);
- printf (STDERR "do_exist\n") if ($debug > 0);
- # do ps, check to see if min <= no. of processes <= max
- $! = $fixproc_error;
- open (COMMAND, "/bin/ps -e | /bin/grep $proc | /bin/wc -l |")
- || die "$0: can't run ps-grep-wc command\n";
- $proc_count = <COMMAND>;
- if (($proc_count < $min{$proc}) || ($proc_count > $max{$proc}))
- {
- return $check_failed_error;
- }
- return $no_error;
- }
- sub do_kill
- {
- local ($proc) = pop(@_);
- local ($second_kill_needed);
- printf (STDERR "do_kill\n") if ($debug > 0);
- # first try kill
- $! = $fixproc_error;
- open (COMMAND, "/bin/ps -e | /bin/grep $proc |")
- || die "$0: can't run ps-grep-awk command\n";
- while (<COMMAND>)
- {
- # match the first field of ps -e
- $! = $fixproc_error;
- /^\s*(\d+)\s/ || die "$0: can't match ps -e output\n";
- system "kill $1";
- }
- # if process still exist, try kill -9
- sleep 2;
- $! = $fixproc_error;
- open (COMMAND, "/bin/ps -e | /bin/grep $proc |")
- || die "$0: can't run ps-grep-awk command\n";
- $second_kill_needed = 0;
- while (<COMMAND>)
- {
- # match the first field of ps -e
- $! = $fixproc_error;
- /^\s*(\d+)\s/ || die "$0: can't match ps -e output\n";
- system "kill -9 $1";
- $second_kill_needed = 1;
- }
- return ($no_error) if ($second_kill_needed == 0);
- # see if kill -9 worked
- sleep 2;
- $! = $fixproc_error;
- open (COMMAND, "/bin/ps -e | /bin/grep $proc |")
- || die "$0: can't run ps-grep-awk command\n";
- while (<COMMAND>)
- { # a process still exist, return error
- return $cannot_kill_error;
- }
- return $no_error; # good, all dead
- }
- sub do_restart
- {
- local ($proc) = pop(@_);
- local ($error_code);
- printf (STDERR "do_restart\n") if ($debug > 0);
- $error_code = &do_kill ($proc);
- return $error_code if ($error_code != $no_error);
- die "$0: internal error 3\n" if ($cmd{$proc} eq '');
- system "$cmd{$proc}";
- # sleep needed here?
- if ($check{$proc} ne 'null')
- {
- return $no_error if (&do_check($proc) == $no_error);
- return $cannot_restart_error;
- }
- }
- sub work_on_proc
- {
- local ($proc) = pop(@_);
- local ($error_code);
- printf (STDERR "work_on_proc\n") if ($debug > 0);
- if ($cmd_line_action eq '')
- {
- # perform action from database
- if ($check{$proc} ne 'null')
- {
- $error_code = &do_check ($proc);
- if ($error_code != $check_failed_error)
- {
- return $error_code;
- }
- }
- return &do_fix ($proc);
- }
- else
- {
- # perform action from command line
- $error_code = $no_error;
- if ($cmd_line_action eq 'kill')
- {
- $error_code = &do_kill ($proc);
- }
- elsif ($cmd_line_action eq 'restart')
- {
- $error_code = &do_restart ($proc);
- }
- elsif ($cmd_line_action eq 'fix')
- {
- $error_code = &do_fix ($proc);
- }
- elsif ($cmd_line_action eq 'check')
- {
- if ( $check{$proc} eq 'null' )
- {
- exit $fixproc_error;
- }
- $error_code = &do_check ($proc);
- }
- elsif ($cmd_line_action eq 'exist')
- {
- $error_code = &do_exist ($proc);
- }
- else
- {
- $! = $fixproc_error;
- die "$0: internal error 1\n";
- }
- }
- }
- sub dump_database
- {
- local ($name);
- for $name (keys(%cmd))
- {
- printf ("name\t%s\n", $name);
- printf ("cmd\t%s\n", $cmd{$name});
- printf ("min\t%s\n", $min{$name});
- printf ("max\t%s\n", $max{$name});
- if ( $check{$name} =~ /[0-9]+/ )
- {
- printf ("check\tshell\n");
- $i = $check{$name};
- while ( $shell_lines[$i] ne $shell_end_marker )
- {
- printf ("%s", $shell_lines[$i]);
- $i++;
- }
- }
- else
- {
- printf ("check\t%s\n", $check{$name});
- }
- if ( $fix{$name} =~ /[0-9]+/ )
- {
- printf ("fix\tshell\n");
- $i = $fix{$name};
- while ( $shell_lines[$i] ne $shell_end_marker )
- {
- printf ("%s", $shell_lines[$i]);
- $i++;
- }
- }
- else
- {
- printf ("fix\t%s\n", $fix{$name});
- }
- printf ("\n");
- }
- }
- sub read_database
- {
- local ($in_check_shell_lines) = 0;
- local ($in_fix_shell_lines) = 0;
- local ($name) = '';
- local ($str1);
- local ($str2);
- $! = $fixproc_error;
- open (DB, $database_file) || die 'cannot open database file $database_file\n';
- while (<DB>)
- {
- if ((! /\S/) || (/^[ \t]*#.*$/))
- {
- # ignore blank lines or lines beginning with "#"
- }
- elsif ($in_check_shell_lines)
- {
- if ( /^\s*end_shell\s*$/ )
- {
- $in_check_shell_lines = 0;
- push (@shell_lines, $shell_end_marker);
- }
- else
- {
- push (@shell_lines, $_);
- }
- }
- elsif ($in_fix_shell_lines)
- {
- if ( /^\s*end_shell\s*$/ )
- {
- $in_fix_shell_lines = 0;
- push (@shell_lines, $shell_end_marker);
- }
- else
- {
- push (@shell_lines, $_);
- }
- }
- else
- {
- if ( ! /^\s*(\S+)\s+(\S.*)\s*$/ )
- {
- $! = $fixproc_error;
- die "$0: syntax error in database\n$_";
- }
- $str1 = $1;
- $str2 = $2;
- if ($str1 eq 'name')
- {
- &finish_db_entry($name);
- $name = $str2;
- }
- elsif ($str1 eq 'cmd')
- {
- $! = $fixproc_error;
- die "$0: cmd specified before name in database\n$_\n"
- if ($name eq '');
- die "$0: cmd specified multiple times for $name in database\n"
- if ($cmd{$name} ne '');
- $cmd{$name} = $str2;
- }
- elsif ($str1 eq 'min')
- {
- $! = $fixproc_error;
- die "$0: min specified before name in database\n$_\n"
- if ($name eq '');
- die "$0: min specified multiple times in database\n$_\n"
- if ($min{$name} ne '');
- die "$0: non-numeric min value in database\n$_\n"
- if ( ! ($str2 =~ /[0-9]+/ ));
- $min{$name} = $str2;
- }
- elsif ($str1 eq 'max')
- {
- $! = $fixproc_error;
- die "$0: max specified before name in database\n$_\n"
- if ($name eq '');
- die "$0: max specified multiple times in database\n$_\n"
- if ($max{$name} ne '');
- die "$0: non-numeric max value in database\n$_\n"
- if ( ! ($str2 =~ /[0-9]+/ ));
- $max{$name} = $str2;
- }
- elsif ($str1 eq 'check')
- {
- $! = $fixproc_error;
- die "$0: check specified before name in database\n$_\n"
- if ($name eq '');
- die "$0: check specified multiple times in database\n$_\n"
- if ($check{$name} ne '');
- if ( $str2 eq 'shell' )
- {
- # if $check{$name} is a number, it is a pointer into
- # $shell_lines[] where the shell commands are kept
- $shell_lines[$#shell_lines+1] = $shell_header;
- $check{$name} = $#shell_lines;
- $in_check_shell_lines = 1;
- }
- else
- {
- $check{$name} = $str2;
- }
- }
- elsif ($str1 eq 'fix')
- {
- $! = $fixproc_error;
- die "$0: fix specified before name in database\n$_\n"
- if ($name eq '');
- die "$0: fix specified multiple times in database\n$_\n"
- if ($fix{$name} ne '');
- if ( $str2 eq 'shell' )
- {
- # if $fix{$name} is a number, it is a pointer into
- # $shell_lines[] where the shell commands are kept
- $shell_lines[$#shell_lines+1] = $shell_header;
- $fix{$name} = $#shell_lines;
- $in_fix_shell_lines = 1;
- }
- else
- {
- $fix{$name} = $str2;
- }
- }
- }
- }
- &finish_db_entry($name);
- }
- sub finish_db_entry
- {
- local ($name) = pop(@_);
- if ($name ne '')
- {
- $! = $fixproc_error;
- die "$0: fix not defined for $name in database\n"
- if ($fix{$name} eq '');
- die "$0: cmd not defined for $name in database\n"
- if ($cmd{$name} eq '');
- $check{$name} = 'exist' if ($check{$name} eq '');
- $max{$name} = 1 if ($max{$name} eq '');
- $min{$name} = 1 if ($min{$name} eq '');
- }
- }
- sub read_args
- {
- local ($i) = 0;
- local ($arg);
- local ($action_arg_count) = 0;
- while ( $i <= $#ARGV )
- {
- $arg = $ARGV[$i];
- if (($arg eq '-min') || ($arg eq '-max'))
- {
- if (($i == $#ARGV - 1) || ($ARGV[$i+1] =~ /\D/)) # \D is non-numeric
- {
- $! = $fixproc_error;
- die "$0: numeric arg missing after -min or -max\n";
- }
- if ($arg eq '-min')
- {
- $min = $ARGV[$i+1];
- }
- else
- {
- $max = $ARGV[$i+1];
- }
- $i += 2;
- }
- elsif ($arg eq '-kill')
- {
- $cmd_line_action = 'kill';
- $action_arg_count++;
- $i++;
- }
- elsif ($arg eq '-check')
- {
- $cmd_line_action = 'check';
- $action_arg_count++;
- $i++;
- }
- elsif ($arg eq '-restart')
- {
- $cmd_line_action = 'restart';
- $action_arg_count++;
- $i++;
- }
- elsif ($arg eq '-exist')
- {
- $cmd_line_action = 'exist';
- $action_arg_count++;
- $i++;
- }
- elsif ($arg eq '-fix')
- {
- $cmd_line_action = 'fix';
- $action_arg_count++;
- $i++;
- }
- elsif ($arg =~ /-d(\d)$/)
- {
- $debug = $1;
- $i++;
- }
- elsif ($arg =~ /^-/)
- {
- $! = $fixproc_error;
- die "$0: unknown switch $arg\n";
- }
- else
- {
- push (@proc_list, $arg);
- $i++;
- }
- }
- $! = $fixproc_error;
- die "$0: no process specified\n" if ($#proc_list == -1);
- die "$0: more than one action specified\n" if ($action_arg_count > 1);
- }
|