Inserting VZGOT development tree within GIT
[safe/jmp/vzgot] / lib / utlprc.c
1 /************************************************/
2 /*                                              */
3 /*      Copyright:                              */
4 /*       Jean-Marc Pigeon <jmp@safe.ca>  2009   */
5 /*                                              */
6 /************************************************/
7 /* This program is free software; you can       */
8 /* redistribute it and/or modify it under the   */
9 /* terms of the GNU General Public License as   */
10 /* published by the Free Software Foundation    */
11 /* version 2 of the License                     */
12 /*                                              */
13 /* This program is distributed in the hope that */
14 /* it will be useful, but WITHOUT ANY WARRANTY; */
15 /* without even the implied warranty of         */
16 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR  */
17 /* PURPOSE.  See the GNU General Public License */
18 /* for more details.                            */
19 /*                                              */
20 /* You should have received a copy of the GNU   */
21 /* General Public License along with this       */
22 /* program; if not, write to the Free Software  */
23 /* Foundation, Inc., 51 Franklin Street,        */
24 /* Fifth Floor, Boston, MA  02110-1301, USA.    */
25 /************************************************/
26 /*                                              */
27 /*      Implement very sub level procedure to   */
28 /*      handle process sub function.            */
29 /*                                              */
30 /************************************************/
31 #include        <sys/resource.h>
32 #include        <sys/prctl.h>
33 #include        <sys/wait.h>
34 #include        <sys/time.h>
35 #include        <unistd.h>
36 #include        <stdlib.h>
37 #include        <stdio.h>
38 #include        <string.h>
39 #include        <time.h>
40 #include        <signal.h>
41 #include        <errno.h>
42 #include        "dbgmem.h"
43 #include        "lowtyp.h"
44 #include        "utlprc.h"
45 /*
46 \f
47 */
48 /************************************************/
49 /*                                              */
50 /*      Procedure to catch signal and do what is*/
51 /*      needed.                                 */
52 /*                                              */
53 /************************************************/
54 static void trpsignal(int sig)
55
56 {
57 switch (sig) {
58   case SIGALRM   :
59     break;
60   default        :
61     (void) fprintf(stderr,"utlprc.c:trpalrm, Unexpected signal <%s> received",
62                            sys_siglist[sig]);
63     (void) fflush(stderr);
64     break;
65   }
66 }
67 /*
68 \f
69 */
70 /************************************************/
71 /*                                              */
72 /*      Procedure to display an core_dump       */
73 /*      message and terminate application       */
74 /*                                              */
75 /************************************************/
76 void prc_core_dump(char *crashdir,char *temps,const char *fmt,va_list args)
77
78 {
79 #define MXSTEP 30
80
81 va_list ap;
82 struct rlimit limites;
83
84 va_copy(ap,args);
85 if (getrlimit(RLIMIT_CORE,&limites)<0) {
86   (void) fprintf(stderr,"getrlimit error='%s'",strerror(errno));
87   }
88 limites.rlim_cur=limites.rlim_max;
89 if (setrlimit(RLIMIT_CORE,&limites)<0) {
90   (void) fprintf(stderr,"setrlimit error='%s'",strerror(errno));
91   }
92 (void) prctl(PR_SET_DUMPABLE,1,0,0,0);/*to allow core-dump      */
93 if (chdir(crashdir)<0) {
94   char command[2000];
95   char dirdump[1000];
96
97   (void) snprintf(dirdump,sizeof(dirdump),"%s/coredump/","/tmp");
98   (void) snprintf(command,sizeof(command),"mkdir -p %s",dirdump);
99   (void) system(command);
100   if (chdir(dirdump)<0) {
101     (void) abort();
102     }
103   crashdir=dirdump;
104   }
105 if (temps!=(char *)0)
106   (void) fprintf(stderr,"%s ",temps);
107 (void) vfprintf(stderr,fmt,ap);
108 (void) fprintf(stderr,"\n");
109 (void) fprintf(stderr,"going to CORE DUMP (in %score.%d)\n",
110                        crashdir,getpid());
111 (void) fflush(stderr);
112 (void) sleep(5);        /*to avoid crash avalanche      */
113 (void) abort();         /*doing the abort               */
114 (void) exit(-1);        /*Theoriticaly unreachable      */
115 }
116 /*
117 ^L
118 */
119 /************************************************/
120 /*                                              */
121 /*      Procedure to check if a child process   */
122 /*      is still alive.                         */
123 /*                                              */
124 /************************************************/
125 int prc_checkprocess(pid_t pid)
126
127 {
128 int status;
129
130 status=false;
131 switch(pid) {
132   case (pid_t)0 :       /*0 means no process    */
133     status=false;
134     break;
135   case (pid_t)1 :       /*init process always OK*/
136     status=true;
137     break;
138   default       :       /*standard process      */
139     if (kill(pid,SIGCHECK)==0)
140       status=true;
141     break;
142   }
143 return status;
144 }
145 /*
146 \f
147 */
148 /************************************************/
149 /*                                              */
150 /*      Procedure to allow exited child process */
151 /*      to leave the zombie stat.               */
152 /*                                              */
153 /************************************************/
154 void prc_nozombie()
155
156 {
157 while (waitpid(-1,(int *)0,WNOHANG)>0);
158 }
159 /*
160 \f
161 */
162 /************************************************/
163 /*                                              */
164 /*      Procedure to add a process number to    */
165 /*      process list                            */
166 /*                                              */
167 /************************************************/
168 PRCTYP *prc_addtoprc(PRCTYP *plst,pid_t pid)
169
170 {
171 register int taille;
172
173 taille=1;
174 if (plst==(PRCTYP *)0) {
175   plst=(PRCTYP *)calloc(1,sizeof(PRCTYP));
176   plst->pqueue=(pid_t *)calloc(taille,sizeof(pid_t));
177   } 
178 plst->pqueue[plst->nbr]=pid;
179 plst->nbr++;
180 taille+=plst->nbr;
181 plst->pqueue=(pid_t *)realloc((void *)plst->pqueue,taille*sizeof(pid_t));
182 return plst;
183 }
184 /*
185 \f
186 */
187 /************************************************/
188 /*                                              */
189 /*      Procedure to terminate all child process*/
190 /*      refered in a process list. if not       */
191 /*      successful 'delay'  after SIGTERM try,  */
192 /*      a SIGKILL signal is applied.            */
193 /*                                              */
194 /************************************************/
195 PRCTYP *prc_childkill(PRCTYP *prclst,int delay)
196
197 {
198 if (prclst!=(PRCTYP *)0) {
199   pid_t *pid;
200   int overkill;
201   int i;
202
203   overkill=false;
204   pid=prclst->pqueue;
205   (void) prc_nozombie();
206   for (i=0;i<prclst->nbr;i++) {
207     if (pid[i]<=1)      /*no way to kill admin process  */
208       continue;
209     if (kill(pid[i],SIGTERM)==0)
210       overkill=true;
211     }
212   while (overkill==true) {
213     struct timespec timer;
214
215     timer.tv_sec=1;
216     timer.tv_nsec=0;
217     overkill=false;
218     while (nanosleep(&timer,&timer)!=0);
219     (void) prc_nozombie();
220     for (i=0;i<prclst->nbr;i++) {
221       if (pid[i]<=1)    /*no way to kill admin process  */
222         continue;
223       if (kill(pid[i],SIGCHECK)==0) 
224         overkill=true;
225       }
226     delay--;
227     if (delay==0)
228       break;
229     }
230   if (overkill==true) {
231     for (i=0;i<prclst->nbr;i++) {
232       if (pid[i]<=1)    /*no way to kill admin process  */
233         continue;
234       if (kill(pid[i],SIGCHECK)==0) {
235                                 /*lets kill for sure            */
236         (void) kill(pid[i],SIGKILL);
237         (void) fprintf(stderr,"prc_childkill, overkilled process'%05d'\n",
238                                pid[i]);
239         (void) fflush(stderr);
240         }
241       }
242     }
243   (void) prc_nozombie();
244   (void) free(pid);
245   (void) free(prclst);
246   prclst=(PRCTYP *)0;
247   }
248 return prclst;
249 }
250 /*
251 \f
252 */
253 /************************************************/
254 /*                                              */
255 /*      Procedure to check exited process among */
256 /*      a process list, return only process     */
257 /*      nomber still up and running.            */
258 /*                                              */
259 /************************************************/
260 PRCTYP *prc_childcheck(PRCTYP *prclst)
261
262 {
263 PRCTYP *newprc;
264
265 newprc=(PRCTYP *)0;
266 if (prclst!=(PRCTYP *)0) {
267   if (prclst->nbr>0) {
268     register int i;
269
270     (void) prc_nozombie();
271     for (i=0;i<prclst->nbr;i++) {
272       if (prc_checkprocess(prclst->pqueue[i])==true) {
273         newprc=prc_addtoprc(newprc,prclst->pqueue[i]);
274         }
275       }
276     }
277   if (prclst->pqueue!=(pid_t *)0)
278     (void) free(prclst->pqueue);
279   (void) free(prclst);
280   }
281 return newprc;
282 }
283 /*
284 \f
285 */
286 /************************************************/
287 /*                                              */
288 /*      Procedure to start or stop a 'Pacemaker'*/
289 /*      within the application.                 */
290 /*                                              */
291 /************************************************/
292 void prc_setpace(unsigned long millisec,int onoff)
293
294 {
295 int static done=false;
296 struct sigaction oldsa;
297
298 if (onoff==true) {
299   if (done==false) {
300     struct sigaction newsa;
301     struct itimerval period;
302
303     newsa.sa_flags=0;
304     newsa.sa_handler=trpsignal;
305     (void) sigemptyset(&newsa.sa_mask);
306     (void) sigaction(SIGALRM,&newsa,&oldsa);
307     period.it_value.tv_sec=millisec/1000;
308     period.it_value.tv_usec=millisec*1000;
309     period.it_interval.tv_sec=period.it_value.tv_sec;
310     period.it_interval.tv_usec=period.it_value.tv_usec;
311     (void) setitimer(ITIMER_REAL,&period,(struct itimerval *)0);
312     done=true;
313     }
314   }
315 else {
316   if (done==true) {
317     struct itimerval period;
318
319     period.it_value.tv_sec=0;
320     period.it_value.tv_usec=0;
321     period.it_interval.tv_sec=period.it_value.tv_sec;
322     period.it_interval.tv_usec=period.it_value.tv_usec;
323     (void) setitimer(ITIMER_REAL,&period,(struct itimerval *)0);
324     (void) sigaction(SIGALRM,&oldsa,(struct sigaction *)0);
325     done=false;
326     }
327   }
328 }