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
33static isc_result_t
34resource2rlim(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
96isc_result_t
97isc_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
185isc_result_t
186isc_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
204isc_result_t
205isc_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