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