/************************************************/ /* */ /* Copyright: */ /* Jean-Marc Pigeon */ /* Distributed under the Gnu Public */ /* License, see the License file in this */ /* package. */ /* */ /* Implement very sub level procedure to */ /* handle clement specific needs. */ /* */ /************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dbgmem.h" #include "lowtyp.h" #include "utlprc.h" #include "subapl.h" /*debug level */ #if DEBUG #define TRALOG LOG_DEBUG #else #define TRALOG LOG_INFO #endif /*setting the applocation version */ const char *curvers=VZBVERS; /*sigterm request flag */ int sigterm=false; /*sigquit request flag */ int sigquit=false; /*sigint request flag */ int sigint=false; /*current debug level */ int debug=0; /*flag application running background/foreground*/ int apl_foreground=false; /*debug log in verbose mode */ int verbose=false; /*base directory (where to store internal data) */ char *base=""; /*no prefix */ /*application name */ char *appname=VZGOT; /* */ /************************************************/ /* */ /* Procedure to catch signal and do what is*/ /* needed. */ /* */ /************************************************/ static void trapsig(int sig) { sigset_t blockmask; sigset_t oldset; struct sigaction sa; (void) sigfillset(&blockmask); (void) sigprocmask(SIG_SETMASK,&blockmask,&oldset); if (debug>=20) (void) fprintf(stderr,"subclm.c:trapsig <%s/%d> received (by pid='%d')\n", sys_siglist[sig],sig,getpid()); switch (sig) { case SIGINT : sigint=true; break; case SIGQUIT : sigquit=true; sigterm=true; break; case SIGUSR1 : debug++; (void) fprintf(stderr,"Increased debug level to '%d' (pid='%d')\n",debug,getpid()); break; case SIGUSR2 : if (debug>0) { debug--; (void) fprintf(stderr,"Decreased debug level to '%d' (pid='%d')\n",debug,getpid()); } break; case SIGTERM : sigterm=true; break; default : (void) fprintf(stderr,"%s, Unexpected signal <%s> received\n", appname,sys_siglist[sig]); break; } /*restarting signal */ (void) sigemptyset(&sa.sa_mask); sa.sa_handler=trapsig; sa.sa_flags=0; (void) sigprocmask(SIG_SETMASK,&oldset,(sigset_t *)0); (void) sigaction(sig,&sa,(struct sigaction *)0); } /* */ /************************************************/ /* */ /* Procedure to catch signal and do what is*/ /* needed. */ /* */ /************************************************/ static void trpmempbls(int sig) { #define OPPB "subclm.c:trpmempbls," switch (sig) { case SIGSEGV : (void) apl_core_dump("Program genuine memory violation"); break; default : (void) apl_core_dump("%s Unexpected signal <%s> received", OPPB,sys_siglist[sig]); break; } } /* */ /************************************************/ /* */ /* Procedure to check if directory is */ /* already existing. */ /* */ /************************************************/ int apl_isdir(char *dirpath) { int status; struct stat bufstat; status=-1; if (stat(dirpath,&bufstat)==0) { if (S_ISDIR(bufstat.st_mode)!=0) { status=0; } } return status; } /* */ /************************************************/ /* */ /* Procedure to free memory used by a */ /* string, do not proceed if point is NULL.*/ /* */ /************************************************/ char *apl_freestr(char *str) { if (str!=(char *)0) { (void) free(str); } return (char *)0; } /* */ /************************************************/ /* */ /* Procedure to extract and return current */ /* version number. */ /* */ /************************************************/ char *apl_getvers() { static char *vernum=(char *)0; static char numero[30]; if (vernum==(char *)0) { int num1,num2,num3,num4; char revision[30]; (void) sscanf(curvers,"%s %d.%d.%d.%d",revision,&num1,&num2,&num3,&num4); (void) sprintf(numero,"%d.%d-%d",num1,num2,num4); vernum=numero; } return vernum; } /* ^L */ /************************************************/ /* */ /* Procedure to return the current time */ /* expressed with a millisecond precision. */ /* */ /************************************************/ u_long apl_getmillisec() { static time_t start=(time_t)0; u_long millisec; struct timeval newtime; millisec=(u_long)0; (void) gettimeofday(&newtime,(struct timezone *)0); if (start==(time_t)0) start=(newtime.tv_sec-1); millisec=newtime.tv_sec-start; millisec*=1000; millisec+=(newtime.tv_usec/1000); return millisec; } /* */ /************************************************/ /* */ /* Procedure to make create a unique name */ /* can be used to store process data */ /* name return is dynamically allocated. */ /* */ /************************************************/ char *apl_uniquename(unsigned int seq) { #define UFTIME "%Y%m%d%H%M%S" #define UNIQUE "%05d-%s-%08lx" char *uniquename; time_t curtime; struct tm *tminfo; char asctemps[100]; curtime=time((time_t)0); tminfo=localtime(&curtime); (void) strftime(asctemps,sizeof(asctemps),UFTIME,tminfo); (void) asprintf(&uniquename,UNIQUE,getpid(),asctemps,apl_getmillisec()+seq); return uniquename; } /* */ /************************************************/ /* */ /* Procedure to return a time seen as local*/ /* time to a long express as YYYYMMDD */ /* */ /************************************************/ u_long apl_date(time_t curtime) { struct tm *tm; tm=localtime(&curtime); return (tm->tm_year*10000)+(tm->tm_mon*100)+tm->tm_mday; } /* */ /************************************************/ /* */ /* Procedure to return the local time in */ /* HH:MM:SS format. */ /* Time is stored in a STATIC memeory area */ /* */ /************************************************/ char *apl_ascsystime(time_t curtime) { #define TTIME "%H:%M:%S" static char asctemps[100]; struct tm *tminfo; tminfo=localtime(&curtime); (void) strftime(asctemps,sizeof(asctemps),TTIME,tminfo); return asctemps; } /* */ /************************************************/ /* */ /* Procedure to return system time from an */ /* YYYY-MM-DDD HH:MM:SS format. */ /* */ /************************************************/ time_t apl_datetimesysasc(char *strdate,char *strtime) { #define DBDTOUNIX "%Y-%m-%d %H:%M:%S" time_t datetime; datetime=(time_t)0; if ((strdate!=(char *)0)&&(strtime!=(char *)0)) { struct tm tm; char strdt[100]; (void) memset(&tm,'\000',sizeof(struct tm)); tm.tm_isdst=-1; (void) snprintf(strdt,sizeof(strdt),"%s %s",strdate,strtime); if (strptime(strdt,DBDTOUNIX,&tm)!=(char *)0) { datetime=mktime(&tm); } else { (void) apl_alert(0,"subclm.c:apl_datetimesysasc Unable to convert <%s> to time_t",strdt); } } return datetime; } /* */ /************************************************/ /* */ /* Procedure to return the local time in */ /* YYYY-MM-DDD format. */ /* date is stored in a STATIC memeory area */ /* */ /************************************************/ char *apl_ascsysdate(time_t curtime) { #define TDATE "%Y-%m-%d" static char asctemps[100]; struct tm *tminfo; tminfo=localtime(&curtime); (void) strftime(asctemps,sizeof(asctemps),TDATE,tminfo); return asctemps; } /* */ /************************************************/ /* */ /* Procedure to return the local time in */ /* YYYY-MM-DDD HH:MM:SS format. */ /* date is stored in a STATIC memeory area */ /* */ /************************************************/ char *apl_ascsysdatetime(time_t curtime) { #define TDTIME "%Y-%m-%d %H:%M:%S" static char asctemps[100]; struct tm *tminfo; tminfo=localtime(&curtime); (void) strftime(asctemps,sizeof(asctemps),TDTIME,tminfo); return asctemps; } /* */ /************************************************/ /* */ /* Procedure to transform the local system */ /* time in ASCII time stamp. */ /* Stored in STATIC memory area. */ /* */ /************************************************/ char *apl_ascsysstamp(time_t curtime) { #define TSTAMP "%a, %d %b %Y %H:%M:%S" static char ascstamp[100]; struct tm *tminfo; char asct[80]; tminfo=localtime(&curtime); (void) strftime(asct,sizeof(asct),TSTAMP,tminfo); (void) snprintf(ascstamp,sizeof(ascstamp),"%s %05ld",asct, ((tminfo->tm_gmtoff/3600)*100)+ ((tminfo->tm_gmtoff%3600)/60)); return ascstamp; } /* */ /************************************************/ /* */ /* Procedure to display an alert in the */ /* debug log. */ /* */ /************************************************/ void apl_alert(const int dlevel,const char *fmt,...) { if (debug>=dlevel) { va_list args; char *strloc; va_start(args,fmt); (void) vasprintf(&strloc,fmt,args); if ((apl_foreground==true)||((verbose==true))) { time_t curtime; char logtime[30]; curtime=time((long *)0); (void) strftime(logtime,sizeof(logtime),"%H:%M:%S",localtime(&curtime)); (void) fprintf(stderr,"%s %s\n",logtime,strloc); (void) fflush(stderr); } else { (void) syslog(TRALOG,"%s\n",strloc); } (void) free(strloc); va_end(args); } } /* */ /************************************************/ /* */ /* Procedure to display an argv list */ /* */ /************************************************/ void apl_argvtrace(const int dlevel,const char *fmt,char *argv[]) { if ((debug>=dlevel)&&(argv[0]!=(char *)0)) { register int i; char *tmp; tmp=strdup(argv[0]); for (i=1;argv[i]!=(char *)0;i++) { char *strloc; (void) asprintf(&strloc,"%s %s",tmp,argv[i]); (void) free(tmp); tmp=strloc; } (void) apl_alert(dlevel,fmt,tmp); (void) free(tmp); } } /* */ /************************************************/ /* */ /* Procedure to 'compute' a new base */ /* according the current directory */ /* return a newly allocated memory */ /* */ /************************************************/ char *apl_mkbase(char *newbase) { char *ptr; ptr=(char *)0; switch (newbase[0]) { case '.' : { char curdir[512]; char newpath[1000]; if (getcwd(curdir,sizeof(curdir))!=(char *)0) { (void) snprintf(newpath,sizeof(newpath),"%s/%s",curdir,newbase); if (chdir(newpath)<0) { (void) apl_alert(0,"Unable to reach directory <%s>",newpath); break; /*immediat exit */ } (void) getcwd(newpath,sizeof(newpath)); if (chdir(curdir)<0) { (void) apl_alert(0,"Unable to reach directory <%s>",curdir); break; /*immediat exit */ } ptr=strdup(newpath); } } break; case '/' : ptr=strdup(newbase); break; default : break; } if (ptr==(char *)0) { (void) apl_alert(0,"Unable to assign new base '%s', immediat exit",newbase); (void) exit(-1); } return ptr; } /* */ /************************************************/ /* */ /* Procedure to 'compute' an application */ /* directory according dir enum value */ /* */ /************************************************/ char *apl_appdir(DIRENUM dir) { char *appdir; char *sysbase; char *apvers; char *subdir; appdir=(char *)0; sysbase=" "; /*something impossible */ apvers=apl_getapvers(); subdir=""; switch (dir) { case (d_null) : sysbase=""; apvers=""; break; case (d_tmp) : sysbase="/var/tmp"; apvers=VZGOT"/"; break; case (d_crash) : sysbase="/var/crash"; break; case (d_etc) : sysbase="/etc"; break; case (d_spool) : sysbase="/var/spool"; break; case (d_lock) : sysbase="/var/lock"; apvers=VZGOT"/"; break; case (d_vzgot) : sysbase="/var/lib"; apvers=VZGOT; subdir="/vzdir"; break; case (d_log) : sysbase="/var/spool"; subdir="logs"; break; case (d_ubin) : sysbase="/usr/bin"; apvers=""; break; case (d_usbin) : sysbase="/usr/sbin"; apvers=""; break; case (d_varlib) : sysbase="/var/lib"; apvers=VZGOT; break; case (d_usrlib) : sysbase="/usr/lib"; break; } (void) asprintf(&appdir,"%s%s/%s%s",base,sysbase,apvers,subdir); return appdir; } /* */ /************************************************/ /* */ /* Procedure to set the SIGV signal trap */ /* purpose is to CORE_DUMP in case we have */ /* a memory failure of some kind. */ /* */ /************************************************/ void apl_trapsegv(int onoff) { static struct sigaction oldsa; if (onoff==true) { struct sigaction newsa; newsa.sa_flags=0; newsa.sa_handler=trpmempbls; (void) sigemptyset(&newsa.sa_mask); (void) sigaction(SIGSEGV,&newsa,&oldsa); } else { (void) sigaction(SIGSEGV,&oldsa,(struct sigaction *)0); } } /* */ /************************************************/ /* */ /* Procedure to prepare a core_dump in */ /* the right directory. */ /* */ /************************************************/ void apl_core_dump(char *frmt,...) { va_list args; char *crashdir; char *temps; va_start(args,frmt); temps=apl_ascsystime(time((time_t *)0)); crashdir=apl_appdir(d_crash); (void) prc_core_dump(crashdir,temps,frmt,args); va_end(args); } /* */ /************************************************/ /* */ /* procedure to set/unset trapped signal */ /* */ /************************************************/ void apl_settrap(int set) { static struct sigaction oldint; static struct sigaction oldterm; static struct sigaction oldquit; static struct sigaction oldusr1; static struct sigaction oldusr2; static int alldone=false; if (set==alldone) { switch (set) { case true : (void) apl_core_dump("apl_settrap already set"); break; case false : (void) apl_core_dump("apl_settrap not previously set"); break; default : (void) apl_core_dump("apl_settrap unproper set value"); break; } } (void) apl_trapsegv(set); if (set==true) { struct sigaction newsa; newsa.sa_flags=0; newsa.sa_handler=trapsig; (void) sigaction(SIGUSR2,&newsa,&oldusr2); (void) sigaction(SIGUSR1,&newsa,&oldusr1); (void) sigaction(SIGINT,&newsa,&oldint); (void) sigaction(SIGTERM,&newsa,&oldterm); (void) sigaction(SIGQUIT,&newsa,&oldquit); } else { (void) sigaction(SIGQUIT,&oldquit,(struct sigaction *)0); (void) sigaction(SIGTERM,&oldterm,(struct sigaction *)0); (void) sigaction(SIGINT,&oldint,(struct sigaction *)0); (void) sigaction(SIGUSR1,&oldusr1,(struct sigaction *)0); (void) sigaction(SIGUSR2,&oldusr2,(struct sigaction *)0); } alldone=set; } /* */ /************************************************/ /* */ /* Procedure to set a string to lower case */ /* only. */ /* */ /************************************************/ char *apl_strtolower(char *str) { if (str!=(char *)0) { register char *ptr; for (ptr=str;*ptr!='\000';ptr++) *ptr=(char)tolower((int)*ptr); } return str; } /* */ /************************************************/ /* */ /* Procedure extract line from a file, */ /* forget about any line starting with */ /* carcom character (if carcom character */ /* not null). */ /* Doesn't return the '\r' and '\n' */ /* character. */ /* */ /************************************************/ char *apl_getstr(FILE *fichier,char *str,u_int taille,char carcom) { char *strloc; (void) memset(str,'\000',taille); while ((strloc=fgets(str,taille,fichier))!=(char *)0) { char *ptrloc; if (carcom!='\000') { if (str[0]==carcom) continue; ptrloc=str; while ((ptrloc=strchr(ptrloc,carcom))!=(char *)0) { if (*(ptrloc-1)=='\\') { (void) memmove(ptrloc-1,ptrloc,strlen(ptrloc)+1); ptrloc++; } else { *ptrloc='\000'; break; } } } ptrloc=strloc+strlen(strloc); while (ptrloc!=(char *)0) { ptrloc--; switch (*ptrloc) { case '\n' : case '\r' : *ptrloc='\000'; break; default : ptrloc=(char *)0; break; } } break; } return strloc; } /* */ /************************************************/ /* */ /* Procedure to application+version name */ /* */ /************************************************/ char *apl_getapvers() { static char *apvers=(char *)0; if (apvers==(char *)0) { static char apinfo[50]; char *ptr; char version[30]; (void) strcpy(version,apl_getvers()); if ((ptr=strchr(version,'-'))!=(char *)0) *ptr='\000'; (void) snprintf(apinfo,sizeof(apinfo),"%s-%s/",appname,version); apvers=apinfo; } return apvers; } /* */ /************************************************/ /* */ /* Procedure to convert a string to a code,*/ /* remaining of the string is copy at the */ /* beginning. */ /* Return a pointer to table, never a NULL */ /* pointer unless the table itself is NULL */ /* */ /************************************************/ VOCTYP *apl_getvoca(const VOCTYP *table,char *str) { VOCTYP *voc; voc=(VOCTYP *)0; if (table!=(VOCTYP *)0) { int i; char *sptr; sptr=str; while (isspace(*sptr)!=0) sptr++; for (i=0;table[i].key!=(char *)0;i++) { int max; max=strlen(table[i].key); if (strncasecmp(table[i].key,sptr,max)==0) { if ((sptr[max]!='\000')&&(isalnum(sptr[max])!=0)) continue;/*it is not the right word */ sptr+=max; while (isspace(*sptr)!=0) sptr++; (void) memmove(str,sptr,strlen(sptr)+1); voc=(VOCTYP *)(table+i); break; } } if (voc==(VOCTYP *)0) voc=(VOCTYP *)(table+i);/*return the "unknown" info */ } return voc; } /* */ /************************************************/ /* */ /* Procedure to remove crlf and space AT */ /* the string end. */ /* Remove space at the string start too. */ /* */ /************************************************/ char *apl_cleanstring(char *str) { if (str!=(char *)0) { register int taille; register char *ptr; taille=strlen(str); ptr=str+taille-1; while (taille>0) { if ((*ptr=='\n') || (*ptr=='\r') || (*ptr==' ')) { *ptr='\000'; ptr--; taille--; continue; } break; } ptr=str; while (isblank(*ptr)!=0) ptr++; if (str!=ptr) (void) memmove(str,ptr,strlen(ptr)+1); } return str; }