1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % L OOO GGGG % 7 % L O O G % 8 % L O O G GG % 9 % L O O G G % 10 % LLLLL OOO GGG % 11 % % 12 % % 13 % MagickCore Log Events % 14 % % 15 % Software Design % 16 % Cristy % 17 % September 2002 % 18 % % 19 % % 20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization % 21 % dedicated to making software imaging solutions freely available. % 22 % % 23 % You may not use this file except in compliance with the License. You may % 24 % obtain a copy of the License at % 25 % % 26 % https://imagemagick.org/script/license.php % 27 % % 28 % Unless required by applicable law or agreed to in writing, software % 29 % distributed under the License is distributed on an "AS IS" BASIS, % 30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31 % See the License for the specific language governing permissions and % 32 % limitations under the License. % 33 % % 34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35 % 36 % 37 */ 38 39 /* 41 Include declarations. 42 */ 43 #include "MagickCore/studio.h" 44 #include "MagickCore/blob.h" 45 #include "MagickCore/client.h" 46 #include "MagickCore/configure.h" 47 #include "MagickCore/configure-private.h" 48 #include "MagickCore/exception.h" 49 #include "MagickCore/exception-private.h" 50 #include "MagickCore/linked-list.h" 51 #include "MagickCore/log.h" 52 #include "MagickCore/log-private.h" 53 #include "MagickCore/memory_.h" 54 #include "MagickCore/memory-private.h" 55 #include "MagickCore/nt-base-private.h" 56 #include "MagickCore/option.h" 57 #include "MagickCore/semaphore.h" 58 #include "MagickCore/timer.h" 59 #include "MagickCore/string_.h" 60 #include "MagickCore/string-private.h" 61 #include "MagickCore/token.h" 62 #include "MagickCore/thread_.h" 63 #include "MagickCore/thread-private.h" 64 #include "MagickCore/utility.h" 65 #include "MagickCore/utility-private.h" 66 #include "MagickCore/version.h" 67 #include "MagickCore/xml-tree.h" 68 #include "MagickCore/xml-tree-private.h" 69 70 /* 72 Define declarations. 73 */ 74 #define LogFilename "log.xml" 75 76 /* 78 Typedef declarations. 79 */ 80 typedef enum 81 { 82 UndefinedHandler = 0x0000, 83 NoHandler = 0x0000, 84 ConsoleHandler = 0x0001, 85 StdoutHandler = 0x0002, 86 StderrHandler = 0x0004, 87 FileHandler = 0x0008, 88 DebugHandler = 0x0010, 89 EventHandler = 0x0020, 90 MethodHandler = 0x0040 91 } LogHandlerType; 92 93 typedef struct _EventInfo 94 { 95 char 96 *name; 97 98 LogEventType 99 event; 100 } EventInfo; 101 102 typedef struct _HandlerInfo 103 { 104 const char 105 *name; 106 107 LogHandlerType 108 handler; 109 } HandlerInfo; 110 111 struct _LogInfo 112 { 113 LogEventType 114 event_mask; 115 116 LogHandlerType 117 handler_mask; 118 119 char 120 *path, 121 *name, 122 *filename, 123 *format; 124 125 size_t 126 generations, 127 limit; 128 129 FILE 130 *file; 131 132 size_t 133 generation; 134 135 MagickBooleanType 136 append, 137 stealth; 138 139 TimerInfo 140 timer; 141 142 size_t 143 signature; 144 145 MagickLogMethod 146 method; 147 }; 148 149 typedef struct _LogMapInfo 150 { 151 const LogEventType 152 event_mask; 153 154 const LogHandlerType 155 handler_mask; 156 157 const char 158 *filename, 159 *format; 160 } LogMapInfo; 161 162 /* 164 Static declarations. 165 */ 166 static const HandlerInfo 167 LogHandlers[32] = 168 { 169 { "Console", ConsoleHandler }, 170 { "Debug", DebugHandler }, 171 { "Event", EventHandler }, 172 { "File", FileHandler }, 173 { "None", NoHandler }, 174 { "Stderr", StderrHandler }, 175 { "Stdout", StdoutHandler }, 176 { (char *) NULL, UndefinedHandler }, 177 { (char *) NULL, UndefinedHandler }, 178 { (char *) NULL, UndefinedHandler }, 179 { (char *) NULL, UndefinedHandler }, 180 { (char *) NULL, UndefinedHandler }, 181 { (char *) NULL, UndefinedHandler }, 182 { (char *) NULL, UndefinedHandler }, 183 { (char *) NULL, UndefinedHandler }, 184 { (char *) NULL, UndefinedHandler }, 185 { (char *) NULL, UndefinedHandler }, 186 { (char *) NULL, UndefinedHandler }, 187 { (char *) NULL, UndefinedHandler }, 188 { (char *) NULL, UndefinedHandler }, 189 { (char *) NULL, UndefinedHandler }, 190 { (char *) NULL, UndefinedHandler }, 191 { (char *) NULL, UndefinedHandler }, 192 { (char *) NULL, UndefinedHandler }, 193 { (char *) NULL, UndefinedHandler }, 194 { (char *) NULL, UndefinedHandler }, 195 { (char *) NULL, UndefinedHandler }, 196 { (char *) NULL, UndefinedHandler }, 197 { (char *) NULL, UndefinedHandler }, 198 { (char *) NULL, UndefinedHandler }, 199 { (char *) NULL, UndefinedHandler }, 200 { (char *) NULL, UndefinedHandler } 201 }; 202 203 static const LogMapInfo 204 LogMap[] = 205 { 206 { NoEvents, ConsoleHandler, "Magick-%g.log", 207 "%t %r %u %v %d %c[%p]: %m/%f/%l/%d\\n %e" } 208 }; 209 210 static char 211 log_name[MagickPathExtent] = "Magick"; 212 213 static LinkedListInfo 214 *log_cache = (LinkedListInfo *) NULL; 215 216 static MagickBooleanType 217 event_logging = MagickFalse; 218 219 static SemaphoreInfo 220 *event_semaphore = (SemaphoreInfo *) NULL, 221 *log_semaphore = (SemaphoreInfo *) NULL; 222 223 /* 225 Forward declarations. 226 */ 227 static LogHandlerType 228 ParseLogHandlers(const char *) magick_attribute((__pure__)); 229 230 static LogInfo 231 *GetLogInfo(const char *,ExceptionInfo *); 232 233 static MagickBooleanType 234 IsLogCacheInstantiated(ExceptionInfo *) magick_attribute((__pure__)), 235 LoadLogCache(LinkedListInfo *,const char *,const char *,const size_t, 236 ExceptionInfo *); 237 238 /* 240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 241 % % 242 % % 243 % % 244 % A c q u i r e L o g C a c h e % 245 % % 246 % % 247 % % 248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 249 % 250 % AcquireLogCache() caches one or more log configurations which provides a 251 % mapping between log attributes and log name. 252 % 253 % The format of the AcquireLogCache method is: 254 % 255 % LinkedListInfo *AcquireLogCache(const char *filename, 256 % ExceptionInfo *exception) 257 % 258 % A description of each parameter follows: 259 % 260 % o filename: the log configuration filename. 261 % 262 % o exception: return any errors or warnings in this structure. 263 % 264 */ 265 static LinkedListInfo *AcquireLogCache(const char *filename, 266 ExceptionInfo *exception) 267 { 268 LinkedListInfo 269 *cache; 270 271 MagickStatusType 272 status; 273 274 register ssize_t 275 i; 276 277 /* 278 Load external log map. 279 */ 280 cache=NewLinkedList(0); 281 status=MagickTrue; 282 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 283 { 284 const StringInfo 285 *option; 286 287 LinkedListInfo 288 *options; 289 290 options=GetConfigureOptions(filename,exception); 291 option=(const StringInfo *) GetNextValueInLinkedList(options); 292 while (option != (const StringInfo *) NULL) 293 { 294 status&=LoadLogCache(cache,(const char *) GetStringInfoDatum(option), 295 GetStringInfoPath(option),0,exception); 296 option=(const StringInfo *) GetNextValueInLinkedList(options); 297 } 298 options=DestroyConfigureOptions(options); 299 } 300 #endif 301 /* 302 Load built-in log map. 303 */ 304 for (i=0; i < (ssize_t) (sizeof(LogMap)/sizeof(*LogMap)); i++) 305 { 306 LogInfo 307 *log_info; 308 309 register const LogMapInfo 310 *p; 311 312 p=LogMap+i; 313 log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info)); 314 if (log_info == (LogInfo *) NULL) 315 { 316 (void) ThrowMagickException(exception,GetMagickModule(), 317 ResourceLimitError,"MemoryAllocationFailed","`%s'",p->filename); 318 continue; 319 } 320 (void) memset(log_info,0,sizeof(*log_info)); 321 log_info->path=ConstantString("[built-in]"); 322 GetTimerInfo((TimerInfo *) &log_info->timer); 323 log_info->event_mask=p->event_mask; 324 log_info->handler_mask=p->handler_mask; 325 log_info->filename=ConstantString(p->filename); 326 log_info->format=ConstantString(p->format); 327 log_info->signature=MagickCoreSignature; 328 status&=AppendValueToLinkedList(cache,log_info); 329 if (status == MagickFalse) 330 (void) ThrowMagickException(exception,GetMagickModule(), 331 ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name); 332 } 333 return(cache); 334 } 335 336 /* 338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 339 % % 340 % % 341 % % 342 % C l o s e M a g i c k L o g % 343 % % 344 % % 345 % % 346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 347 % 348 % CloseMagickLog() closes the Magick log. 349 % 350 % The format of the CloseMagickLog method is: 351 % 352 % CloseMagickLog(void) 353 % 354 */ 355 MagickExport void CloseMagickLog(void) 356 { 357 ExceptionInfo 358 *exception; 359 360 LogInfo 361 *log_info; 362 363 if (IsEventLogging() == MagickFalse) 364 return; 365 exception=AcquireExceptionInfo(); 366 log_info=GetLogInfo("*",exception); 367 exception=DestroyExceptionInfo(exception); 368 LockSemaphoreInfo(log_semaphore); 369 if (log_info->file != (FILE *) NULL) 370 { 371 (void) FormatLocaleFile(log_info->file,"</log>\n"); 372 (void) fclose(log_info->file); 373 log_info->file=(FILE *) NULL; 374 } 375 UnlockSemaphoreInfo(log_semaphore); 376 } 377 378 /* 380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 381 % % 382 % % 383 % % 384 + G e t L o g I n f o % 385 % % 386 % % 387 % % 388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 389 % 390 % GetLogInfo() searches the log list for the specified name and if found 391 % returns attributes for that log. 392 % 393 % The format of the GetLogInfo method is: 394 % 395 % LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception) 396 % 397 % A description of each parameter follows: 398 % 399 % o name: the log name. 400 % 401 % o exception: return any errors or warnings in this structure. 402 % 403 */ 404 static LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception) 405 { 406 register LogInfo 407 *p; 408 409 assert(exception != (ExceptionInfo *) NULL); 410 if (IsLogCacheInstantiated(exception) == MagickFalse) 411 return((LogInfo *) NULL); 412 /* 413 Search for log tag. 414 */ 415 LockSemaphoreInfo(log_semaphore); 416 ResetLinkedListIterator(log_cache); 417 p=(LogInfo *) GetNextValueInLinkedList(log_cache); 418 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0)) 419 { 420 UnlockSemaphoreInfo(log_semaphore); 421 return(p); 422 } 423 while (p != (LogInfo *) NULL) 424 { 425 if (LocaleCompare(name,p->name) == 0) 426 break; 427 p=(LogInfo *) GetNextValueInLinkedList(log_cache); 428 } 429 if (p != (LogInfo *) NULL) 430 (void) InsertValueInLinkedList(log_cache,0, 431 RemoveElementByValueFromLinkedList(log_cache,p)); 432 UnlockSemaphoreInfo(log_semaphore); 433 return(p); 434 } 435 436 /* 438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 439 % % 440 % % 441 % % 442 % G e t L o g I n f o L i s t % 443 % % 444 % % 445 % % 446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 447 % 448 % GetLogInfoList() returns any logs that match the specified pattern. 449 % 450 % The format of the GetLogInfoList function is: 451 % 452 % const LogInfo **GetLogInfoList(const char *pattern, 453 % size_t *number_preferences,ExceptionInfo *exception) 454 % 455 % A description of each parameter follows: 456 % 457 % o pattern: Specifies a pointer to a text string containing a pattern. 458 % 459 % o number_preferences: This integer returns the number of logs in the list. 460 % 461 % o exception: return any errors or warnings in this structure. 462 % 463 */ 464 #if defined(__cplusplus) || defined(c_plusplus) 465 extern "C" { 466 #endif 467 468 static int LogInfoCompare(const void *x,const void *y) 469 { 470 const LogInfo 471 **p, 472 **q; 473 474 p=(const LogInfo **) x, 475 q=(const LogInfo **) y; 476 if (LocaleCompare((*p)->path,(*q)->path) == 0) 477 return(LocaleCompare((*p)->name,(*q)->name)); 478 return(LocaleCompare((*p)->path,(*q)->path)); 479 } 480 481 #if defined(__cplusplus) || defined(c_plusplus) 482 } 483 #endif 484 485 MagickExport const LogInfo **GetLogInfoList(const char *pattern, 486 size_t *number_preferences,ExceptionInfo *exception) 487 { 488 const LogInfo 489 **preferences; 490 491 register const LogInfo 492 *p; 493 494 register ssize_t 495 i; 496 497 /* 498 Allocate log list. 499 */ 500 assert(pattern != (char *) NULL); 501 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern); 502 assert(number_preferences != (size_t *) NULL); 503 *number_preferences=0; 504 p=GetLogInfo("*",exception); 505 if (p == (const LogInfo *) NULL) 506 return((const LogInfo **) NULL); 507 preferences=(const LogInfo **) AcquireQuantumMemory((size_t) 508 GetNumberOfElementsInLinkedList(log_cache)+1UL,sizeof(*preferences)); 509 if (preferences == (const LogInfo **) NULL) 510 return((const LogInfo **) NULL); 511 /* 512 Generate log list. 513 */ 514 LockSemaphoreInfo(log_semaphore); 515 ResetLinkedListIterator(log_cache); 516 p=(const LogInfo *) GetNextValueInLinkedList(log_cache); 517 for (i=0; p != (const LogInfo *) NULL; ) 518 { 519 if ((p->stealth == MagickFalse) && 520 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse)) 521 preferences[i++]=p; 522 p=(const LogInfo *) GetNextValueInLinkedList(log_cache); 523 } 524 UnlockSemaphoreInfo(log_semaphore); 525 qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogInfoCompare); 526 preferences[i]=(LogInfo *) NULL; 527 *number_preferences=(size_t) i; 528 return(preferences); 529 } 530 531 /* 533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 534 % % 535 % % 536 % % 537 % G e t L o g L i s t % 538 % % 539 % % 540 % % 541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 542 % 543 % GetLogList() returns any logs that match the specified pattern. 544 % 545 % The format of the GetLogList function is: 546 % 547 % char **GetLogList(const char *pattern,size_t *number_preferences, 548 % ExceptionInfo *exception) 549 % 550 % A description of each parameter follows: 551 % 552 % o pattern: Specifies a pointer to a text string containing a pattern. 553 % 554 % o number_preferences: This integer returns the number of logs in the list. 555 % 556 % o exception: return any errors or warnings in this structure. 557 % 558 */ 559 560 #if defined(__cplusplus) || defined(c_plusplus) 561 extern "C" { 562 #endif 563 564 static int LogCompare(const void *x,const void *y) 565 { 566 register const char 567 **p, 568 **q; 569 570 p=(const char **) x; 571 q=(const char **) y; 572 return(LocaleCompare(*p,*q)); 573 } 574 575 #if defined(__cplusplus) || defined(c_plusplus) 576 } 577 #endif 578 579 MagickExport char **GetLogList(const char *pattern,size_t *number_preferences, 580 ExceptionInfo *exception) 581 { 582 char 583 **preferences; 584 585 register const LogInfo 586 *p; 587 588 register ssize_t 589 i; 590 591 /* 592 Allocate log list. 593 */ 594 assert(pattern != (char *) NULL); 595 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern); 596 assert(number_preferences != (size_t *) NULL); 597 *number_preferences=0; 598 p=GetLogInfo("*",exception); 599 if (p == (const LogInfo *) NULL) 600 return((char **) NULL); 601 preferences=(char **) AcquireQuantumMemory((size_t) 602 GetNumberOfElementsInLinkedList(log_cache)+1UL,sizeof(*preferences)); 603 if (preferences == (char **) NULL) 604 return((char **) NULL); 605 /* 606 Generate log list. 607 */ 608 LockSemaphoreInfo(log_semaphore); 609 ResetLinkedListIterator(log_cache); 610 p=(const LogInfo *) GetNextValueInLinkedList(log_cache); 611 for (i=0; p != (const LogInfo *) NULL; ) 612 { 613 if ((p->stealth == MagickFalse) && 614 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse)) 615 preferences[i++]=ConstantString(p->name); 616 p=(const LogInfo *) GetNextValueInLinkedList(log_cache); 617 } 618 UnlockSemaphoreInfo(log_semaphore); 619 qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogCompare); 620 preferences[i]=(char *) NULL; 621 *number_preferences=(size_t) i; 622 return(preferences); 623 } 624 625 /* 627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 628 % % 629 % % 630 % % 631 % G e t L o g N a m e % 632 % % 633 % % 634 % % 635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 636 % 637 % GetLogName() returns the current log name. 638 % 639 % The format of the GetLogName method is: 640 % 641 % const char *GetLogName(void) 642 % 643 */ 644 MagickExport const char *GetLogName(void) 645 { 646 return(log_name); 647 } 648 649 /* 651 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 652 % % 653 % % 654 % % 655 + I s L o g C a c h e I n s t a n t i a t e d % 656 % % 657 % % 658 % % 659 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 660 % 661 % IsLogCacheInstantiated() determines if the log list is instantiated. If 662 % not, it instantiates the list and returns it. 663 % 664 % The format of the IsLogInstantiated method is: 665 % 666 % MagickBooleanType IsLogCacheInstantiated(ExceptionInfo *exception) 667 % 668 % A description of each parameter follows. 669 % 670 % o exception: return any errors or warnings in this structure. 671 % 672 */ 673 674 static inline void CheckEventLogging() 675 { 676 /* 677 Are we logging events? 678 */ 679 if (IsLinkedListEmpty(log_cache) != MagickFalse) 680 event_logging=MagickFalse; 681 else 682 { 683 LogInfo 684 *p; 685 686 ResetLinkedListIterator(log_cache); 687 p=(LogInfo *) GetNextValueInLinkedList(log_cache); 688 event_logging=(p != (LogInfo *) NULL) && (p->event_mask != NoEvents) ? 689 MagickTrue: MagickFalse; 690 } 691 } 692 693 static MagickBooleanType IsLogCacheInstantiated(ExceptionInfo *exception) 694 { 695 if (log_cache == (LinkedListInfo *) NULL) 696 { 697 if (log_semaphore == (SemaphoreInfo *) NULL) 698 ActivateSemaphoreInfo(&log_semaphore); 699 LockSemaphoreInfo(log_semaphore); 700 if (log_cache == (LinkedListInfo *) NULL) 701 { 702 log_cache=AcquireLogCache(LogFilename,exception); 703 CheckEventLogging(); 704 } 705 UnlockSemaphoreInfo(log_semaphore); 706 } 707 return(log_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse); 708 } 709 710 /* 712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 713 % % 714 % % 715 % % 716 % I s E v e n t L o g g i n g % 717 % % 718 % % 719 % % 720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 721 % 722 % IsEventLogging() returns MagickTrue if debug of events is enabled otherwise 723 % MagickFalse. 724 % 725 % The format of the IsEventLogging method is: 726 % 727 % MagickBooleanType IsEventLogging(void) 728 % 729 */ 730 MagickExport MagickBooleanType IsEventLogging(void) 731 { 732 return(event_logging); 733 } 734 735 /* 737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 738 % % 739 % % 740 % % 741 % L i s t L o g I n f o % 742 % % 743 % % 744 % % 745 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 746 % 747 % ListLogInfo() lists the log info to a file. 748 % 749 % The format of the ListLogInfo method is: 750 % 751 % MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception) 752 % 753 % A description of each parameter follows. 754 % 755 % o file: An pointer to a FILE. 756 % 757 % o exception: return any errors or warnings in this structure. 758 % 759 */ 760 MagickExport MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception) 761 { 762 #define MegabytesToBytes(value) ((MagickSizeType) (value)*1024*1024) 763 764 const char 765 *path; 766 767 const LogInfo 768 **log_info; 769 770 register ssize_t 771 i; 772 773 size_t 774 number_aliases; 775 776 ssize_t 777 j; 778 779 if (file == (const FILE *) NULL) 780 file=stdout; 781 log_info=GetLogInfoList("*",&number_aliases,exception); 782 if (log_info == (const LogInfo **) NULL) 783 return(MagickFalse); 784 j=0; 785 path=(const char *) NULL; 786 for (i=0; i < (ssize_t) number_aliases; i++) 787 { 788 if (log_info[i]->stealth != MagickFalse) 789 continue; 790 if ((path == (const char *) NULL) || 791 (LocaleCompare(path,log_info[i]->path) != 0)) 792 { 793 size_t 794 length; 795 796 if (log_info[i]->path != (char *) NULL) 797 (void) FormatLocaleFile(file,"\nPath: %s\n\n",log_info[i]->path); 798 length=0; 799 for (j=0; j < (ssize_t) (8*sizeof(LogHandlerType)); j++) 800 { 801 size_t 802 mask; 803 804 if (LogHandlers[j].name == (const char *) NULL) 805 break; 806 mask=1; 807 mask<<=j; 808 if ((log_info[i]->handler_mask & mask) != 0) 809 { 810 (void) FormatLocaleFile(file,"%s ",LogHandlers[j].name); 811 length+=strlen(LogHandlers[j].name); 812 } 813 } 814 for (j=(ssize_t) length; j <= 12; j++) 815 (void) FormatLocaleFile(file," "); 816 (void) FormatLocaleFile(file," Generations Limit Format\n"); 817 (void) FormatLocaleFile(file,"-----------------------------------------" 818 "--------------------------------------\n"); 819 } 820 path=log_info[i]->path; 821 if (log_info[i]->filename != (char *) NULL) 822 { 823 (void) FormatLocaleFile(file,"%s",log_info[i]->filename); 824 for (j=(ssize_t) strlen(log_info[i]->filename); j <= 16; j++) 825 (void) FormatLocaleFile(file," "); 826 } 827 (void) FormatLocaleFile(file,"%9g ",(double) log_info[i]->generations); 828 (void) FormatLocaleFile(file,"%8g ",(double) log_info[i]->limit); 829 if (log_info[i]->format != (char *) NULL) 830 (void) FormatLocaleFile(file,"%s",log_info[i]->format); 831 (void) FormatLocaleFile(file,"\n"); 832 } 833 (void) fflush(file); 834 log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info); 835 return(MagickTrue); 836 } 837 838 /* 840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 841 % % 842 % % 843 % % 844 + L o g C o m p o n e n t G e n e s i s % 845 % % 846 % % 847 % % 848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 849 % 850 % LogComponentGenesis() instantiates the log component. 851 % 852 % The format of the LogComponentGenesis method is: 853 % 854 % MagickBooleanType LogComponentGenesis(void) 855 % 856 */ 857 MagickPrivate MagickBooleanType LogComponentGenesis(void) 858 { 859 ExceptionInfo 860 *exception; 861 862 if (log_semaphore == (SemaphoreInfo *) NULL) 863 log_semaphore=AcquireSemaphoreInfo(); 864 exception=AcquireExceptionInfo(); 865 (void) GetLogInfo("*",exception); 866 exception=DestroyExceptionInfo(exception); 867 event_semaphore=AcquireSemaphoreInfo(); 868 return(MagickTrue); 869 } 870 871 /* 873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 874 % % 875 % % 876 % % 877 + L o g C o m p o n e n t T e r m i n u s % 878 % % 879 % % 880 % % 881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 882 % 883 % LogComponentTerminus() destroys the logging component. 884 % 885 % The format of the LogComponentTerminus method is: 886 % 887 % LogComponentTerminus(void) 888 % 889 */ 890 891 static void *DestroyLogElement(void *log_info) 892 { 893 register LogInfo 894 *p; 895 896 p=(LogInfo *) log_info; 897 if (p->file != (FILE *) NULL) 898 { 899 (void) FormatLocaleFile(p->file,"</log>\n"); 900 (void) fclose(p->file); 901 p->file=(FILE *) NULL; 902 } 903 if (p->format != (char *) NULL) 904 p->format=DestroyString(p->format); 905 if (p->path != (char *) NULL) 906 p->path=DestroyString(p->path); 907 if (p->filename != (char *) NULL) 908 p->filename=DestroyString(p->filename); 909 p=(LogInfo *) RelinquishMagickMemory(p); 910 return((void *) NULL); 911 } 912 913 MagickPrivate void LogComponentTerminus(void) 914 { 915 if (event_semaphore == (SemaphoreInfo *) NULL) 916 ActivateSemaphoreInfo(&event_semaphore); 917 LockSemaphoreInfo(event_semaphore); 918 UnlockSemaphoreInfo(event_semaphore); 919 RelinquishSemaphoreInfo(&event_semaphore); 920 if (log_semaphore == (SemaphoreInfo *) NULL) 921 ActivateSemaphoreInfo(&log_semaphore); 922 LockSemaphoreInfo(log_semaphore); 923 if (log_cache != (LinkedListInfo *) NULL) 924 log_cache=DestroyLinkedList(log_cache,DestroyLogElement); 925 event_logging=MagickFalse; 926 UnlockSemaphoreInfo(log_semaphore); 927 RelinquishSemaphoreInfo(&log_semaphore); 928 } 929 930 /* 932 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 933 % % 934 % % 935 % % 936 % L o g M a g i c k E v e n t % 937 % % 938 % % 939 % % 940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 941 % 942 % LogMagickEvent() logs an event as determined by the log configuration file. 943 % If an error occurs, MagickFalse is returned otherwise MagickTrue. 944 % 945 % The format of the LogMagickEvent method is: 946 % 947 % MagickBooleanType LogMagickEvent(const LogEventType type, 948 % const char *module,const char *function,const size_t line, 949 % const char *format,...) 950 % 951 % A description of each parameter follows: 952 % 953 % o type: the event type. 954 % 955 % o filename: the source module filename. 956 % 957 % o function: the function name. 958 % 959 % o line: the line number of the source module. 960 % 961 % o format: the output format. 962 % 963 */ 964 static char *TranslateEvent(const char *module,const char *function, 965 const size_t line,const char *domain,const char *event) 966 { 967 char 968 *text; 969 970 double 971 elapsed_time, 972 user_time; 973 974 ExceptionInfo 975 *exception; 976 977 LogInfo 978 *log_info; 979 980 register char 981 *q; 982 983 register const char 984 *p; 985 986 size_t 987 extent; 988 989 time_t 990 seconds; 991 992 exception=AcquireExceptionInfo(); 993 log_info=(LogInfo *) GetLogInfo("*",exception); 994 exception=DestroyExceptionInfo(exception); 995 seconds=time((time_t *) NULL); 996 elapsed_time=GetElapsedTime(&log_info->timer); 997 user_time=GetUserTime(&log_info->timer); 998 text=AcquireString(event); 999 if (log_info->format == (char *) NULL) 1000 return(text); 1001 extent=strlen(event)+MagickPathExtent; 1002 if (LocaleCompare(log_info->format,"xml") == 0) 1003 { 1004 char 1005 timestamp[MagickPathExtent]; 1006 1007 /* 1008 Translate event in "XML" format. 1009 */ 1010 (void) FormatMagickTime(seconds,extent,timestamp); 1011 (void) FormatLocaleString(text,extent, 1012 "<entry>\n" 1013 " <timestamp>%s</timestamp>\n" 1014 " <elapsed-time>%lu:%02lu.%03lu</elapsed-time>\n" 1015 " <user-time>%0.3f</user-time>\n" 1016 " <process-id>%.20g</process-id>\n" 1017 " <thread-id>%.20g</thread-id>\n" 1018 " <module>%s</module>\n" 1019 " <function>%s</function>\n" 1020 " <line>%.20g</line>\n" 1021 " <domain>%s</domain>\n" 1022 " <event>%s</event>\n" 1023 "</entry>",timestamp,(unsigned long) (elapsed_time/60.0), 1024 (unsigned long) floor(fmod(elapsed_time,60.0)),(unsigned long) 1025 (1000.0*(elapsed_time-floor(elapsed_time))+0.5),user_time, 1026 (double) getpid(),(double) GetMagickThreadSignature(),module,function, 1027 (double) line,domain,event); 1028 return(text); 1029 } 1030 /* 1031 Translate event in "human readable" format. 1032 */ 1033 q=text; 1034 for (p=log_info->format; *p != '\0'; p++) 1035 { 1036 *q='\0'; 1037 if ((size_t) (q-text+MagickPathExtent) >= extent) 1038 { 1039 extent+=MagickPathExtent; 1040 text=(char *) ResizeQuantumMemory(text,extent+MagickPathExtent, 1041 sizeof(*text)); 1042 if (text == (char *) NULL) 1043 return((char *) NULL); 1044 q=text+strlen(text); 1045 } 1046 /* 1047 The format of the log is defined by embedding special format characters: 1048 1049 %c client name 1050 %d domain 1051 %e event 1052 %f function 1053 %g generation 1054 %l line 1055 %m module 1056 %n log name 1057 %p process id 1058 %r real CPU time 1059 %t wall clock time 1060 %u user CPU time 1061 %v version 1062 %% percent sign 1063 \n newline 1064 \r carriage return 1065 */ 1066 if ((*p == '\\') && (*(p+1) == 'r')) 1067 { 1068 *q++='\r'; 1069 p++; 1070 continue; 1071 } 1072 if ((*p == '\\') && (*(p+1) == 'n')) 1073 { 1074 *q++='\n'; 1075 p++; 1076 continue; 1077 } 1078 if (*p != '%') 1079 { 1080 *q++=(*p); 1081 continue; 1082 } 1083 p++; 1084 switch (*p) 1085 { 1086 case 'c': 1087 { 1088 q+=CopyMagickString(q,GetClientName(),extent); 1089 break; 1090 } 1091 case 'd': 1092 { 1093 q+=CopyMagickString(q,domain,extent); 1094 break; 1095 } 1096 case 'e': 1097 { 1098 q+=CopyMagickString(q,event,extent); 1099 break; 1100 } 1101 case 'f': 1102 { 1103 q+=CopyMagickString(q,function,extent); 1104 break; 1105 } 1106 case 'g': 1107 { 1108 if (log_info->generations == 0) 1109 { 1110 (void) CopyMagickString(q,"0",extent); 1111 q++; 1112 break; 1113 } 1114 q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation % 1115 log_info->generations)); 1116 break; 1117 } 1118 case 'l': 1119 { 1120 q+=FormatLocaleString(q,extent,"%.20g",(double) line); 1121 break; 1122 } 1123 case 'm': 1124 { 1125 register const char 1126 *r; 1127 1128 for (r=module+strlen(module)-1; r > module; r--) 1129 if (*r == *DirectorySeparator) 1130 { 1131 r++; 1132 break; 1133 } 1134 q+=CopyMagickString(q,r,extent); 1135 break; 1136 } 1137 case 'n': 1138 { 1139 q+=CopyMagickString(q,GetLogName(),extent); 1140 break; 1141 } 1142 case 'p': 1143 { 1144 q+=FormatLocaleString(q,extent,"%.20g",(double) getpid()); 1145 break; 1146 } 1147 case 'r': 1148 { 1149 q+=FormatLocaleString(q,extent,"%lu:%02lu.%03lu",(unsigned long) 1150 (elapsed_time/60.0),(unsigned long) floor(fmod(elapsed_time,60.0)), 1151 (unsigned long) (1000.0*(elapsed_time-floor(elapsed_time))+0.5)); 1152 break; 1153 } 1154 case 't': 1155 { 1156 q+=FormatMagickTime(seconds,extent,q); 1157 break; 1158 } 1159 case 'u': 1160 { 1161 q+=FormatLocaleString(q,extent,"%0.3fu",user_time); 1162 break; 1163 } 1164 case 'v': 1165 { 1166 q+=CopyMagickString(q,MagickLibVersionText,extent); 1167 break; 1168 } 1169 case '%': 1170 { 1171 *q++=(*p); 1172 break; 1173 } 1174 default: 1175 { 1176 *q++='%'; 1177 *q++=(*p); 1178 break; 1179 } 1180 } 1181 } 1182 *q='\0'; 1183 return(text); 1184 } 1185 1186 static char *TranslateFilename(const LogInfo *log_info) 1187 { 1188 char 1189 *filename; 1190 1191 register char 1192 *q; 1193 1194 register const char 1195 *p; 1196 1197 size_t 1198 extent; 1199 1200 /* 1201 Translate event in "human readable" format. 1202 */ 1203 assert(log_info != (LogInfo *) NULL); 1204 assert(log_info->filename != (char *) NULL); 1205 filename=AcquireString((char *) NULL); 1206 extent=MagickPathExtent; 1207 q=filename; 1208 for (p=log_info->filename; *p != '\0'; p++) 1209 { 1210 *q='\0'; 1211 if ((size_t) (q-filename+MagickPathExtent) >= extent) 1212 { 1213 extent+=MagickPathExtent; 1214 filename=(char *) ResizeQuantumMemory(filename,extent+MagickPathExtent, 1215 sizeof(*filename)); 1216 if (filename == (char *) NULL) 1217 return((char *) NULL); 1218 q=filename+strlen(filename); 1219 } 1220 /* 1221 The format of the filename is defined by embedding special format 1222 characters: 1223 1224 %c client name 1225 %n log name 1226 %p process id 1227 %v version 1228 %% percent sign 1229 */ 1230 if (*p != '%') 1231 { 1232 *q++=(*p); 1233 continue; 1234 } 1235 p++; 1236 switch (*p) 1237 { 1238 case 'c': 1239 { 1240 q+=CopyMagickString(q,GetClientName(),extent); 1241 break; 1242 } 1243 case 'g': 1244 { 1245 if (log_info->generations == 0) 1246 { 1247 (void) CopyMagickString(q,"0",extent); 1248 q++; 1249 break; 1250 } 1251 q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation % 1252 log_info->generations)); 1253 break; 1254 } 1255 case 'n': 1256 { 1257 q+=CopyMagickString(q,GetLogName(),extent); 1258 break; 1259 } 1260 case 'p': 1261 { 1262 q+=FormatLocaleString(q,extent,"%.20g",(double) getpid()); 1263 break; 1264 } 1265 case 'v': 1266 { 1267 q+=CopyMagickString(q,MagickLibVersionText,extent); 1268 break; 1269 } 1270 case '%': 1271 { 1272 *q++=(*p); 1273 break; 1274 } 1275 default: 1276 { 1277 *q++='%'; 1278 *q++=(*p); 1279 break; 1280 } 1281 } 1282 } 1283 *q='\0'; 1284 return(filename); 1285 } 1286 1287 MagickExport MagickBooleanType LogMagickEventList(const LogEventType type, 1288 const char *module,const char *function,const size_t line,const char *format, 1289 va_list operands) 1290 { 1291 char 1292 event[MagickPathExtent], 1293 *text; 1294 1295 const char 1296 *domain; 1297 1298 ExceptionInfo 1299 *exception; 1300 1301 int 1302 n; 1303 1304 LogInfo 1305 *log_info; 1306 1307 exception=AcquireExceptionInfo(); 1308 log_info=(LogInfo *) GetLogInfo("*",exception); 1309 exception=DestroyExceptionInfo(exception); 1310 if (event_semaphore == (SemaphoreInfo *) NULL) 1311 ActivateSemaphoreInfo(&event_semaphore); 1312 LockSemaphoreInfo(event_semaphore); 1313 if ((log_info->event_mask & type) == 0) 1314 { 1315 UnlockSemaphoreInfo(event_semaphore); 1316 return(MagickTrue); 1317 } 1318 domain=CommandOptionToMnemonic(MagickLogEventOptions,type); 1319 #if defined(MAGICKCORE_HAVE_VSNPRINTF) 1320 n=vsnprintf(event,MagickPathExtent,format,operands); 1321 #else 1322 n=vsprintf(event,format,operands); 1323 #endif 1324 if (n < 0) 1325 event[MagickPathExtent-1]='\0'; 1326 text=TranslateEvent(module,function,line,domain,event); 1327 if (text == (char *) NULL) 1328 { 1329 (void) ContinueTimer((TimerInfo *) &log_info->timer); 1330 UnlockSemaphoreInfo(event_semaphore); 1331 return(MagickFalse); 1332 } 1333 if ((log_info->handler_mask & ConsoleHandler) != 0) 1334 { 1335 (void) FormatLocaleFile(stderr,"%s\n",text); 1336 (void) fflush(stderr); 1337 } 1338 if ((log_info->handler_mask & DebugHandler) != 0) 1339 { 1340 #if defined(MAGICKCORE_WINDOWS_SUPPORT) 1341 OutputDebugString(text); 1342 OutputDebugString("\n"); 1343 #endif 1344 } 1345 if ((log_info->handler_mask & EventHandler) != 0) 1346 { 1347 #if defined(MAGICKCORE_WINDOWS_SUPPORT) 1348 (void) NTReportEvent(text,MagickFalse); 1349 #endif 1350 } 1351 if ((log_info->handler_mask & FileHandler) != 0) 1352 { 1353 struct stat 1354 file_info; 1355 1356 file_info.st_size=0; 1357 if (log_info->file != (FILE *) NULL) 1358 (void) fstat(fileno(log_info->file),&file_info); 1359 if (file_info.st_size > (ssize_t) (1024*1024*log_info->limit)) 1360 { 1361 (void) FormatLocaleFile(log_info->file,"</log>\n"); 1362 (void) fclose(log_info->file); 1363 log_info->file=(FILE *) NULL; 1364 } 1365 if (log_info->file == (FILE *) NULL) 1366 { 1367 char 1368 *filename; 1369 1370 filename=TranslateFilename(log_info); 1371 if (filename == (char *) NULL) 1372 { 1373 (void) ContinueTimer((TimerInfo *) &log_info->timer); 1374 UnlockSemaphoreInfo(event_semaphore); 1375 return(MagickFalse); 1376 } 1377 log_info->append=IsPathAccessible(filename); 1378 log_info->file=fopen_utf8(filename,"ab"); 1379 filename=(char *) RelinquishMagickMemory(filename); 1380 if (log_info->file == (FILE *) NULL) 1381 { 1382 UnlockSemaphoreInfo(event_semaphore); 1383 return(MagickFalse); 1384 } 1385 log_info->generation++; 1386 if (log_info->append == MagickFalse) 1387 (void) FormatLocaleFile(log_info->file,"<?xml version=\"1.0\" " 1388 "encoding=\"UTF-8\" standalone=\"yes\"?>\n"); 1389 (void) FormatLocaleFile(log_info->file,"<log>\n"); 1390 } 1391 (void) FormatLocaleFile(log_info->file," <event>%s</event>\n",text); 1392 (void) fflush(log_info->file); 1393 } 1394 if ((log_info->handler_mask & MethodHandler) != 0) 1395 { 1396 if (log_info->method != (MagickLogMethod) NULL) 1397 log_info->method(type,text); 1398 } 1399 if ((log_info->handler_mask & StdoutHandler) != 0) 1400 { 1401 (void) FormatLocaleFile(stdout,"%s\n",text); 1402 (void) fflush(stdout); 1403 } 1404 if ((log_info->handler_mask & StderrHandler) != 0) 1405 { 1406 (void) FormatLocaleFile(stderr,"%s\n",text); 1407 (void) fflush(stderr); 1408 } 1409 text=(char *) RelinquishMagickMemory(text); 1410 (void) ContinueTimer((TimerInfo *) &log_info->timer); 1411 UnlockSemaphoreInfo(event_semaphore); 1412 return(MagickTrue); 1413 } 1414 1415 MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, 1416 const char *module,const char *function,const size_t line, 1417 const char *format,...) 1418 { 1419 va_list 1420 operands; 1421 1422 MagickBooleanType 1423 status; 1424 1425 if (IsEventLogging() == MagickFalse) 1426 return(MagickFalse); 1427 va_start(operands,format); 1428 status=LogMagickEventList(type,module,function,line,format,operands); 1429 va_end(operands); 1430 return(status); 1431 } 1432 1433 /* 1435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1436 % % 1437 % % 1438 % % 1439 + L o a d L o g C a c h e % 1440 % % 1441 % % 1442 % % 1443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1444 % 1445 % LoadLogCache() loads the log configurations which provides a 1446 % mapping between log attributes and log name. 1447 % 1448 % The format of the LoadLogCache method is: 1449 % 1450 % MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml, 1451 % const char *filename,const size_t depth,ExceptionInfo *exception) 1452 % 1453 % A description of each parameter follows: 1454 % 1455 % o xml: The log list in XML format. 1456 % 1457 % o filename: The log list filename. 1458 % 1459 % o depth: depth of <include /> statements. 1460 % 1461 % o exception: return any errors or warnings in this structure. 1462 % 1463 */ 1464 static MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml, 1465 const char *filename,const size_t depth,ExceptionInfo *exception) 1466 { 1467 char 1468 keyword[MagickPathExtent], 1469 *token; 1470 1471 const char 1472 *q; 1473 1474 LogInfo 1475 *log_info = (LogInfo *) NULL; 1476 1477 MagickStatusType 1478 status; 1479 1480 size_t 1481 extent; 1482 1483 /* 1484 Load the log map file. 1485 */ 1486 if (xml == (const char *) NULL) 1487 return(MagickFalse); 1488 status=MagickTrue; 1489 token=AcquireString(xml); 1490 extent=strlen(token)+MagickPathExtent; 1491 for (q=(const char *) xml; *q != '\0'; ) 1492 { 1493 /* 1494 Interpret XML. 1495 */ 1496 GetNextToken(q,&q,extent,token); 1497 if (*token == '\0') 1498 break; 1499 (void) CopyMagickString(keyword,token,MagickPathExtent); 1500 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0) 1501 { 1502 /* 1503 Doctype element. 1504 */ 1505 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0')) 1506 GetNextToken(q,&q,extent,token); 1507 continue; 1508 } 1509 if (LocaleNCompare(keyword,"<!--",4) == 0) 1510 { 1511 /* 1512 Comment element. 1513 */ 1514 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0')) 1515 GetNextToken(q,&q,extent,token); 1516 continue; 1517 } 1518 if (LocaleCompare(keyword,"<include") == 0) 1519 { 1520 /* 1521 Include element. 1522 */ 1523 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0')) 1524 { 1525 (void) CopyMagickString(keyword,token,MagickPathExtent); 1526 GetNextToken(q,&q,extent,token); 1527 if (*token != '=') 1528 continue; 1529 GetNextToken(q,&q,extent,token); 1530 if (LocaleCompare(keyword,"file") == 0) 1531 { 1532 if (depth > MagickMaxRecursionDepth) 1533 (void) ThrowMagickException(exception,GetMagickModule(), 1534 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token); 1535 else 1536 { 1537 char 1538 path[MagickPathExtent], 1539 *file_xml; 1540 1541 GetPathComponent(filename,HeadPath,path); 1542 if (*path != '\0') 1543 (void) ConcatenateMagickString(path,DirectorySeparator, 1544 MagickPathExtent); 1545 if (*token == *DirectorySeparator) 1546 (void) CopyMagickString(path,token,MagickPathExtent); 1547 else 1548 (void) ConcatenateMagickString(path,token,MagickPathExtent); 1549 file_xml=FileToXML(path,~0UL); 1550 if (file_xml != (char *) NULL) 1551 { 1552 status&=LoadLogCache(cache,file_xml,path,depth+1, 1553 exception); 1554 file_xml=DestroyString(file_xml); 1555 } 1556 } 1557 } 1558 } 1559 continue; 1560 } 1561 if (LocaleCompare(keyword,"<logmap>") == 0) 1562 { 1563 /* 1564 Allocate memory for the log list. 1565 */ 1566 log_info=(LogInfo *) AcquireCriticalMemory(sizeof(*log_info)); 1567 (void) memset(log_info,0,sizeof(*log_info)); 1568 log_info->path=ConstantString(filename); 1569 GetTimerInfo((TimerInfo *) &log_info->timer); 1570 log_info->signature=MagickCoreSignature; 1571 continue; 1572 } 1573 if (log_info == (LogInfo *) NULL) 1574 continue; 1575 if (LocaleCompare(keyword,"</logmap>") == 0) 1576 { 1577 status=AppendValueToLinkedList(cache,log_info); 1578 if (status == MagickFalse) 1579 (void) ThrowMagickException(exception,GetMagickModule(), 1580 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename); 1581 log_info=(LogInfo *) NULL; 1582 continue; 1583 } 1584 GetNextToken(q,(const char **) NULL,extent,token); 1585 if (*token != '=') 1586 continue; 1587 GetNextToken(q,&q,extent,token); 1588 GetNextToken(q,&q,extent,token); 1589 switch (*keyword) 1590 { 1591 case 'E': 1592 case 'e': 1593 { 1594 if (LocaleCompare((char *) keyword,"events") == 0) 1595 { 1596 log_info->event_mask=(LogEventType) (log_info->event_mask | 1597 ParseCommandOption(MagickLogEventOptions,MagickTrue,token)); 1598 break; 1599 } 1600 break; 1601 } 1602 case 'F': 1603 case 'f': 1604 { 1605 if (LocaleCompare((char *) keyword,"filename") == 0) 1606 { 1607 if (log_info->filename != (char *) NULL) 1608 log_info->filename=(char *) 1609 RelinquishMagickMemory(log_info->filename); 1610 log_info->filename=ConstantString(token); 1611 break; 1612 } 1613 if (LocaleCompare((char *) keyword,"format") == 0) 1614 { 1615 if (log_info->format != (char *) NULL) 1616 log_info->format=(char *) 1617 RelinquishMagickMemory(log_info->format); 1618 log_info->format=ConstantString(token); 1619 break; 1620 } 1621 break; 1622 } 1623 case 'G': 1624 case 'g': 1625 { 1626 if (LocaleCompare((char *) keyword,"generations") == 0) 1627 { 1628 if (LocaleCompare(token,"unlimited") == 0) 1629 { 1630 log_info->generations=(~0UL); 1631 break; 1632 } 1633 log_info->generations=StringToUnsignedLong(token); 1634 break; 1635 } 1636 break; 1637 } 1638 case 'L': 1639 case 'l': 1640 { 1641 if (LocaleCompare((char *) keyword,"limit") == 0) 1642 { 1643 if (LocaleCompare(token,"unlimited") == 0) 1644 { 1645 log_info->limit=(~0UL); 1646 break; 1647 } 1648 log_info->limit=StringToUnsignedLong(token); 1649 break; 1650 } 1651 break; 1652 } 1653 case 'O': 1654 case 'o': 1655 { 1656 if (LocaleCompare((char *) keyword,"output") == 0) 1657 { 1658 log_info->handler_mask=(LogHandlerType) 1659 (log_info->handler_mask | ParseLogHandlers(token)); 1660 break; 1661 } 1662 break; 1663 } 1664 default: 1665 break; 1666 } 1667 } 1668 token=DestroyString(token); 1669 if (cache == (LinkedListInfo *) NULL) 1670 return(MagickFalse); 1671 return(status != 0 ? MagickTrue : MagickFalse); 1672 } 1673 1674 /* 1676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1677 % % 1678 % % 1679 % % 1680 + P a r s e L o g H a n d l e r s % 1681 % % 1682 % % 1683 % % 1684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1685 % 1686 % ParseLogHandlers() parses a string defining which handlers takes a log 1687 % message and exports them. 1688 % 1689 % The format of the ParseLogHandlers method is: 1690 % 1691 % LogHandlerType ParseLogHandlers(const char *handlers) 1692 % 1693 % A description of each parameter follows: 1694 % 1695 % o handlers: one or more handlers separated by commas. 1696 % 1697 */ 1698 static LogHandlerType ParseLogHandlers(const char *handlers) 1699 { 1700 LogHandlerType 1701 handler_mask; 1702 1703 register const char 1704 *p; 1705 1706 register ssize_t 1707 i; 1708 1709 size_t 1710 length; 1711 1712 handler_mask=NoHandler; 1713 for (p=handlers; p != (char *) NULL; p=strchr(p,',')) 1714 { 1715 while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) || 1716 (*p == ','))) 1717 p++; 1718 for (i=0; LogHandlers[i].name != (char *) NULL; i++) 1719 { 1720 length=strlen(LogHandlers[i].name); 1721 if (LocaleNCompare(p,LogHandlers[i].name,length) == 0) 1722 { 1723 handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler); 1724 break; 1725 } 1726 } 1727 if (LogHandlers[i].name == (char *) NULL) 1728 return(UndefinedHandler); 1729 } 1730 return(handler_mask); 1731 } 1732 1733 /* 1735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1736 % % 1737 % % 1738 % % 1739 % S e t L o g E v e n t M a s k % 1740 % % 1741 % % 1742 % % 1743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1744 % 1745 % SetLogEventMask() accepts a list that determines which events to log. All 1746 % other events are ignored. By default, no debug is enabled. This method 1747 % returns the previous log event mask. 1748 % 1749 % The format of the SetLogEventMask method is: 1750 % 1751 % LogEventType SetLogEventMask(const char *events) 1752 % 1753 % A description of each parameter follows: 1754 % 1755 % o events: log these events. 1756 % 1757 */ 1758 MagickExport LogEventType SetLogEventMask(const char *events) 1759 { 1760 ExceptionInfo 1761 *exception; 1762 1763 LogInfo 1764 *log_info; 1765 1766 ssize_t 1767 option; 1768 1769 exception=AcquireExceptionInfo(); 1770 log_info=(LogInfo *) GetLogInfo("*",exception); 1771 exception=DestroyExceptionInfo(exception); 1772 option=ParseCommandOption(MagickLogEventOptions,MagickTrue,events); 1773 LockSemaphoreInfo(log_semaphore); 1774 log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0); 1775 log_info->event_mask=(LogEventType) option; 1776 if (option == -1) 1777 log_info->event_mask=UndefinedEvents; 1778 CheckEventLogging(); 1779 UnlockSemaphoreInfo(log_semaphore); 1780 return(log_info->event_mask); 1781 } 1782 1783 /* 1785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1786 % % 1787 % % 1788 % % 1789 % S e t L o g F o r m a t % 1790 % % 1791 % % 1792 % % 1793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1794 % 1795 % SetLogFormat() sets the format for the "human readable" log record. 1796 % 1797 % The format of the LogMagickFormat method is: 1798 % 1799 % SetLogFormat(const char *format) 1800 % 1801 % A description of each parameter follows: 1802 % 1803 % o format: the log record format. 1804 % 1805 */ 1806 MagickExport void SetLogFormat(const char *format) 1807 { 1808 LogInfo 1809 *log_info; 1810 1811 ExceptionInfo 1812 *exception; 1813 1814 exception=AcquireExceptionInfo(); 1815 log_info=(LogInfo *) GetLogInfo("*",exception); 1816 exception=DestroyExceptionInfo(exception); 1817 LockSemaphoreInfo(log_semaphore); 1818 if (log_info->format != (char *) NULL) 1819 log_info->format=DestroyString(log_info->format); 1820 log_info->format=ConstantString(format); 1821 UnlockSemaphoreInfo(log_semaphore); 1822 } 1823 1824 /* 1826 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1827 % % 1828 % % 1829 % % 1830 % S e t L o g M e t h o d % 1831 % % 1832 % % 1833 % % 1834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1835 % 1836 % SetLogMethod() sets the method that will be called when an event is logged. 1837 % 1838 % The format of the SetLogMethod method is: 1839 % 1840 % void SetLogMethod(MagickLogMethod method) 1841 % 1842 % A description of each parameter follows: 1843 % 1844 % o method: pointer to a method that will be called when LogMagickEvent is 1845 % being called. 1846 % 1847 */ 1848 MagickExport void SetLogMethod(MagickLogMethod method) 1849 { 1850 ExceptionInfo 1851 *exception; 1852 1853 LogInfo 1854 *log_info; 1855 1856 exception=AcquireExceptionInfo(); 1857 log_info=(LogInfo *) GetLogInfo("*",exception); 1858 exception=DestroyExceptionInfo(exception); 1859 LockSemaphoreInfo(log_semaphore); 1860 log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0); 1861 log_info->handler_mask=(LogHandlerType) (log_info->handler_mask | 1862 MethodHandler); 1863 log_info->method=method; 1864 UnlockSemaphoreInfo(log_semaphore); 1865 } 1866 1867 /* 1869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1870 % % 1871 % % 1872 % % 1873 % S e t L o g N a m e % 1874 % % 1875 % % 1876 % % 1877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1878 % 1879 % SetLogName() sets the log name and returns it. 1880 % 1881 % The format of the SetLogName method is: 1882 % 1883 % const char *SetLogName(const char *name) 1884 % 1885 % A description of each parameter follows: 1886 % 1887 % o log_name: SetLogName() returns the current client name. 1888 % 1889 % o name: Specifies the new client name. 1890 % 1891 */ 1892 MagickExport const char *SetLogName(const char *name) 1893 { 1894 if ((name != (char *) NULL) && (*name != '\0')) 1895 (void) CopyMagickString(log_name,name,MagickPathExtent); 1896 return(log_name); 1897 } 1898