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