Merge branch 'vendor/MPFR' into gcc441
[dragonfly.git] / contrib / bind-9.3 / lib / isc / unix / resource.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000, 2001  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: resource.c,v 1.11.206.1 2004/03/06 08:15:01 marka Exp $ */
19
20 #include <config.h>
21
22 #include <sys/types.h>
23 #include <sys/time.h>   /* Required on some systems for <sys/resource.h>. */
24 #include <sys/resource.h>
25
26 #include <isc/platform.h>
27 #include <isc/resource.h>
28 #include <isc/result.h>
29 #include <isc/util.h>
30
31 #include "errno2result.h"
32
33 static isc_result_t
34 resource2rlim(isc_resource_t resource, int *rlim_resource) {
35         isc_result_t result = ISC_R_SUCCESS;
36
37         switch (resource) {
38         case isc_resource_coresize:
39                 *rlim_resource = RLIMIT_CORE;
40                 break;
41         case isc_resource_cputime:
42                 *rlim_resource = RLIMIT_CPU;
43                 break;          
44         case isc_resource_datasize:
45                 *rlim_resource = RLIMIT_DATA;
46                 break;          
47         case isc_resource_filesize:
48                 *rlim_resource = RLIMIT_FSIZE;
49                 break;          
50         case isc_resource_lockedmemory:
51 #ifdef RLIMIT_MEMLOCK
52                 *rlim_resource = RLIMIT_MEMLOCK;
53 #else
54                 result = ISC_R_NOTIMPLEMENTED;
55 #endif
56                 break;
57         case isc_resource_openfiles:
58 #ifdef RLIMIT_NOFILE
59                 *rlim_resource = RLIMIT_NOFILE;
60 #else
61                 result = ISC_R_NOTIMPLEMENTED;
62 #endif
63                 break;
64         case isc_resource_processes:
65 #ifdef RLIMIT_NPROC
66                 *rlim_resource = RLIMIT_NPROC;
67 #else
68                 result = ISC_R_NOTIMPLEMENTED;
69 #endif
70                 break;
71         case isc_resource_residentsize:
72 #ifdef RLIMIT_RSS
73                 *rlim_resource = RLIMIT_RSS;
74 #else
75                 result = ISC_R_NOTIMPLEMENTED;
76 #endif
77                 break;
78         case isc_resource_stacksize:
79                 *rlim_resource = RLIMIT_STACK;
80                 break;
81         default:
82                 /*
83                  * This test is not very robust if isc_resource_t
84                  * changes, but generates a clear assertion message.
85                  */
86                 REQUIRE(resource >= isc_resource_coresize &&
87                         resource <= isc_resource_stacksize);
88
89                 result = ISC_R_RANGE;
90                 break;
91         }
92
93         return (result);
94 }
95
96 isc_result_t
97 isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
98         struct rlimit rl;
99         ISC_PLATFORM_RLIMITTYPE rlim_value;
100         int unixresult;
101         int unixresource;
102         isc_result_t result;
103
104         result = resource2rlim(resource, &unixresource);
105         if (result != ISC_R_SUCCESS)
106                 return (result);
107
108         if (value == ISC_RESOURCE_UNLIMITED)
109                 rlim_value = RLIM_INFINITY;
110
111         else {
112                 /*
113                  * isc_resourcevalue_t was chosen as an unsigned 64 bit
114                  * integer so that it could contain the maximum range of
115                  * reasonable values.  Unfortunately, this exceeds the typical
116                  * range on Unix systems.  Ensure the range of
117                  * ISC_PLATFORM_RLIMITTYPE is not overflowed.
118                  */
119                 isc_resourcevalue_t rlim_max;
120                 isc_boolean_t rlim_t_is_signed =
121                         ISC_TF(((double)(ISC_PLATFORM_RLIMITTYPE)-1) < 0);
122
123                 if (rlim_t_is_signed)
124                         rlim_max = ~((ISC_PLATFORM_RLIMITTYPE)1 <<
125                                      (sizeof(ISC_PLATFORM_RLIMITTYPE) * 8 - 1));
126                 else
127                         rlim_max = (ISC_PLATFORM_RLIMITTYPE)-1;
128
129                 if (value > rlim_max)
130                         value = rlim_max;
131
132                 rlim_value = value;
133         }
134
135         /*
136          * The BIND 8 documentation reports:
137          *
138          *      Note: on some operating systems the server cannot set an
139          *      unlimited value and cannot determine the maximum number of
140          *      open files the kernel can support. On such systems, choosing
141          *      unlimited will cause the server to use the larger of the
142          *      rlim_max for RLIMIT_NOFILE and the value returned by
143          *      sysconf(_SC_OPEN_MAX). If the actual kernel limit is larger
144          *      than this value, use limit files to specify the limit
145          *      explicitly.
146          *
147          * The CHANGES for 8.1.2-T3A also mention:
148          *
149          *      352. [bug] Because of problems with setting an infinite
150          *      rlim_max for RLIMIT_NOFILE on some systems, previous versions
151          *      of the server implemented "limit files unlimited" by setting
152          *      the limit to the value returned by sysconf(_SC_OPEN_MAX).  The
153          *      server will now use RLIM_INFINITY on systems which allow it.
154          *
155          * At some point the BIND 8 server stopped using SC_OPEN_MAX for this
156          * purpose at all, but it isn't clear to me when or why, as my access
157          * to the CVS archive is limited at the time of this writing.  What
158          * BIND 8 *does* do is to set RLIMIT_NOFILE to either RLIMIT_INFINITY
159          * on a half dozen operating systems or to FD_SETSIZE on the rest,
160          * the latter of which is probably fewer than the real limit.  (Note
161          * that libisc's socket module will have problems with any fd over
162          * FD_SETSIZE.  This should be fixed in the socket module, not a
163          * limitation here.  BIND 8's eventlib also has a problem, making
164          * its RLIMIT_INFINITY setting useless, because it closes and ignores
165          * any fd over FD_SETSIZE.)
166          *
167          * More troubling is the reference to some operating systems not being
168          * able to set an unlimited value for the number of open files.  I'd
169          * hate to put in code that is really only there to support archaic
170          * systems that the rest of libisc won't work on anyway.  So what this
171          * extremely verbose comment is here to say is the following:
172          *
173          *   I'm aware there might be an issue with not limiting the value
174          *   for RLIMIT_NOFILE on some systems, but since I don't know yet
175          *   what those systems are and what the best workaround is (use
176          *   sysconf()?  rlim_max from getrlimit()?  FD_SETSIZE?) so nothing
177          *   is currently being done to clamp the value for open files.
178          */
179
180         rl.rlim_cur = rl.rlim_max = rlim_value;
181         unixresult = setrlimit(unixresource, &rl);
182
183         if (unixresult == 0)
184                 return (ISC_R_SUCCESS);
185         else
186                 return (isc__errno2result(errno));
187 }
188
189 isc_result_t
190 isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
191         int unixresult;
192         int unixresource;
193         struct rlimit rl;
194         isc_result_t result;
195
196         result = resource2rlim(resource, &unixresource);
197         if (result == ISC_R_SUCCESS) {
198                 unixresult = getrlimit(unixresource, &rl);
199                 INSIST(unixresult == 0);
200                 *value = rl.rlim_max;
201         }
202
203         return (result);
204 }