1258945Sroberto/*
2258945Sroberto * Copyright (C) 2004, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
3258945Sroberto * Copyright (C) 2000, 2001  Internet Software Consortium.
4258945Sroberto *
5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any
6258945Sroberto * purpose with or without fee is hereby granted, provided that the above
7258945Sroberto * copyright notice and this permission notice appear in all copies.
8258945Sroberto *
9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11258945Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15258945Sroberto * PERFORMANCE OF THIS SOFTWARE.
16258945Sroberto */
17258945Sroberto
18280849Scy/* $Id: resource.c,v 1.23 2009/02/13 23:48:14 tbox Exp $ */
19258945Sroberto
20258945Sroberto#include <config.h>
21258945Sroberto
22258945Sroberto#include <sys/types.h>
23258945Sroberto#include <sys/time.h>	/* Required on some systems for <sys/resource.h>. */
24258945Sroberto#include <sys/resource.h>
25258945Sroberto
26258945Sroberto#include <isc/platform.h>
27258945Sroberto#include <isc/resource.h>
28258945Sroberto#include <isc/result.h>
29258945Sroberto#include <isc/util.h>
30258945Sroberto
31258945Sroberto#ifdef __linux__
32258945Sroberto#include <linux/fs.h>	/* To get the large NR_OPEN. */
33258945Sroberto#endif
34258945Sroberto
35258945Sroberto#if defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
36258945Sroberto#include <sys/dyntune.h>
37258945Sroberto#endif
38258945Sroberto
39258945Sroberto#include "errno2result.h"
40258945Sroberto
41258945Srobertostatic isc_result_t
42258945Srobertoresource2rlim(isc_resource_t resource, int *rlim_resource) {
43258945Sroberto	isc_result_t result = ISC_R_SUCCESS;
44258945Sroberto
45258945Sroberto	switch (resource) {
46258945Sroberto	case isc_resource_coresize:
47258945Sroberto		*rlim_resource = RLIMIT_CORE;
48258945Sroberto		break;
49258945Sroberto	case isc_resource_cputime:
50258945Sroberto		*rlim_resource = RLIMIT_CPU;
51258945Sroberto		break;
52258945Sroberto	case isc_resource_datasize:
53258945Sroberto		*rlim_resource = RLIMIT_DATA;
54258945Sroberto		break;
55258945Sroberto	case isc_resource_filesize:
56258945Sroberto		*rlim_resource = RLIMIT_FSIZE;
57258945Sroberto		break;
58258945Sroberto	case isc_resource_lockedmemory:
59258945Sroberto#ifdef RLIMIT_MEMLOCK
60258945Sroberto		*rlim_resource = RLIMIT_MEMLOCK;
61258945Sroberto#else
62258945Sroberto		result = ISC_R_NOTIMPLEMENTED;
63258945Sroberto#endif
64258945Sroberto		break;
65258945Sroberto	case isc_resource_openfiles:
66258945Sroberto#ifdef RLIMIT_NOFILE
67258945Sroberto		*rlim_resource = RLIMIT_NOFILE;
68258945Sroberto#else
69258945Sroberto		result = ISC_R_NOTIMPLEMENTED;
70258945Sroberto#endif
71258945Sroberto		break;
72258945Sroberto	case isc_resource_processes:
73258945Sroberto#ifdef RLIMIT_NPROC
74258945Sroberto		*rlim_resource = RLIMIT_NPROC;
75258945Sroberto#else
76258945Sroberto		result = ISC_R_NOTIMPLEMENTED;
77258945Sroberto#endif
78258945Sroberto		break;
79258945Sroberto	case isc_resource_residentsize:
80258945Sroberto#ifdef RLIMIT_RSS
81258945Sroberto		*rlim_resource = RLIMIT_RSS;
82258945Sroberto#else
83258945Sroberto		result = ISC_R_NOTIMPLEMENTED;
84258945Sroberto#endif
85258945Sroberto		break;
86258945Sroberto	case isc_resource_stacksize:
87258945Sroberto		*rlim_resource = RLIMIT_STACK;
88258945Sroberto		break;
89258945Sroberto	default:
90258945Sroberto		/*
91258945Sroberto		 * This test is not very robust if isc_resource_t
92258945Sroberto		 * changes, but generates a clear assertion message.
93258945Sroberto		 */
94258945Sroberto		REQUIRE(resource >= isc_resource_coresize &&
95258945Sroberto			resource <= isc_resource_stacksize);
96258945Sroberto
97258945Sroberto		result = ISC_R_RANGE;
98258945Sroberto		break;
99258945Sroberto	}
100258945Sroberto
101258945Sroberto	return (result);
102258945Sroberto}
103258945Sroberto
104258945Srobertoisc_result_t
105258945Srobertoisc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
106258945Sroberto	struct rlimit rl;
107258945Sroberto	ISC_PLATFORM_RLIMITTYPE rlim_value;
108258945Sroberto	int unixresult;
109258945Sroberto	int unixresource;
110258945Sroberto	isc_result_t result;
111258945Sroberto
112258945Sroberto	result = resource2rlim(resource, &unixresource);
113258945Sroberto	if (result != ISC_R_SUCCESS)
114258945Sroberto		return (result);
115258945Sroberto
116258945Sroberto	if (value == ISC_RESOURCE_UNLIMITED)
117258945Sroberto		rlim_value = RLIM_INFINITY;
118258945Sroberto
119258945Sroberto	else {
120258945Sroberto		/*
121258945Sroberto		 * isc_resourcevalue_t was chosen as an unsigned 64 bit
122258945Sroberto		 * integer so that it could contain the maximum range of
123258945Sroberto		 * reasonable values.  Unfortunately, this exceeds the typical
124258945Sroberto		 * range on Unix systems.  Ensure the range of
125258945Sroberto		 * ISC_PLATFORM_RLIMITTYPE is not overflowed.
126258945Sroberto		 */
127258945Sroberto		isc_resourcevalue_t rlim_max;
128258945Sroberto		isc_boolean_t rlim_t_is_signed =
129258945Sroberto			ISC_TF(((double)(ISC_PLATFORM_RLIMITTYPE)-1) < 0);
130258945Sroberto
131258945Sroberto		if (rlim_t_is_signed)
132258945Sroberto			rlim_max = ~((ISC_PLATFORM_RLIMITTYPE)1 <<
133258945Sroberto				     (sizeof(ISC_PLATFORM_RLIMITTYPE) * 8 - 1));
134258945Sroberto		else
135258945Sroberto			rlim_max = (ISC_PLATFORM_RLIMITTYPE)-1;
136258945Sroberto
137258945Sroberto		if (value > rlim_max)
138258945Sroberto			value = rlim_max;
139258945Sroberto
140258945Sroberto		rlim_value = value;
141258945Sroberto	}
142258945Sroberto
143258945Sroberto	rl.rlim_cur = rl.rlim_max = rlim_value;
144258945Sroberto	unixresult = setrlimit(unixresource, &rl);
145258945Sroberto
146258945Sroberto	if (unixresult == 0)
147258945Sroberto		return (ISC_R_SUCCESS);
148258945Sroberto
149258945Sroberto#if defined(OPEN_MAX) && defined(__APPLE__)
150258945Sroberto	/*
151258945Sroberto	 * The Darwin kernel doesn't accept RLIM_INFINITY for rlim_cur; the
152258945Sroberto	 * maximum possible value is OPEN_MAX.  BIND8 used to use
153258945Sroberto	 * sysconf(_SC_OPEN_MAX) for such a case, but this value is much
154258945Sroberto	 * smaller than OPEN_MAX and is not really effective.
155258945Sroberto	 */
156258945Sroberto	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
157258945Sroberto		rl.rlim_cur = OPEN_MAX;
158258945Sroberto		unixresult = setrlimit(unixresource, &rl);
159258945Sroberto		if (unixresult == 0)
160258945Sroberto			return (ISC_R_SUCCESS);
161258945Sroberto	}
162258945Sroberto#elif defined(__linux__)
163258945Sroberto#ifndef NR_OPEN
164258945Sroberto#define NR_OPEN (1024*1024)
165258945Sroberto#endif
166258945Sroberto
167258945Sroberto	/*
168258945Sroberto	 * Some Linux kernels don't accept RLIM_INFINIT; the maximum
169258945Sroberto	 * possible value is the NR_OPEN defined in linux/fs.h.
170258945Sroberto	 */
171258945Sroberto	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
172258945Sroberto		rl.rlim_cur = rl.rlim_max = NR_OPEN;
173258945Sroberto		unixresult = setrlimit(unixresource, &rl);
174258945Sroberto		if (unixresult == 0)
175258945Sroberto			return (ISC_R_SUCCESS);
176258945Sroberto	}
177258945Sroberto#elif defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
178258945Sroberto	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
179258945Sroberto		uint64_t maxfiles;
180258945Sroberto		if (gettune("maxfiles_lim", &maxfiles) == 0) {
181258945Sroberto			rl.rlim_cur = rl.rlim_max = maxfiles;
182258945Sroberto			unixresult = setrlimit(unixresource, &rl);
183258945Sroberto			if (unixresult == 0)
184258945Sroberto				return (ISC_R_SUCCESS);
185258945Sroberto		}
186258945Sroberto	}
187258945Sroberto#endif
188258945Sroberto	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
189258945Sroberto		if (getrlimit(unixresource, &rl) == 0) {
190258945Sroberto			rl.rlim_cur = rl.rlim_max;
191258945Sroberto			unixresult = setrlimit(unixresource, &rl);
192258945Sroberto			if (unixresult == 0)
193258945Sroberto				return (ISC_R_SUCCESS);
194258945Sroberto		}
195258945Sroberto	}
196258945Sroberto	return (isc__errno2result(errno));
197258945Sroberto}
198258945Sroberto
199258945Srobertoisc_result_t
200258945Srobertoisc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
201258945Sroberto	int unixresult;
202258945Sroberto	int unixresource;
203258945Sroberto	struct rlimit rl;
204258945Sroberto	isc_result_t result;
205258945Sroberto
206258945Sroberto	result = resource2rlim(resource, &unixresource);
207258945Sroberto	if (result == ISC_R_SUCCESS) {
208258945Sroberto		unixresult = getrlimit(unixresource, &rl);
209258945Sroberto		INSIST(unixresult == 0);
210258945Sroberto		*value = rl.rlim_max;
211258945Sroberto	}
212258945Sroberto
213258945Sroberto	return (result);
214258945Sroberto}
215258945Sroberto
216258945Srobertoisc_result_t
217258945Srobertoisc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
218258945Sroberto	int unixresult;
219258945Sroberto	int unixresource;
220258945Sroberto	struct rlimit rl;
221258945Sroberto	isc_result_t result;
222258945Sroberto
223258945Sroberto	result = resource2rlim(resource, &unixresource);
224258945Sroberto	if (result == ISC_R_SUCCESS) {
225258945Sroberto		unixresult = getrlimit(unixresource, &rl);
226258945Sroberto		INSIST(unixresult == 0);
227258945Sroberto		*value = rl.rlim_cur;
228258945Sroberto	}
229258945Sroberto
230258945Sroberto	return (result);
231258945Sroberto}
232