X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=userapps%2Fopensource%2Fnet-snmp%2Flocal%2Ffixproc;fp=userapps%2Fopensource%2Fnet-snmp%2Flocal%2Ffixproc;h=d6021bfd035edb3f47e3ecc450f5e2be63f88a56;hb=9dffd9f7659a1b28265e0dc9497343eb3d108d02;hp=0000000000000000000000000000000000000000;hpb=e48c2529a5a7e7dbf1797bb6d1bf964bc03e78a7;p=bcm963xx.git diff --git a/userapps/opensource/net-snmp/local/fixproc b/userapps/opensource/net-snmp/local/fixproc new file mode 100755 index 00000000..d6021bfd --- /dev/null +++ b/userapps/opensource/net-snmp/local/fixproc @@ -0,0 +1,694 @@ +#!/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 + +$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 ($i) = pop (@_); + + printf (stderr "create_sh_script\n") if ($debug > 0); + + $! = $fixproc_error; + open (file, ">"."$file") || die "$0: cannot open $file\n"; + while ( $shell_lines[$i] ne $shell_end_marker ) + { + printf (file "%s", $shell_lines[$i]); + $i++; + } + close (file); + system "chmod +x $file"; + return 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 ($tmpfile) = "/tmp/fix_$$"; + + &create_sh_script ($fix{$proc}, $tmpfile); + + # return code is number divided by 256 + $error_code = (system "$tmpfile") / 256; + system "rm $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 ($tmpfile) = "/tmp/check_$$"; + + &create_sh_script ($check{$proc}, $tmpfile); + + # return code is number divided by 256 + $error_code = (system "$tmpfile") / 256; + system "rm $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 = ; + 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 () + { + # 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 () + { + # 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 () + { # 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 () + { + 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); + } +