1135446Strhodes/* 2193149Sdougb * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000, 2001 Internet Software Consortium. 4135446Strhodes * 5182645Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18234010Sdougb/* $Id: resource.c,v 1.23 2009/02/13 23:48:14 tbox Exp $ */ 19135446Strhodes 20135446Strhodes#include <config.h> 21135446Strhodes 22135446Strhodes#include <sys/types.h> 23135446Strhodes#include <sys/time.h> /* Required on some systems for <sys/resource.h>. */ 24135446Strhodes#include <sys/resource.h> 25135446Strhodes 26135446Strhodes#include <isc/platform.h> 27135446Strhodes#include <isc/resource.h> 28135446Strhodes#include <isc/result.h> 29135446Strhodes#include <isc/util.h> 30135446Strhodes 31182645Sdougb#ifdef __linux__ 32182645Sdougb#include <linux/fs.h> /* To get the large NR_OPEN. */ 33182645Sdougb#endif 34182645Sdougb 35186462Sdougb#if defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H) 36182645Sdougb#include <sys/dyntune.h> 37182645Sdougb#endif 38182645Sdougb 39135446Strhodes#include "errno2result.h" 40135446Strhodes 41135446Strhodesstatic isc_result_t 42135446Strhodesresource2rlim(isc_resource_t resource, int *rlim_resource) { 43135446Strhodes isc_result_t result = ISC_R_SUCCESS; 44135446Strhodes 45135446Strhodes switch (resource) { 46135446Strhodes case isc_resource_coresize: 47135446Strhodes *rlim_resource = RLIMIT_CORE; 48135446Strhodes break; 49135446Strhodes case isc_resource_cputime: 50135446Strhodes *rlim_resource = RLIMIT_CPU; 51186462Sdougb break; 52135446Strhodes case isc_resource_datasize: 53135446Strhodes *rlim_resource = RLIMIT_DATA; 54186462Sdougb break; 55135446Strhodes case isc_resource_filesize: 56135446Strhodes *rlim_resource = RLIMIT_FSIZE; 57186462Sdougb break; 58135446Strhodes case isc_resource_lockedmemory: 59135446Strhodes#ifdef RLIMIT_MEMLOCK 60135446Strhodes *rlim_resource = RLIMIT_MEMLOCK; 61135446Strhodes#else 62135446Strhodes result = ISC_R_NOTIMPLEMENTED; 63135446Strhodes#endif 64135446Strhodes break; 65135446Strhodes case isc_resource_openfiles: 66135446Strhodes#ifdef RLIMIT_NOFILE 67135446Strhodes *rlim_resource = RLIMIT_NOFILE; 68135446Strhodes#else 69135446Strhodes result = ISC_R_NOTIMPLEMENTED; 70135446Strhodes#endif 71135446Strhodes break; 72135446Strhodes case isc_resource_processes: 73135446Strhodes#ifdef RLIMIT_NPROC 74135446Strhodes *rlim_resource = RLIMIT_NPROC; 75135446Strhodes#else 76135446Strhodes result = ISC_R_NOTIMPLEMENTED; 77135446Strhodes#endif 78135446Strhodes break; 79135446Strhodes case isc_resource_residentsize: 80135446Strhodes#ifdef RLIMIT_RSS 81135446Strhodes *rlim_resource = RLIMIT_RSS; 82135446Strhodes#else 83135446Strhodes result = ISC_R_NOTIMPLEMENTED; 84135446Strhodes#endif 85135446Strhodes break; 86135446Strhodes case isc_resource_stacksize: 87135446Strhodes *rlim_resource = RLIMIT_STACK; 88135446Strhodes break; 89135446Strhodes default: 90186462Sdougb /* 91135446Strhodes * This test is not very robust if isc_resource_t 92135446Strhodes * changes, but generates a clear assertion message. 93135446Strhodes */ 94135446Strhodes REQUIRE(resource >= isc_resource_coresize && 95135446Strhodes resource <= isc_resource_stacksize); 96135446Strhodes 97135446Strhodes result = ISC_R_RANGE; 98135446Strhodes break; 99135446Strhodes } 100135446Strhodes 101135446Strhodes return (result); 102135446Strhodes} 103135446Strhodes 104135446Strhodesisc_result_t 105135446Strhodesisc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) { 106135446Strhodes struct rlimit rl; 107135446Strhodes ISC_PLATFORM_RLIMITTYPE rlim_value; 108135446Strhodes int unixresult; 109135446Strhodes int unixresource; 110135446Strhodes isc_result_t result; 111135446Strhodes 112135446Strhodes result = resource2rlim(resource, &unixresource); 113135446Strhodes if (result != ISC_R_SUCCESS) 114135446Strhodes return (result); 115135446Strhodes 116135446Strhodes if (value == ISC_RESOURCE_UNLIMITED) 117135446Strhodes rlim_value = RLIM_INFINITY; 118135446Strhodes 119135446Strhodes else { 120135446Strhodes /* 121135446Strhodes * isc_resourcevalue_t was chosen as an unsigned 64 bit 122135446Strhodes * integer so that it could contain the maximum range of 123135446Strhodes * reasonable values. Unfortunately, this exceeds the typical 124135446Strhodes * range on Unix systems. Ensure the range of 125135446Strhodes * ISC_PLATFORM_RLIMITTYPE is not overflowed. 126135446Strhodes */ 127135446Strhodes isc_resourcevalue_t rlim_max; 128135446Strhodes isc_boolean_t rlim_t_is_signed = 129135446Strhodes ISC_TF(((double)(ISC_PLATFORM_RLIMITTYPE)-1) < 0); 130135446Strhodes 131135446Strhodes if (rlim_t_is_signed) 132135446Strhodes rlim_max = ~((ISC_PLATFORM_RLIMITTYPE)1 << 133135446Strhodes (sizeof(ISC_PLATFORM_RLIMITTYPE) * 8 - 1)); 134135446Strhodes else 135135446Strhodes rlim_max = (ISC_PLATFORM_RLIMITTYPE)-1; 136135446Strhodes 137135446Strhodes if (value > rlim_max) 138135446Strhodes value = rlim_max; 139135446Strhodes 140135446Strhodes rlim_value = value; 141135446Strhodes } 142135446Strhodes 143135446Strhodes rl.rlim_cur = rl.rlim_max = rlim_value; 144135446Strhodes unixresult = setrlimit(unixresource, &rl); 145135446Strhodes 146135446Strhodes if (unixresult == 0) 147135446Strhodes return (ISC_R_SUCCESS); 148182645Sdougb 149182645Sdougb#if defined(OPEN_MAX) && defined(__APPLE__) 150182645Sdougb /* 151182645Sdougb * The Darwin kernel doesn't accept RLIM_INFINITY for rlim_cur; the 152182645Sdougb * maximum possible value is OPEN_MAX. BIND8 used to use 153182645Sdougb * sysconf(_SC_OPEN_MAX) for such a case, but this value is much 154182645Sdougb * smaller than OPEN_MAX and is not really effective. 155182645Sdougb */ 156182645Sdougb if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) { 157182645Sdougb rl.rlim_cur = OPEN_MAX; 158182645Sdougb unixresult = setrlimit(unixresource, &rl); 159182645Sdougb if (unixresult == 0) 160182645Sdougb return (ISC_R_SUCCESS); 161182645Sdougb } 162193149Sdougb#elif defined(__linux__) 163193149Sdougb#ifndef NR_OPEN 164193149Sdougb#define NR_OPEN (1024*1024) 165193149Sdougb#endif 166193149Sdougb 167182645Sdougb /* 168182645Sdougb * Some Linux kernels don't accept RLIM_INFINIT; the maximum 169182645Sdougb * possible value is the NR_OPEN defined in linux/fs.h. 170182645Sdougb */ 171182645Sdougb if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) { 172182645Sdougb rl.rlim_cur = rl.rlim_max = NR_OPEN; 173182645Sdougb unixresult = setrlimit(unixresource, &rl); 174182645Sdougb if (unixresult == 0) 175182645Sdougb return (ISC_R_SUCCESS); 176182645Sdougb } 177186462Sdougb#elif defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H) 178182645Sdougb if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) { 179182645Sdougb uint64_t maxfiles; 180182645Sdougb if (gettune("maxfiles_lim", &maxfiles) == 0) { 181182645Sdougb rl.rlim_cur = rl.rlim_max = maxfiles; 182182645Sdougb unixresult = setrlimit(unixresource, &rl); 183182645Sdougb if (unixresult == 0) 184182645Sdougb return (ISC_R_SUCCESS); 185182645Sdougb } 186182645Sdougb } 187182645Sdougb#endif 188182645Sdougb if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) { 189182645Sdougb if (getrlimit(unixresource, &rl) == 0) { 190182645Sdougb rl.rlim_cur = rl.rlim_max; 191182645Sdougb unixresult = setrlimit(unixresource, &rl); 192182645Sdougb if (unixresult == 0) 193182645Sdougb return (ISC_R_SUCCESS); 194182645Sdougb } 195182645Sdougb } 196182645Sdougb return (isc__errno2result(errno)); 197135446Strhodes} 198135446Strhodes 199135446Strhodesisc_result_t 200135446Strhodesisc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) { 201135446Strhodes int unixresult; 202135446Strhodes int unixresource; 203135446Strhodes struct rlimit rl; 204135446Strhodes isc_result_t result; 205135446Strhodes 206135446Strhodes result = resource2rlim(resource, &unixresource); 207135446Strhodes if (result == ISC_R_SUCCESS) { 208135446Strhodes unixresult = getrlimit(unixresource, &rl); 209135446Strhodes INSIST(unixresult == 0); 210135446Strhodes *value = rl.rlim_max; 211135446Strhodes } 212135446Strhodes 213135446Strhodes return (result); 214135446Strhodes} 215182645Sdougb 216182645Sdougbisc_result_t 217186462Sdougbisc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) { 218182645Sdougb int unixresult; 219182645Sdougb int unixresource; 220182645Sdougb struct rlimit rl; 221182645Sdougb isc_result_t result; 222182645Sdougb 223182645Sdougb result = resource2rlim(resource, &unixresource); 224182645Sdougb if (result == ISC_R_SUCCESS) { 225182645Sdougb unixresult = getrlimit(unixresource, &rl); 226182645Sdougb INSIST(unixresult == 0); 227182645Sdougb *value = rl.rlim_cur; 228182645Sdougb } 229182645Sdougb 230182645Sdougb return (result); 231182645Sdougb} 232