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