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 int lc_abort(lua_State* L)
472 /* Register functions */
474 int luaopen_util_pposix(lua_State *L)
478 lua_pushcfunction(L, lc_abort);
479 lua_setfield(L, -2, "abort");
481 lua_pushcfunction(L, lc_daemonize);
482 lua_setfield(L, -2, "daemonize");
484 lua_pushcfunction(L, lc_syslog_open);
485 lua_setfield(L, -2, "syslog_open");
487 lua_pushcfunction(L, lc_syslog_close);
488 lua_setfield(L, -2, "syslog_close");
490 lua_pushcfunction(L, lc_syslog_log);
491 lua_setfield(L, -2, "syslog_log");
493 lua_pushcfunction(L, lc_syslog_setmask);
494 lua_setfield(L, -2, "syslog_setminlevel");
496 lua_pushcfunction(L, lc_getpid);
497 lua_setfield(L, -2, "getpid");
499 lua_pushcfunction(L, lc_getuid);
500 lua_setfield(L, -2, "getuid");
501 lua_pushcfunction(L, lc_getgid);
502 lua_setfield(L, -2, "getgid");
504 lua_pushcfunction(L, lc_setuid);
505 lua_setfield(L, -2, "setuid");
506 lua_pushcfunction(L, lc_setgid);
507 lua_setfield(L, -2, "setgid");
509 lua_pushcfunction(L, lc_setrlimit);
510 lua_setfield(L, -2, "setrlimit");
512 lua_pushcfunction(L, lc_getrlimit);
513 lua_setfield(L, -2, "getrlimit");
515 lua_pushliteral(L, "pposix");
516 lua_setfield(L, -2, "_NAME");
518 lua_pushliteral(L, MODULE_VERSION);
519 lua_setfield(L, -2, "_VERSION");