1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12 #include <inttypes.h>
13 #include <stdbool.h>
14 #include <sys/resource.h>
15 #include <sys/time.h> /* Required on some systems for <sys/resource.h>. */
16 #include <sys/types.h>
17
18 #include <isc/platform.h>
19 #include <isc/resource.h>
20 #include <isc/result.h>
21 #include <isc/util.h>
22
23 #ifdef __linux__
24 #include <linux/fs.h> /* To get the large NR_OPEN. */
25 #endif /* ifdef __linux__ */
26
27 #include "errno2result.h"
28
29 static isc_result_t
resource2rlim(isc_resource_t resource,int * rlim_resource)30 resource2rlim(isc_resource_t resource, int *rlim_resource) {
31 isc_result_t result = ISC_R_SUCCESS;
32
33 switch (resource) {
34 case isc_resource_coresize:
35 *rlim_resource = RLIMIT_CORE;
36 break;
37 case isc_resource_cputime:
38 *rlim_resource = RLIMIT_CPU;
39 break;
40 case isc_resource_datasize:
41 *rlim_resource = RLIMIT_DATA;
42 break;
43 case isc_resource_filesize:
44 *rlim_resource = RLIMIT_FSIZE;
45 break;
46 case isc_resource_lockedmemory:
47 #ifdef RLIMIT_MEMLOCK
48 *rlim_resource = RLIMIT_MEMLOCK;
49 #else /* ifdef RLIMIT_MEMLOCK */
50 result = ISC_R_NOTIMPLEMENTED;
51 #endif /* ifdef RLIMIT_MEMLOCK */
52 break;
53 case isc_resource_openfiles:
54 #ifdef RLIMIT_NOFILE
55 *rlim_resource = RLIMIT_NOFILE;
56 #else /* ifdef RLIMIT_NOFILE */
57 result = ISC_R_NOTIMPLEMENTED;
58 #endif /* ifdef RLIMIT_NOFILE */
59 break;
60 case isc_resource_processes:
61 #ifdef RLIMIT_NPROC
62 *rlim_resource = RLIMIT_NPROC;
63 #else /* ifdef RLIMIT_NPROC */
64 result = ISC_R_NOTIMPLEMENTED;
65 #endif /* ifdef RLIMIT_NPROC */
66 break;
67 case isc_resource_residentsize:
68 #ifdef RLIMIT_RSS
69 *rlim_resource = RLIMIT_RSS;
70 #else /* ifdef RLIMIT_RSS */
71 result = ISC_R_NOTIMPLEMENTED;
72 #endif /* ifdef RLIMIT_RSS */
73 break;
74 case isc_resource_stacksize:
75 *rlim_resource = RLIMIT_STACK;
76 break;
77 default:
78 /*
79 * This test is not very robust if isc_resource_t
80 * changes, but generates a clear assertion message.
81 */
82 REQUIRE(resource >= isc_resource_coresize &&
83 resource <= isc_resource_stacksize);
84
85 result = ISC_R_RANGE;
86 break;
87 }
88
89 return (result);
90 }
91
92 isc_result_t
isc_resource_setlimit(isc_resource_t resource,isc_resourcevalue_t value)93 isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
94 struct rlimit rl;
95 rlim_t rlim_value;
96 int unixresult;
97 int unixresource;
98 isc_result_t result;
99
100 result = resource2rlim(resource, &unixresource);
101 if (result != ISC_R_SUCCESS) {
102 return (result);
103 }
104
105 if (value == ISC_RESOURCE_UNLIMITED) {
106 rlim_value = RLIM_INFINITY;
107 } else {
108 /*
109 * isc_resourcevalue_t was chosen as an unsigned 64 bit
110 * integer so that it could contain the maximum range of
111 * reasonable values. Unfortunately, this exceeds the typical
112 * range on Unix systems. Ensure the range of
113 * rlim_t is not overflowed.
114 */
115 isc_resourcevalue_t rlim_max;
116 bool rlim_t_is_signed = (((double)(rlim_t)-1) < 0);
117
118 if (rlim_t_is_signed) {
119 rlim_max = ~((rlim_t)1 << (sizeof(rlim_t) * 8 - 1));
120 } else {
121 rlim_max = (rlim_t)-1;
122 }
123
124 if (value > rlim_max) {
125 value = rlim_max;
126 }
127
128 rlim_value = value;
129 }
130
131 rl.rlim_cur = rl.rlim_max = rlim_value;
132 unixresult = setrlimit(unixresource, &rl);
133
134 if (unixresult == 0) {
135 return (ISC_R_SUCCESS);
136 }
137
138 #if defined(OPEN_MAX) && defined(__APPLE__)
139 /*
140 * The Darwin kernel doesn't accept RLIM_INFINITY for rlim_cur; the
141 * maximum possible value is OPEN_MAX. BIND8 used to use
142 * sysconf(_SC_OPEN_MAX) for such a case, but this value is much
143 * smaller than OPEN_MAX and is not really effective.
144 */
145 if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
146 rl.rlim_cur = OPEN_MAX;
147 unixresult = setrlimit(unixresource, &rl);
148 if (unixresult == 0) {
149 return (ISC_R_SUCCESS);
150 }
151 }
152 #elif defined(__linux__)
153 #ifndef NR_OPEN
154 #define NR_OPEN (1024 * 1024)
155 #endif /* ifndef NR_OPEN */
156
157 /*
158 * Some Linux kernels don't accept RLIM_INFINIT; the maximum
159 * possible value is the NR_OPEN defined in linux/fs.h.
160 */
161 if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
162 rl.rlim_cur = rl.rlim_max = NR_OPEN;
163 unixresult = setrlimit(unixresource, &rl);
164 if (unixresult == 0) {
165 return (ISC_R_SUCCESS);
166 }
167 }
168 #endif /* if defined(OPEN_MAX) && defined(__APPLE__) */
169 if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
170 if (getrlimit(unixresource, &rl) == 0) {
171 rl.rlim_cur = rl.rlim_max;
172 unixresult = setrlimit(unixresource, &rl);
173 if (unixresult == 0) {
174 return (ISC_R_SUCCESS);
175 }
176 }
177 }
178 return (isc__errno2result(errno));
179 }
180
181 isc_result_t
isc_resource_getlimit(isc_resource_t resource,isc_resourcevalue_t * value)182 isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
183 int unixresource;
184 struct rlimit rl;
185 isc_result_t result;
186
187 result = resource2rlim(resource, &unixresource);
188 if (result != ISC_R_SUCCESS) {
189 return (result);
190 }
191
192 if (getrlimit(unixresource, &rl) != 0) {
193 return (isc__errno2result(errno));
194 }
195
196 *value = rl.rlim_max;
197 return (ISC_R_SUCCESS);
198 }
199
200 isc_result_t
isc_resource_getcurlimit(isc_resource_t resource,isc_resourcevalue_t * value)201 isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
202 int unixresource;
203 struct rlimit rl;
204 isc_result_t result;
205
206 result = resource2rlim(resource, &unixresource);
207 if (result != ISC_R_SUCCESS) {
208 return (result);
209 }
210
211 if (getrlimit(unixresource, &rl) != 0) {
212 return (isc__errno2result(errno));
213 }
214
215 *value = rl.rlim_cur;
216 return (ISC_R_SUCCESS);
217 }
218