Blame lib/isc/unix/resource.c

Packit Service ae04f2
/*
Packit Service ae04f2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
Packit Service ae04f2
 *
Packit Service ae04f2
 * This Source Code Form is subject to the terms of the Mozilla Public
Packit Service ae04f2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit Service ae04f2
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
Packit Service ae04f2
 *
Packit Service ae04f2
 * See the COPYRIGHT file distributed with this work for additional
Packit Service ae04f2
 * information regarding copyright ownership.
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
Packit Service ae04f2
#include <config.h>
Packit Service ae04f2
Packit Service ae04f2
#include <inttypes.h>
Packit Service ae04f2
#include <stdbool.h>
Packit Service ae04f2
Packit Service ae04f2
#include <sys/types.h>
Packit Service ae04f2
#include <sys/time.h>	/* Required on some systems for <sys/resource.h>. */
Packit Service ae04f2
#include <sys/resource.h>
Packit Service ae04f2
Packit Service ae04f2
#include <isc/platform.h>
Packit Service ae04f2
#include <isc/resource.h>
Packit Service ae04f2
#include <isc/result.h>
Packit Service ae04f2
#include <isc/util.h>
Packit Service ae04f2
Packit Service ae04f2
#ifdef __linux__
Packit Service ae04f2
#include <linux/fs.h>	/* To get the large NR_OPEN. */
Packit Service ae04f2
#endif
Packit Service ae04f2
Packit Service ae04f2
#if defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
Packit Service ae04f2
#include <sys/dyntune.h>
Packit Service ae04f2
#endif
Packit Service ae04f2
Packit Service ae04f2
#include "errno2result.h"
Packit Service ae04f2
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
resource2rlim(isc_resource_t resource, int *rlim_resource) {
Packit Service ae04f2
	isc_result_t result = ISC_R_SUCCESS;
Packit Service ae04f2
Packit Service ae04f2
	switch (resource) {
Packit Service ae04f2
	case isc_resource_coresize:
Packit Service ae04f2
		*rlim_resource = RLIMIT_CORE;
Packit Service ae04f2
		break;
Packit Service ae04f2
	case isc_resource_cputime:
Packit Service ae04f2
		*rlim_resource = RLIMIT_CPU;
Packit Service ae04f2
		break;
Packit Service ae04f2
	case isc_resource_datasize:
Packit Service ae04f2
		*rlim_resource = RLIMIT_DATA;
Packit Service ae04f2
		break;
Packit Service ae04f2
	case isc_resource_filesize:
Packit Service ae04f2
		*rlim_resource = RLIMIT_FSIZE;
Packit Service ae04f2
		break;
Packit Service ae04f2
	case isc_resource_lockedmemory:
Packit Service ae04f2
#ifdef RLIMIT_MEMLOCK
Packit Service ae04f2
		*rlim_resource = RLIMIT_MEMLOCK;
Packit Service ae04f2
#else
Packit Service ae04f2
		result = ISC_R_NOTIMPLEMENTED;
Packit Service ae04f2
#endif
Packit Service ae04f2
		break;
Packit Service ae04f2
	case isc_resource_openfiles:
Packit Service ae04f2
#ifdef RLIMIT_NOFILE
Packit Service ae04f2
		*rlim_resource = RLIMIT_NOFILE;
Packit Service ae04f2
#else
Packit Service ae04f2
		result = ISC_R_NOTIMPLEMENTED;
Packit Service ae04f2
#endif
Packit Service ae04f2
		break;
Packit Service ae04f2
	case isc_resource_processes:
Packit Service ae04f2
#ifdef RLIMIT_NPROC
Packit Service ae04f2
		*rlim_resource = RLIMIT_NPROC;
Packit Service ae04f2
#else
Packit Service ae04f2
		result = ISC_R_NOTIMPLEMENTED;
Packit Service ae04f2
#endif
Packit Service ae04f2
		break;
Packit Service ae04f2
	case isc_resource_residentsize:
Packit Service ae04f2
#ifdef RLIMIT_RSS
Packit Service ae04f2
		*rlim_resource = RLIMIT_RSS;
Packit Service ae04f2
#else
Packit Service ae04f2
		result = ISC_R_NOTIMPLEMENTED;
Packit Service ae04f2
#endif
Packit Service ae04f2
		break;
Packit Service ae04f2
	case isc_resource_stacksize:
Packit Service ae04f2
		*rlim_resource = RLIMIT_STACK;
Packit Service ae04f2
		break;
Packit Service ae04f2
	default:
Packit Service ae04f2
		/*
Packit Service ae04f2
		 * This test is not very robust if isc_resource_t
Packit Service ae04f2
		 * changes, but generates a clear assertion message.
Packit Service ae04f2
		 */
Packit Service ae04f2
		REQUIRE(resource >= isc_resource_coresize &&
Packit Service ae04f2
			resource <= isc_resource_stacksize);
Packit Service ae04f2
Packit Service ae04f2
		result = ISC_R_RANGE;
Packit Service ae04f2
		break;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	return (result);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) {
Packit Service ae04f2
	struct rlimit rl;
Packit Service ae04f2
	ISC_PLATFORM_RLIMITTYPE rlim_value;
Packit Service ae04f2
	int unixresult;
Packit Service ae04f2
	int unixresource;
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	result = resource2rlim(resource, &unixresource);
Packit Service ae04f2
	if (result != ISC_R_SUCCESS)
Packit Service ae04f2
		return (result);
Packit Service ae04f2
Packit Service ae04f2
	if (value == ISC_RESOURCE_UNLIMITED)
Packit Service ae04f2
		rlim_value = RLIM_INFINITY;
Packit Service ae04f2
Packit Service ae04f2
	else {
Packit Service ae04f2
		/*
Packit Service ae04f2
		 * isc_resourcevalue_t was chosen as an unsigned 64 bit
Packit Service ae04f2
		 * integer so that it could contain the maximum range of
Packit Service ae04f2
		 * reasonable values.  Unfortunately, this exceeds the typical
Packit Service ae04f2
		 * range on Unix systems.  Ensure the range of
Packit Service ae04f2
		 * ISC_PLATFORM_RLIMITTYPE is not overflowed.
Packit Service ae04f2
		 */
Packit Service ae04f2
		isc_resourcevalue_t rlim_max;
Packit Service ae04f2
		bool rlim_t_is_signed =
Packit Service ae04f2
			(((double)(ISC_PLATFORM_RLIMITTYPE)-1) < 0);
Packit Service ae04f2
Packit Service ae04f2
		if (rlim_t_is_signed)
Packit Service ae04f2
			rlim_max = ~((ISC_PLATFORM_RLIMITTYPE)1 <<
Packit Service ae04f2
				     (sizeof(ISC_PLATFORM_RLIMITTYPE) * 8 - 1));
Packit Service ae04f2
		else
Packit Service ae04f2
			rlim_max = (ISC_PLATFORM_RLIMITTYPE)-1;
Packit Service ae04f2
Packit Service ae04f2
		if (value > rlim_max)
Packit Service ae04f2
			value = rlim_max;
Packit Service ae04f2
Packit Service ae04f2
		rlim_value = value;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	rl.rlim_cur = rl.rlim_max = rlim_value;
Packit Service ae04f2
	unixresult = setrlimit(unixresource, &rl);
Packit Service ae04f2
Packit Service ae04f2
	if (unixresult == 0)
Packit Service ae04f2
		return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
#if defined(OPEN_MAX) && defined(__APPLE__)
Packit Service ae04f2
	/*
Packit Service ae04f2
	 * The Darwin kernel doesn't accept RLIM_INFINITY for rlim_cur; the
Packit Service ae04f2
	 * maximum possible value is OPEN_MAX.  BIND8 used to use
Packit Service ae04f2
	 * sysconf(_SC_OPEN_MAX) for such a case, but this value is much
Packit Service ae04f2
	 * smaller than OPEN_MAX and is not really effective.
Packit Service ae04f2
	 */
Packit Service ae04f2
	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
Packit Service ae04f2
		rl.rlim_cur = OPEN_MAX;
Packit Service ae04f2
		unixresult = setrlimit(unixresource, &rl);
Packit Service ae04f2
		if (unixresult == 0)
Packit Service ae04f2
			return (ISC_R_SUCCESS);
Packit Service ae04f2
	}
Packit Service ae04f2
#elif defined(__linux__)
Packit Service ae04f2
#ifndef NR_OPEN
Packit Service ae04f2
#define NR_OPEN (1024*1024)
Packit Service ae04f2
#endif
Packit Service ae04f2
Packit Service ae04f2
	/*
Packit Service ae04f2
	 * Some Linux kernels don't accept RLIM_INFINIT; the maximum
Packit Service ae04f2
	 * possible value is the NR_OPEN defined in linux/fs.h.
Packit Service ae04f2
	 */
Packit Service ae04f2
	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
Packit Service ae04f2
		rl.rlim_cur = rl.rlim_max = NR_OPEN;
Packit Service ae04f2
		unixresult = setrlimit(unixresource, &rl);
Packit Service ae04f2
		if (unixresult == 0)
Packit Service ae04f2
			return (ISC_R_SUCCESS);
Packit Service ae04f2
	}
Packit Service ae04f2
#elif defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H)
Packit Service ae04f2
	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
Packit Service ae04f2
		uint64_t maxfiles;
Packit Service ae04f2
		if (gettune("maxfiles_lim", &maxfiles) == 0) {
Packit Service ae04f2
			rl.rlim_cur = rl.rlim_max = maxfiles;
Packit Service ae04f2
			unixresult = setrlimit(unixresource, &rl);
Packit Service ae04f2
			if (unixresult == 0)
Packit Service ae04f2
				return (ISC_R_SUCCESS);
Packit Service ae04f2
		}
Packit Service ae04f2
	}
Packit Service ae04f2
#endif
Packit Service ae04f2
	if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) {
Packit Service ae04f2
		if (getrlimit(unixresource, &rl) == 0) {
Packit Service ae04f2
			rl.rlim_cur = rl.rlim_max;
Packit Service ae04f2
			unixresult = setrlimit(unixresource, &rl);
Packit Service ae04f2
			if (unixresult == 0)
Packit Service ae04f2
				return (ISC_R_SUCCESS);
Packit Service ae04f2
		}
Packit Service ae04f2
	}
Packit Service ae04f2
	return (isc__errno2result(errno));
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
Packit Service ae04f2
	int unixresource;
Packit Service ae04f2
	struct rlimit rl;
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	result = resource2rlim(resource, &unixresource);
Packit Service ae04f2
	if (result != ISC_R_SUCCESS) {
Packit Service ae04f2
		return (result);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	if (getrlimit(unixresource, &rl) != 0) {
Packit Service ae04f2
		return (isc__errno2result(errno));
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	*value = rl.rlim_max;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) {
Packit Service ae04f2
	int unixresource;
Packit Service ae04f2
	struct rlimit rl;
Packit Service ae04f2
	isc_result_t result;
Packit Service ae04f2
Packit Service ae04f2
	result = resource2rlim(resource, &unixresource);
Packit Service ae04f2
	if (result != ISC_R_SUCCESS) {
Packit Service ae04f2
		return (result);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	if (getrlimit(unixresource, &rl) != 0) {
Packit Service ae04f2
		return (isc__errno2result(errno));
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	*value = rl.rlim_cur;
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
}