/************************************************/ /* */ /* Copyright: */ /* Jean-Marc Pigeon 2009 */ /* */ /************************************************/ /* This program is free software; you can */ /* redistribute it and/or modify it under the */ /* terms of the GNU General Public License as */ /* published by the Free Software Foundation */ /* version 2 of the License */ /* */ /* This program is distributed in the hope that */ /* it will be useful, but WITHOUT ANY WARRANTY; */ /* without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR */ /* PURPOSE. See the GNU General Public License */ /* for more details. */ /* */ /* You should have received a copy of the GNU */ /* General Public License along with this */ /* program; if not, write to the Free Software */ /* Foundation, Inc., 51 Franklin Street, */ /* Fifth Floor, Boston, MA 02110-1301, USA. */ /************************************************/ /* */ /* Implement very sub level procedure to */ /* handle process sub function. */ /* */ /************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "dbgmem.h" #include "lowtyp.h" #include "utlprc.h" /* */ /************************************************/ /* */ /* Procedure to catch signal and do what is*/ /* needed. */ /* */ /************************************************/ static void trpsignal(int sig) { switch (sig) { case SIGALRM : break; default : (void) fprintf(stderr,"utlprc.c:trpalrm, Unexpected signal <%s> received", sys_siglist[sig]); (void) fflush(stderr); break; } } /* */ /************************************************/ /* */ /* Procedure to display an core_dump */ /* message and terminate application */ /* */ /************************************************/ void prc_core_dump(char *crashdir,char *temps,const char *fmt,va_list args) { #define MXSTEP 30 va_list ap; struct rlimit limites; va_copy(ap,args); if (getrlimit(RLIMIT_CORE,&limites)<0) { (void) fprintf(stderr,"getrlimit error='%s'",strerror(errno)); } limites.rlim_cur=limites.rlim_max; if (setrlimit(RLIMIT_CORE,&limites)<0) { (void) fprintf(stderr,"setrlimit error='%s'",strerror(errno)); } (void) prctl(PR_SET_DUMPABLE,1,0,0,0);/*to allow core-dump */ if (chdir(crashdir)<0) { char command[2000]; char dirdump[1000]; (void) snprintf(dirdump,sizeof(dirdump),"%s/coredump/","/tmp"); (void) snprintf(command,sizeof(command),"mkdir -p %s",dirdump); (void) system(command); if (chdir(dirdump)<0) { (void) abort(); } crashdir=dirdump; } if (temps!=(char *)0) (void) fprintf(stderr,"%s ",temps); (void) vfprintf(stderr,fmt,ap); (void) fprintf(stderr,"\n"); (void) fprintf(stderr,"going to CORE DUMP (in %score.%d)\n", crashdir,getpid()); (void) fflush(stderr); (void) sleep(5); /*to avoid crash avalanche */ (void) abort(); /*doing the abort */ (void) exit(-1); /*Theoriticaly unreachable */ } /* ^L */ /************************************************/ /* */ /* Procedure to check if a child process */ /* is still alive. */ /* */ /************************************************/ int prc_checkprocess(pid_t pid) { int status; status=false; switch(pid) { case (pid_t)0 : /*0 means no process */ status=false; break; case (pid_t)1 : /*init process always OK*/ status=true; break; default : /*standard process */ if (kill(pid,SIGCHECK)==0) status=true; break; } return status; } /* */ /************************************************/ /* */ /* Procedure to allow exited child process */ /* to leave the zombie stat. */ /* */ /************************************************/ void prc_nozombie() { while (waitpid(-1,(int *)0,WNOHANG)>0); } /* */ /************************************************/ /* */ /* Procedure to add a process number to */ /* process list */ /* */ /************************************************/ PRCTYP *prc_addtoprc(PRCTYP *plst,pid_t pid) { register int taille; taille=1; if (plst==(PRCTYP *)0) { plst=(PRCTYP *)calloc(1,sizeof(PRCTYP)); plst->pqueue=(pid_t *)calloc(taille,sizeof(pid_t)); } plst->pqueue[plst->nbr]=pid; plst->nbr++; taille+=plst->nbr; plst->pqueue=(pid_t *)realloc((void *)plst->pqueue,taille*sizeof(pid_t)); return plst; } /* */ /************************************************/ /* */ /* Procedure to terminate all child process*/ /* refered in a process list. if not */ /* successful 'delay' after SIGTERM try, */ /* a SIGKILL signal is applied. */ /* */ /************************************************/ PRCTYP *prc_childkill(PRCTYP *prclst,int delay) { if (prclst!=(PRCTYP *)0) { pid_t *pid; int overkill; int i; overkill=false; pid=prclst->pqueue; (void) prc_nozombie(); for (i=0;inbr;i++) { if (pid[i]<=1) /*no way to kill admin process */ continue; if (kill(pid[i],SIGTERM)==0) overkill=true; } while (overkill==true) { struct timespec timer; timer.tv_sec=1; timer.tv_nsec=0; overkill=false; while (nanosleep(&timer,&timer)!=0); (void) prc_nozombie(); for (i=0;inbr;i++) { if (pid[i]<=1) /*no way to kill admin process */ continue; if (kill(pid[i],SIGCHECK)==0) overkill=true; } delay--; if (delay==0) break; } if (overkill==true) { for (i=0;inbr;i++) { if (pid[i]<=1) /*no way to kill admin process */ continue; if (kill(pid[i],SIGCHECK)==0) { /*lets kill for sure */ (void) kill(pid[i],SIGKILL); (void) fprintf(stderr,"prc_childkill, overkilled process'%05d'\n", pid[i]); (void) fflush(stderr); } } } (void) prc_nozombie(); (void) free(pid); (void) free(prclst); prclst=(PRCTYP *)0; } return prclst; } /* */ /************************************************/ /* */ /* Procedure to check exited process among */ /* a process list, return only process */ /* nomber still up and running. */ /* */ /************************************************/ PRCTYP *prc_childcheck(PRCTYP *prclst) { PRCTYP *newprc; newprc=(PRCTYP *)0; if (prclst!=(PRCTYP *)0) { if (prclst->nbr>0) { register int i; (void) prc_nozombie(); for (i=0;inbr;i++) { if (prc_checkprocess(prclst->pqueue[i])==true) { newprc=prc_addtoprc(newprc,prclst->pqueue[i]); } } } if (prclst->pqueue!=(pid_t *)0) (void) free(prclst->pqueue); (void) free(prclst); } return newprc; } /* */ /************************************************/ /* */ /* Procedure to start or stop a 'Pacemaker'*/ /* within the application. */ /* */ /************************************************/ void prc_setpace(unsigned long millisec,int onoff) { int static done=false; struct sigaction oldsa; if (onoff==true) { if (done==false) { struct sigaction newsa; struct itimerval period; newsa.sa_flags=0; newsa.sa_handler=trpsignal; (void) sigemptyset(&newsa.sa_mask); (void) sigaction(SIGALRM,&newsa,&oldsa); period.it_value.tv_sec=millisec/1000; period.it_value.tv_usec=millisec*1000; period.it_interval.tv_sec=period.it_value.tv_sec; period.it_interval.tv_usec=period.it_value.tv_usec; (void) setitimer(ITIMER_REAL,&period,(struct itimerval *)0); done=true; } } else { if (done==true) { struct itimerval period; period.it_value.tv_sec=0; period.it_value.tv_usec=0; period.it_interval.tv_sec=period.it_value.tv_sec; period.it_interval.tv_usec=period.it_value.tv_usec; (void) setitimer(ITIMER_REAL,&period,(struct itimerval *)0); (void) sigaction(SIGALRM,&oldsa,(struct sigaction *)0); done=false; } } }