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.2"
22 #include <sys/resource.h>
23 #include <sys/types.h>
36 /* Daemonization support */
38 static int lc_daemonize(lua_State *L)
45 lua_pushboolean(L, 0);
46 lua_pushstring(L, "already-daemonized");
50 /* Attempt initial fork */
51 if((pid = fork()) < 0)
54 lua_pushboolean(L, 0);
55 lua_pushstring(L, "fork-failed");
60 /* We are the parent process */
61 lua_pushboolean(L, 1);
62 lua_pushnumber(L, pid);
66 /* and we are the child process */
69 /* We failed to become session leader */
70 /* (we probably already were) */
71 lua_pushboolean(L, 0);
72 lua_pushstring(L, "setsid-failed");
76 /* Close stdin, stdout, stderr */
81 /* Final fork, use it wisely */
85 /* Show's over, let's continue */
86 lua_pushboolean(L, 1);
93 const char * const facility_strings[] = {
95 #if !(defined(sun) || defined(__sun))
100 #if !(defined(sun) || defined(__sun))
119 int facility_constants[] = {
121 #if !(defined(sun) || defined(__sun))
126 #if !(defined(sun) || defined(__sun))
148 The parameter ident in the call of openlog() is probably stored as-is.
149 Thus, if the string it points to is changed, syslog() may start
150 prepending the changed string, and if the string it points to ceases to
151 exist, the results are undefined. Most portable is to use a string
155 char* syslog_ident = NULL;
157 int lc_syslog_open(lua_State* L)
159 int facility = luaL_checkoption(L, 2, "daemon", facility_strings);
160 facility = facility_constants[facility];
162 luaL_checkstring(L, 1);
167 syslog_ident = strdup(lua_tostring(L, 1));
169 openlog(syslog_ident, LOG_PID, facility);
173 const char * const level_strings[] = {
181 int level_constants[] = {
189 int lc_syslog_log(lua_State* L)
191 int level = luaL_checkoption(L, 1, "notice", level_strings);
192 level = level_constants[level];
194 luaL_checkstring(L, 2);
196 syslog(level, "%s", lua_tostring(L, 2));
200 int lc_syslog_close(lua_State* L)
211 int lc_syslog_setmask(lua_State* L)
213 int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
217 mask |= LOG_MASK(level_constants[level_idx]);
218 } while (++level_idx<=4);
226 int lc_getpid(lua_State* L)
228 lua_pushinteger(L, getpid());
232 /* UID/GID functions */
234 int lc_getuid(lua_State* L)
236 lua_pushinteger(L, getuid());
240 int lc_getgid(lua_State* L)
242 lua_pushinteger(L, getgid());
246 int lc_setuid(lua_State* L)
249 if(lua_gettop(L) < 1)
251 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
253 /* Passed UID is actually a string, so look up the UID */
255 p = getpwnam(lua_tostring(L, 1));
258 lua_pushboolean(L, 0);
259 lua_pushstring(L, "no-such-user");
266 uid = lua_tonumber(L, 1);
271 /* Ok, attempt setuid */
276 lua_pushboolean(L, 0);
280 lua_pushstring(L, "invalid-uid");
283 lua_pushstring(L, "permission-denied");
286 lua_pushstring(L, "unknown-error");
293 lua_pushboolean(L, 1);
298 /* Seems we couldn't find a valid UID to switch to */
299 lua_pushboolean(L, 0);
300 lua_pushstring(L, "invalid-uid");
304 int lc_setgid(lua_State* L)
307 if(lua_gettop(L) < 1)
309 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
311 /* Passed GID is actually a string, so look up the GID */
313 g = getgrnam(lua_tostring(L, 1));
316 lua_pushboolean(L, 0);
317 lua_pushstring(L, "no-such-group");
324 gid = lua_tonumber(L, 1);
329 /* Ok, attempt setgid */
334 lua_pushboolean(L, 0);
338 lua_pushstring(L, "invalid-gid");
341 lua_pushstring(L, "permission-denied");
344 lua_pushstring(L, "unknown-error");
351 lua_pushboolean(L, 1);
356 /* Seems we couldn't find a valid GID to switch to */
357 lua_pushboolean(L, 0);
358 lua_pushstring(L, "invalid-gid");
362 int lc_umask(lua_State* L)
364 char old_mode_string[7];
365 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8));
367 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode);
368 old_mode_string[sizeof(old_mode_string)-1] = 0;
369 lua_pushstring(L, old_mode_string);
374 /* Like POSIX's setrlimit()/getrlimit() API functions.
377 * pposix.setrlimit( resource, soft limit, hard limit)
379 * Any negative limit will be replace with the current limit by an additional call of getrlimit().
382 * pposix.setrlimit("NOFILE", 1000, 2000)
384 int string2resource(const char *s) {
385 if (!strcmp(s, "CORE")) return RLIMIT_CORE;
386 if (!strcmp(s, "CPU")) return RLIMIT_CPU;
387 if (!strcmp(s, "DATA")) return RLIMIT_DATA;
388 if (!strcmp(s, "FSIZE")) return RLIMIT_FSIZE;
389 if (!strcmp(s, "NOFILE")) return RLIMIT_NOFILE;
390 if (!strcmp(s, "STACK")) return RLIMIT_STACK;
391 #if !(defined(sun) || defined(__sun))
392 if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK;
393 if (!strcmp(s, "NPROC")) return RLIMIT_NPROC;
394 if (!strcmp(s, "RSS")) return RLIMIT_RSS;
399 int lc_setrlimit(lua_State *L) {
400 int arguments = lua_gettop(L);
403 const char *resource = NULL;
405 if(arguments < 1 || arguments > 3) {
406 lua_pushboolean(L, 0);
407 lua_pushstring(L, "incorrect-arguments");
410 resource = luaL_checkstring(L, 1);
411 softlimit = luaL_checkinteger(L, 2);
412 hardlimit = luaL_checkinteger(L, 3);
414 rid = string2resource(resource);
417 struct rlimit lim_current;
419 if (softlimit < 0 || hardlimit < 0) {
420 if (getrlimit(rid, &lim_current)) {
421 lua_pushboolean(L, 0);
422 lua_pushstring(L, "getrlimit-failed");
427 if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur;
428 else lim.rlim_cur = softlimit;
429 if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max;
430 else lim.rlim_max = hardlimit;
432 if (setrlimit(rid, &lim)) {
433 lua_pushboolean(L, 0);
434 lua_pushstring(L, "setrlimit-failed");
438 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
439 lua_pushboolean(L, 0);
440 lua_pushstring(L, "invalid-resource");
443 lua_pushboolean(L, 1);
447 int lc_getrlimit(lua_State *L) {
448 int arguments = lua_gettop(L);
449 const char *resource = NULL;
453 if (arguments != 1) {
454 lua_pushboolean(L, 0);
455 lua_pushstring(L, "invalid-arguments");
459 resource = luaL_checkstring(L, 1);
460 rid = string2resource(resource);
462 if (getrlimit(rid, &lim)) {
463 lua_pushboolean(L, 0);
464 lua_pushstring(L, "getrlimit-failed.");
468 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
469 lua_pushboolean(L, 0);
470 lua_pushstring(L, "invalid-resource");
473 lua_pushboolean(L, 1);
474 lua_pushnumber(L, lim.rlim_cur);
475 lua_pushnumber(L, lim.rlim_max);
479 int lc_abort(lua_State* L)
485 /* Register functions */
487 int luaopen_util_pposix(lua_State *L)
489 luaL_Reg exports[] = {
490 { "abort", lc_abort },
492 { "daemonize", lc_daemonize },
494 { "syslog_open", lc_syslog_open },
495 { "syslog_close", lc_syslog_close },
496 { "syslog_log", lc_syslog_log },
497 { "syslog_setminlevel", lc_syslog_setmask },
499 { "getpid", lc_getpid },
500 { "getuid", lc_getuid },
501 { "getgid", lc_getgid },
503 { "setuid", lc_setuid },
504 { "setgid", lc_setgid },
506 { "umask", lc_umask },
508 { "setrlimit", lc_setrlimit },
509 { "getrlimit", lc_getrlimit },
514 luaL_register(L, "pposix", exports);
516 lua_pushliteral(L, "pposix");
517 lua_setfield(L, -2, "_NAME");
519 lua_pushliteral(L, MODULE_VERSION);
520 lua_setfield(L, -2, "_VERSION");