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