xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/isc/unix/resource.c (revision 4afad4b7fa6d4a0d3dedf41d1587a7250710ae54)
1 /*	$NetBSD: resource.c,v 1.1 2024/02/18 20:57:57 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 #include <inttypes.h>
17 #include <stdbool.h>
18 #include <sys/resource.h>
19 #include <sys/time.h> /* Required on some systems for <sys/resource.h>. */
20 #include <sys/types.h>
21 
22 #include <isc/platform.h>
23 #include <isc/resource.h>
24 #include <isc/result.h>
25 #include <isc/util.h>
26 
27 #ifdef __linux__
28 #include <linux/fs.h> /* To get the large NR_OPEN. */
29 #endif		      /* ifdef __linux__ */
30 
31 #include "errno2result.h"
32 
33 static isc_result_t
resource2rlim(isc_resource_t resource,int * rlim_resource)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  /* ifdef RLIMIT_MEMLOCK */
54 		result = ISC_R_NOTIMPLEMENTED;
55 #endif /* ifdef RLIMIT_MEMLOCK */
56 		break;
57 	case isc_resource_openfiles:
58 #ifdef RLIMIT_NOFILE
59 		*rlim_resource = RLIMIT_NOFILE;
60 #else  /* ifdef RLIMIT_NOFILE */
61 		result = ISC_R_NOTIMPLEMENTED;
62 #endif /* ifdef RLIMIT_NOFILE */
63 		break;
64 	case isc_resource_processes:
65 #ifdef RLIMIT_NPROC
66 		*rlim_resource = RLIMIT_NPROC;
67 #else  /* ifdef RLIMIT_NPROC */
68 		result = ISC_R_NOTIMPLEMENTED;
69 #endif /* ifdef RLIMIT_NPROC */
70 		break;
71 	case isc_resource_residentsize:
72 #ifdef RLIMIT_RSS
73 		*rlim_resource = RLIMIT_RSS;
74 #else  /* ifdef RLIMIT_RSS */
75 		result = ISC_R_NOTIMPLEMENTED;
76 #endif /* ifdef RLIMIT_RSS */
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
isc_resource_setlimit(isc_resource_t resource,isc_resourcevalue_t value)97 isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
98 	struct rlimit rl;
99 	rlim_t 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 
109 	if (value == ISC_RESOURCE_UNLIMITED) {
110 		rlim_value = RLIM_INFINITY;
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 		 * rlim_t is not overflowed.
118 		 */
119 		isc_resourcevalue_t rlim_max;
120 		bool rlim_t_is_signed = (((double)(rlim_t)-1) < 0);
121 
122 		if (rlim_t_is_signed) {
123 			rlim_max = ~((rlim_t)1 << (sizeof(rlim_t) * 8 - 1));
124 		} else {
125 			rlim_max = (rlim_t)-1;
126 		}
127 
128 		if (value > rlim_max) {
129 			value = rlim_max;
130 		}
131 
132 		rlim_value = value;
133 	}
134 
135 	rl.rlim_cur = rl.rlim_max = rlim_value;
136 	unixresult = setrlimit(unixresource, &rl);
137 
138 	if (unixresult == 0) {
139 		return (ISC_R_SUCCESS);
140 	}
141 
142 #if defined(OPEN_MAX) && defined(__APPLE__)
143 	/*
144 	 * The Darwin kernel doesn't accept RLIM_INFINITY for rlim_cur; the
145 	 * maximum possible value is OPEN_MAX.  BIND8 used to use
146 	 * sysconf(_SC_OPEN_MAX) for such a case, but this value is much
147 	 * smaller than OPEN_MAX and is not really effective.
148 	 */
149 	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
150 		rl.rlim_cur = OPEN_MAX;
151 		unixresult = setrlimit(unixresource, &rl);
152 		if (unixresult == 0) {
153 			return (ISC_R_SUCCESS);
154 		}
155 	}
156 #elif defined(__linux__)
157 #ifndef NR_OPEN
158 #define NR_OPEN (1024 * 1024)
159 #endif /* ifndef NR_OPEN */
160 
161 	/*
162 	 * Some Linux kernels don't accept RLIM_INFINIT; the maximum
163 	 * possible value is the NR_OPEN defined in linux/fs.h.
164 	 */
165 	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
166 		rl.rlim_cur = rl.rlim_max = NR_OPEN;
167 		unixresult = setrlimit(unixresource, &rl);
168 		if (unixresult == 0) {
169 			return (ISC_R_SUCCESS);
170 		}
171 	}
172 #endif /* if defined(OPEN_MAX) && defined(__APPLE__) */
173 	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
174 		if (getrlimit(unixresource, &rl) == 0) {
175 			rl.rlim_cur = rl.rlim_max;
176 			unixresult = setrlimit(unixresource, &rl);
177 			if (unixresult == 0) {
178 				return (ISC_R_SUCCESS);
179 			}
180 		}
181 	}
182 	return (isc__errno2result(errno));
183 }
184 
185 isc_result_t
isc_resource_getlimit(isc_resource_t resource,isc_resourcevalue_t * value)186 isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
187 	int unixresource;
188 	struct rlimit rl;
189 	isc_result_t result;
190 
191 	result = resource2rlim(resource, &unixresource);
192 	if (result != ISC_R_SUCCESS) {
193 		return (result);
194 	}
195 
196 	if (getrlimit(unixresource, &rl) != 0) {
197 		return (isc__errno2result(errno));
198 	}
199 
200 	*value = rl.rlim_max;
201 	return (ISC_R_SUCCESS);
202 }
203 
204 isc_result_t
isc_resource_getcurlimit(isc_resource_t resource,isc_resourcevalue_t * value)205 isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
206 	int unixresource;
207 	struct rlimit rl;
208 	isc_result_t result;
209 
210 	result = resource2rlim(resource, &unixresource);
211 	if (result != ISC_R_SUCCESS) {
212 		return (result);
213 	}
214 
215 	if (getrlimit(unixresource, &rl) != 0) {
216 		return (isc__errno2result(errno));
217 	}
218 
219 	*value = rl.rlim_cur;
220 	return (ISC_R_SUCCESS);
221 }
222