Inserting VZGOT development tree within GIT
[safe/jmp/vzgot] / lib / subapl.c
1 /************************************************/
2 /*                                              */
3 /*      Copyright:                              */
4 /*               Jean-Marc Pigeon <jmp@safe.ca> */
5 /*      Distributed under the Gnu Public        */
6 /*      License, see the License file in this   */
7 /*      package.                                */
8 /*                                              */
9 /*      Implement very sub level procedure to   */
10 /*      handle clement specific needs.          */
11 /*                                              */
12 /************************************************/
13 #include        <sys/time.h>
14 #include        <sys/stat.h>
15 #include        <sys/resource.h>
16 #include        <sys/prctl.h>
17 #include        <unistd.h>
18 #include        <time.h>
19 #include        <stdio.h>
20 #include        <errno.h>
21 #include        <syslog.h>
22 #include        <signal.h>
23 #include        <stdarg.h>
24 #include        <string.h>
25 #include        <ctype.h>
26 #include        "dbgmem.h"
27 #include        "lowtyp.h"
28 #include        "utlprc.h"
29 #include        "subapl.h"
30
31 /*debug level                                   */
32 #if DEBUG
33 #define TRALOG  LOG_DEBUG
34 #else
35 #define TRALOG  LOG_INFO
36 #endif
37
38 /*setting the applocation version               */
39 const   char *curvers=VZBVERS;
40 /*sigterm request flag                          */
41         int sigterm=false;
42 /*sigquit request flag                          */
43         int sigquit=false;
44 /*sigint request flag                           */
45         int sigint=false;
46 /*current debug level                           */
47         int debug=0;
48 /*flag application running background/foreground*/
49         int apl_foreground=false;
50 /*debug log in verbose mode                     */
51         int verbose=false;
52 /*base directory (where to store internal data) */
53         char    *base=""; /*no prefix           */
54
55 /*application name                              */
56         char    *appname=VZGOT;
57 /*
58 \f
59 */
60 /************************************************/
61 /*                                              */
62 /*      Procedure to catch signal and do what is*/
63 /*      needed.                                 */
64 /*                                              */
65 /************************************************/
66 static void trapsig(int sig)
67
68 {
69 sigset_t blockmask;
70 sigset_t oldset;
71 struct sigaction sa;
72
73 (void) sigfillset(&blockmask);
74 (void) sigprocmask(SIG_SETMASK,&blockmask,&oldset);
75 if (debug>=20)
76   (void) fprintf(stderr,"subclm.c:trapsig <%s/%d> received (by pid='%d')\n",
77                          sys_siglist[sig],sig,getpid());
78 switch (sig) {
79   case SIGINT   :
80     sigint=true;
81     break;
82   case SIGQUIT  :
83     sigquit=true;
84     sigterm=true;
85     break;
86   case SIGUSR1  :
87     debug++;
88     (void) fprintf(stderr,"Increased debug level to '%d' (pid='%d')\n",debug,getpid());
89     break;
90   case SIGUSR2  :
91     if (debug>0) {
92       debug--;
93       (void) fprintf(stderr,"Decreased debug level to '%d' (pid='%d')\n",debug,getpid());
94       }
95     break;
96   case SIGTERM  :
97     sigterm=true;
98     break;
99   default        :
100     (void) fprintf(stderr,"%s, Unexpected signal <%s> received\n",
101                            appname,sys_siglist[sig]);
102     break;
103   }
104 /*restarting signal             */
105 (void) sigemptyset(&sa.sa_mask);
106 sa.sa_handler=trapsig;
107 sa.sa_flags=0;
108 (void) sigprocmask(SIG_SETMASK,&oldset,(sigset_t *)0);
109 (void) sigaction(sig,&sa,(struct sigaction *)0);
110 }
111 /*
112 \f
113 */
114 /************************************************/
115 /*                                              */
116 /*      Procedure to catch signal and do what is*/
117 /*      needed.                                 */
118 /*                                              */
119 /************************************************/
120 static void trpmempbls(int sig)
121
122 {
123 #define OPPB    "subclm.c:trpmempbls,"
124
125 switch (sig) {
126   case SIGSEGV   :
127     (void) apl_core_dump("Program genuine memory violation");
128     break;
129   default        :
130     (void) apl_core_dump("%s Unexpected signal <%s> received",
131                          OPPB,sys_siglist[sig]);
132     break;
133   }
134 }
135 /*
136 \f
137 */
138 /************************************************/
139 /*                                              */
140 /*      Procedure to check if directory is      */
141 /*      already existing.                       */
142 /*                                              */
143 /************************************************/
144 int apl_isdir(char *dirpath)
145
146 {
147 int status;
148 struct stat bufstat;
149
150 status=-1;
151 if (stat(dirpath,&bufstat)==0) {
152   if (S_ISDIR(bufstat.st_mode)!=0) {
153     status=0;
154     }
155   }
156 return status;
157 }
158 /*
159 \f
160 */
161 /************************************************/
162 /*                                              */
163 /*      Procedure to free memory used by a      */
164 /*      string, do not proceed if point is NULL.*/
165 /*                                              */
166 /************************************************/
167 char *apl_freestr(char *str)
168
169 {
170 if (str!=(char *)0) {
171   (void) free(str);
172   }
173 return (char *)0;
174 }
175 /*
176 \f
177 */
178 /************************************************/
179 /*                                              */
180 /*      Procedure to extract and return current */
181 /*      version number.                         */
182 /*                                              */
183 /************************************************/
184 char *apl_getvers()
185
186 {
187 static char *vernum=(char *)0;
188 static char numero[30];
189
190 if (vernum==(char *)0) {
191   int num1,num2,num3,num4;
192   char revision[30];
193
194   (void) sscanf(curvers,"%s %d.%d.%d.%d",revision,&num1,&num2,&num3,&num4);
195   (void) sprintf(numero,"%d.%d-%d",num1,num2,num4);
196   vernum=numero;
197   }
198 return vernum;
199 }
200 /*
201 ^L
202 */
203 /************************************************/
204 /*                                              */
205 /*      Procedure to return the current time    */
206 /*      expressed with a millisecond precision. */
207 /*                                              */
208 /************************************************/
209 u_long apl_getmillisec()
210
211 {
212 static time_t start=(time_t)0;
213
214 u_long millisec;
215 struct timeval newtime;
216
217 millisec=(u_long)0;
218 (void) gettimeofday(&newtime,(struct timezone *)0);
219 if (start==(time_t)0)
220   start=(newtime.tv_sec-1);
221 millisec=newtime.tv_sec-start;
222 millisec*=1000;
223 millisec+=(newtime.tv_usec/1000);
224 return millisec;
225 }
226 /*
227 \f
228 */
229 /************************************************/
230 /*                                              */
231 /*      Procedure to make create a unique name  */
232 /*      can be used to store process data       */
233 /*      name return is dynamically allocated.   */
234 /*                                              */
235 /************************************************/
236 char *apl_uniquename(unsigned int seq)
237
238 {
239 #define UFTIME  "%Y%m%d%H%M%S"
240 #define UNIQUE  "%05d-%s-%08lx"
241
242 char *uniquename;
243 time_t curtime;
244 struct tm *tminfo;
245 char asctemps[100];
246
247 curtime=time((time_t)0);
248 tminfo=localtime(&curtime);
249 (void) strftime(asctemps,sizeof(asctemps),UFTIME,tminfo);
250 (void) asprintf(&uniquename,UNIQUE,getpid(),asctemps,apl_getmillisec()+seq);
251 return uniquename;
252 }
253 /*
254 \f
255 */
256 /************************************************/
257 /*                                              */
258 /*      Procedure to return a time seen as local*/
259 /*      time to a long express as YYYYMMDD      */
260 /*                                              */
261 /************************************************/
262 u_long apl_date(time_t curtime)
263
264 {
265 struct tm *tm;
266
267 tm=localtime(&curtime);
268 return (tm->tm_year*10000)+(tm->tm_mon*100)+tm->tm_mday;
269 }
270 /*
271 \f
272 */
273 /************************************************/
274 /*                                              */
275 /*      Procedure to return the local time in   */
276 /*      HH:MM:SS format.                        */
277 /*      Time is stored in a STATIC memeory area */
278 /*                                              */
279 /************************************************/
280 char *apl_ascsystime(time_t curtime)
281
282 {
283 #define TTIME   "%H:%M:%S"
284
285 static char asctemps[100];
286
287 struct tm *tminfo;
288
289 tminfo=localtime(&curtime);
290 (void) strftime(asctemps,sizeof(asctemps),TTIME,tminfo);
291 return asctemps;
292 }
293 /*
294 \f
295 */
296 /************************************************/
297 /*                                              */
298 /*      Procedure to return system time from an */
299 /*      YYYY-MM-DDD HH:MM:SS format.            */
300 /*                                              */
301 /************************************************/
302 time_t apl_datetimesysasc(char *strdate,char *strtime)
303
304 {
305 #define DBDTOUNIX       "%Y-%m-%d %H:%M:%S"
306 time_t datetime;
307
308 datetime=(time_t)0;
309 if ((strdate!=(char *)0)&&(strtime!=(char *)0)) {
310   struct tm tm;
311   char strdt[100];
312
313   (void) memset(&tm,'\000',sizeof(struct tm));
314   tm.tm_isdst=-1;
315   (void) snprintf(strdt,sizeof(strdt),"%s %s",strdate,strtime);
316   if (strptime(strdt,DBDTOUNIX,&tm)!=(char *)0) {
317     datetime=mktime(&tm);
318     }
319   else {
320     (void) apl_alert(0,"subclm.c:apl_datetimesysasc Unable to convert <%s> to time_t",strdt);
321     }
322   }
323 return datetime;
324 }
325 /*
326 \f
327 */
328 /************************************************/
329 /*                                              */
330 /*      Procedure to return the local time in   */
331 /*      YYYY-MM-DDD format.                     */
332 /*      date is stored in a STATIC memeory area */
333 /*                                              */
334 /************************************************/
335 char *apl_ascsysdate(time_t curtime)
336
337 {
338 #define TDATE   "%Y-%m-%d"
339
340 static char asctemps[100];
341
342 struct tm *tminfo;
343
344 tminfo=localtime(&curtime);
345 (void) strftime(asctemps,sizeof(asctemps),TDATE,tminfo);
346 return asctemps;
347 }
348 /*
349 \f
350 */
351 /************************************************/
352 /*                                              */
353 /*      Procedure to return the local time in   */
354 /*      YYYY-MM-DDD HH:MM:SS format.            */
355 /*      date is stored in a STATIC memeory area */
356 /*                                              */
357 /************************************************/
358 char *apl_ascsysdatetime(time_t curtime)
359
360 {
361 #define TDTIME  "%Y-%m-%d %H:%M:%S"
362
363 static char asctemps[100];
364
365 struct tm *tminfo;
366
367 tminfo=localtime(&curtime);
368 (void) strftime(asctemps,sizeof(asctemps),TDTIME,tminfo);
369 return asctemps;
370 }
371 /*
372 \f
373 */
374 /************************************************/
375 /*                                              */
376 /*      Procedure to transform the local system */
377 /*      time in ASCII time stamp.               */
378 /*      Stored in STATIC memory area.           */
379 /*                                              */
380 /************************************************/
381 char *apl_ascsysstamp(time_t curtime)
382
383 {
384 #define TSTAMP  "%a, %d %b %Y %H:%M:%S"
385
386 static char ascstamp[100];
387
388 struct tm *tminfo;
389 char asct[80];
390
391 tminfo=localtime(&curtime);
392 (void) strftime(asct,sizeof(asct),TSTAMP,tminfo);
393 (void) snprintf(ascstamp,sizeof(ascstamp),"%s %05ld",asct,
394                                           ((tminfo->tm_gmtoff/3600)*100)+
395                                           ((tminfo->tm_gmtoff%3600)/60));
396 return ascstamp;
397 }
398 /*
399 \f
400 */
401 /************************************************/
402 /*                                              */
403 /*      Procedure to display an alert in the    */
404 /*      debug log.                              */
405 /*                                              */
406 /************************************************/
407 void apl_alert(const int dlevel,const char *fmt,...)
408
409 {
410 if (debug>=dlevel)
411   {
412   va_list args;
413   char *strloc;
414
415   va_start(args,fmt);
416   (void) vasprintf(&strloc,fmt,args);
417   if ((apl_foreground==true)||((verbose==true))) {
418     time_t curtime;
419     char logtime[30];
420
421     curtime=time((long *)0);
422     (void) strftime(logtime,sizeof(logtime),"%H:%M:%S",localtime(&curtime));
423     (void) fprintf(stderr,"%s %s\n",logtime,strloc);
424     (void) fflush(stderr);
425     }
426   else {
427     (void) syslog(TRALOG,"%s\n",strloc);
428     }
429   (void) free(strloc);
430   va_end(args);
431   }
432 }
433 /*
434 \f
435 */
436 /************************************************/
437 /*                                              */
438 /*      Procedure to display an argv list       */
439 /*                                              */
440 /************************************************/
441 void apl_argvtrace(const int dlevel,const char *fmt,char *argv[])
442
443 {
444 if ((debug>=dlevel)&&(argv[0]!=(char *)0)) {
445   register int i;
446   char *tmp;
447
448   tmp=strdup(argv[0]);
449   for (i=1;argv[i]!=(char *)0;i++) {
450     char *strloc;
451
452     (void) asprintf(&strloc,"%s %s",tmp,argv[i]);
453     (void) free(tmp);
454     tmp=strloc;
455     }
456   (void) apl_alert(dlevel,fmt,tmp);
457   (void) free(tmp);
458   }
459 }
460 /*
461 \f
462 */
463 /************************************************/
464 /*                                              */
465 /*      Procedure to 'compute' a new base       */
466 /*      according the current directory         */
467 /*      return a newly allocated memory         */
468 /*                                              */
469 /************************************************/
470 char *apl_mkbase(char *newbase)
471
472 {
473 char *ptr;
474
475 ptr=(char *)0;
476 switch (newbase[0]) {
477   case  '.'     : {
478     char curdir[512];
479     char newpath[1000];
480
481     if (getcwd(curdir,sizeof(curdir))!=(char *)0) {
482       (void) snprintf(newpath,sizeof(newpath),"%s/%s",curdir,newbase);
483       if (chdir(newpath)<0) {
484         (void) apl_alert(0,"Unable to reach directory <%s>",newpath);
485         break;  /*immediat exit */
486         }
487       (void) getcwd(newpath,sizeof(newpath));
488       if (chdir(curdir)<0) {
489         (void) apl_alert(0,"Unable to reach directory <%s>",curdir);
490         break;  /*immediat exit */
491         }
492       ptr=strdup(newpath);
493       } 
494     } 
495     break;
496   case  '/'     :
497     ptr=strdup(newbase);
498     break;
499   default       :
500     break;
501   }
502 if (ptr==(char *)0) {
503   (void) apl_alert(0,"Unable to assign new base '%s', immediat exit",newbase);
504   (void) exit(-1);
505   }
506 return ptr;
507 }
508 /*
509 \f
510 */
511 /************************************************/
512 /*                                              */
513 /*      Procedure to 'compute' an application   */
514 /*      directory according dir enum value      */
515 /*                                              */
516 /************************************************/
517 char *apl_appdir(DIRENUM dir)
518
519 {
520 char *appdir;
521 char *sysbase;
522 char *apvers;
523 char *subdir;
524
525 appdir=(char *)0;
526 sysbase=" ";    /*something impossible          */
527 apvers=apl_getapvers();
528 subdir="";
529 switch (dir) {
530   case (d_null)         :
531     sysbase="";
532     apvers=""; 
533     break;
534   case (d_tmp)          :
535     sysbase="/var/tmp";
536     apvers=VZGOT"/"; 
537     break;
538   case (d_crash)        :
539     sysbase="/var/crash";
540     break;
541   case (d_etc)          :
542     sysbase="/etc";
543     break;
544   case (d_spool)        :
545     sysbase="/var/spool";
546     break;
547   case (d_lock)         :
548     sysbase="/var/lock";
549     apvers=VZGOT"/";
550     break;
551   case (d_vzgot)        :
552     sysbase="/var/lib";
553     apvers=VZGOT;
554     subdir="/vzdir";    
555     break;
556   case (d_log)          :
557     sysbase="/var/spool";
558     subdir="logs";
559     break;
560   case (d_ubin)         :
561     sysbase="/usr/bin";
562     apvers=""; 
563     break;
564   case (d_usbin)        :
565     sysbase="/usr/sbin";
566     apvers=""; 
567     break;
568   case (d_varlib)       :
569     sysbase="/var/lib";
570     apvers=VZGOT; 
571     break;
572   case (d_usrlib)       :
573     sysbase="/usr/lib";
574     break;
575   }
576 (void) asprintf(&appdir,"%s%s/%s%s",base,sysbase,apvers,subdir);
577 return appdir;
578 }
579 /*
580 \f
581 */
582 /************************************************/
583 /*                                              */
584 /*      Procedure to set the SIGV signal trap   */
585 /*      purpose is to CORE_DUMP in case we have */
586 /*      a memory failure of some kind.          */
587 /*                                              */
588 /************************************************/
589 void apl_trapsegv(int onoff)
590
591 {
592 static struct sigaction oldsa;
593
594 if (onoff==true) {
595   struct sigaction newsa;
596
597   newsa.sa_flags=0;
598   newsa.sa_handler=trpmempbls;
599   (void) sigemptyset(&newsa.sa_mask);
600   (void) sigaction(SIGSEGV,&newsa,&oldsa);
601   }
602 else {
603   (void) sigaction(SIGSEGV,&oldsa,(struct sigaction *)0);
604   }
605 }
606 /*
607 \f
608 */
609 /************************************************/
610 /*                                              */
611 /*      Procedure to prepare a core_dump in     */
612 /*      the right directory.                    */
613 /*                                              */
614 /************************************************/
615 void apl_core_dump(char *frmt,...)
616
617 {
618 va_list args;
619 char *crashdir;
620 char *temps;
621
622 va_start(args,frmt);
623 temps=apl_ascsystime(time((time_t *)0));
624 crashdir=apl_appdir(d_crash);
625 (void) prc_core_dump(crashdir,temps,frmt,args);
626 va_end(args);
627 }
628 /*
629 \f
630 */
631 /************************************************/
632 /*                                              */
633 /*      procedure to set/unset trapped signal   */
634 /*                                              */
635 /************************************************/
636 void apl_settrap(int set)
637
638 {
639 static struct sigaction oldint;
640 static struct sigaction oldterm;
641 static struct sigaction oldquit;
642 static struct sigaction oldusr1;
643 static struct sigaction oldusr2;
644
645 static int alldone=false;
646
647 if (set==alldone) {
648   switch (set) {
649     case true   :
650       (void) apl_core_dump("apl_settrap already set");
651       break;
652     case false  :
653       (void) apl_core_dump("apl_settrap not previously set");
654       break;
655     default     :
656       (void) apl_core_dump("apl_settrap unproper set value");
657       break;
658     } 
659   }
660 (void) apl_trapsegv(set);
661 if (set==true) {
662   struct sigaction newsa;
663
664   newsa.sa_flags=0;
665   newsa.sa_handler=trapsig;
666   (void) sigaction(SIGUSR2,&newsa,&oldusr2);
667   (void) sigaction(SIGUSR1,&newsa,&oldusr1);
668   (void) sigaction(SIGINT,&newsa,&oldint);
669   (void) sigaction(SIGTERM,&newsa,&oldterm);
670   (void) sigaction(SIGQUIT,&newsa,&oldquit);
671   }
672 else {
673   (void) sigaction(SIGQUIT,&oldquit,(struct sigaction *)0);
674   (void) sigaction(SIGTERM,&oldterm,(struct sigaction *)0);
675   (void) sigaction(SIGINT,&oldint,(struct sigaction *)0);
676   (void) sigaction(SIGUSR1,&oldusr1,(struct sigaction *)0);
677   (void) sigaction(SIGUSR2,&oldusr2,(struct sigaction *)0);
678   }
679 alldone=set;
680 }
681 /*
682 \f
683 */
684 /************************************************/
685 /*                                              */
686 /*      Procedure to set a string to lower case */
687 /*      only.                                   */
688 /*                                              */
689 /************************************************/
690 char *apl_strtolower(char *str)
691
692 {
693 if (str!=(char *)0) {
694   register char *ptr;
695
696   for (ptr=str;*ptr!='\000';ptr++)
697     *ptr=(char)tolower((int)*ptr);
698   }
699 return str;
700 }
701 /*
702 \f
703 */
704 /************************************************/
705 /*                                              */
706 /*      Procedure extract line from a file,     */
707 /*      forget about any line starting with     */
708 /*      carcom character (if carcom character   */
709 /*      not null).                              */
710 /*      Doesn't return the '\r' and '\n'        */
711 /*      character.                              */
712 /*                                              */
713 /************************************************/
714 char *apl_getstr(FILE *fichier,char *str,u_int taille,char carcom)
715
716 {
717 char *strloc;
718
719 (void) memset(str,'\000',taille);
720 while ((strloc=fgets(str,taille,fichier))!=(char *)0) {
721   char *ptrloc;
722
723   if (carcom!='\000') {
724     if (str[0]==carcom)
725       continue;
726     ptrloc=str;
727     while ((ptrloc=strchr(ptrloc,carcom))!=(char *)0) {
728       if (*(ptrloc-1)=='\\') {
729         (void) memmove(ptrloc-1,ptrloc,strlen(ptrloc)+1);
730         ptrloc++;
731         }
732       else {
733         *ptrloc='\000';
734         break;
735         }
736       }
737     }
738   ptrloc=strloc+strlen(strloc);
739   while (ptrloc!=(char *)0) {
740     ptrloc--;
741     switch (*ptrloc) {
742       case '\n'     :
743       case '\r'     :
744         *ptrloc='\000';
745         break;
746       default       :
747         ptrloc=(char *)0;
748         break;
749       }
750     }
751   break;
752   }
753 return strloc;
754 }
755 /*
756 \f
757 */
758 /************************************************/
759 /*                                              */
760 /*      Procedure to application+version name   */
761 /*                                              */
762 /************************************************/
763 char *apl_getapvers()
764
765 {
766 static char *apvers=(char *)0;
767
768 if (apvers==(char *)0) {
769   static char apinfo[50];
770
771   char *ptr;
772   char version[30];
773
774   (void) strcpy(version,apl_getvers());
775   if ((ptr=strchr(version,'-'))!=(char *)0)
776     *ptr='\000';
777   (void) snprintf(apinfo,sizeof(apinfo),"%s-%s/",appname,version);
778   apvers=apinfo;
779   }
780 return apvers;
781 }
782 /*
783 \f
784 */
785 /************************************************/
786 /*                                              */
787 /*      Procedure to convert a string to a code,*/
788 /*      remaining of the string is copy at the  */
789 /*      beginning.                              */
790 /*      Return a pointer to table, never a NULL */
791 /*      pointer unless the table itself is NULL */
792 /*                                              */
793 /************************************************/
794 VOCTYP *apl_getvoca(const VOCTYP *table,char *str)
795
796 {
797 VOCTYP *voc;
798
799 voc=(VOCTYP *)0;
800 if (table!=(VOCTYP *)0) {
801   int i;
802   char *sptr;
803
804   sptr=str; 
805   while (isspace(*sptr)!=0)
806     sptr++;
807   for (i=0;table[i].key!=(char *)0;i++) {
808     int max;
809
810     max=strlen(table[i].key);
811     if (strncasecmp(table[i].key,sptr,max)==0) {
812       if ((sptr[max]!='\000')&&(isalnum(sptr[max])!=0))
813         continue;/*it is not the right word     */
814       sptr+=max;
815       while (isspace(*sptr)!=0)
816         sptr++;
817       (void) memmove(str,sptr,strlen(sptr)+1);
818       voc=(VOCTYP *)(table+i);
819       break;
820       }
821     }
822   if (voc==(VOCTYP *)0)
823    voc=(VOCTYP *)(table+i);/*return the "unknown" info  */
824   }
825 return voc;
826 }
827 /*
828 \f
829 */
830 /************************************************/
831 /*                                              */
832 /*      Procedure to remove crlf and space AT   */
833 /*      the string end.                         */
834 /*      Remove space at the string start too.   */
835 /*                                              */
836 /************************************************/
837 char *apl_cleanstring(char *str)
838
839 {
840 if (str!=(char *)0) {
841   register int taille;
842   register char *ptr;
843
844   taille=strlen(str); 
845   ptr=str+taille-1;
846   while (taille>0) {
847     if ((*ptr=='\n') || (*ptr=='\r') || (*ptr==' ')) {
848       *ptr='\000';
849       ptr--;
850       taille--;
851       continue;
852       }
853     break;
854     }
855   ptr=str;
856   while (isblank(*ptr)!=0)
857     ptr++;
858   if (str!=ptr)
859     (void) memmove(str,ptr,strlen(ptr)+1);
860   }
861 return str;
862 }