2 -- Copyright (C) 2008-2009 Matthew Wild
3 -- Copyright (C) 2008-2009 Waqas Hussain
4 -- Copyright (C) 2009 Tobias Markmann
6 -- This project is MIT/X11 licensed. Please see the
7 -- COPYING file in the source package for more information.
13 * POSIX support functions for Lua
16 #define MODULE_VERSION "0.3.1"
21 #include <sys/resource.h>
22 #include <sys/types.h>
35 /* Daemonization support */
37 static int lc_daemonize(lua_State *L)
44 lua_pushboolean(L, 0);
45 lua_pushstring(L, "already-daemonized");
49 /* Attempt initial fork */
50 if((pid = fork()) < 0)
53 lua_pushboolean(L, 0);
54 lua_pushstring(L, "fork-failed");
59 /* We are the parent process */
60 lua_pushboolean(L, 1);
61 lua_pushnumber(L, pid);
65 /* and we are the child process */
68 /* We failed to become session leader */
69 /* (we probably already were) */
70 lua_pushboolean(L, 0);
71 lua_pushstring(L, "setsid-failed");
75 /* Close stdin, stdout, stderr */
80 /* Final fork, use it wisely */
84 /* Show's over, let's continue */
85 lua_pushboolean(L, 1);
92 const char * const facility_strings[] = {
94 #if !(defined(sun) || defined(__sun))
99 #if !(defined(sun) || defined(__sun))
118 int facility_constants[] = {
120 #if !(defined(sun) || defined(__sun))
125 #if !(defined(sun) || defined(__sun))
147 The parameter ident in the call of openlog() is probably stored as-is.
148 Thus, if the string it points to is changed, syslog() may start
149 prepending the changed string, and if the string it points to ceases to
150 exist, the results are undefined. Most portable is to use a string
154 char* syslog_ident = NULL;
156 int lc_syslog_open(lua_State* L)
158 int facility = luaL_checkoption(L, 2, "daemon", facility_strings);
159 facility = facility_constants[facility];
161 luaL_checkstring(L, 1);
166 syslog_ident = strdup(lua_tostring(L, 1));
168 openlog(syslog_ident, LOG_PID, facility);
172 const char * const level_strings[] = {
180 int level_constants[] = {
188 int lc_syslog_log(lua_State* L)
190 int level = luaL_checkoption(L, 1, "notice", level_strings);
191 level = level_constants[level];
193 luaL_checkstring(L, 2);
195 syslog(level, "%s", lua_tostring(L, 2));
199 int lc_syslog_close(lua_State* L)
210 int lc_syslog_setmask(lua_State* L)
212 int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
216 mask |= LOG_MASK(level_constants[level_idx]);
217 } while (++level_idx<=4);
225 int lc_getpid(lua_State* L)
227 lua_pushinteger(L, getpid());
231 /* UID/GID functions */
233 int lc_getuid(lua_State* L)
235 lua_pushinteger(L, getuid());
239 int lc_getgid(lua_State* L)
241 lua_pushinteger(L, getgid());
245 int lc_setuid(lua_State* L)
248 if(lua_gettop(L) < 1)
250 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
252 /* Passed UID is actually a string, so look up the UID */
254 p = getpwnam(lua_tostring(L, 1));
257 lua_pushboolean(L, 0);
258 lua_pushstring(L, "no-such-user");
265 uid = lua_tonumber(L, 1);
270 /* Ok, attempt setuid */
275 lua_pushboolean(L, 0);
279 lua_pushstring(L, "invalid-uid");
282 lua_pushstring(L, "permission-denied");
285 lua_pushstring(L, "unknown-error");
292 lua_pushboolean(L, 1);
297 /* Seems we couldn't find a valid UID to switch to */
298 lua_pushboolean(L, 0);
299 lua_pushstring(L, "invalid-uid");
303 int lc_setgid(lua_State* L)
306 if(lua_gettop(L) < 1)
308 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
310 /* Passed GID is actually a string, so look up the GID */
312 g = getgrnam(lua_tostring(L, 1));
315 lua_pushboolean(L, 0);
316 lua_pushstring(L, "no-such-group");
323 gid = lua_tonumber(L, 1);
328 /* Ok, attempt setgid */
333 lua_pushboolean(L, 0);
337 lua_pushstring(L, "invalid-gid");
340 lua_pushstring(L, "permission-denied");
343 lua_pushstring(L, "unknown-error");
350 lua_pushboolean(L, 1);
355 /* Seems we couldn't find a valid GID to switch to */
356 lua_pushboolean(L, 0);
357 lua_pushstring(L, "invalid-gid");
361 /* Like POSIX's setrlimit()/getrlimit() API functions.
364 * pposix.setrlimit( resource, soft limit, hard limit)
366 * Any negative limit will be replace with the current limit by an additional call of getrlimit().
369 * pposix.setrlimit("NOFILE", 1000, 2000)
371 int string2resource(const char *s) {
372 if (!strcmp(s, "CORE")) return RLIMIT_CORE;
373 if (!strcmp(s, "CPU")) return RLIMIT_CPU;
374 if (!strcmp(s, "DATA")) return RLIMIT_DATA;
375 if (!strcmp(s, "FSIZE")) return RLIMIT_FSIZE;
376 if (!strcmp(s, "NOFILE")) return RLIMIT_NOFILE;
377 if (!strcmp(s, "STACK")) return RLIMIT_STACK;
378 #if !(defined(sun) || defined(__sun))
379 if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK;
380 if (!strcmp(s, "NPROC")) return RLIMIT_NPROC;
381 if (!strcmp(s, "RSS")) return RLIMIT_RSS;
386 int lc_setrlimit(lua_State *L) {
387 int arguments = lua_gettop(L);
390 const char *resource = NULL;
392 if(arguments < 1 || arguments > 3) {
393 lua_pushboolean(L, 0);
394 lua_pushstring(L, "incorrect-arguments");
397 resource = luaL_checkstring(L, 1);
398 softlimit = luaL_checkinteger(L, 2);
399 hardlimit = luaL_checkinteger(L, 3);
401 rid = string2resource(resource);
404 struct rlimit lim_current;
406 if (softlimit < 0 || hardlimit < 0) {
407 if (getrlimit(rid, &lim_current)) {
408 lua_pushboolean(L, 0);
409 lua_pushstring(L, "getrlimit-failed");
414 if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur;
415 else lim.rlim_cur = softlimit;
416 if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max;
417 else lim.rlim_max = hardlimit;
419 if (setrlimit(rid, &lim)) {
420 lua_pushboolean(L, 0);
421 lua_pushstring(L, "setrlimit-failed");
425 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
426 lua_pushboolean(L, 0);
427 lua_pushstring(L, "invalid-resource");
430 lua_pushboolean(L, 1);
434 int lc_getrlimit(lua_State *L) {
435 int arguments = lua_gettop(L);
436 const char *resource = NULL;
440 if (arguments != 1) {
441 lua_pushboolean(L, 0);
442 lua_pushstring(L, "invalid-arguments");
446 resource = luaL_checkstring(L, 1);
447 rid = string2resource(resource);
449 if (getrlimit(rid, &lim)) {
450 lua_pushboolean(L, 0);
451 lua_pushstring(L, "getrlimit-failed.");
455 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
456 lua_pushboolean(L, 0);
457 lua_pushstring(L, "invalid-resource");
460 lua_pushboolean(L, 1);
461 lua_pushnumber(L, lim.rlim_cur);
462 lua_pushnumber(L, lim.rlim_max);
466 void lc_abort(lua_State* L)
471 /* Register functions */
473 int luaopen_util_pposix(lua_State *L)
477 lua_pushcfunction(L, lc_abort);
478 lua_setfield(L, -2, "abort");
480 lua_pushcfunction(L, lc_daemonize);
481 lua_setfield(L, -2, "daemonize");
483 lua_pushcfunction(L, lc_syslog_open);
484 lua_setfield(L, -2, "syslog_open");
486 lua_pushcfunction(L, lc_syslog_close);
487 lua_setfield(L, -2, "syslog_close");
489 lua_pushcfunction(L, lc_syslog_log);
490 lua_setfield(L, -2, "syslog_log");
492 lua_pushcfunction(L, lc_syslog_setmask);
493 lua_setfield(L, -2, "syslog_setminlevel");
495 lua_pushcfunction(L, lc_getpid);
496 lua_setfield(L, -2, "getpid");
498 lua_pushcfunction(L, lc_getuid);
499 lua_setfield(L, -2, "getuid");
500 lua_pushcfunction(L, lc_getgid);
501 lua_setfield(L, -2, "getgid");
503 lua_pushcfunction(L, lc_setuid);
504 lua_setfield(L, -2, "setuid");
505 lua_pushcfunction(L, lc_setgid);
506 lua_setfield(L, -2, "setgid");
508 lua_pushcfunction(L, lc_setrlimit);
509 lua_setfield(L, -2, "setrlimit");
511 lua_pushcfunction(L, lc_getrlimit);
512 lua_setfield(L, -2, "getrlimit");
514 lua_pushliteral(L, "pposix");
515 lua_setfield(L, -2, "_NAME");
517 lua_pushliteral(L, MODULE_VERSION);
518 lua_setfield(L, -2, "_VERSION");