00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #include "magick/studio.h"
00043 #include "magick/blob.h"
00044 #include "magick/client.h"
00045 #include "magick/configure.h"
00046 #include "magick/exception.h"
00047 #include "magick/exception-private.h"
00048 #include "magick/hashmap.h"
00049 #include "magick/log.h"
00050 #include "magick/memory_.h"
00051 #include "magick/option.h"
00052 #include "magick/semaphore.h"
00053 #include "magick/timer.h"
00054 #include "magick/string_.h"
00055 #include "magick/token.h"
00056 #include "magick/thread_.h"
00057 #include "magick/thread-private.h"
00058 #include "magick/utility.h"
00059 #include "magick/version.h"
00060 #include "magick/xml-tree.h"
00061
00062
00063
00064
00065 #define LogFilename "log.xml"
00066
00067
00068
00069
00070 typedef enum
00071 {
00072 UndefinedHandler = 0x0000,
00073 NoHandler = 0x0000,
00074 ConsoleHandler = 0x0001,
00075 StdoutHandler = 0x0002,
00076 StderrHandler = 0x0004,
00077 FileHandler = 0x0008,
00078 DebugHandler = 0x0010,
00079 EventHandler = 0x0020
00080 } LogHandlerType;
00081
00082 typedef struct _EventInfo
00083 {
00084 char
00085 *name;
00086
00087 LogEventType
00088 event;
00089 } EventInfo;
00090
00091 typedef struct _HandlerInfo
00092 {
00093 const char
00094 *name;
00095
00096 LogHandlerType
00097 handler;
00098 } HandlerInfo;
00099
00100 struct _LogInfo
00101 {
00102 LogEventType
00103 event_mask;
00104
00105 LogHandlerType
00106 handler_mask;
00107
00108 char
00109 *path,
00110 *name,
00111 *filename,
00112 *format;
00113
00114 unsigned long
00115 generations,
00116 limit;
00117
00118 FILE
00119 *file;
00120
00121 unsigned long
00122 generation;
00123
00124 MagickBooleanType
00125 append,
00126 exempt,
00127 stealth;
00128
00129 TimerInfo
00130 timer;
00131
00132 unsigned long
00133 signature;
00134 };
00135
00136 typedef struct _LogMapInfo
00137 {
00138 const LogEventType
00139 event_mask;
00140
00141 const LogHandlerType
00142 handler_mask;
00143
00144 const char
00145 *filename,
00146 *format;
00147 } LogMapInfo;
00148
00149
00150
00151
00152 static const HandlerInfo
00153 LogHandlers[] =
00154 {
00155 { "console", ConsoleHandler },
00156 { "debug", DebugHandler },
00157 { "event", EventHandler },
00158 { "file", FileHandler },
00159 { "none", NoHandler },
00160 { "stderr", StderrHandler },
00161 { "stdout", StdoutHandler },
00162 { (char *) NULL, UndefinedHandler }
00163 };
00164
00165 static const LogMapInfo
00166 LogMap[] =
00167 {
00168 { NoEvents, ConsoleHandler, "Magick-%d.log",
00169 "%t %r %u %v %d %c[%p]: %m/%f/%l/%d\n %e" }
00170 };
00171
00172 static char
00173 log_name[MaxTextExtent] = "Magick";
00174
00175 static LinkedListInfo
00176 *log_list = (LinkedListInfo *) NULL;
00177
00178 static SemaphoreInfo
00179 *log_semaphore = (SemaphoreInfo *) NULL;
00180
00181 static volatile MagickBooleanType
00182 instantiate_log = MagickFalse;
00183
00184
00185
00186
00187 static LogHandlerType
00188 ParseLogHandlers(const char *);
00189
00190 static LogInfo
00191 *GetLogInfo(const char *,ExceptionInfo *);
00192
00193 static MagickBooleanType
00194 InitializeLogList(ExceptionInfo *),
00195 LoadLogLists(const char *,ExceptionInfo *);
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 MagickExport void CloseMagickLog(void)
00216 {
00217 ExceptionInfo
00218 *exception;
00219
00220 LogInfo
00221 *log_info;
00222
00223 if (IsEventLogging() == MagickFalse)
00224 return;
00225 exception=AcquireExceptionInfo();
00226 log_info=GetLogInfo("*",exception);
00227 exception=DestroyExceptionInfo(exception);
00228 (void) LockSemaphoreInfo(log_semaphore);
00229 if (log_info->file != (FILE *) NULL)
00230 {
00231 if (log_info->append == MagickFalse)
00232 (void) fprintf(log_info->file,"</log>\n");
00233 (void) fclose(log_info->file);
00234 log_info->file=(FILE *) NULL;
00235 }
00236 (void) UnlockSemaphoreInfo(log_semaphore);
00237 }
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264 static LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
00265 {
00266 register LogInfo
00267 *p;
00268
00269 assert(exception != (ExceptionInfo *) NULL);
00270 if ((log_list == (LinkedListInfo *) NULL) || (instantiate_log == MagickFalse))
00271 if (InitializeLogList(exception) == MagickFalse)
00272 return((LogInfo *) NULL);
00273 if ((log_list == (LinkedListInfo *) NULL) ||
00274 (IsLinkedListEmpty(log_list) != MagickFalse))
00275 return((LogInfo *) NULL);
00276 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
00277 return((LogInfo *) GetValueFromLinkedList(log_list,0));
00278
00279
00280
00281 (void) LockSemaphoreInfo(log_semaphore);
00282 ResetLinkedListIterator(log_list);
00283 p=(LogInfo *) GetNextValueInLinkedList(log_list);
00284 while (p != (LogInfo *) NULL)
00285 {
00286 if (LocaleCompare(name,p->name) == 0)
00287 break;
00288 p=(LogInfo *) GetNextValueInLinkedList(log_list);
00289 }
00290 if (p != (LogInfo *) NULL)
00291 (void) InsertValueInLinkedList(log_list,0,
00292 RemoveElementByValueFromLinkedList(log_list,p));
00293 (void) UnlockSemaphoreInfo(log_semaphore);
00294 return(p);
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 #if defined(__cplusplus) || defined(c_plusplus)
00325 extern "C" {
00326 #endif
00327
00328 static int LogInfoCompare(const void *x,const void *y)
00329 {
00330 const LogInfo
00331 **p,
00332 **q;
00333
00334 p=(const LogInfo **) x,
00335 q=(const LogInfo **) y;
00336 if (LocaleCompare((*p)->path,(*q)->path) == 0)
00337 return(LocaleCompare((*p)->name,(*q)->name));
00338 return(LocaleCompare((*p)->path,(*q)->path));
00339 }
00340
00341 #if defined(__cplusplus) || defined(c_plusplus)
00342 }
00343 #endif
00344
00345 MagickExport const LogInfo **GetLogInfoList(const char *pattern,
00346 unsigned long *number_preferences,ExceptionInfo *exception)
00347 {
00348 const LogInfo
00349 **preferences;
00350
00351 register const LogInfo
00352 *p;
00353
00354 register long
00355 i;
00356
00357
00358
00359
00360 assert(pattern != (char *) NULL);
00361 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
00362 assert(number_preferences != (unsigned long *) NULL);
00363 *number_preferences=0;
00364 p=GetLogInfo("*",exception);
00365 if (p == (const LogInfo *) NULL)
00366 return((const LogInfo **) NULL);
00367 preferences=(const LogInfo **) AcquireQuantumMemory((size_t)
00368 GetNumberOfElementsInLinkedList(log_list)+1UL,sizeof(*preferences));
00369 if (preferences == (const LogInfo **) NULL)
00370 return((const LogInfo **) NULL);
00371
00372
00373
00374 (void) LockSemaphoreInfo(log_semaphore);
00375 ResetLinkedListIterator(log_list);
00376 p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00377 for (i=0; p != (const LogInfo *) NULL; )
00378 {
00379 if ((p->stealth == MagickFalse) &&
00380 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
00381 preferences[i++]=p;
00382 p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00383 }
00384 (void) UnlockSemaphoreInfo(log_semaphore);
00385 qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogInfoCompare);
00386 preferences[i]=(LogInfo *) NULL;
00387 *number_preferences=(unsigned long) i;
00388 return(preferences);
00389 }
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 #if defined(__cplusplus) || defined(c_plusplus)
00420 extern "C" {
00421 #endif
00422
00423 static int LogCompare(const void *x,const void *y)
00424 {
00425 register const char
00426 **p,
00427 **q;
00428
00429 p=(const char **) x;
00430 q=(const char **) y;
00431 return(LocaleCompare(*p,*q));
00432 }
00433
00434 #if defined(__cplusplus) || defined(c_plusplus)
00435 }
00436 #endif
00437
00438 MagickExport char **GetLogList(const char *pattern,
00439 unsigned long *number_preferences,ExceptionInfo *exception)
00440 {
00441 char
00442 **preferences;
00443
00444 register const LogInfo
00445 *p;
00446
00447 register long
00448 i;
00449
00450
00451
00452
00453 assert(pattern != (char *) NULL);
00454 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
00455 assert(number_preferences != (unsigned long *) NULL);
00456 *number_preferences=0;
00457 p=GetLogInfo("*",exception);
00458 if (p == (const LogInfo *) NULL)
00459 return((char **) NULL);
00460 preferences=(char **) AcquireQuantumMemory((size_t)
00461 GetNumberOfElementsInLinkedList(log_list)+1UL,sizeof(*preferences));
00462 if (preferences == (char **) NULL)
00463 return((char **) NULL);
00464
00465
00466
00467 (void) LockSemaphoreInfo(log_semaphore);
00468 ResetLinkedListIterator(log_list);
00469 p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00470 for (i=0; p != (const LogInfo *) NULL; )
00471 {
00472 if ((p->stealth == MagickFalse) &&
00473 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
00474 preferences[i++]=ConstantString(p->name);
00475 p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00476 }
00477 (void) UnlockSemaphoreInfo(log_semaphore);
00478 qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogCompare);
00479 preferences[i]=(char *) NULL;
00480 *number_preferences=(unsigned long) i;
00481 return(preferences);
00482 }
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502 MagickExport const char *GetLogName(void)
00503 {
00504 return(log_name);
00505 }
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529 static MagickBooleanType InitializeLogList(ExceptionInfo *exception)
00530 {
00531 if ((log_list == (LinkedListInfo *) NULL) && (instantiate_log == MagickFalse))
00532 {
00533 if (log_semaphore == (SemaphoreInfo *) NULL)
00534 AcquireSemaphoreInfo(&log_semaphore);
00535 (void) LockSemaphoreInfo(log_semaphore);
00536 if ((log_list == (LinkedListInfo *) NULL) &&
00537 (instantiate_log == MagickFalse))
00538 {
00539 (void) LoadLogLists(LogFilename,exception);
00540 instantiate_log=MagickTrue;
00541 }
00542 (void) UnlockSemaphoreInfo(log_semaphore);
00543 }
00544 return(log_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
00545 }
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 MagickExport MagickBooleanType IsEventLogging(void)
00567 {
00568 const LogInfo
00569 *log_info;
00570
00571 ExceptionInfo
00572 *exception;
00573
00574 if ((log_list == (LinkedListInfo *) NULL) ||
00575 (IsLinkedListEmpty(log_list) != MagickFalse))
00576 return(MagickFalse);
00577 exception=AcquireExceptionInfo();
00578 log_info=GetLogInfo("*",exception);
00579 exception=DestroyExceptionInfo(exception);
00580 return(log_info->event_mask != NoEvents ? MagickTrue : MagickFalse);
00581 }
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606 MagickExport MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
00607 {
00608 #define MegabytesToBytes(value) ((MagickSizeType) (value)*1024*1024)
00609
00610 char
00611 limit[MaxTextExtent];
00612
00613 const char
00614 *path;
00615
00616 const LogInfo
00617 **log_info;
00618
00619 long
00620 j;
00621
00622 register long
00623 i;
00624
00625 unsigned long
00626 number_aliases;
00627
00628 if (file == (const FILE *) NULL)
00629 file=stdout;
00630 log_info=GetLogInfoList("*",&number_aliases,exception);
00631 if (log_info == (const LogInfo **) NULL)
00632 return(MagickFalse);
00633 j=0;
00634 path=(const char *) NULL;
00635 for (i=0; i < (long) number_aliases; i++)
00636 {
00637 if (log_info[i]->stealth != MagickFalse)
00638 continue;
00639 if ((path == (const char *) NULL) ||
00640 (LocaleCompare(path,log_info[i]->path) != 0))
00641 {
00642 if (log_info[i]->path != (char *) NULL)
00643 (void) fprintf(file,"\nPath: %s\n\n",log_info[i]->path);
00644 (void) fprintf(file,"Filename Generations Limit Format\n");
00645 (void) fprintf(file,"-------------------------------------------------"
00646 "------------------------------\n");
00647 }
00648 path=log_info[i]->path;
00649 if (log_info[i]->filename != (char *) NULL)
00650 {
00651 (void) fprintf(file,"%s",log_info[i]->filename);
00652 for (j=(long) strlen(log_info[i]->filename); j <= 16; j++)
00653 (void) fprintf(file," ");
00654 }
00655 (void) fprintf(file,"%9lu ",log_info[i]->generations);
00656 (void) FormatMagickSize(MegabytesToBytes(log_info[i]->limit),limit);
00657 (void) fprintf(file,"%8s ",limit);
00658 if (log_info[i]->format != (char *) NULL)
00659 (void) fprintf(file,"%s",log_info[i]->format);
00660 (void) fprintf(file,"\n");
00661 }
00662 (void) fflush(file);
00663 log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info);
00664 return(MagickTrue);
00665 }
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685 MagickExport MagickBooleanType LogComponentGenesis(void)
00686 {
00687 AcquireSemaphoreInfo(&log_semaphore);
00688 return(MagickTrue);
00689 }
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710 static void *DestroyLogElement(void *log_info)
00711 {
00712 register LogInfo
00713 *p;
00714
00715 p=(LogInfo *) log_info;
00716 if (p->file != (FILE *) NULL)
00717 {
00718 if (p->append == MagickFalse)
00719 (void) fprintf(p->file,"</log>\n");
00720 (void) fclose(p->file);
00721 p->file=(FILE *) NULL;
00722 }
00723 if (p->exempt == MagickFalse)
00724 {
00725 if (p->format != (char *) NULL)
00726 p->format=DestroyString(p->format);
00727 if (p->path != (char *) NULL)
00728 p->path=DestroyString(p->path);
00729 if (p->filename != (char *) NULL)
00730 p->filename=DestroyString(p->filename);
00731 }
00732 p=(LogInfo *) RelinquishMagickMemory(p);
00733 return((void *) NULL);
00734 }
00735
00736 MagickExport void LogComponentTerminus(void)
00737 {
00738 if (log_semaphore == (SemaphoreInfo *) NULL)
00739 AcquireSemaphoreInfo(&log_semaphore);
00740 (void) LockSemaphoreInfo(log_semaphore);
00741 if (log_list != (LinkedListInfo *) NULL)
00742 log_list=DestroyLinkedList(log_list,DestroyLogElement);
00743 instantiate_log=MagickFalse;
00744 (void) UnlockSemaphoreInfo(log_semaphore);
00745 DestroySemaphoreInfo(&log_semaphore);
00746 }
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781 static char *TranslateEvent(const LogEventType magick_unused(type),
00782 const char *module,const char *function,const unsigned long line,
00783 const char *domain,const char *event)
00784 {
00785 char
00786 *text;
00787
00788 double
00789 elapsed_time,
00790 user_time;
00791
00792 ExceptionInfo
00793 *exception;
00794
00795 LogInfo
00796 *log_info;
00797
00798 register char
00799 *q;
00800
00801 register const char
00802 *p;
00803
00804 size_t
00805 extent;
00806
00807 time_t
00808 seconds;
00809
00810 exception=AcquireExceptionInfo();
00811 log_info=(LogInfo *) GetLogInfo("*",exception);
00812 exception=DestroyExceptionInfo(exception);
00813 seconds=time((time_t *) NULL);
00814 elapsed_time=GetElapsedTime(&log_info->timer);
00815 user_time=GetUserTime(&log_info->timer);
00816 text=AcquireString(event);
00817 if (log_info->format == (char *) NULL)
00818 return(text);
00819 extent=strlen(event)+MaxTextExtent;
00820 if (LocaleCompare(log_info->format,"xml") == 0)
00821 {
00822 char
00823 timestamp[MaxTextExtent];
00824
00825
00826
00827
00828 (void) FormatMagickTime(seconds,extent,timestamp);
00829 (void) FormatMagickString(text,extent,
00830 "<entry>\n"
00831 " <timestamp>%s</timestamp>\n"
00832 " <elapsed-time>%ld:%02ld.%03ld</elapsed-time>\n"
00833 " <user-time>%0.3f</user-time>\n"
00834 " <process-id>%ld</process-id>\n"
00835 " <thread-id>%lu</thread-id>\n"
00836 " <module>%s</module>\n"
00837 " <function>%s</function>\n"
00838 " <line>%lu</line>\n"
00839 " <domain>%s</domain>\n"
00840 " <event>%s</event>\n"
00841 "</entry>",timestamp,(long) (elapsed_time/60.0),(long)
00842 floor(fmod(elapsed_time,60.0)),(long) (1000.0*(elapsed_time-
00843 floor(elapsed_time))+0.5),user_time,(long) getpid(),
00844 GetMagickThreadSignature(),module,function,line,domain,event);
00845 return(text);
00846 }
00847
00848
00849
00850 q=text;
00851 for (p=log_info->format; *p != '\0'; p++)
00852 {
00853 *q='\0';
00854 if ((size_t) (q-text+MaxTextExtent) >= extent)
00855 {
00856 extent+=MaxTextExtent;
00857 text=(char *) ResizeQuantumMemory(text,extent+MaxTextExtent,
00858 sizeof(*text));
00859 if (text == (char *) NULL)
00860 return((char *) NULL);
00861 q=text+strlen(text);
00862 }
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883 if ((*p == '\\') && (*(p+1) == 'r'))
00884 {
00885 *q++='\r';
00886 p++;
00887 continue;
00888 }
00889 if ((*p == '\\') && (*(p+1) == 'n'))
00890 {
00891 *q++='\n';
00892 p++;
00893 continue;
00894 }
00895 if (*p != '%')
00896 {
00897 *q++=(*p);
00898 continue;
00899 }
00900 p++;
00901 switch (*p)
00902 {
00903 case 'c':
00904 {
00905 q+=CopyMagickString(q,GetClientName(),extent);
00906 break;
00907 }
00908 case 'd':
00909 {
00910 q+=CopyMagickString(q,domain,extent);
00911 break;
00912 }
00913 case 'e':
00914 {
00915 q+=CopyMagickString(q,event,extent);
00916 break;
00917 }
00918 case 'f':
00919 {
00920 q+=CopyMagickString(q,function,extent);
00921 break;
00922 }
00923 case 'g':
00924 {
00925 if (log_info->generations == 0)
00926 {
00927 (void) CopyMagickString(q,"0",extent);
00928 q++;
00929 break;
00930 }
00931 q+=FormatMagickString(q,extent,"%lu",log_info->generation %
00932 log_info->generations);
00933 break;
00934 }
00935 case 'l':
00936 {
00937 q+=FormatMagickString(q,extent,"%lu",line);
00938 break;
00939 }
00940 case 'm':
00941 {
00942 register const char
00943 *p;
00944
00945 for (p=module+strlen(module)-1; p > module; p--)
00946 if (*p == *DirectorySeparator)
00947 {
00948 p++;
00949 break;
00950 }
00951 q+=CopyMagickString(q,p,extent);
00952 break;
00953 }
00954 case 'n':
00955 {
00956 q+=CopyMagickString(q,GetLogName(),extent);
00957 break;
00958 }
00959 case 'p':
00960 {
00961 q+=FormatMagickString(q,extent,"%ld",(long) getpid());
00962 break;
00963 }
00964 case 'r':
00965 {
00966 q+=FormatMagickString(q,extent,"%ld:%02ld.%03ld",(long)
00967 (elapsed_time/60.0),(long) floor(fmod(elapsed_time,60.0)),
00968 (long) (1000.0*(elapsed_time-floor(elapsed_time))+0.5));
00969 break;
00970 }
00971 case 't':
00972 {
00973 q+=FormatMagickTime(seconds,extent,q);
00974 break;
00975 }
00976 case 'u':
00977 {
00978 q+=FormatMagickString(q,extent,"%0.3fu",user_time);
00979 break;
00980 }
00981 case 'v':
00982 {
00983 q+=CopyMagickString(q,MagickLibVersionText,extent);
00984 break;
00985 }
00986 case '%':
00987 {
00988 *q++=(*p);
00989 break;
00990 }
00991 default:
00992 {
00993 *q++='%';
00994 *q++=(*p);
00995 break;
00996 }
00997 }
00998 }
00999 *q='\0';
01000 return(text);
01001 }
01002
01003 static char *TranslateFilename(const LogInfo *log_info)
01004 {
01005 char
01006 *filename;
01007
01008 register char
01009 *q;
01010
01011 register const char
01012 *p;
01013
01014 size_t
01015 extent;
01016
01017
01018
01019
01020 assert(log_info != (LogInfo *) NULL);
01021 assert(log_info->filename != (char *) NULL);
01022 filename=AcquireString((char *) NULL);
01023 extent=MaxTextExtent;
01024 q=filename;
01025 for (p=log_info->filename; *p != '\0'; p++)
01026 {
01027 *q='\0';
01028 if ((size_t) (q-filename+MaxTextExtent) >= extent)
01029 {
01030 extent+=MaxTextExtent;
01031 filename=(char *) ResizeQuantumMemory(filename,extent+MaxTextExtent,
01032 sizeof(*filename));
01033 if (filename == (char *) NULL)
01034 return((char *) NULL);
01035 q=filename+strlen(filename);
01036 }
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047 if (*p != '%')
01048 {
01049 *q++=(*p);
01050 continue;
01051 }
01052 p++;
01053 switch (*p)
01054 {
01055 case 'c':
01056 {
01057 q+=CopyMagickString(q,GetClientName(),extent);
01058 break;
01059 }
01060 case 'g':
01061 {
01062 if (log_info->generations == 0)
01063 {
01064 (void) CopyMagickString(q,"0",extent);
01065 q++;
01066 break;
01067 }
01068 q+=FormatMagickString(q,extent,"%lu",log_info->generation %
01069 log_info->generations);
01070 break;
01071 }
01072 case 'n':
01073 {
01074 q+=CopyMagickString(q,GetLogName(),extent);
01075 break;
01076 }
01077 case 'p':
01078 {
01079 q+=FormatMagickString(q,extent,"%ld",(long) getpid());
01080 break;
01081 }
01082 case 'v':
01083 {
01084 q+=CopyMagickString(q,MagickLibVersionText,extent);
01085 break;
01086 }
01087 case '%':
01088 {
01089 *q++=(*p);
01090 break;
01091 }
01092 default:
01093 {
01094 *q++='%';
01095 *q++=(*p);
01096 break;
01097 }
01098 }
01099 }
01100 *q='\0';
01101 return(filename);
01102 }
01103
01104 MagickBooleanType LogMagickEventList(const LogEventType type,const char *module,
01105 const char *function,const unsigned long line,const char *format,
01106 va_list operands)
01107 {
01108 char
01109 event[MaxTextExtent],
01110 *text;
01111
01112 const char
01113 *domain;
01114
01115 ExceptionInfo
01116 *exception;
01117
01118 int
01119 n;
01120
01121 LogInfo
01122 *log_info;
01123
01124 if (IsEventLogging() == MagickFalse)
01125 return(MagickFalse);
01126 exception=AcquireExceptionInfo();
01127 log_info=(LogInfo *) GetLogInfo("*",exception);
01128 exception=DestroyExceptionInfo(exception);
01129 (void) LockSemaphoreInfo(log_semaphore);
01130 if ((log_info->event_mask & type) == 0)
01131 {
01132 (void) UnlockSemaphoreInfo(log_semaphore);
01133 return(MagickTrue);
01134 }
01135 domain=MagickOptionToMnemonic(MagickLogEventOptions,type);
01136 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
01137 n=vsnprintf(event,MaxTextExtent,format,operands);
01138 #else
01139 n=vsprintf(event,format,operands);
01140 #endif
01141 if (n < 0)
01142 event[MaxTextExtent-1]='\0';
01143 text=TranslateEvent(type,module,function,line,domain,event);
01144 if (text == (char *) NULL)
01145 {
01146 (void) ContinueTimer((TimerInfo *) &log_info->timer);
01147 (void) UnlockSemaphoreInfo(log_semaphore);
01148 return(MagickFalse);
01149 }
01150 if ((log_info->handler_mask & ConsoleHandler) != 0)
01151 {
01152 (void) fprintf(stderr,"%s\n",text);
01153 (void) fflush(stderr);
01154 }
01155 if ((log_info->handler_mask & DebugHandler) != 0)
01156 {
01157 #if defined(__WINDOWS__)
01158 OutputDebugString(text);
01159 #endif
01160 }
01161 if ((log_info->handler_mask & EventHandler) != 0)
01162 {
01163 #if defined(__WINDOWS__)
01164 (void) NTReportEvent(text,MagickFalse);
01165 #endif
01166 }
01167 if ((log_info->handler_mask & FileHandler) != 0)
01168 {
01169 struct stat
01170 file_info;
01171
01172 file_info.st_size=0;
01173 if (log_info->file != (FILE *) NULL)
01174 (void) fstat(fileno(log_info->file),&file_info);
01175 if (file_info.st_size > (off_t) (1024*1024*log_info->limit))
01176 {
01177 (void) fprintf(log_info->file,"</log>\n");
01178 (void) fclose(log_info->file);
01179 log_info->file=(FILE *) NULL;
01180 }
01181 if (log_info->file == (FILE *) NULL)
01182 {
01183 char
01184 *filename;
01185
01186 filename=TranslateFilename(log_info);
01187 if (filename == (char *) NULL)
01188 {
01189 (void) ContinueTimer((TimerInfo *) &log_info->timer);
01190 (void) UnlockSemaphoreInfo(log_semaphore);
01191 return(MagickFalse);
01192 }
01193 log_info->append=IsPathAccessible(filename);
01194 log_info->file=OpenMagickStream(filename,"ab");
01195 filename=(char *) RelinquishMagickMemory(filename);
01196 if (log_info->file == (FILE *) NULL)
01197 {
01198 (void) UnlockSemaphoreInfo(log_semaphore);
01199 return(MagickFalse);
01200 }
01201 log_info->generation++;
01202 if (log_info->append == MagickFalse)
01203 {
01204 (void) fprintf(log_info->file,"<?xml version=\"1.0\" "
01205 "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
01206 (void) fprintf(log_info->file,"<log>\n");
01207 }
01208 }
01209 (void) fprintf(log_info->file,"%s\n",text);
01210 (void) fflush(log_info->file);
01211 }
01212 if ((log_info->handler_mask & StdoutHandler) != 0)
01213 {
01214 (void) fprintf(stdout,"%s\n",text);
01215 (void) fflush(stdout);
01216 }
01217 if ((log_info->handler_mask & StderrHandler) != 0)
01218 {
01219 (void) fprintf(stderr,"%s\n",text);
01220 (void) fflush(stderr);
01221 }
01222 text=(char *) RelinquishMagickMemory(text);
01223 (void) ContinueTimer((TimerInfo *) &log_info->timer);
01224 (void) UnlockSemaphoreInfo(log_semaphore);
01225 return(MagickTrue);
01226 }
01227
01228 MagickBooleanType LogMagickEvent(const LogEventType type,const char *module,
01229 const char *function,const unsigned long line,const char *format,...)
01230 {
01231 va_list
01232 operands;
01233
01234 MagickBooleanType
01235 status;
01236
01237 va_start(operands,format);
01238 status=LogMagickEventList(type,module,function,line,format,operands);
01239 va_end(operands);
01240 return(status);
01241 }
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273 static MagickBooleanType LoadLogList(const char *xml,const char *filename,
01274 const unsigned long depth,ExceptionInfo *exception)
01275 {
01276 char
01277 keyword[MaxTextExtent],
01278 *token;
01279
01280 const char
01281 *q;
01282
01283 LogInfo
01284 *log_info = (LogInfo *) NULL;
01285
01286 MagickStatusType
01287 status;
01288
01289
01290
01291
01292 if (xml == (const char *) NULL)
01293 return(MagickFalse);
01294 if (log_list == (LinkedListInfo *) NULL)
01295 {
01296 log_list=NewLinkedList(0);
01297 if (log_list == (LinkedListInfo *) NULL)
01298 {
01299 ThrowFileException(exception,ResourceLimitError,
01300 "MemoryAllocationFailed",filename);
01301 return(MagickFalse);
01302 }
01303 }
01304 status=MagickTrue;
01305 token=AcquireString((const char *) xml);
01306 for (q=(const char *) xml; *q != '\0'; )
01307 {
01308
01309
01310
01311 GetMagickToken(q,&q,token);
01312 if (*token == '\0')
01313 break;
01314 (void) CopyMagickString(keyword,token,MaxTextExtent);
01315 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
01316 {
01317
01318
01319
01320 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
01321 GetMagickToken(q,&q,token);
01322 continue;
01323 }
01324 if (LocaleNCompare(keyword,"<!--",4) == 0)
01325 {
01326
01327
01328
01329 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
01330 GetMagickToken(q,&q,token);
01331 continue;
01332 }
01333 if (LocaleCompare(keyword,"<include") == 0)
01334 {
01335
01336
01337
01338 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
01339 {
01340 (void) CopyMagickString(keyword,token,MaxTextExtent);
01341 GetMagickToken(q,&q,token);
01342 if (*token != '=')
01343 continue;
01344 GetMagickToken(q,&q,token);
01345 if (LocaleCompare(keyword,"file") == 0)
01346 {
01347 if (depth > 200)
01348 (void) ThrowMagickException(exception,GetMagickModule(),
01349 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
01350 else
01351 {
01352 char
01353 path[MaxTextExtent],
01354 *xml;
01355
01356 GetPathComponent(filename,HeadPath,path);
01357 if (*path != '\0')
01358 (void) ConcatenateMagickString(path,DirectorySeparator,
01359 MaxTextExtent);
01360 if (*token == *DirectorySeparator)
01361 (void) CopyMagickString(path,token,MaxTextExtent);
01362 else
01363 (void) ConcatenateMagickString(path,token,MaxTextExtent);
01364 xml=FileToString(path,~0,exception);
01365 if (xml != (char *) NULL)
01366 {
01367 status|=LoadLogList(xml,path,depth+1,exception);
01368 xml=DestroyString(xml);
01369 }
01370 }
01371 }
01372 }
01373 continue;
01374 }
01375 if (LocaleCompare(keyword,"<logmap>") == 0)
01376 {
01377
01378
01379
01380 log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
01381 if (log_info == (LogInfo *) NULL)
01382 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
01383 (void) ResetMagickMemory(log_info,0,sizeof(*log_info));
01384 log_info->path=ConstantString(filename);
01385 GetTimerInfo((TimerInfo *) &log_info->timer);
01386 log_info->exempt=MagickFalse;
01387 log_info->signature=MagickSignature;
01388 continue;
01389 }
01390 if (log_info == (LogInfo *) NULL)
01391 continue;
01392 if (LocaleCompare(keyword,"</logmap>") == 0)
01393 {
01394 status=AppendValueToLinkedList(log_list,log_info);
01395 if (status == MagickFalse)
01396 (void) ThrowMagickException(exception,GetMagickModule(),
01397 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
01398 log_info=(LogInfo *) NULL;
01399 }
01400 GetMagickToken(q,(const char **) NULL,token);
01401 if (*token != '=')
01402 continue;
01403 GetMagickToken(q,&q,token);
01404 GetMagickToken(q,&q,token);
01405 switch (*keyword)
01406 {
01407 case 'E':
01408 case 'e':
01409 {
01410 if (LocaleCompare((char *) keyword,"events") == 0)
01411 {
01412 log_info->event_mask=(LogEventType) (log_info->event_mask |
01413 ParseMagickOption(MagickLogEventOptions,MagickTrue,token));
01414 break;
01415 }
01416 break;
01417 }
01418 case 'F':
01419 case 'f':
01420 {
01421 if (LocaleCompare((char *) keyword,"filename") == 0)
01422 {
01423 if (log_info->filename != (char *) NULL)
01424 log_info->filename=(char *)
01425 RelinquishMagickMemory(log_info->filename);
01426 log_info->filename=ConstantString(token);
01427 break;
01428 }
01429 if (LocaleCompare((char *) keyword,"format") == 0)
01430 {
01431 if (log_info->format != (char *) NULL)
01432 log_info->format=(char *)
01433 RelinquishMagickMemory(log_info->format);
01434 log_info->format=ConstantString(token);
01435 break;
01436 }
01437 break;
01438 }
01439 case 'G':
01440 case 'g':
01441 {
01442 if (LocaleCompare((char *) keyword,"generations") == 0)
01443 {
01444 if (LocaleCompare(token,"unlimited") == 0)
01445 {
01446 log_info->generations=(~0UL);
01447 break;
01448 }
01449 log_info->generations=(unsigned long) atol(token);
01450 break;
01451 }
01452 break;
01453 }
01454 case 'L':
01455 case 'l':
01456 {
01457 if (LocaleCompare((char *) keyword,"limit") == 0)
01458 {
01459 if (LocaleCompare(token,"unlimited") == 0)
01460 {
01461 log_info->limit=(~0UL);
01462 break;
01463 }
01464 log_info->limit=(unsigned long) atol(token);
01465 break;
01466 }
01467 break;
01468 }
01469 case 'O':
01470 case 'o':
01471 {
01472 if (LocaleCompare((char *) keyword,"output") == 0)
01473 {
01474 log_info->handler_mask=(LogHandlerType)
01475 (log_info->handler_mask | ParseLogHandlers(token));
01476 break;
01477 }
01478 break;
01479 }
01480 default:
01481 break;
01482 }
01483 }
01484 token=DestroyString(token);
01485 if (log_list == (LinkedListInfo *) NULL)
01486 return(MagickFalse);
01487 return(status != 0 ? MagickTrue : MagickFalse);
01488 }
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516 static MagickBooleanType LoadLogLists(const char *filename,
01517 ExceptionInfo *exception)
01518 {
01519 const StringInfo
01520 *option;
01521
01522 LinkedListInfo
01523 *options;
01524
01525 MagickStatusType
01526 status;
01527
01528 register long
01529 i;
01530
01531
01532
01533
01534 status=MagickFalse;
01535 if (log_list == (LinkedListInfo *) NULL)
01536 {
01537 log_list=NewLinkedList(0);
01538 if (log_list == (LinkedListInfo *) NULL)
01539 {
01540 ThrowFileException(exception,ResourceLimitError,
01541 "MemoryAllocationFailed",filename);
01542 return(MagickFalse);
01543 }
01544 }
01545 for (i=0; i < (long) (sizeof(LogMap)/sizeof(*LogMap)); i++)
01546 {
01547 LogInfo
01548 *log_info;
01549
01550 register const LogMapInfo
01551 *p;
01552
01553 p=LogMap+i;
01554 log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
01555 if (log_info == (LogInfo *) NULL)
01556 {
01557 (void) ThrowMagickException(exception,GetMagickModule(),
01558 ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
01559 continue;
01560 }
01561 (void) ResetMagickMemory(log_info,0,sizeof(*log_info));
01562 log_info->path=(char *) "[built-in]";
01563 GetTimerInfo((TimerInfo *) &log_info->timer);
01564 log_info->event_mask=p->event_mask;
01565 log_info->handler_mask=p->handler_mask;
01566 log_info->filename=(char *) p->filename;
01567 log_info->format=(char *) p->format;
01568 log_info->exempt=MagickTrue;
01569 log_info->signature=MagickSignature;
01570 status=AppendValueToLinkedList(log_list,log_info);
01571 if (status == MagickFalse)
01572 (void) ThrowMagickException(exception,GetMagickModule(),
01573 ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
01574 }
01575
01576
01577
01578 options=GetConfigureOptions(filename,exception);
01579 option=(const StringInfo *) GetNextValueInLinkedList(options);
01580 while (option != (const StringInfo *) NULL)
01581 {
01582 status|=LoadLogList((const char *) GetStringInfoDatum(option),
01583 GetStringInfoPath(option),0,exception);
01584 option=(const StringInfo *) GetNextValueInLinkedList(options);
01585 }
01586 options=DestroyConfigureOptions(options);
01587 return(status != 0 ? MagickTrue : MagickFalse);
01588 }
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613 static LogHandlerType ParseLogHandlers(const char *handlers)
01614 {
01615 LogHandlerType
01616 handler_mask;
01617
01618 register const char
01619 *p;
01620
01621 register long
01622 i;
01623
01624 size_t
01625 length;
01626
01627 handler_mask=NoHandler;
01628 for (p=handlers; p != (char *) NULL; p=strchr(p,','))
01629 {
01630 while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) ||
01631 (*p == ',')))
01632 p++;
01633 for (i=0; LogHandlers[i].name != (char *) NULL; i++)
01634 {
01635 length=strlen(LogHandlers[i].name);
01636 if (LocaleNCompare(p,LogHandlers[i].name,length) == 0)
01637 {
01638 handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler);
01639 break;
01640 }
01641 }
01642 if (LogHandlers[i].name == (char *) NULL)
01643 return(UndefinedHandler);
01644 }
01645 return(handler_mask);
01646 }
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672 MagickExport LogEventType SetLogEventMask(const char *events)
01673 {
01674 ExceptionInfo
01675 *exception;
01676
01677 LogInfo
01678 *log_info;
01679
01680 long
01681 option;
01682
01683 exception=AcquireExceptionInfo();
01684 log_info=(LogInfo *) GetLogInfo("*",exception);
01685 exception=DestroyExceptionInfo(exception);
01686 option=ParseMagickOption(MagickLogEventOptions,MagickTrue,events);
01687 (void) LockSemaphoreInfo(log_semaphore);
01688 log_info=(LogInfo *) GetValueFromLinkedList(log_list,0);
01689 log_info->event_mask=(LogEventType) option;
01690 if (option == -1)
01691 log_info->event_mask=UndefinedEvents;
01692 (void) UnlockSemaphoreInfo(log_semaphore);
01693 return(log_info->event_mask);
01694 }
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718 MagickExport void SetLogFormat(const char *format)
01719 {
01720 LogInfo
01721 *log_info;
01722
01723 ExceptionInfo
01724 *exception;
01725
01726 exception=AcquireExceptionInfo();
01727 log_info=(LogInfo *) GetLogInfo("*",exception);
01728 exception=DestroyExceptionInfo(exception);
01729 (void) LockSemaphoreInfo(log_semaphore);
01730 if (log_info->format != (char *) NULL)
01731 log_info->format=DestroyString(log_info->format);
01732 log_info->format=ConstantString(format);
01733 (void) UnlockSemaphoreInfo(log_semaphore);
01734 }
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760 MagickExport const char *SetLogName(const char *name)
01761 {
01762 if ((name != (char *) NULL) && (*name != '\0'))
01763 (void) CopyMagickString(log_name,name,MaxTextExtent);
01764 return(log_name);
01765 }