|
SASC
DVBSoftCAM
|
00001 /* 00002 * Softcam plugin to VDR (C++) 00003 * 00004 * This code is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This code is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00018 */ 00019 00020 #include <stdlib.h> 00021 #include <stdio.h> 00022 #include <stdarg.h> 00023 #include <time.h> 00024 #include <sys/time.h> 00025 00026 #include <vdr/tools.h> 00027 #include <vdr/thread.h> 00028 00029 #include "log.h" 00030 #include "misc.h" 00031 00032 #define LMOD_SUP 32 00033 #define LMOD_CFG_VALID 0x80000000 00034 00035 struct LogConfig logcfg = { 00036 1,0,0,0,0, 00037 0, 00038 "/var/log/vdr-sc" 00039 }; 00040 00041 static const struct LogModule lm_general = { 00042 (LMOD_ENABLE|L_GEN_ALL)&LOPT_MASK, 00043 (LMOD_ENABLE|L_GEN_ALL)&LOPT_MASK, 00044 "general", { "error","warn","info","debug","misc" } 00045 }; 00046 00047 static const struct LogModule *mods[LMOD_SUP] = { &lm_general }; 00048 static int config[LMOD_SUP] = { LMOD_ENABLE|L_GEN_ALL|LMOD_CFG_VALID }; 00049 static int cmask[LMOD_SUP] = { LMOD_ENABLE|L_GEN_ALL }; 00050 static cMutex logfileMutex; 00051 static FILE *logfile=0; 00052 static bool logfileShutup=false, logfileReopen=false; 00053 static long long logfileSize; 00054 00055 static unsigned int lastCrc=0; 00056 static int lastC=0, lastCount=0; 00057 static cTimeMs lastTime; 00058 static cMutex lastMutex; 00059 00060 // -- cLogging ----------------------------------------------------------------- 00061 00062 void (*cLogging::LogPrint)(const struct LogHeader *lh, const char *txt)=cLogging::PrivateLogPrint; 00063 00064 bool cLogging::AddModule(int m, const struct LogModule *lm) 00065 { 00066 if(m<LMOD_SUP) { 00067 if(mods[m]) Printf(L_GEN_DEBUG,"duplicate logging module id %d (%s & %s)",m,mods[m]->Name,lm->Name); 00068 mods[m]=lm; 00069 if(config[m]&LMOD_CFG_VALID) UpgradeOptions(m); 00070 else SetModuleDefault(LCLASS(m,0)); 00071 //printf("module %-16s added. mod=%x supp=%08x def=%08x cfg=%08x\n",lm->Name,m,lm->OptSupported,lm->OptDefault,config[m]); 00072 } 00073 else Printf(L_GEN_DEBUG,"failed to add logging module %d (%s)",m,lm->Name); 00074 return true; 00075 } 00076 00077 void cLogging::SetLogPrint(void (*lp)(const struct LogHeader *lh, const char *txt)) 00078 { 00079 LogPrint=lp; 00080 } 00081 00082 const struct LogModule *cLogging::GetModule(int c) 00083 { 00084 int m=LMOD(c); 00085 return m<LMOD_SUP ? mods[m] : 0; 00086 } 00087 00088 bool cLogging::GetHeader(int c, struct LogHeader *lh) 00089 { 00090 const struct LogModule *lm=GetModule(c); 00091 if(lm) { 00092 if(!logcfg.noTimestamp) { 00093 struct timeval t; 00094 gettimeofday(&t,NULL); 00095 struct tm tm_r; 00096 int q=strftime(lh->stamp,sizeof(lh->stamp),"%b %e %T",localtime_r(&t.tv_sec,&tm_r)); 00097 snprintf(lh->stamp+q,sizeof(lh->stamp)-q,".%03u",(unsigned int)(t.tv_usec/1000)); 00098 } 00099 else lh->stamp[0]=0; 00100 int i, o=LOPT(c)&~LMOD_ENABLE; 00101 for(i=0; i<LOPT_NUM; i++,o>>=1) if(o&1) break; 00102 snprintf(lh->tag,sizeof(lh->tag),"%s.%s",lm->Name,(i>=1 && i<LOPT_NUM && lm->OptName[i-1])?lm->OptName[i-1]:"unknown"); 00103 lh->c=c; 00104 return true; 00105 } 00106 return false; 00107 } 00108 00109 void cLogging::LogLine(const struct LogHeader *lh, const char *txt, bool doCrc) 00110 { 00111 if(doCrc) { 00112 unsigned int crc=crc32_le(0,(const unsigned char *)txt,strlen(txt)+1); 00113 lastMutex.Lock(); 00114 if(lastCrc==crc && lastC==lh->c && ++lastCount<4000000 && lastTime.Elapsed()<=30*1000) { 00115 lastMutex.Unlock(); 00116 return; 00117 } 00118 else { 00119 unsigned int saveCrc=lastCrc; 00120 int saveCount=lastCount, saveC=lastC; 00121 lastTime.Set(); 00122 lastCrc=crc; lastC=lh->c; lastCount=0; 00123 lastMutex.Unlock(); 00124 if(saveCount>1) { 00125 struct LogHeader lh2; 00126 if(GetHeader(saveC,&lh2)) { 00127 char buff[128]; 00128 snprintf(buff,sizeof(buff),"last message repeated %d times",saveCount); 00129 LogLine(&lh2,buff,false); 00130 } 00131 if(saveCrc==crc && saveC==lh->c) return; 00132 } 00133 } 00134 } 00135 00136 LogPrint(lh,txt); 00137 } 00138 00139 void cLogging::PrivateLogPrint(const struct LogHeader *lh, const char *txt) 00140 { 00141 if(logcfg.logFile) { 00142 logfileMutex.Lock(); 00143 if(logfileReopen) { 00144 logfileReopen=false; logfileShutup=false; 00145 if(logfile) { 00146 PRINTF(L_GEN_DEBUG,"logfile closed, reopen as '%s'",logcfg.logFilename); 00147 fclose(logfile); 00148 logfile=0; 00149 } 00150 } 00151 if(!logfile && !logfileShutup) { 00152 logfile=fopen(logcfg.logFilename,"a"); 00153 if(logfile) { 00154 setlinebuf(logfile); 00155 logfileSize=ftell(logfile); 00156 if(logfileSize<0) { 00157 logfileSize=0; 00158 PRINTF(L_GEN_ERROR,"cannot determine size of logfile '%s', assuming zero",logcfg.logFilename); 00159 } 00160 PRINTF(L_GEN_DEBUG,"logfile '%s' opened",logcfg.logFilename); 00161 } 00162 else { 00163 logfileShutup=true; 00164 PRINTF(L_GEN_ERROR,"failed to open logfile '%s': %s",logcfg.logFilename,strerror(errno)); 00165 } 00166 } 00167 if(logfile) { 00168 int q=fprintf(logfile,"%s [%s] %s\n",lh->stamp,lh->tag,txt); 00169 if(q>0) logfileSize+=q; 00170 00171 if(logcfg.maxFilesize>0 && logfileSize>((long long)logcfg.maxFilesize*1024)) { 00172 fprintf(logfile,"%s [%s] %s\n",lh->stamp,lh->tag,"logfile closed, filesize limit reached"); 00173 fclose(logfile); 00174 logfile=0; logfileShutup=false; 00175 char *name=bprintf("%s.old",logcfg.logFilename); 00176 if(rename(logcfg.logFilename,name)) { 00177 logfileShutup=true; 00178 PRINTF(L_GEN_ERROR,"failed to rotate logfile: %s",strerror(errno)); 00179 PRINTF(L_GEN_ERROR,"logging to file disabled!"); 00180 } 00181 free(name); 00182 } 00183 } 00184 logfileMutex.Unlock(); 00185 } 00186 00187 if(logcfg.logCon) 00188 printf("%s [%s] %s\n",lh->stamp,lh->tag,txt); 00189 00190 if(logcfg.logSys || LMOD(lh->c)==L_GEN) { 00191 int pri=-1; 00192 switch(lh->c) { 00193 case L_GEN_ERROR: 00194 case L_GEN_WARN: if(SysLogLevel>0) pri=LOG_ERR; break; 00195 case L_GEN_INFO: if(SysLogLevel>1) pri=LOG_INFO; break; 00196 case L_GEN_DEBUG: if(SysLogLevel>2) pri=LOG_DEBUG; break; 00197 case L_GEN_MISC: if(logcfg.logSys) pri=LOG_DEBUG; break; 00198 default: pri=LOG_DEBUG; break; 00199 } 00200 if(pri>=0) 00201 syslog(pri,"[%d] [%s] %s",cThread::ThreadId(),lh->tag,txt); 00202 } 00203 } 00204 00205 bool cLogging::Enabled(int c) 00206 { 00207 int m=LMOD(c); 00208 int o=LOPT(c)|LMOD_CFG_VALID|LMOD_ENABLE; 00209 return m<LMOD_SUP && (config[m] & o)==o; 00210 } 00211 00212 void cLogging::Printf(int c, const char *format, ...) 00213 { 00214 if(Enabled(c)) { 00215 struct LogHeader lh; 00216 if(GetHeader(c,&lh)) { 00217 char buff[1024]; 00218 va_list ap; 00219 va_start(ap,format); 00220 vsnprintf(buff,sizeof(buff),format,ap); 00221 va_end(ap); 00222 LogLine(&lh,buff); 00223 } 00224 } 00225 } 00226 00227 void cLogging::Puts(int c, const char *txt) 00228 { 00229 if(txt && Enabled(c)) { 00230 struct LogHeader lh; 00231 if(GetHeader(c,&lh)) { 00232 LogLine(&lh,txt); 00233 } 00234 } 00235 } 00236 00237 void cLogging::PutLB(int c, cLineBuff *lb) 00238 { 00239 if(lb->Length()>0) { 00240 Puts(c,lb->Line()); 00241 lb->Flush(); 00242 } 00243 } 00244 00245 void cLogging::Dump(int c, const void *data, int n, const char *format, ...) 00246 { 00247 if(Enabled(c)) { 00248 struct LogHeader lh; 00249 if(GetHeader(c,&lh)) { 00250 char buff[1024]; 00251 va_list ap; 00252 va_start(ap,format); 00253 vsnprintf(buff,sizeof(buff),format,ap); 00254 va_end(ap); 00255 LogLine(&lh,buff); 00256 const unsigned char *d=(const unsigned char *)data; 00257 for(int i=0; i<n;) { 00258 int q=sprintf(buff,"%04x:",i); 00259 for(int l=0 ; l<16 && i<n ; l++) q+=sprintf(&buff[q]," %02x",d[i++]); 00260 LogLine(&lh,buff); 00261 } 00262 } 00263 } 00264 } 00265 00266 void cLogging::LineDump(int c, const void *data, int n, const char *format, ...) 00267 { 00268 if(Enabled(c)) { 00269 struct LogHeader lh; 00270 if(GetHeader(c,&lh)) { 00271 char buff[4096]; 00272 va_list ap; 00273 va_start(ap,format); 00274 unsigned int q=vsnprintf(buff,sizeof(buff),format,ap); 00275 va_end(ap); 00276 const unsigned char *d=(const unsigned char *)data; 00277 for(int i=0; i<n; i++) { 00278 if(q>=sizeof(buff)-8) { 00279 q+=snprintf(&buff[q],sizeof(buff)-q,"...."); 00280 break; 00281 } 00282 q+=snprintf(&buff[q],sizeof(buff)-q," %02x",d[i]); 00283 } 00284 LogLine(&lh,buff); 00285 } 00286 } 00287 } 00288 00289 void cLogging::SetModuleDefault(int c) 00290 { 00291 const struct LogModule *lm=GetModule(c); 00292 if(lm) { 00293 int m=LMOD(c); 00294 config[m]=(lm->OptDefault&LOPT_MASK)|LMOD_CFG_VALID; 00295 cmask[m] = lm->OptSupported&LOPT_MASK; 00296 } 00297 } 00298 00299 void cLogging::SetModuleOptions(int c) 00300 { 00301 const struct LogModule *lm=GetModule(c); 00302 if(lm) config[LMOD(c)]=(LOPT(c)&(lm->OptSupported&LOPT_MASK))|LMOD_CFG_VALID; 00303 } 00304 00305 int cLogging::GetModuleOptions(int c) 00306 { 00307 const struct LogModule *lm=GetModule(c); 00308 return lm ? LOPT(config[LMOD(c)]) : -1; 00309 } 00310 00311 void cLogging::SetModuleOption(int c, bool on) 00312 { 00313 const struct LogModule *lm=GetModule(c); 00314 if(lm) { 00315 int m=LMOD(c); 00316 int o=LOPT(c)&(lm->OptSupported&LOPT_MASK); 00317 if(o) { 00318 if(on) config[m]|=o; else config[m]&=(~o); 00319 config[m]|=LMOD_CFG_VALID; 00320 } 00321 } 00322 } 00323 00324 void cLogging::UpgradeOptions(int m) 00325 { 00326 const struct LogModule *lm=mods[m]; 00327 if(lm) { 00328 config[m]&=(lm->OptSupported&LOPT_MASK); 00329 config[m]|=(lm->OptDefault&LOPT_MASK)&(~cmask[m]); 00330 cmask[m] =lm->OptSupported&LOPT_MASK; 00331 config[m]|=LMOD_CFG_VALID; 00332 } 00333 } 00334 00335 const char *cLogging::GetModuleName(int c) 00336 { 00337 const struct LogModule *lm=GetModule(c); 00338 return lm ? lm->Name : 0; 00339 } 00340 00341 const char *cLogging::GetOptionName(int c) 00342 { 00343 const struct LogModule *lm=GetModule(c); 00344 if(lm) { 00345 int o=LOPT(c)&~LMOD_ENABLE; 00346 if(lm->OptSupported & o) { 00347 int i; 00348 for(i=0; i<LOPT_NUM; i++,o>>=1) if(o&1) break; 00349 return (i>=1 && i<LOPT_NUM && lm->OptName[i-1]) ? lm->OptName[i-1] : 0; 00350 } 00351 } 00352 return 0; 00353 } 00354 00355 bool cLogging::GetConfig(cLineBuff *lb) 00356 { 00357 lb->Flush(); 00358 bool cont=false; 00359 for(int m=1; m<LMOD_SUP; m++) 00360 if(config[m]&LMOD_CFG_VALID) { 00361 lb->Printf("%s%d:%x:%x",cont?",":"",m,config[m]&~LMOD_CFG_VALID,cmask[m]); 00362 cont=true; 00363 } 00364 return cont; 00365 } 00366 00367 void cLogging::ParseConfig(const char *txt) 00368 { 00369 int n=0, l, m, o, d; 00370 while(sscanf(&txt[n],"%d:%x:%x%n",&m,&o,&d,&l)==3) { 00371 if(m>=1 && m<LMOD_SUP) { 00372 config[m]=(o&LOPT_MASK)|LMOD_CFG_VALID; 00373 cmask[m] =(d&LOPT_MASK); 00374 UpgradeOptions(m); 00375 } 00376 n+=l; 00377 if(txt[n]!=',') break; 00378 n++; 00379 } 00380 } 00381 00382 void cLogging::ReopenLogfile(void) 00383 { 00384 logfileMutex.Lock(); 00385 logfileReopen=true; 00386 logfileMutex.Unlock(); 00387 } 00388 00389 int cLogging::GetClassByName(const char *name) 00390 { 00391 const char *s=index(name,'.'); 00392 if(s) { 00393 unsigned int l=s-name; 00394 for(int m=1; m<LMOD_SUP; m++) { 00395 const struct LogModule *lm=mods[m]; 00396 if(lm && strlen(lm->Name)==l && !strncasecmp(name,lm->Name,l)) { 00397 s++; 00398 if(!strcasecmp(s,"enable")) 00399 return LCLASS(m,1); 00400 for(int o=1; o<LOPT_NUM; o++) 00401 if((lm->OptSupported&(1<<o)) && lm->OptName[o-1] && !strcasecmp(s,lm->OptName[o-1])) 00402 return LCLASS(m,1<<o); 00403 break; 00404 } 00405 } 00406 } 00407 return -1; 00408 } 00409 00410 // -- cUserMsg ----------------------------------------------------------------- 00411 00412 cUserMsg::cUserMsg(const char *m) 00413 { 00414 msg=strdup(m); 00415 } 00416 00417 cUserMsg::~cUserMsg() 00418 { 00419 free(msg); 00420 } 00421 00422 // -- cUserMsgs ---------------------------------------------------------------- 00423 00424 cUserMsgs ums; 00425 00426 cUserMsgs::cUserMsgs(void) 00427 { 00428 mutex=new cMutex; 00429 } 00430 00431 cUserMsgs::~cUserMsgs() 00432 { 00433 delete mutex; 00434 } 00435 00436 void cUserMsgs::Queue(const char *fmt, ...) 00437 { 00438 if(logcfg.logUser) { 00439 char buff[1024]; 00440 va_list ap; 00441 va_start(ap,fmt); 00442 vsnprintf(buff,sizeof(buff),fmt,ap); 00443 va_end(ap); 00444 mutex->Lock(); 00445 Add(new cUserMsg(buff)); 00446 mutex->Unlock(); 00447 } 00448 } 00449 00450 cUserMsg *cUserMsgs::GetQueuedMsg(void) 00451 { 00452 mutex->Lock(); 00453 cUserMsg *um=First(); 00454 if(um) Del(um,false); 00455 mutex->Unlock(); 00456 return um; 00457 } 00458 00459 // -- cLogLineBuff ------------------------------------------------------------- 00460 00461 cLogLineBuff::cLogLineBuff(int C) 00462 :cLineBuff(256) 00463 { 00464 c=C; 00465 } 00466 00467 cLogLineBuff::~cLogLineBuff() 00468 { 00469 Flush(); 00470 } 00471 00472 void cLogLineBuff::Flush(void) 00473 { 00474 cLogging::PutLB(c,this); 00475 }