diff options
Diffstat (limited to 'lib/isc/resource.c')
-rw-r--r-- | lib/isc/resource.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/lib/isc/resource.c b/lib/isc/resource.c new file mode 100644 index 0000000..d83762c --- /dev/null +++ b/lib/isc/resource.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <inttypes.h> +#include <stdbool.h> +#include <sys/resource.h> +#include <sys/time.h> /* Required on some systems for <sys/resource.h>. */ +#include <sys/types.h> + +#include <isc/resource.h> +#include <isc/result.h> +#include <isc/util.h> + +#ifdef __linux__ +#include <linux/fs.h> /* To get the large NR_OPEN. */ +#endif /* ifdef __linux__ */ + +#include "errno2result.h" + +static isc_result_t +resource2rlim(isc_resource_t resource, int *rlim_resource) { + isc_result_t result = ISC_R_SUCCESS; + + switch (resource) { + case isc_resource_coresize: + *rlim_resource = RLIMIT_CORE; + break; + case isc_resource_cputime: + *rlim_resource = RLIMIT_CPU; + break; + case isc_resource_datasize: + *rlim_resource = RLIMIT_DATA; + break; + case isc_resource_filesize: + *rlim_resource = RLIMIT_FSIZE; + break; + case isc_resource_lockedmemory: +#ifdef RLIMIT_MEMLOCK + *rlim_resource = RLIMIT_MEMLOCK; +#else /* ifdef RLIMIT_MEMLOCK */ + result = ISC_R_NOTIMPLEMENTED; +#endif /* ifdef RLIMIT_MEMLOCK */ + break; + case isc_resource_openfiles: +#ifdef RLIMIT_NOFILE + *rlim_resource = RLIMIT_NOFILE; +#else /* ifdef RLIMIT_NOFILE */ + result = ISC_R_NOTIMPLEMENTED; +#endif /* ifdef RLIMIT_NOFILE */ + break; + case isc_resource_processes: +#ifdef RLIMIT_NPROC + *rlim_resource = RLIMIT_NPROC; +#else /* ifdef RLIMIT_NPROC */ + result = ISC_R_NOTIMPLEMENTED; +#endif /* ifdef RLIMIT_NPROC */ + break; + case isc_resource_residentsize: +#ifdef RLIMIT_RSS + *rlim_resource = RLIMIT_RSS; +#else /* ifdef RLIMIT_RSS */ + result = ISC_R_NOTIMPLEMENTED; +#endif /* ifdef RLIMIT_RSS */ + break; + case isc_resource_stacksize: + *rlim_resource = RLIMIT_STACK; + break; + default: + /* + * This test is not very robust if isc_resource_t + * changes, but generates a clear assertion message. + */ + REQUIRE(resource >= isc_resource_coresize && + resource <= isc_resource_stacksize); + + result = ISC_R_RANGE; + break; + } + + return (result); +} + +isc_result_t +isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) { + struct rlimit rl; + rlim_t rlim_value; + int unixresult; + int unixresource; + isc_result_t result; + + result = resource2rlim(resource, &unixresource); + if (result != ISC_R_SUCCESS) { + return (result); + } + + if (value == ISC_RESOURCE_UNLIMITED) { + rlim_value = RLIM_INFINITY; + } else { + /* + * isc_resourcevalue_t was chosen as an unsigned 64 bit + * integer so that it could contain the maximum range of + * reasonable values. Unfortunately, this exceeds the typical + * range on Unix systems. Ensure the range of + * rlim_t is not overflowed. + */ + isc_resourcevalue_t rlim_max; + bool rlim_t_is_signed = (((double)(rlim_t)-1) < 0); + + if (rlim_t_is_signed) { + rlim_max = ~((rlim_t)1 << (sizeof(rlim_t) * 8 - 1)); + } else { + rlim_max = (rlim_t)-1; + } + + if (value > rlim_max) { + value = rlim_max; + } + + rlim_value = value; + } + + rl.rlim_cur = rl.rlim_max = rlim_value; + unixresult = setrlimit(unixresource, &rl); + + if (unixresult == 0) { + return (ISC_R_SUCCESS); + } + +#if defined(OPEN_MAX) && defined(__APPLE__) + /* + * The Darwin kernel doesn't accept RLIM_INFINITY for rlim_cur; the + * maximum possible value is OPEN_MAX. BIND8 used to use + * sysconf(_SC_OPEN_MAX) for such a case, but this value is much + * smaller than OPEN_MAX and is not really effective. + */ + if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) { + rl.rlim_cur = OPEN_MAX; + unixresult = setrlimit(unixresource, &rl); + if (unixresult == 0) { + return (ISC_R_SUCCESS); + } + } +#elif defined(__linux__) +#ifndef NR_OPEN +#define NR_OPEN (1024 * 1024) +#endif /* ifndef NR_OPEN */ + + /* + * Some Linux kernels don't accept RLIM_INFINIT; the maximum + * possible value is the NR_OPEN defined in linux/fs.h. + */ + if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) { + rl.rlim_cur = rl.rlim_max = NR_OPEN; + unixresult = setrlimit(unixresource, &rl); + if (unixresult == 0) { + return (ISC_R_SUCCESS); + } + } +#endif /* if defined(OPEN_MAX) && defined(__APPLE__) */ + if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) { + if (getrlimit(unixresource, &rl) == 0) { + rl.rlim_cur = rl.rlim_max; + unixresult = setrlimit(unixresource, &rl); + if (unixresult == 0) { + return (ISC_R_SUCCESS); + } + } + } + return (isc__errno2result(errno)); +} + +isc_result_t +isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) { + int unixresource; + struct rlimit rl; + isc_result_t result; + + result = resource2rlim(resource, &unixresource); + if (result != ISC_R_SUCCESS) { + return (result); + } + + if (getrlimit(unixresource, &rl) != 0) { + return (isc__errno2result(errno)); + } + + *value = rl.rlim_max; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) { + int unixresource; + struct rlimit rl; + isc_result_t result; + + result = resource2rlim(resource, &unixresource); + if (result != ISC_R_SUCCESS) { + return (result); + } + + if (getrlimit(unixresource, &rl) != 0) { + return (isc__errno2result(errno)); + } + + *value = rl.rlim_cur; + return (ISC_R_SUCCESS); +} |