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