运维需要对一些关键的服务进程进行守护,例如tomcat进程,mysql之类,这种进程没有自己的守护进程,而我们又不可能去改它们的源代码。
为此我用perl写了一个守护进程,根据传入的命令,启动要守护的进程,若是进程挂了,则重新启动进程。
即使子进程被杀死了,也能自动起来,但是程序有点缺陷:
1. 这个守护进程只是针对那些永远不退出的进程有效。
2. 若是杀死了守护进程,被守护的进程有可能不会退出,还要手动去杀死被守护进程,才能退出。因为我们找到杀死整个进程树的方法,
?
- #!/usr/bin/perl ?
- ?
- #################################################### ?
- ?
- #功能:实现把传入的命令执行,并守护,当命令被杀死了,能够重新启动命令 ?
- ?
- #系统环境:centos?5 ?
- ?
-
#编译环境:perl,?v5.8.8?built?for?i386-linux-thread-multi ?
- ?
- #执行:????????????? ?
- ?
-
#echo?"i=0;"?>?/root/w.sh ?
- ?
-
#echo?'while(true)'?>>?/root/w.sh ?
- ?
-
#echo?"do"?>>?/root/w.sh ?
- ?
-
#echo?'?echo?$i;let?i=$i+1;sleep?1;'?>>?/root/w.sh ?
- ?
-
#echo?'done'?>>?/root/w.sh ?
- ?
-
#perl?deamon.pl?"sh?/root/w.sh?>>?/root/w.log"?
- ?
- # ?
- ?
- #################################################### ?
- ?
- use?POSIX?(); ?
- ?
- use?Carp; ?
- ?
- ?
- ?
-
our?$logfile="/tmp/deamon.log";?#输出日志 ?
- ?
- our?$child_pid;?#记录子进程的id,以便父进程去杀死子进程 ?
- ?
- our?$parent_pid;#记录父进程的id,以便区分父子进程 ?
- ?
- our?$maxloop=10000;?#放置大量产生子进程 ?
- ?
- our?$loop=0; ?
- ?
- our?$CMD=$ARGV[0]; ?
- ?
- if(!$CMD){ ?
- ?
-
????die("please?input?a?cmdn"); ?
- ?
- } ?
- ?
- ?
- ?
- #杀死父子进程 ?
- ?
- sub?kill_pid{ ?
- ?
-
????logs("catch?quit?signaln"); ?
- ?
- ????if($parent_pid){#判断是不是父进程 ?
- ?
- ????????#父进程杀死所有的子进程 ?
- ?
-
????????logs("parent?kill?childn"); ?
- ?
- ????????kill(15,$child_pid); ?
- ?
- ????????kill(15,-$$); ?
- ?
-
????????logs("parent?quitn"); ?
- ?
- ????????exit?0; ?
- ?
-
????}else{ ?
- ?
- ????????#子进程退出 ?
- ?
-
????????logs("child?quitn");???????? ?
- ?
- ????????exit?0; ?
- ?
- ????} ?
- ?
- }; ?
- ?
-
$SIG{'INT'}?=?'kill_pid';?#?中断退出 ?
- ?
-
$SIG{'TERM'}?=?'kill_pid'; ?
- ?
-
$SIG{CHLD}?=?'IGNORE';?#?忽略?SIGCHLD?信号,系统会自动回收结束的子进程 ?
- ?
- #deamon方式 ?
- ?
- daemonize(); ?
- ?
- #启动服务 ?
- ?
-
logs("START?deamon?'$CMD'n"); ?
- ?
- ?
- ?
- while(1){ ?
- ?
- ????#防止输入的命令不是服务性命令,例如ls,执行很短时间的命令,或者后台执行的命令,这样最多会产生$maxloop个进程,不会把系统崩溃 ?
- ?
- ????$loop++; ?
- ?
- ????if($loop>$maxloop){ ?
- ?
- ????????exit?0;???? ?
- ?
- ????} ?
- ?
- ???? ?
- ?
- ????#产生子进程 ?
- ?
- ????$child_pid=fork(); ?
- ?
-
????if?(not?defined?$child_pid)?{ ?
- ?
-
????????print?"cannot?forkn"; ?
- ?
- ????????exit?0; ?
- ?
- ????} ?
- ?
- ????if($child_pid) ?
- ?
- ????{?#?child?>;?0,?so?we're?the?parent ?
- ?
- ?????????$parent_pid=1;? ?
- ?
-
?????logs("launching?'$CMD'n");? ?
- ?
- ?????setpgrp(0,?0);?#成为进程首领 ?
- ?
- ?????wait();#等待子进程结束,若是结束则继续循环生成子进程 ?
- ?
-
????}else{? ?
- ?
- ????????????$parent_pid=0; ?
- ?
- ????????????system($CMD);#?child?handles,子进程应该也是死循环的 ?
- ?
-
????????????logs("system?return?:?$r?"); ?
- ?
- ?????#执行命令非正常退出 ?
- ?
- ?????if?($??==?-1)?{ ?
- ?
-
????????logs("failed?to?execute:?$!?"); ?
- ?
- ?????????} ?
- ?
- ?????????elsif?($??&?127)?{ ?
- ?
-
?????????logs("child?died?with?signal",($??&?127),",",($??&?128)???'with'?:?'without','?coredump'); ?
- ?
- ?????????} ?
- ?
-
?????????else?{ ?
- ?
-
?????????logs("child?exited?with?value?",$??>>?8); ?
- ?
- ?????????????#若是$CMD正常退出的话,表示$CMD不是服务性程序 ?
- ?
-
?????????????????logs("cannot?deamon?on?'$CMD'"); ?
- ?
- ?????????} ?
- ?
- ?????#子进程退出???? ?
- ?
- ?????exit?0; ?
- ?
- ????}? ?
- ?
- } ?
- ?
- ?
- ?
- #记录日志 ?
- ?
- sub?logs{ ?
- ?
-
????open(LOGFILE,">>$logfile")?or?die("cannot?open?$logfile"); ?
- ?
-
????????my($sec,$min,$hour,$mday,$mon,$year)=localtime(); ?
- ?
-
????print?LOGFILE?sprintf("%04d-%02d-%02d?%02d:%02d:%02d?",($year<?2000?($year+1900):$year),($mon+1),$sec); ?
- ?
-
????for?my?$msg?(@_){ ?
- ?
- ????????print?LOGFILE?$msg; ?
- ?
- ????} ?
- ?
-
????print?LOGFILE?"n"; ?
- ?
-
????close(LOGFILE); ?
- ?
- } ?
- ?
- ?
- ?
- #deamon方式 ?
- ?
- sub?daemonize?{ ?
- ?
- ?
- ?
- ????????#????使当前进程对自己所写文件拥有完全控制权,避免继承的umask()设置带来困挠。这一步可选 ?
- ?
- ????????umask(0); ?
- ?
- ????????#????关闭0、1、2三个句柄。许多daemon程序用sysconf()获取_SC_OPEN_MAX,并在一个?环中关闭所有可能打开的文件句柄。目的在于释放不必要的系统资源,它们是有限资源。 ?
- ?
-
????????close?STDIN; ?
- ?
-
????????close?STDOUT; ?
- ?
-
????????close?STDERR; ?
- ?
-
????chdir?'/'?or?croak?"Can't?chdir?to?/:?$!";?#减少管理员卸载(unmount)文件系统时可能遇上的麻烦。这一步可选,也可chdir()到其它目录。 ?
- ?
-
????open?STDIN,?'/dev/null'?or?croak?"Can't?read?/dev/null:?$!"; ?
- ?
-
????open?STDOUT,?'>/dev/null'?or?croak?"Can't?write?to?/dev/null:?$!"; ?
- ?
-
????open?STDERR,?'>&STDOUT'?or?croak?"Can't?dup?stdout:?$!"; ?
- ?
-
????defined(my?$pid?=?fork)?or?croak?"Can't?fork:?$!"; ?
- ?
- ????exit?if?$pid; ?
- ?
-
????#创建新的session和process?group,成为其leader,并脱离控制终端。 ?
- ?
-
????setsid?or?croak?"Can't?start?a?new?session:?$!"; ?
- ?
-
????$SIG{CHLD}?=?'IGNORE