1 /* $NetBSD: resource.c,v 1.4 2014/12/10 04:38:01 christos Exp $ */
2
3 /*
4 * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001 Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /* Id: resource.c,v 1.23 2009/02/13 23:48:14 tbox Exp */
21
22 #include <config.h>
23
24 #include <sys/types.h>
25 #include <sys/time.h> /* Required on some systems for <sys/resource.h>. */
26 #include <sys/resource.h>
27
28 #include <isc/platform.h>
29 #include <isc/resource.h>
30 #include <isc/result.h>
31 #include <isc/util.h>
32
33 #ifdef __linux__
34 #include <linux/fs.h> /* To get the large NR_OPEN. */
35 #endif
36
37 #if defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
38 #include <sys/dyntune.h>
39 #endif
40
41 #include "errno2result.h"
42
43 static isc_result_t
resource2rlim(isc_resource_t resource,int * rlim_resource)44 resource2rlim(isc_resource_t resource, int *rlim_resource) {
45 isc_result_t result = ISC_R_SUCCESS;
46
47 switch (resource) {
48 case isc_resource_coresize:
49 *rlim_resource = RLIMIT_CORE;
50 break;
51 case isc_resource_cputime:
52 *rlim_resource = RLIMIT_CPU;
53 break;
54 case isc_resource_datasize:
55 *rlim_resource = RLIMIT_DATA;
56 break;
57 case isc_resource_filesize:
58 *rlim_resource = RLIMIT_FSIZE;
59 break;
60 case isc_resource_lockedmemory:
61 #ifdef RLIMIT_MEMLOCK
62 *rlim_resource = RLIMIT_MEMLOCK;
63 #else
64 result = ISC_R_NOTIMPLEMENTED;
65 #endif
66 break;
67 case isc_resource_openfiles:
68 #ifdef RLIMIT_NOFILE
69 *rlim_resource = RLIMIT_NOFILE;
70 #else
71 result = ISC_R_NOTIMPLEMENTED;
72 #endif
73 break;
74 case isc_resource_processes:
75 #ifdef RLIMIT_NPROC
76 *rlim_resource = RLIMIT_NPROC;
77 #else
78 result = ISC_R_NOTIMPLEMENTED;
79 #endif
80 break;
81 case isc_resource_residentsize:
82 #ifdef RLIMIT_RSS
83 *rlim_resource = RLIMIT_RSS;
84 #else
85 result = ISC_R_NOTIMPLEMENTED;
86 #endif
87 break;
88 case isc_resource_stacksize:
89 *rlim_resource = RLIMIT_STACK;
90 break;
91 default:
92 /*
93 * This test is not very robust if isc_resource_t
94 * changes, but generates a clear assertion message.
95 */
96 REQUIRE(resource >= isc_resource_coresize &&
97 resource <= isc_resource_stacksize);
98
99 result = ISC_R_RANGE;
100 break;
101 }
102
103 return (result);
104 }
105
106 isc_result_t
isc_resource_setlimit(isc_resource_t resource,isc_resourcevalue_t value)107 isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
108 struct rlimit rl;
109 ISC_PLATFORM_RLIMITTYPE rlim_value;
110 int unixresult;
111 int unixresource;
112 isc_result_t result;
113
114 result = resource2rlim(resource, &unixresource);
115 if (result != ISC_R_SUCCESS)
116 return (result);
117
118 if (value == ISC_RESOURCE_UNLIMITED)
119 rlim_value = RLIM_INFINITY;
120
121 else {
122 /*
123 * isc_resourcevalue_t was chosen as an unsigned 64 bit
124 * integer so that it could contain the maximum range of
125 * reasonable values. Unfortunately, this exceeds the typical
126 * range on Unix systems. Ensure the range of
127 * ISC_PLATFORM_RLIMITTYPE is not overflowed.
128 */
129 isc_resourcevalue_t rlim_max;
130 isc_boolean_t rlim_t_is_signed =
131 ISC_TF(((double)(ISC_PLATFORM_RLIMITTYPE)-1) < 0);
132
133 if (rlim_t_is_signed)
134 rlim_max = ~((ISC_PLATFORM_RLIMITTYPE)1 <<
135 (sizeof(ISC_PLATFORM_RLIMITTYPE) * 8 - 1));
136 else
137 rlim_max = (ISC_PLATFORM_RLIMITTYPE)-1;
138
139 if (value > rlim_max)
140 value = rlim_max;
141
142 rlim_value = value;
143 }
144
145 rl.rlim_cur = rl.rlim_max = rlim_value;
146 unixresult = setrlimit(unixresource, &rl);
147
148 if (unixresult == 0)
149 return (ISC_R_SUCCESS);
150
151 #if defined(OPEN_MAX) && defined(__APPLE__)
152 /*
153 * The Darwin kernel doesn't accept RLIM_INFINITY for rlim_cur; the
154 * maximum possible value is OPEN_MAX. BIND8 used to use
155 * sysconf(_SC_OPEN_MAX) for such a case, but this value is much
156 * smaller than OPEN_MAX and is not really effective.
157 */
158 if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
159 rl.rlim_cur = OPEN_MAX;
160 unixresult = setrlimit(unixresource, &rl);
161 if (unixresult == 0)
162 return (ISC_R_SUCCESS);
163 }
164 #elif defined(__linux__)
165 #ifndef NR_OPEN
166 #define NR_OPEN (1024*1024)
167 #endif
168
169 /*
170 * Some Linux kernels don't accept RLIM_INFINIT; the maximum
171 * possible value is the NR_OPEN defined in linux/fs.h.
172 */
173 if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
174 rl.rlim_cur = rl.rlim_max = NR_OPEN;
175 unixresult = setrlimit(unixresource, &rl);
176 if (unixresult == 0)
177 return (ISC_R_SUCCESS);
178 }
179 #elif defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
180 if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
181 uint64_t maxfiles;
182 if (gettune("maxfiles_lim", &maxfiles) == 0) {
183 rl.rlim_cur = rl.rlim_max = maxfiles;
184 unixresult = setrlimit(unixresource, &rl);
185 if (unixresult == 0)
186 return (ISC_R_SUCCESS);
187 }
188 }
189 #endif
190 if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
191 if (getrlimit(unixresource, &rl) == 0) {
192 rl.rlim_cur = rl.rlim_max;
193 unixresult = setrlimit(unixresource, &rl);
194 if (unixresult == 0)
195 return (ISC_R_SUCCESS);
196 }
197 }
198 return (isc__errno2result(errno));
199 }
200
201 isc_result_t
isc_resource_getlimit(isc_resource_t resource,isc_resourcevalue_t * value)202 isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
203 int unixresult;
204 int unixresource;
205 struct rlimit rl;
206 isc_result_t result;
207
208 result = resource2rlim(resource, &unixresource);
209 if (result == ISC_R_SUCCESS) {
210 unixresult = getrlimit(unixresource, &rl);
211 INSIST(unixresult == 0);
212 *value = rl.rlim_max;
213 }
214
215 return (result);
216 }
217
218 isc_result_t
isc_resource_getcurlimit(isc_resource_t resource,isc_resourcevalue_t * value)219 isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
220 int unixresult;
221 int unixresource;
222 struct rlimit rl;
223 isc_result_t result;
224
225 result = resource2rlim(resource, &unixresource);
226 if (result == ISC_R_SUCCESS) {
227 unixresult = getrlimit(unixresource, &rl);
228 INSIST(unixresult == 0);
229 *value = rl.rlim_cur;
230 }
231
232 return (result);
233 }
234