1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %           RRRR    EEEEE   SSSSS   OOO   U   U  RRRR    CCCC  EEEEE          %
7 %           R   R   E       SS     O   O  U   U  R   R  C      E              %
8 %           RRRR    EEE      SSS   O   O  U   U  RRRR   C      EEE            %
9 %           R R     E          SS  O   O  U   U  R R    C      E              %
10 %           R  R    EEEEE   SSSSS   OOO    UUU   R  R    CCCC  EEEEE          %
11 %                                                                             %
12 %                                                                             %
13 %                        Get/Set MagickCore Resources                         %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                               September 2002                                %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2021 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 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/cache.h"
44 #include "MagickCore/cache-private.h"
45 #include "MagickCore/configure.h"
46 #include "MagickCore/exception.h"
47 #include "MagickCore/exception-private.h"
48 #include "MagickCore/linked-list.h"
49 #include "MagickCore/log.h"
50 #include "MagickCore/image.h"
51 #include "MagickCore/image-private.h"
52 #include "MagickCore/memory_.h"
53 #include "MagickCore/nt-base-private.h"
54 #include "MagickCore/option.h"
55 #include "MagickCore/policy.h"
56 #include "MagickCore/random_.h"
57 #include "MagickCore/registry.h"
58 #include "MagickCore/resource_.h"
59 #include "MagickCore/resource-private.h"
60 #include "MagickCore/semaphore.h"
61 #include "MagickCore/signature-private.h"
62 #include "MagickCore/string_.h"
63 #include "MagickCore/string-private.h"
64 #include "MagickCore/splay-tree.h"
65 #include "MagickCore/thread-private.h"
66 #include "MagickCore/token.h"
67 #include "MagickCore/utility.h"
68 #include "MagickCore/utility-private.h"
69 
70 /*
71   Define declarations.
72 */
73 #define MagickPathTemplate "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"  /* min 6 X's */
74 #define NumberOfResourceTypes  \
75   (sizeof(resource_semaphore)/sizeof(*resource_semaphore))
76 
77 /*
78   Typedef declarations.
79 */
80 typedef struct _ResourceInfo
81 {
82   MagickOffsetType
83     width,
84     height,
85     list_length,
86     area,
87     memory,
88     map,
89     disk,
90     file,
91     thread,
92     throttle,
93     time;
94 
95   MagickSizeType
96     width_limit,
97     height_limit,
98     list_length_limit,
99     area_limit,
100     memory_limit,
101     map_limit,
102     disk_limit,
103     file_limit,
104     thread_limit,
105     throttle_limit,
106     time_limit;
107 } ResourceInfo;
108 
109 /*
110   Global declarations.
111 */
112 static RandomInfo
113   *random_info = (RandomInfo *) NULL;
114 
115 static ResourceInfo
116   resource_info =
117   {
118     MagickULLConstant(0),              /* initial width */
119     MagickULLConstant(0),              /* initial height */
120     MagickULLConstant(0),              /* initial list length */
121     MagickULLConstant(0),              /* initial area */
122     MagickULLConstant(0),              /* initial memory */
123     MagickULLConstant(0),              /* initial map */
124     MagickULLConstant(0),              /* initial disk */
125     MagickULLConstant(0),              /* initial file */
126     MagickULLConstant(0),              /* initial thread */
127     MagickULLConstant(0),              /* initial throttle */
128     MagickULLConstant(0),              /* initial time */
129     MAGICK_SSIZE_MAX/sizeof(Quantum)/5,/* width limit */
130     MAGICK_SSIZE_MAX/sizeof(Quantum)/5,/* height limit */
131     MagickResourceInfinity,            /* list length limit */
132     MagickULLConstant(3072)*1024*1024, /* area limit */
133     MagickULLConstant(1536)*1024*1024, /* memory limit */
134     MagickULLConstant(3072)*1024*1024, /* map limit */
135     MagickResourceInfinity,            /* disk limit */
136     MagickULLConstant(768),            /* file limit */
137     MagickULLConstant(1),              /* thread limit */
138     MagickULLConstant(0),              /* throttle limit */
139     MagickResourceInfinity             /* time limit */
140   };
141 
142 static SemaphoreInfo
143   *resource_semaphore[] = {
144      (SemaphoreInfo *) NULL,
145      (SemaphoreInfo *) NULL,
146      (SemaphoreInfo *) NULL,
147      (SemaphoreInfo *) NULL,
148      (SemaphoreInfo *) NULL,
149      (SemaphoreInfo *) NULL,
150      (SemaphoreInfo *) NULL,
151      (SemaphoreInfo *) NULL,
152      (SemaphoreInfo *) NULL,
153      (SemaphoreInfo *) NULL,
154      (SemaphoreInfo *) NULL,
155      (SemaphoreInfo *) NULL
156   };
157 
158 static SplayTreeInfo
159   *temporary_resources = (SplayTreeInfo *) NULL;
160 
161 /*
162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163 %                                                                             %
164 %                                                                             %
165 %                                                                             %
166 %   A c q u i r e M a g i c k R e s o u r c e                                 %
167 %                                                                             %
168 %                                                                             %
169 %                                                                             %
170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171 %
172 %  AcquireMagickResource() acquires resources of the specified type.
173 %  MagickFalse is returned if the specified resource is exhausted otherwise
174 %  MagickTrue.
175 %
176 %  The format of the AcquireMagickResource() method is:
177 %
178 %      MagickBooleanType AcquireMagickResource(const ResourceType type,
179 %        const MagickSizeType size)
180 %
181 %  A description of each parameter follows:
182 %
183 %    o type: the type of resource.
184 %
185 %    o size: the number of bytes needed from for this resource.
186 %
187 */
AcquireMagickResource(const ResourceType type,const MagickSizeType size)188 MagickExport MagickBooleanType AcquireMagickResource(const ResourceType type,
189   const MagickSizeType size)
190 {
191   MagickBooleanType
192     bi,
193     status;
194 
195   MagickOffsetType
196     current,
197     request;
198 
199   MagickSizeType
200     limit;
201 
202   request=(MagickOffsetType) size;
203   if (request < 0)
204     return(MagickFalse);
205   limit=0;
206   current=0;
207   bi=MagickFalse;
208   status=MagickFalse;
209   switch (type)
210   {
211     case DiskResource:
212     case FileResource:
213     case MapResource:
214     case MemoryResource:
215     case TimeResource:
216     {
217       if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
218         ActivateSemaphoreInfo(&resource_semaphore[type]);
219       LockSemaphoreInfo(resource_semaphore[type]);
220       break;
221     }
222     default: ;
223   }
224   switch (type)
225   {
226     case AreaResource:
227     {
228       bi=MagickTrue;
229       resource_info.area=request;
230       limit=resource_info.area_limit;
231       if ((limit == MagickResourceInfinity) || (size < limit))
232         status=MagickTrue;
233       break;
234     }
235     case DiskResource:
236     {
237       bi=MagickTrue;
238       limit=resource_info.disk_limit;
239       if (((MagickSizeType) resource_info.disk+request) >
240           (MagickSizeType) resource_info.disk)
241         {
242           resource_info.disk+=request;
243           if ((limit == MagickResourceInfinity) ||
244               (resource_info.disk < (MagickOffsetType) limit))
245             status=MagickTrue;
246           else
247             resource_info.disk-=request;
248         }
249       current=resource_info.disk;
250       break;
251     }
252     case FileResource:
253     {
254       limit=resource_info.file_limit;
255       if (((MagickSizeType) resource_info.file+request) >
256           (MagickSizeType) resource_info.file)
257         {
258           resource_info.file+=request;
259           if ((limit == MagickResourceInfinity) ||
260               (resource_info.file < (MagickOffsetType) limit))
261             status=MagickTrue;
262         }
263       current=resource_info.file;
264       break;
265     }
266     case HeightResource:
267     {
268       bi=MagickTrue;
269       resource_info.height=request;
270       limit=resource_info.height_limit;
271       if ((limit == MagickResourceInfinity) || (size < limit))
272         status=MagickTrue;
273       break;
274     }
275     case ListLengthResource:
276     {
277       resource_info.list_length=request;
278       limit=resource_info.list_length_limit;
279       if ((limit == MagickResourceInfinity) || (size < limit))
280         status=MagickTrue;
281       break;
282     }
283     case MapResource:
284     {
285       bi=MagickTrue;
286       limit=resource_info.map_limit;
287       if (((MagickSizeType) resource_info.map+request) >
288           (MagickSizeType) resource_info.map)
289         {
290           resource_info.map+=request;
291           if ((limit == MagickResourceInfinity) ||
292               (resource_info.map < (MagickOffsetType) limit))
293             status=MagickTrue;
294           else
295             resource_info.map-=request;
296         }
297       current=resource_info.map;
298       break;
299     }
300     case MemoryResource:
301     {
302       bi=MagickTrue;
303       limit=resource_info.memory_limit;
304       if (((MagickSizeType) resource_info.memory+request) >
305           (MagickSizeType) resource_info.memory)
306         {
307           resource_info.memory+=request;
308           if ((limit == MagickResourceInfinity) ||
309               (resource_info.memory < (MagickOffsetType) limit))
310             status=MagickTrue;
311           else
312             resource_info.memory-=request;
313         }
314       current=resource_info.memory;
315       break;
316     }
317     case ThreadResource:
318     {
319       limit=resource_info.thread_limit;
320       if ((limit == MagickResourceInfinity) ||
321           (resource_info.thread < (MagickOffsetType) limit))
322         status=MagickTrue;
323       break;
324     }
325     case ThrottleResource:
326     {
327       limit=resource_info.throttle_limit;
328       if ((limit == MagickResourceInfinity) ||
329           (resource_info.throttle < (MagickOffsetType) limit))
330         status=MagickTrue;
331       break;
332     }
333     case TimeResource:
334     {
335       limit=resource_info.time_limit;
336       if (((MagickSizeType) resource_info.time+request) >
337           (MagickSizeType) resource_info.time)
338         {
339           resource_info.time+=request;
340           if ((limit == MagickResourceInfinity) ||
341               (resource_info.time < (MagickOffsetType) limit))
342             status=MagickTrue;
343           else
344             resource_info.time-=request;
345         }
346       current=resource_info.time;
347       break;
348     }
349     case WidthResource:
350     {
351       bi=MagickTrue;
352       resource_info.width=request;
353       limit=resource_info.width_limit;
354       if ((limit == MagickResourceInfinity) || (size < limit))
355         status=MagickTrue;
356       break;
357     }
358     default:
359     {
360       current=0;
361       break;
362     }
363   }
364   switch (type)
365   {
366     case DiskResource:
367     case FileResource:
368     case MapResource:
369     case MemoryResource:
370     case TimeResource:
371     {
372       UnlockSemaphoreInfo(resource_semaphore[type]);
373       break;
374     }
375     default: ;
376   }
377   if (IsEventLogging() != MagickFalse)
378     {
379       char
380         resource_current[MagickFormatExtent],
381         resource_limit[MagickFormatExtent],
382         resource_request[MagickFormatExtent];
383 
384       (void) FormatMagickSize(size,bi,(bi != MagickFalse) ? "B" :
385         (const char *) NULL,MagickFormatExtent,resource_request);
386       (void) FormatMagickSize((MagickSizeType) current,bi,(bi != MagickFalse) ?
387         "B" : (const char *) NULL,MagickFormatExtent,resource_current);
388       (void) FormatMagickSize(limit,bi,(bi != MagickFalse) ? "B" :
389         (const char *) NULL,MagickFormatExtent,resource_limit);
390       (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
391         CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
392         resource_request,resource_current,resource_limit);
393     }
394   return(status);
395 }
396 
397 /*
398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
399 %                                                                             %
400 %                                                                             %
401 %                                                                             %
402 +   A s y n c h r o n o u s R e s o u r c e C o m p o n e n t T e r m i n u s %
403 %                                                                             %
404 %                                                                             %
405 %                                                                             %
406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407 %
408 %  AsynchronousResourceComponentTerminus() destroys the resource environment.
409 %  It differs from ResourceComponentTerminus() in that it can be called from a
410 %  asynchronous signal handler.
411 %
412 %  The format of the ResourceComponentTerminus() method is:
413 %
414 %      ResourceComponentTerminus(void)
415 %
416 */
AsynchronousResourceComponentTerminus(void)417 MagickPrivate void AsynchronousResourceComponentTerminus(void)
418 {
419   const char
420     *path;
421 
422   if (temporary_resources == (SplayTreeInfo *) NULL)
423     return;
424   /*
425     Remove any lingering temporary files.
426   */
427   ResetSplayTreeIterator(temporary_resources);
428   path=(const char *) GetNextKeyInSplayTree(temporary_resources);
429   while (path != (const char *) NULL)
430   {
431     (void) ShredFile(path);
432     path=(const char *) GetNextKeyInSplayTree(temporary_resources);
433   }
434 }
435 
436 /*
437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438 %                                                                             %
439 %                                                                             %
440 %                                                                             %
441 %   A c q u i r e U n i q u e F i l e R e s o u r c e                         %
442 %                                                                             %
443 %                                                                             %
444 %                                                                             %
445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
446 %
447 %  AcquireUniqueFileResource() returns a unique file name, and returns a file
448 %  descriptor for the file open for reading and writing.
449 %
450 %  The format of the AcquireUniqueFileResource() method is:
451 %
452 %      int AcquireUniqueFileResource(char *path)
453 %
454 %  A description of each parameter follows:
455 %
456 %   o  path:  Specifies a pointer to an array of characters.  The unique path
457 %      name is returned in this array.
458 %
459 */
460 
DestroyTemporaryResources(void * temporary_resource)461 static void *DestroyTemporaryResources(void *temporary_resource)
462 {
463   (void) ShredFile((char *) temporary_resource);
464   temporary_resource=DestroyString((char *) temporary_resource);
465   return((void *) NULL);
466 }
467 
GetPathTemplate(char * path)468 MagickExport MagickBooleanType GetPathTemplate(char *path)
469 {
470   char
471     *directory,
472     *value;
473 
474   ExceptionInfo
475     *exception;
476 
477   MagickBooleanType
478     status;
479 
480   struct stat
481     attributes;
482 
483   (void) FormatLocaleString(path,MagickPathExtent,"magick-" MagickPathTemplate);
484   exception=AcquireExceptionInfo();
485   directory=(char *) GetImageRegistry(StringRegistryType,"temporary-path",
486     exception);
487   exception=DestroyExceptionInfo(exception);
488   if (directory == (char *) NULL)
489     directory=GetEnvironmentValue("MAGICK_TEMPORARY_PATH");
490   if (directory == (char *) NULL)
491     directory=GetEnvironmentValue("MAGICK_TMPDIR");
492   if (directory == (char *) NULL)
493     directory=GetEnvironmentValue("TMPDIR");
494 #if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__) || defined(__CYGWIN__)
495   if (directory == (char *) NULL)
496     directory=GetEnvironmentValue("TMP");
497   if (directory == (char *) NULL)
498     directory=GetEnvironmentValue("TEMP");
499 #endif
500 #if defined(__VMS)
501   if (directory == (char *) NULL)
502     directory=GetEnvironmentValue("MTMPDIR");
503 #endif
504 #if defined(P_tmpdir)
505   if (directory == (char *) NULL)
506     directory=ConstantString(P_tmpdir);
507 #endif
508   if (directory == (char *) NULL)
509     return(MagickTrue);
510   value=GetPolicyValue("resource:temporary-path");
511   if (value != (char *) NULL)
512     {
513       (void) CloneString(&directory,value);
514       value=DestroyString(value);
515     }
516   if (strlen(directory) > (MagickPathExtent-25))
517     {
518       directory=DestroyString(directory);
519       return(MagickFalse);
520     }
521   status=GetPathAttributes(directory,&attributes);
522   if ((status == MagickFalse) || !S_ISDIR(attributes.st_mode))
523     {
524       directory=DestroyString(directory);
525       return(MagickFalse);
526     }
527   if (directory[strlen(directory)-1] == *DirectorySeparator)
528     (void) FormatLocaleString(path,MagickPathExtent,"%smagick-"
529       MagickPathTemplate,directory);
530   else
531     (void) FormatLocaleString(path,MagickPathExtent,
532       "%s%smagick-" MagickPathTemplate,directory,DirectorySeparator);
533   directory=DestroyString(directory);
534 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
535   {
536     char
537       *p;
538 
539     /*
540       Ghostscript does not like backslashes so we need to replace them. The
541       forward slash also works under Windows.
542     */
543     for (p=(path[1] == *DirectorySeparator ? path+2 : path); *p != '\0'; p++)
544       if (*p == *DirectorySeparator)
545         *p='/';
546   }
547 #endif
548   return(MagickTrue);
549 }
550 
AcquireUniqueFileResource(char * path)551 MagickExport int AcquireUniqueFileResource(char *path)
552 {
553 #if !defined(O_NOFOLLOW)
554 #define O_NOFOLLOW 0
555 #endif
556 #if !defined(TMP_MAX)
557 # define TMP_MAX  238328
558 #endif
559 
560   int
561     c,
562     file;
563 
564   char
565     *p;
566 
567   ssize_t
568     i;
569 
570   static const char
571     portable_filename[65] =
572       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
573 
574   StringInfo
575     *key;
576 
577   unsigned char
578     *datum;
579 
580   assert(path != (char *) NULL);
581   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"...");
582   if (random_info == (RandomInfo *) NULL)
583     {
584       if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
585         ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
586       LockSemaphoreInfo(resource_semaphore[FileResource]);
587       if (random_info == (RandomInfo *) NULL)
588         random_info=AcquireRandomInfo();
589       UnlockSemaphoreInfo(resource_semaphore[FileResource]);
590     }
591   file=(-1);
592   for (i=0; i < (ssize_t) TMP_MAX; i++)
593   {
594     ssize_t
595       j;
596 
597     /*
598       Get temporary pathname.
599     */
600     (void) GetPathTemplate(path);
601     key=GetRandomKey(random_info,strlen(MagickPathTemplate)-6);
602     p=path+strlen(path)-strlen(MagickPathTemplate);
603     datum=GetStringInfoDatum(key);
604     for (j=0; j < (ssize_t) GetStringInfoLength(key); j++)
605     {
606       c=(int) (datum[j] & 0x3f);
607       *p++=portable_filename[c];
608     }
609     key=DestroyStringInfo(key);
610 #if defined(MAGICKCORE_HAVE_MKSTEMP)
611     file=mkstemp(path);
612     if (file != -1)
613       {
614 #if defined(MAGICKCORE_HAVE_FCHMOD)
615         (void) fchmod(file,0600);
616 #endif
617 #if defined(__OS2__)
618         setmode(file,O_BINARY);
619 #endif
620         break;
621       }
622 #endif
623     key=GetRandomKey(random_info,strlen(MagickPathTemplate));
624     p=path+strlen(path)-strlen(MagickPathTemplate);
625     datum=GetStringInfoDatum(key);
626     for (j=0; j < (ssize_t) GetStringInfoLength(key); j++)
627     {
628       c=(int) (datum[j] & 0x3f);
629       *p++=portable_filename[c];
630     }
631     key=DestroyStringInfo(key);
632     file=open_utf8(path,O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_NOFOLLOW,
633       S_MODE);
634     if ((file >= 0) || (errno != EEXIST))
635       break;
636   }
637   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
638   if (file == -1)
639     return(file);
640   if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
641     ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
642   LockSemaphoreInfo(resource_semaphore[FileResource]);
643   if (temporary_resources == (SplayTreeInfo *) NULL)
644     temporary_resources=NewSplayTree(CompareSplayTreeString,
645       DestroyTemporaryResources,(void *(*)(void *)) NULL);
646   UnlockSemaphoreInfo(resource_semaphore[FileResource]);
647   (void) AddValueToSplayTree(temporary_resources,ConstantString(path),
648     (const void *) NULL);
649   return(file);
650 }
651 
652 /*
653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654 %                                                                             %
655 %                                                                             %
656 %                                                                             %
657 %   G e t M a g i c k R e s o u r c e                                         %
658 %                                                                             %
659 %                                                                             %
660 %                                                                             %
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 %
663 %  GetMagickResource() returns the specified resource.
664 %
665 %  The format of the GetMagickResource() method is:
666 %
667 %      MagickSizeType GetMagickResource(const ResourceType type)
668 %
669 %  A description of each parameter follows:
670 %
671 %    o type: the type of resource.
672 %
673 */
GetMagickResource(const ResourceType type)674 MagickExport MagickSizeType GetMagickResource(const ResourceType type)
675 {
676   MagickSizeType
677     resource;
678 
679   resource=0;
680   switch (type)
681   {
682     case DiskResource:
683     case FileResource:
684     case MapResource:
685     case MemoryResource:
686     case TimeResource:
687     {
688       if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
689         ActivateSemaphoreInfo(&resource_semaphore[type]);
690       LockSemaphoreInfo(resource_semaphore[type]);
691       break;
692     }
693     default: ;
694   }
695   switch (type)
696   {
697     case AreaResource:
698     {
699       resource=(MagickSizeType) resource_info.area;
700       break;
701     }
702     case DiskResource:
703     {
704       resource=(MagickSizeType) resource_info.disk;
705       break;
706     }
707     case FileResource:
708     {
709       resource=(MagickSizeType) resource_info.file;
710       break;
711     }
712     case HeightResource:
713     {
714       resource=(MagickSizeType) resource_info.height;
715       break;
716     }
717     case ListLengthResource:
718     {
719       resource=(MagickSizeType) resource_info.list_length;
720       break;
721     }
722     case MapResource:
723     {
724       resource=(MagickSizeType) resource_info.map;
725       break;
726     }
727     case MemoryResource:
728     {
729       resource=(MagickSizeType) resource_info.memory;
730       break;
731     }
732     case TimeResource:
733     {
734       resource=(MagickSizeType) resource_info.time;
735       break;
736     }
737     case ThreadResource:
738     {
739       resource=(MagickSizeType) resource_info.thread;
740       break;
741     }
742     case ThrottleResource:
743     {
744       resource=(MagickSizeType) resource_info.throttle;
745       break;
746     }
747     case WidthResource:
748     {
749       resource=(MagickSizeType) resource_info.width;
750       break;
751     }
752     default:
753       break;
754   }
755   switch (type)
756   {
757     case DiskResource:
758     case FileResource:
759     case MapResource:
760     case MemoryResource:
761     case TimeResource:
762     {
763       UnlockSemaphoreInfo(resource_semaphore[type]);
764       break;
765     }
766     default: ;
767   }
768   return(resource);
769 }
770 
771 /*
772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
773 %                                                                             %
774 %                                                                             %
775 %                                                                             %
776 %   G e t M a g i c k R e s o u r c e L i m i t                               %
777 %                                                                             %
778 %                                                                             %
779 %                                                                             %
780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
781 %
782 %  GetMagickResourceLimit() returns the specified resource limit.
783 %
784 %  The format of the GetMagickResourceLimit() method is:
785 %
786 %      MagickSizeType GetMagickResourceLimit(const ResourceType type)
787 %
788 %  A description of each parameter follows:
789 %
790 %    o type: the type of resource.
791 %
792 */
GetMagickResourceLimit(const ResourceType type)793 MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
794 {
795   MagickSizeType
796     resource;
797 
798   switch (type)
799   {
800     case AreaResource:
801       return(resource_info.area_limit);
802     case HeightResource:
803       return(resource_info.height_limit);
804     case ListLengthResource:
805       return(resource_info.list_length_limit);
806     case ThreadResource:
807       return(resource_info.thread_limit);
808     case ThrottleResource:
809       return(resource_info.throttle_limit);
810     case WidthResource:
811       return(resource_info.width_limit);
812     default: ;
813   }
814   resource=0;
815   if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
816     ActivateSemaphoreInfo(&resource_semaphore[type]);
817   LockSemaphoreInfo(resource_semaphore[type]);
818   switch (type)
819   {
820     case DiskResource:
821     {
822       resource=resource_info.disk_limit;
823       break;
824     }
825     case FileResource:
826     {
827       resource=resource_info.file_limit;
828       break;
829     }
830     case MapResource:
831     {
832       resource=resource_info.map_limit;
833       break;
834     }
835     case MemoryResource:
836     {
837       resource=resource_info.memory_limit;
838       break;
839     }
840     case TimeResource:
841     {
842       resource=resource_info.time_limit;
843       break;
844     }
845     default:
846       break;
847   }
848   UnlockSemaphoreInfo(resource_semaphore[type]);
849   return(resource);
850 }
851 
852 /*
853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
854 %                                                                             %
855 %                                                                             %
856 %                                                                             %
857 %  L i s t M a g i c k R e s o u r c e I n f o                                %
858 %                                                                             %
859 %                                                                             %
860 %                                                                             %
861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
862 %
863 %  ListMagickResourceInfo() lists the resource info to a file.
864 %
865 %  The format of the ListMagickResourceInfo method is:
866 %
867 %      MagickBooleanType ListMagickResourceInfo(FILE *file,
868 %        ExceptionInfo *exception)
869 %
870 %  A description of each parameter follows.
871 %
872 %    o file:  An pointer to a FILE.
873 %
874 %    o exception: return any errors or warnings in this structure.
875 %
876 */
ListMagickResourceInfo(FILE * file,ExceptionInfo * magick_unused (exception))877 MagickExport MagickBooleanType ListMagickResourceInfo(FILE *file,
878   ExceptionInfo *magick_unused(exception))
879 {
880   char
881     area_limit[MagickFormatExtent],
882     disk_limit[MagickFormatExtent],
883     height_limit[MagickFormatExtent],
884     list_length_limit[MagickFormatExtent],
885     map_limit[MagickFormatExtent],
886     memory_limit[MagickFormatExtent],
887     time_limit[MagickFormatExtent],
888     width_limit[MagickFormatExtent];
889 
890   magick_unreferenced(exception);
891 
892   if (file == (const FILE *) NULL)
893     file=stdout;
894   if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
895     ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
896   LockSemaphoreInfo(resource_semaphore[FileResource]);
897   (void) FormatMagickSize(resource_info.width_limit,MagickFalse,"P",
898     MagickFormatExtent,width_limit);
899   (void) FormatMagickSize(resource_info.height_limit,MagickFalse,"P",
900     MagickFormatExtent,height_limit);
901   (void) FormatMagickSize(resource_info.area_limit,MagickFalse,"P",
902     MagickFormatExtent,area_limit);
903   (void) CopyMagickString(list_length_limit,"unlimited",MagickFormatExtent);
904   if (resource_info.list_length_limit != MagickResourceInfinity)
905     (void) FormatMagickSize(resource_info.list_length_limit,MagickTrue,"B",
906       MagickFormatExtent,list_length_limit);
907   (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,"B",
908     MagickFormatExtent,memory_limit);
909   (void) FormatMagickSize(resource_info.map_limit,MagickTrue,"B",
910     MagickFormatExtent,map_limit);
911   (void) CopyMagickString(disk_limit,"unlimited",MagickFormatExtent);
912   if (resource_info.disk_limit != MagickResourceInfinity)
913     (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,"B",
914       MagickFormatExtent,disk_limit);
915   (void) CopyMagickString(time_limit,"unlimited",MagickFormatExtent);
916   if (resource_info.time_limit != MagickResourceInfinity)
917     (void) FormatLocaleString(time_limit,MagickFormatExtent,"%.20g",(double)
918       ((MagickOffsetType) resource_info.time_limit));
919   (void) FormatLocaleFile(file,"Resource limits:\n");
920   (void) FormatLocaleFile(file,"  Width: %s\n",width_limit);
921   (void) FormatLocaleFile(file,"  Height: %s\n",height_limit);
922   (void) FormatLocaleFile(file,"  Area: %s\n",area_limit);
923   (void) FormatLocaleFile(file,"  List length: %s\n",list_length_limit);
924   (void) FormatLocaleFile(file,"  Memory: %s\n",memory_limit);
925   (void) FormatLocaleFile(file,"  Map: %s\n",map_limit);
926   (void) FormatLocaleFile(file,"  Disk: %s\n",disk_limit);
927   (void) FormatLocaleFile(file,"  File: %.20g\n",(double) ((MagickOffsetType)
928     resource_info.file_limit));
929   (void) FormatLocaleFile(file,"  Thread: %.20g\n",(double) ((MagickOffsetType)
930     resource_info.thread_limit));
931   (void) FormatLocaleFile(file,"  Throttle: %.20g\n",(double)
932     ((MagickOffsetType) resource_info.throttle_limit));
933   (void) FormatLocaleFile(file,"  Time: %s\n",time_limit);
934   (void) fflush(file);
935   UnlockSemaphoreInfo(resource_semaphore[FileResource]);
936   return(MagickTrue);
937 }
938 
939 /*
940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
941 %                                                                             %
942 %                                                                             %
943 %                                                                             %
944 %   R e l i n q u i s h M a g i c k R e s o u r c e                           %
945 %                                                                             %
946 %                                                                             %
947 %                                                                             %
948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
949 %
950 %  RelinquishMagickResource() relinquishes resources of the specified type.
951 %
952 %  The format of the RelinquishMagickResource() method is:
953 %
954 %      void RelinquishMagickResource(const ResourceType type,
955 %        const MagickSizeType size)
956 %
957 %  A description of each parameter follows:
958 %
959 %    o type: the type of resource.
960 %
961 %    o size: the size of the resource.
962 %
963 */
RelinquishMagickResource(const ResourceType type,const MagickSizeType size)964 MagickExport void RelinquishMagickResource(const ResourceType type,
965   const MagickSizeType size)
966 {
967   MagickBooleanType
968     bi;
969 
970   MagickSizeType
971     current,
972     limit;
973 
974   bi=MagickFalse;
975   limit=0;
976   current=0;
977   switch (type)
978   {
979     case DiskResource:
980     case FileResource:
981     case MapResource:
982     case MemoryResource:
983     case TimeResource:
984     {
985       if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
986         ActivateSemaphoreInfo(&resource_semaphore[type]);
987       LockSemaphoreInfo(resource_semaphore[type]);
988       break;
989     }
990     default: ;
991   }
992   switch (type)
993   {
994     case DiskResource:
995     {
996       bi=MagickTrue;
997       resource_info.disk-=size;
998       current=(MagickSizeType) resource_info.disk;
999       limit=resource_info.disk_limit;
1000       assert(resource_info.disk >= 0);
1001       break;
1002     }
1003     case FileResource:
1004     {
1005       resource_info.file-=size;
1006       current=(MagickSizeType) resource_info.file;
1007       limit=resource_info.file_limit;
1008       assert(resource_info.file >= 0);
1009       break;
1010     }
1011     case MapResource:
1012     {
1013       bi=MagickTrue;
1014       resource_info.map-=size;
1015       current=(MagickSizeType) resource_info.map;
1016       limit=resource_info.map_limit;
1017       assert(resource_info.map >= 0);
1018       break;
1019     }
1020     case MemoryResource:
1021     {
1022       bi=MagickTrue;
1023       resource_info.memory-=size;
1024       current=(MagickSizeType) resource_info.memory;
1025       limit=resource_info.memory_limit;
1026       assert(resource_info.memory >= 0);
1027       break;
1028     }
1029     case TimeResource:
1030     {
1031       bi=MagickTrue;
1032       resource_info.time-=size;
1033       current=(MagickSizeType) resource_info.time;
1034       limit=resource_info.time_limit;
1035       assert(resource_info.time >= 0);
1036       break;
1037     }
1038     default:
1039     {
1040       current=0;
1041       break;
1042     }
1043   }
1044   switch (type)
1045   {
1046     case DiskResource:
1047     case FileResource:
1048     case MapResource:
1049     case MemoryResource:
1050     case TimeResource:
1051     {
1052       UnlockSemaphoreInfo(resource_semaphore[type]);
1053       break;
1054     }
1055     default: ;
1056   }
1057   if (IsEventLogging() != MagickFalse)
1058     {
1059       char
1060         resource_current[MagickFormatExtent],
1061         resource_limit[MagickFormatExtent],
1062         resource_request[MagickFormatExtent];
1063 
1064       (void) FormatMagickSize(size,bi,(bi != MagickFalse) ? "B" :
1065         (const char *) NULL,MagickFormatExtent,resource_request);
1066       (void) FormatMagickSize(current,bi,(bi != MagickFalse) ? "B" :
1067         (const char *) NULL,MagickFormatExtent,resource_current);
1068       (void) FormatMagickSize(limit,bi,(bi != MagickFalse) ? "B" :
1069         (const char *) NULL,MagickFormatExtent,resource_limit);
1070       (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
1071         CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
1072           resource_request,resource_current,resource_limit);
1073     }
1074 }
1075 
1076 /*
1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078 %                                                                             %
1079 %                                                                             %
1080 %                                                                             %
1081 %    R e l i n q u i s h U n i q u e F i l e R e s o u r c e                  %
1082 %                                                                             %
1083 %                                                                             %
1084 %                                                                             %
1085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1086 %
1087 %  RelinquishUniqueFileResource() relinquishes a unique file resource.
1088 %
1089 %  The format of the RelinquishUniqueFileResource() method is:
1090 %
1091 %      MagickBooleanType RelinquishUniqueFileResource(const char *path)
1092 %
1093 %  A description of each parameter follows:
1094 %
1095 %    o name: the name of the temporary resource.
1096 %
1097 */
RelinquishUniqueFileResource(const char * path)1098 MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
1099 {
1100   char
1101     cache_path[MagickPathExtent];
1102 
1103   MagickBooleanType
1104     status;
1105 
1106   assert(path != (const char *) NULL);
1107   status=MagickFalse;
1108   (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path);
1109   if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
1110     ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
1111   LockSemaphoreInfo(resource_semaphore[FileResource]);
1112   if (temporary_resources != (SplayTreeInfo *) NULL)
1113     status=DeleteNodeFromSplayTree(temporary_resources,(const void *) path);
1114   UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1115   (void) CopyMagickString(cache_path,path,MagickPathExtent);
1116   AppendImageFormat("cache",cache_path);
1117   if (access_utf8(cache_path,F_OK) == 0)
1118     (void) ShredFile(cache_path);
1119   if (status == MagickFalse)
1120     status=ShredFile(path);
1121   return(status);
1122 }
1123 
1124 /*
1125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1126 %                                                                             %
1127 %                                                                             %
1128 %                                                                             %
1129 +   R e s o u r c e C o m p o n e n t G e n e s i s                           %
1130 %                                                                             %
1131 %                                                                             %
1132 %                                                                             %
1133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1134 %
1135 %  ResourceComponentGenesis() instantiates the resource component.
1136 %
1137 %  The format of the ResourceComponentGenesis method is:
1138 %
1139 %      MagickBooleanType ResourceComponentGenesis(void)
1140 %
1141 */
1142 
ResourceComponentGenesis(void)1143 MagickPrivate MagickBooleanType ResourceComponentGenesis(void)
1144 {
1145   char
1146     *limit;
1147 
1148   MagickSizeType
1149     memory;
1150 
1151   ssize_t
1152     i;
1153 
1154   ssize_t
1155     files,
1156     pages,
1157     pagesize;
1158 
1159   /*
1160     Set Magick resource limits.
1161   */
1162   for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1163     if (resource_semaphore[i] == (SemaphoreInfo *) NULL)
1164       resource_semaphore[i]=AcquireSemaphoreInfo();
1165   (void) SetMagickResourceLimit(WidthResource,resource_info.width_limit);
1166   limit=GetEnvironmentValue("MAGICK_WIDTH_LIMIT");
1167   if (limit != (char *) NULL)
1168     {
1169       (void) SetMagickResourceLimit(WidthResource,StringToMagickSizeType(limit,
1170         100.0));
1171       limit=DestroyString(limit);
1172     }
1173   (void) SetMagickResourceLimit(HeightResource,resource_info.height_limit);
1174   limit=GetEnvironmentValue("MAGICK_HEIGHT_LIMIT");
1175   if (limit != (char *) NULL)
1176     {
1177       (void) SetMagickResourceLimit(HeightResource,StringToMagickSizeType(
1178         limit,100.0));
1179       limit=DestroyString(limit);
1180     }
1181   pagesize=GetMagickPageSize();
1182   pages=(-1);
1183 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
1184   pages=(ssize_t) sysconf(_SC_PHYS_PAGES);
1185 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1186   pages=pages/2;
1187 #endif
1188 #endif
1189   memory=(MagickSizeType) pages*pagesize;
1190   if ((pagesize <= 0) || (pages <= 0))
1191     memory=2048UL*1024UL*1024UL;
1192 #if defined(PixelCacheThreshold)
1193   memory=PixelCacheThreshold;
1194 #endif
1195   (void) SetMagickResourceLimit(AreaResource,2*memory);
1196   limit=GetEnvironmentValue("MAGICK_AREA_LIMIT");
1197   if (limit != (char *) NULL)
1198     {
1199       (void) SetMagickResourceLimit(AreaResource,StringToMagickSizeType(limit,
1200         100.0));
1201       limit=DestroyString(limit);
1202     }
1203   (void) SetMagickResourceLimit(MemoryResource,memory);
1204   limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT");
1205   if (limit != (char *) NULL)
1206     {
1207       (void) SetMagickResourceLimit(MemoryResource,StringToMagickSizeType(
1208         limit,100.0));
1209       limit=DestroyString(limit);
1210     }
1211   (void) SetMagickResourceLimit(MapResource,2*memory);
1212   limit=GetEnvironmentValue("MAGICK_MAP_LIMIT");
1213   if (limit != (char *) NULL)
1214     {
1215       (void) SetMagickResourceLimit(MapResource,StringToMagickSizeType(limit,
1216         100.0));
1217       limit=DestroyString(limit);
1218     }
1219   (void) SetMagickResourceLimit(DiskResource,MagickResourceInfinity);
1220   limit=GetEnvironmentValue("MAGICK_DISK_LIMIT");
1221   if (limit != (char *) NULL)
1222     {
1223       (void) SetMagickResourceLimit(DiskResource,StringToMagickSizeType(limit,
1224         100.0));
1225       limit=DestroyString(limit);
1226     }
1227   files=(-1);
1228 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
1229   files=(ssize_t) sysconf(_SC_OPEN_MAX);
1230 #endif
1231 #if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
1232   if (files < 0)
1233     {
1234       struct rlimit
1235         resources;
1236 
1237       if (getrlimit(RLIMIT_NOFILE,&resources) != -1)
1238         files=(ssize_t) resources.rlim_cur;
1239   }
1240 #endif
1241 #if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
1242   if (files < 0)
1243     files=(ssize_t) getdtablesize();
1244 #endif
1245   if (files < 0)
1246     files=64;
1247   (void) SetMagickResourceLimit(FileResource,MagickMax((size_t)
1248     (3*files/4),64));
1249   limit=GetEnvironmentValue("MAGICK_FILE_LIMIT");
1250   if (limit != (char *) NULL)
1251     {
1252       (void) SetMagickResourceLimit(FileResource,StringToMagickSizeType(limit,
1253         100.0));
1254       limit=DestroyString(limit);
1255     }
1256   (void) SetMagickResourceLimit(ThreadResource,GetOpenMPMaximumThreads());
1257   limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT");
1258   if (limit != (char *) NULL)
1259     {
1260       (void) SetMagickResourceLimit(ThreadResource,StringToMagickSizeType(
1261         limit,100.0));
1262       limit=DestroyString(limit);
1263     }
1264   (void) SetMagickResourceLimit(ThrottleResource,0);
1265   limit=GetEnvironmentValue("MAGICK_THROTTLE_LIMIT");
1266   if (limit != (char *) NULL)
1267     {
1268       (void) SetMagickResourceLimit(ThrottleResource,StringToMagickSizeType(
1269         limit,100.0));
1270       limit=DestroyString(limit);
1271     }
1272   (void) SetMagickResourceLimit(TimeResource,MagickResourceInfinity);
1273   limit=GetEnvironmentValue("MAGICK_TIME_LIMIT");
1274   if (limit != (char *) NULL)
1275     {
1276       (void) SetMagickResourceLimit(TimeResource,StringToMagickSizeType(limit,
1277         100.0));
1278       limit=DestroyString(limit);
1279     }
1280   (void) SetMagickResourceLimit(ListLengthResource,MagickResourceInfinity);
1281   limit=GetEnvironmentValue("MAGICK_LIST_LENGTH_LIMIT");
1282   if (limit != (char *) NULL)
1283     {
1284       (void) SetMagickResourceLimit(ListLengthResource,
1285         StringToMagickSizeType(limit,100.0));
1286       limit=DestroyString(limit);
1287     }
1288   return(MagickTrue);
1289 }
1290 
1291 /*
1292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1293 %                                                                             %
1294 %                                                                             %
1295 %                                                                             %
1296 +   R e s o u r c e C o m p o n e n t T e r m i n u s                         %
1297 %                                                                             %
1298 %                                                                             %
1299 %                                                                             %
1300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1301 %
1302 %  ResourceComponentTerminus() destroys the resource component.
1303 %
1304 %  The format of the ResourceComponentTerminus() method is:
1305 %
1306 %      ResourceComponentTerminus(void)
1307 %
1308 */
ResourceComponentTerminus(void)1309 MagickPrivate void ResourceComponentTerminus(void)
1310 {
1311   ssize_t
1312     i;
1313 
1314   for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1315     if (resource_semaphore[i] == (SemaphoreInfo *) NULL)
1316       resource_semaphore[i]=AcquireSemaphoreInfo();
1317   LockSemaphoreInfo(resource_semaphore[FileResource]);
1318   if (temporary_resources != (SplayTreeInfo *) NULL)
1319     temporary_resources=DestroySplayTree(temporary_resources);
1320   if (random_info != (RandomInfo *) NULL)
1321     random_info=DestroyRandomInfo(random_info);
1322   UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1323   for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1324     RelinquishSemaphoreInfo(&resource_semaphore[i]);
1325 }
1326 
1327 /*
1328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1329 %                                                                             %
1330 %                                                                             %
1331 %                                                                             %
1332 %   S e t M a g i c k R e s o u r c e L i m i t                               %
1333 %                                                                             %
1334 %                                                                             %
1335 %                                                                             %
1336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1337 %
1338 %  SetMagickResourceLimit() sets the limit for a particular resource.
1339 %
1340 %  The format of the SetMagickResourceLimit() method is:
1341 %
1342 %      MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1343 %        const MagickSizeType limit)
1344 %
1345 %  A description of each parameter follows:
1346 %
1347 %    o type: the type of resource.
1348 %
1349 %    o limit: the maximum limit for the resource.
1350 %
1351 */
SetMagickResourceLimit(const ResourceType type,const MagickSizeType limit)1352 MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1353   const MagickSizeType limit)
1354 {
1355   char
1356     *value;
1357 
1358   MagickBooleanType
1359     status;
1360 
1361   status=MagickTrue;
1362   value=(char *) NULL;
1363   switch (type)
1364   {
1365     case DiskResource:
1366     case FileResource:
1367     case MapResource:
1368     case MemoryResource:
1369     case TimeResource:
1370     {
1371       if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
1372         ActivateSemaphoreInfo(&resource_semaphore[type]);
1373       LockSemaphoreInfo(resource_semaphore[type]);
1374       break;
1375     }
1376     default: ;
1377   }
1378   switch (type)
1379   {
1380     case AreaResource:
1381     {
1382       value=GetPolicyValue("resource:area");
1383       if (value == (char *) NULL)
1384         resource_info.area_limit=limit;
1385       else
1386         resource_info.area_limit=MagickMin(limit,StringToMagickSizeType(value,
1387           100.0));
1388       break;
1389     }
1390     case DiskResource:
1391     {
1392       value=GetPolicyValue("resource:disk");
1393       if (value == (char *) NULL)
1394         resource_info.disk_limit=limit;
1395       else
1396         resource_info.disk_limit=MagickMin(limit,StringToMagickSizeType(value,
1397           100.0));
1398       break;
1399     }
1400     case FileResource:
1401     {
1402       value=GetPolicyValue("resource:file");
1403       if (value == (char *) NULL)
1404         resource_info.file_limit=limit;
1405       else
1406         resource_info.file_limit=MagickMin(limit,StringToMagickSizeType(value,
1407           100.0));
1408       break;
1409     }
1410     case HeightResource:
1411     {
1412       value=GetPolicyValue("resource:height");
1413       if (value == (char *) NULL)
1414         resource_info.height_limit=limit;
1415       else
1416         resource_info.height_limit=MagickMin(limit,StringToMagickSizeType(
1417           value,100.0));
1418       resource_info.height_limit=MagickMin(resource_info.height_limit,
1419         (MagickSizeType) MAGICK_SSIZE_MAX);
1420       break;
1421     }
1422     case ListLengthResource:
1423     {
1424       value=GetPolicyValue("resource:list-length");
1425       if (value == (char *) NULL)
1426         resource_info.list_length_limit=limit;
1427       else
1428         resource_info.list_length_limit=MagickMin(limit,
1429           StringToMagickSizeType(value,100.0));
1430       break;
1431     }
1432     case MapResource:
1433     {
1434       value=GetPolicyValue("resource:map");
1435       if (value == (char *) NULL)
1436         resource_info.map_limit=limit;
1437       else
1438         resource_info.map_limit=MagickMin(limit,StringToMagickSizeType(
1439           value,100.0));
1440       break;
1441     }
1442     case MemoryResource:
1443     {
1444       value=GetPolicyValue("resource:memory");
1445       if (value == (char *) NULL)
1446         resource_info.memory_limit=limit;
1447       else
1448         resource_info.memory_limit=MagickMin(limit,StringToMagickSizeType(
1449           value,100.0));
1450       break;
1451     }
1452     case ThreadResource:
1453     {
1454       value=GetPolicyValue("resource:thread");
1455       if (value == (char *) NULL)
1456         resource_info.thread_limit=limit;
1457       else
1458         resource_info.thread_limit=MagickMin(limit,StringToMagickSizeType(
1459           value,100.0));
1460       if (resource_info.thread_limit > GetOpenMPMaximumThreads())
1461         resource_info.thread_limit=GetOpenMPMaximumThreads();
1462       else
1463         if (resource_info.thread_limit == 0)
1464           resource_info.thread_limit=1;
1465       break;
1466     }
1467     case ThrottleResource:
1468     {
1469       value=GetPolicyValue("resource:throttle");
1470       if (value == (char *) NULL)
1471         resource_info.throttle_limit=limit;
1472       else
1473         resource_info.throttle_limit=MagickMax(limit,StringToMagickSizeType(
1474           value,100.0));
1475       break;
1476     }
1477     case TimeResource:
1478     {
1479       value=GetPolicyValue("resource:time");
1480       if (value == (char *) NULL)
1481         resource_info.time_limit=limit;
1482       else
1483         resource_info.time_limit=MagickMin(limit,StringToMagickSizeType(value,
1484           100.0));
1485       ResetPixelCacheEpoch();
1486       break;
1487     }
1488     case WidthResource:
1489     {
1490       value=GetPolicyValue("resource:width");
1491       if (value == (char *) NULL)
1492         resource_info.width_limit=limit;
1493       else
1494         resource_info.width_limit=MagickMin(limit,StringToMagickSizeType(value,
1495           100.0));
1496       resource_info.width_limit=MagickMin(resource_info.width_limit,
1497         (MagickSizeType) MAGICK_SSIZE_MAX);
1498       break;
1499     }
1500     default:
1501     {
1502       status=MagickFalse;
1503       break;
1504     }
1505   }
1506   switch (type)
1507   {
1508     case DiskResource:
1509     case FileResource:
1510     case MapResource:
1511     case MemoryResource:
1512     case TimeResource:
1513     {
1514       UnlockSemaphoreInfo(resource_semaphore[type]);
1515       break;
1516     }
1517     default: ;
1518   }
1519   if (value != (char *) NULL)
1520     value=DestroyString(value);
1521   return(status);
1522 }
1523