/*
 * POSIX library for Lua 5.1, 5.2 & 5.3.
 * (c) Gary V. Vaughan <gary@vaughan.pe>, 2013-2015
 * (c) Reuben Thomas <rrt@sc3d.org> 2010-2013
 * (c) Natanael Copa <natanael.copa@gmail.com> 2008-2010
 * Clean up and bug fixes by Leo Razoumov <slonik.az@gmail.com> 2006-10-11
 * Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br> 07 Apr 2006 23:17:49
 * Based on original by Claudio Terra for Lua 3.x.
 * With contributions by Roberto Ierusalimschy.
 * With documentation from Steve Donovan 2012
 */
/***
 Control Maximum System Resource Consumption.

@module posix.sys.resource
*/

#include <config.h>

#include <sys/resource.h>

#include "_helpers.c"

/* OpenBSD 5.6 recommends using RLIMIT_DATA in place of missing RLIMIT_AS */
#ifndef RLIMIT_AS
#  define RLIMIT_AS RLIMIT_DATA
#endif


/***
Resource limit record.
@table PosixRlimit
@int rlim_cur current soft limit
@int rlim_max hard limit
*/
static int
pushrlimit(lua_State *L, struct rlimit *lim)
{
	if (!lim)
		return lua_pushnil(L), 1;

	lua_createtable(L, 0, 2);

	setnumberfield(lim, rlim_cur);
	setnumberfield(lim, rlim_max);

	settypemetatable("PosixRlimit");
	return 1;
}


/***
Get resource limits for this process.
@function getrlimit
@int resource one of `RLIMIT_CORE`, `RLIMIT_CPU`, `RLIMIT_DATA`, `RLIMIT_FSIZE`,
  `RLIMIT_NOFILE`, `RLIMIT_STACK` or `RLIMIT_AS`
@treturn[1] int softlimit
@treturn[1] int hardlimit, if successful
@return[2] nil
@treturn[2] string error message
@treturn[2] int errnum
@see getrlimit(2)
@see setrlimit
*/
static int
Pgetrlimit(lua_State *L)
{
	struct rlimit lim;
	int r;
	checknargs(L, 1);
	r = getrlimit(checkint(L, 1), &lim);
	if (r < 0)
		return pusherror(L, "getrlimit");
	return pushrlimit(L, &lim);
}


/***
Set a resource limit for subsequent child processes.
@function setrlimit
@string resource one of "core", "cpu", "data", "fsize",
 "nofile", "stack" or "as"
@param[opt] softlimit process may receive a signal when reached
@param[opt] hardlimit process may be terminated when reached
@treturn[1] int `0`, if successful
@return[2] nil
@treturn[2] string error message
@treturn[2] int errnum
@see getrlimit(2)
@see limit.lua
@usage P.setrlimit ("nofile", 1000, 2000)
*/

static const char *Srlimit_fields[] = { "rlim_cur", "rlim_max" };

static int
Psetrlimit(lua_State *L)
{
	struct rlimit lim;
	int rid = checkint(L, 1);

	luaL_checktype(L, 2, LUA_TTABLE);
	checknargs(L, 2);

	lim.rlim_cur = checknumberfield(L, 2, "rlim_cur");
	lim.rlim_max = checknumberfield(L, 2, "rlim_max");
	checkfieldnames(L, 2, Srlimit_fields);

	return pushresult(L, setrlimit(rid, &lim), "setrlimit");
}


static const luaL_Reg posix_sys_resource_fns[] =
{
	LPOSIX_FUNC( Pgetrlimit		),
	LPOSIX_FUNC( Psetrlimit		),
	{NULL, NULL}
};


/***
Constants.
@section constants
*/

/***
Rlimit constants.
@table posix.sys.resource
@int RLIM_INFINITY unlimited resource usage
@int RLIM_SAVED_CUR saved current resource soft limit
@int RLIM_SAVED_MAX saved resource hard limit
@int RLIMIT_CORE maximum bytes allowed for a core file
@int RLIMIT_CPU maximum cputime secconds allowed per process
@int RLIMIT_DATA maximum data segment bytes per process
@int RLIMIT_FSIZE maximum bytes in any file
@int RLIMIT_NOFILE maximum number of open files per process
@int RLIMIT_STACK maximum stack segment bytes per process
@int RLIMIT_AS maximum bytes total address space per process
@usage
  -- Print resource constants supported on this host.
  for name, value in pairs (require "posix.sys.resource") do
    if type (value) == "number" then
      print (name, value)
     end
  end
*/

LUALIB_API int
luaopen_posix_sys_resource(lua_State *L)
{
	luaL_register(L, "posix.sys.resource", posix_sys_resource_fns);
	lua_pushliteral(L, "posix.sys.resource for " LUA_VERSION " / " PACKAGE_STRING);
	lua_setfield(L, -2, "version");

	LPOSIX_CONST( RLIM_INFINITY	);
#if defined RLIM_SAVED_CUR
	LPOSIX_CONST( RLIM_SAVED_CUR	);
#endif
#if defined RLIM_SAVED_MAX
	LPOSIX_CONST( RLIM_SAVED_MAX	);
#endif
	LPOSIX_CONST( RLIMIT_CORE	);
	LPOSIX_CONST( RLIMIT_CPU	);
	LPOSIX_CONST( RLIMIT_DATA	);
	LPOSIX_CONST( RLIMIT_FSIZE	);
	LPOSIX_CONST( RLIMIT_NOFILE	);
	LPOSIX_CONST( RLIMIT_STACK	);
	LPOSIX_CONST( RLIMIT_AS		);

	return 1;
}
