1 /*
2  * Copyright (C) 2004, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000, 2001  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /* $Id: resource.c,v 1.23 2009/02/13 23:48:14 tbox Exp $ */
19 
20 #include <config.h>
21 
22 #include <sys/types.h>
23 #include <sys/time.h>	/* Required on some systems for <sys/resource.h>. */
24 #include <sys/resource.h>
25 
26 #include <isc/platform.h>
27 #include <isc/resource.h>
28 #include <isc/result.h>
29 #include <isc/util.h>
30 
31 #ifdef __linux__
32 #include <linux/fs.h>	/* To get the large NR_OPEN. */
33 #endif
34 
35 #if defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
36 #include <sys/dyntune.h>
37 #endif
38 
39 #include "errno2result.h"
40 
41 static isc_result_t
resource2rlim(isc_resource_t resource,int * rlim_resource)42 resource2rlim(isc_resource_t resource, int *rlim_resource) {
43 	isc_result_t result = ISC_R_SUCCESS;
44 
45 	switch (resource) {
46 	case isc_resource_coresize:
47 		*rlim_resource = RLIMIT_CORE;
48 		break;
49 	case isc_resource_cputime:
50 		*rlim_resource = RLIMIT_CPU;
51 		break;
52 	case isc_resource_datasize:
53 		*rlim_resource = RLIMIT_DATA;
54 		break;
55 	case isc_resource_filesize:
56 		*rlim_resource = RLIMIT_FSIZE;
57 		break;
58 	case isc_resource_lockedmemory:
59 #ifdef RLIMIT_MEMLOCK
60 		*rlim_resource = RLIMIT_MEMLOCK;
61 #else
62 		result = ISC_R_NOTIMPLEMENTED;
63 #endif
64 		break;
65 	case isc_resource_openfiles:
66 #ifdef RLIMIT_NOFILE
67 		*rlim_resource = RLIMIT_NOFILE;
68 #else
69 		result = ISC_R_NOTIMPLEMENTED;
70 #endif
71 		break;
72 	case isc_resource_processes:
73 #ifdef RLIMIT_NPROC
74 		*rlim_resource = RLIMIT_NPROC;
75 #else
76 		result = ISC_R_NOTIMPLEMENTED;
77 #endif
78 		break;
79 	case isc_resource_residentsize:
80 #ifdef RLIMIT_RSS
81 		*rlim_resource = RLIMIT_RSS;
82 #else
83 		result = ISC_R_NOTIMPLEMENTED;
84 #endif
85 		break;
86 	case isc_resource_stacksize:
87 		*rlim_resource = RLIMIT_STACK;
88 		break;
89 	default:
90 		/*
91 		 * This test is not very robust if isc_resource_t
92 		 * changes, but generates a clear assertion message.
93 		 */
94 		REQUIRE(resource >= isc_resource_coresize &&
95 			resource <= isc_resource_stacksize);
96 
97 		result = ISC_R_RANGE;
98 		break;
99 	}
100 
101 	return (result);
102 }
103 
104 isc_result_t
isc_resource_setlimit(isc_resource_t resource,isc_resourcevalue_t value)105 isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
106 	struct rlimit rl;
107 	ISC_PLATFORM_RLIMITTYPE rlim_value;
108 	int unixresult;
109 	int unixresource;
110 	isc_result_t result;
111 
112 	result = resource2rlim(resource, &unixresource);
113 	if (result != ISC_R_SUCCESS)
114 		return (result);
115 
116 	if (value == ISC_RESOURCE_UNLIMITED)
117 		rlim_value = RLIM_INFINITY;
118 
119 	else {
120 		/*
121 		 * isc_resourcevalue_t was chosen as an unsigned 64 bit
122 		 * integer so that it could contain the maximum range of
123 		 * reasonable values.  Unfortunately, this exceeds the typical
124 		 * range on Unix systems.  Ensure the range of
125 		 * ISC_PLATFORM_RLIMITTYPE is not overflowed.
126 		 */
127 		isc_resourcevalue_t rlim_max;
128 		isc_boolean_t rlim_t_is_signed =
129 			ISC_TF(((double)(ISC_PLATFORM_RLIMITTYPE)-1) < 0);
130 
131 		if (rlim_t_is_signed)
132 			rlim_max = ~((ISC_PLATFORM_RLIMITTYPE)1 <<
133 				     (sizeof(ISC_PLATFORM_RLIMITTYPE) * 8 - 1));
134 		else
135 			rlim_max = (ISC_PLATFORM_RLIMITTYPE)-1;
136 
137 		if (value > rlim_max)
138 			value = rlim_max;
139 
140 		rlim_value = value;
141 	}
142 
143 	rl.rlim_cur = rl.rlim_max = rlim_value;
144 	unixresult = setrlimit(unixresource, &rl);
145 
146 	if (unixresult == 0)
147 		return (ISC_R_SUCCESS);
148 
149 #if defined(OPEN_MAX) && defined(__APPLE__)
150 	/*
151 	 * The Darwin kernel doesn't accept RLIM_INFINITY for rlim_cur; the
152 	 * maximum possible value is OPEN_MAX.  BIND8 used to use
153 	 * sysconf(_SC_OPEN_MAX) for such a case, but this value is much
154 	 * smaller than OPEN_MAX and is not really effective.
155 	 */
156 	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
157 		rl.rlim_cur = OPEN_MAX;
158 		unixresult = setrlimit(unixresource, &rl);
159 		if (unixresult == 0)
160 			return (ISC_R_SUCCESS);
161 	}
162 #elif defined(__linux__)
163 #ifndef NR_OPEN
164 #define NR_OPEN (1024*1024)
165 #endif
166 
167 	/*
168 	 * Some Linux kernels don't accept RLIM_INFINIT; the maximum
169 	 * possible value is the NR_OPEN defined in linux/fs.h.
170 	 */
171 	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
172 		rl.rlim_cur = rl.rlim_max = NR_OPEN;
173 		unixresult = setrlimit(unixresource, &rl);
174 		if (unixresult == 0)
175 			return (ISC_R_SUCCESS);
176 	}
177 #elif defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
178 	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
179 		uint64_t maxfiles;
180 		if (gettune("maxfiles_lim", &maxfiles) == 0) {
181 			rl.rlim_cur = rl.rlim_max = maxfiles;
182 			unixresult = setrlimit(unixresource, &rl);
183 			if (unixresult == 0)
184 				return (ISC_R_SUCCESS);
185 		}
186 	}
187 #endif
188 	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
189 		if (getrlimit(unixresource, &rl) == 0) {
190 			rl.rlim_cur = rl.rlim_max;
191 			unixresult = setrlimit(unixresource, &rl);
192 			if (unixresult == 0)
193 				return (ISC_R_SUCCESS);
194 		}
195 	}
196 	return (isc__errno2result(errno));
197 }
198 
199 isc_result_t
isc_resource_getlimit(isc_resource_t resource,isc_resourcevalue_t * value)200 isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
201 	int unixresult;
202 	int unixresource;
203 	struct rlimit rl;
204 	isc_result_t result;
205 
206 	result = resource2rlim(resource, &unixresource);
207 	if (result == ISC_R_SUCCESS) {
208 		unixresult = getrlimit(unixresource, &rl);
209 		INSIST(unixresult == 0);
210 		*value = rl.rlim_max;
211 	}
212 
213 	return (result);
214 }
215 
216 isc_result_t
isc_resource_getcurlimit(isc_resource_t resource,isc_resourcevalue_t * value)217 isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
218 	int unixresult;
219 	int unixresource;
220 	struct rlimit rl;
221 	isc_result_t result;
222 
223 	result = resource2rlim(resource, &unixresource);
224 	if (result == ISC_R_SUCCESS) {
225 		unixresult = getrlimit(unixresource, &rl);
226 		INSIST(unixresult == 0);
227 		*value = rl.rlim_cur;
228 	}
229 
230 	return (result);
231 }
232