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