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