2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 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.4"
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_initgroups(lua_State* L)
368 if(!lua_isstring(L, 1))
371 lua_pushstring(L, "invalid-username");
374 p = getpwnam(lua_tostring(L, 1));
378 lua_pushstring(L, "no-such-user");
381 if(lua_gettop(L) < 2)
383 switch(lua_type(L, 2))
389 gid = lua_tointeger(L, 2);
393 lua_pushstring(L, "invalid-gid");
396 ret = initgroups(lua_tostring(L, 1), gid);
400 lua_pushboolean(L, 1);
405 lua_pushstring(L, "no-memory");
409 lua_pushstring(L, "permission-denied");
413 lua_pushstring(L, "unknown-error");
418 int lc_umask(lua_State* L)
420 char old_mode_string[7];
421 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8));
423 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode);
424 old_mode_string[sizeof(old_mode_string)-1] = 0;
425 lua_pushstring(L, old_mode_string);
430 int lc_mkdir(lua_State* L)
432 int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR
433 | S_IRGRP | S_IWGRP | S_IXGRP
434 | S_IROTH | S_IXOTH); /* mode 775 */
436 lua_pushboolean(L, ret==0);
439 lua_pushstring(L, strerror(errno));
445 /* Like POSIX's setrlimit()/getrlimit() API functions.
448 * pposix.setrlimit( resource, soft limit, hard limit)
450 * Any negative limit will be replace with the current limit by an additional call of getrlimit().
453 * pposix.setrlimit("NOFILE", 1000, 2000)
455 int string2resource(const char *s) {
456 if (!strcmp(s, "CORE")) return RLIMIT_CORE;
457 if (!strcmp(s, "CPU")) return RLIMIT_CPU;
458 if (!strcmp(s, "DATA")) return RLIMIT_DATA;
459 if (!strcmp(s, "FSIZE")) return RLIMIT_FSIZE;
460 if (!strcmp(s, "NOFILE")) return RLIMIT_NOFILE;
461 if (!strcmp(s, "STACK")) return RLIMIT_STACK;
462 #if !(defined(sun) || defined(__sun))
463 if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK;
464 if (!strcmp(s, "NPROC")) return RLIMIT_NPROC;
465 if (!strcmp(s, "RSS")) return RLIMIT_RSS;
470 int lc_setrlimit(lua_State *L) {
471 int arguments = lua_gettop(L);
474 const char *resource = NULL;
476 if(arguments < 1 || arguments > 3) {
477 lua_pushboolean(L, 0);
478 lua_pushstring(L, "incorrect-arguments");
481 resource = luaL_checkstring(L, 1);
482 softlimit = luaL_checkinteger(L, 2);
483 hardlimit = luaL_checkinteger(L, 3);
485 rid = string2resource(resource);
488 struct rlimit lim_current;
490 if (softlimit < 0 || hardlimit < 0) {
491 if (getrlimit(rid, &lim_current)) {
492 lua_pushboolean(L, 0);
493 lua_pushstring(L, "getrlimit-failed");
498 if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur;
499 else lim.rlim_cur = softlimit;
500 if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max;
501 else lim.rlim_max = hardlimit;
503 if (setrlimit(rid, &lim)) {
504 lua_pushboolean(L, 0);
505 lua_pushstring(L, "setrlimit-failed");
509 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
510 lua_pushboolean(L, 0);
511 lua_pushstring(L, "invalid-resource");
514 lua_pushboolean(L, 1);
518 int lc_getrlimit(lua_State *L) {
519 int arguments = lua_gettop(L);
520 const char *resource = NULL;
524 if (arguments != 1) {
525 lua_pushboolean(L, 0);
526 lua_pushstring(L, "invalid-arguments");
530 resource = luaL_checkstring(L, 1);
531 rid = string2resource(resource);
533 if (getrlimit(rid, &lim)) {
534 lua_pushboolean(L, 0);
535 lua_pushstring(L, "getrlimit-failed.");
539 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
540 lua_pushboolean(L, 0);
541 lua_pushstring(L, "invalid-resource");
544 lua_pushboolean(L, 1);
545 lua_pushnumber(L, lim.rlim_cur);
546 lua_pushnumber(L, lim.rlim_max);
550 int lc_abort(lua_State* L)
556 /* Register functions */
558 int luaopen_util_pposix(lua_State *L)
560 luaL_Reg exports[] = {
561 { "abort", lc_abort },
563 { "daemonize", lc_daemonize },
565 { "syslog_open", lc_syslog_open },
566 { "syslog_close", lc_syslog_close },
567 { "syslog_log", lc_syslog_log },
568 { "syslog_setminlevel", lc_syslog_setmask },
570 { "getpid", lc_getpid },
571 { "getuid", lc_getuid },
572 { "getgid", lc_getgid },
574 { "setuid", lc_setuid },
575 { "setgid", lc_setgid },
576 { "initgroups", lc_initgroups },
578 { "umask", lc_umask },
580 { "mkdir", lc_mkdir },
582 { "setrlimit", lc_setrlimit },
583 { "getrlimit", lc_getrlimit },
588 luaL_register(L, "pposix", exports);
590 lua_pushliteral(L, "pposix");
591 lua_setfield(L, -2, "_NAME");
593 lua_pushliteral(L, MODULE_VERSION);
594 lua_setfield(L, -2, "_VERSION");