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.5"
22 #include <sys/resource.h>
23 #include <sys/types.h>
25 #include <sys/utsname.h>
37 /* Daemonization support */
39 static int lc_daemonize(lua_State *L)
46 lua_pushboolean(L, 0);
47 lua_pushstring(L, "already-daemonized");
51 /* Attempt initial fork */
52 if((pid = fork()) < 0)
55 lua_pushboolean(L, 0);
56 lua_pushstring(L, "fork-failed");
61 /* We are the parent process */
62 lua_pushboolean(L, 1);
63 lua_pushnumber(L, pid);
67 /* and we are the child process */
70 /* We failed to become session leader */
71 /* (we probably already were) */
72 lua_pushboolean(L, 0);
73 lua_pushstring(L, "setsid-failed");
77 /* Close stdin, stdout, stderr */
82 /* Final fork, use it wisely */
86 /* Show's over, let's continue */
87 lua_pushboolean(L, 1);
94 const char * const facility_strings[] = {
96 #if !(defined(sun) || defined(__sun))
101 #if !(defined(sun) || defined(__sun))
120 int facility_constants[] = {
122 #if !(defined(sun) || defined(__sun))
127 #if !(defined(sun) || defined(__sun))
149 The parameter ident in the call of openlog() is probably stored as-is.
150 Thus, if the string it points to is changed, syslog() may start
151 prepending the changed string, and if the string it points to ceases to
152 exist, the results are undefined. Most portable is to use a string
156 char* syslog_ident = NULL;
158 int lc_syslog_open(lua_State* L)
160 int facility = luaL_checkoption(L, 2, "daemon", facility_strings);
161 facility = facility_constants[facility];
163 luaL_checkstring(L, 1);
168 syslog_ident = strdup(lua_tostring(L, 1));
170 openlog(syslog_ident, LOG_PID, facility);
174 const char * const level_strings[] = {
182 int level_constants[] = {
190 int lc_syslog_log(lua_State* L)
192 int level = luaL_checkoption(L, 1, "notice", level_strings);
193 level = level_constants[level];
195 luaL_checkstring(L, 2);
197 syslog(level, "%s", lua_tostring(L, 2));
201 int lc_syslog_close(lua_State* L)
212 int lc_syslog_setmask(lua_State* L)
214 int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
218 mask |= LOG_MASK(level_constants[level_idx]);
219 } while (++level_idx<=4);
227 int lc_getpid(lua_State* L)
229 lua_pushinteger(L, getpid());
233 /* UID/GID functions */
235 int lc_getuid(lua_State* L)
237 lua_pushinteger(L, getuid());
241 int lc_getgid(lua_State* L)
243 lua_pushinteger(L, getgid());
247 int lc_setuid(lua_State* L)
250 if(lua_gettop(L) < 1)
252 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
254 /* Passed UID is actually a string, so look up the UID */
256 p = getpwnam(lua_tostring(L, 1));
259 lua_pushboolean(L, 0);
260 lua_pushstring(L, "no-such-user");
267 uid = lua_tonumber(L, 1);
272 /* Ok, attempt setuid */
277 lua_pushboolean(L, 0);
281 lua_pushstring(L, "invalid-uid");
284 lua_pushstring(L, "permission-denied");
287 lua_pushstring(L, "unknown-error");
294 lua_pushboolean(L, 1);
299 /* Seems we couldn't find a valid UID to switch to */
300 lua_pushboolean(L, 0);
301 lua_pushstring(L, "invalid-uid");
305 int lc_setgid(lua_State* L)
308 if(lua_gettop(L) < 1)
310 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
312 /* Passed GID is actually a string, so look up the GID */
314 g = getgrnam(lua_tostring(L, 1));
317 lua_pushboolean(L, 0);
318 lua_pushstring(L, "no-such-group");
325 gid = lua_tonumber(L, 1);
330 /* Ok, attempt setgid */
335 lua_pushboolean(L, 0);
339 lua_pushstring(L, "invalid-gid");
342 lua_pushstring(L, "permission-denied");
345 lua_pushstring(L, "unknown-error");
352 lua_pushboolean(L, 1);
357 /* Seems we couldn't find a valid GID to switch to */
358 lua_pushboolean(L, 0);
359 lua_pushstring(L, "invalid-gid");
363 int lc_initgroups(lua_State* L)
369 if(!lua_isstring(L, 1))
372 lua_pushstring(L, "invalid-username");
375 p = getpwnam(lua_tostring(L, 1));
379 lua_pushstring(L, "no-such-user");
382 if(lua_gettop(L) < 2)
384 switch(lua_type(L, 2))
390 gid = lua_tointeger(L, 2);
394 lua_pushstring(L, "invalid-gid");
397 ret = initgroups(lua_tostring(L, 1), gid);
404 lua_pushstring(L, "no-memory");
408 lua_pushstring(L, "permission-denied");
412 lua_pushstring(L, "unknown-error");
417 lua_pushboolean(L, 1);
423 int lc_umask(lua_State* L)
425 char old_mode_string[7];
426 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8));
428 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode);
429 old_mode_string[sizeof(old_mode_string)-1] = 0;
430 lua_pushstring(L, old_mode_string);
435 int lc_mkdir(lua_State* L)
437 int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR
438 | S_IRGRP | S_IWGRP | S_IXGRP
439 | S_IROTH | S_IXOTH); /* mode 775 */
441 lua_pushboolean(L, ret==0);
444 lua_pushstring(L, strerror(errno));
450 /* Like POSIX's setrlimit()/getrlimit() API functions.
453 * pposix.setrlimit( resource, soft limit, hard limit)
455 * Any negative limit will be replace with the current limit by an additional call of getrlimit().
458 * pposix.setrlimit("NOFILE", 1000, 2000)
460 int string2resource(const char *s) {
461 if (!strcmp(s, "CORE")) return RLIMIT_CORE;
462 if (!strcmp(s, "CPU")) return RLIMIT_CPU;
463 if (!strcmp(s, "DATA")) return RLIMIT_DATA;
464 if (!strcmp(s, "FSIZE")) return RLIMIT_FSIZE;
465 if (!strcmp(s, "NOFILE")) return RLIMIT_NOFILE;
466 if (!strcmp(s, "STACK")) return RLIMIT_STACK;
467 #if !(defined(sun) || defined(__sun))
468 if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK;
469 if (!strcmp(s, "NPROC")) return RLIMIT_NPROC;
470 if (!strcmp(s, "RSS")) return RLIMIT_RSS;
475 int lc_setrlimit(lua_State *L) {
476 int arguments = lua_gettop(L);
479 const char *resource = NULL;
481 if(arguments < 1 || arguments > 3) {
482 lua_pushboolean(L, 0);
483 lua_pushstring(L, "incorrect-arguments");
486 resource = luaL_checkstring(L, 1);
487 softlimit = luaL_checkinteger(L, 2);
488 hardlimit = luaL_checkinteger(L, 3);
490 rid = string2resource(resource);
493 struct rlimit lim_current;
495 if (softlimit < 0 || hardlimit < 0) {
496 if (getrlimit(rid, &lim_current)) {
497 lua_pushboolean(L, 0);
498 lua_pushstring(L, "getrlimit-failed");
503 if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur;
504 else lim.rlim_cur = softlimit;
505 if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max;
506 else lim.rlim_max = hardlimit;
508 if (setrlimit(rid, &lim)) {
509 lua_pushboolean(L, 0);
510 lua_pushstring(L, "setrlimit-failed");
514 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
515 lua_pushboolean(L, 0);
516 lua_pushstring(L, "invalid-resource");
519 lua_pushboolean(L, 1);
523 int lc_getrlimit(lua_State *L) {
524 int arguments = lua_gettop(L);
525 const char *resource = NULL;
529 if (arguments != 1) {
530 lua_pushboolean(L, 0);
531 lua_pushstring(L, "invalid-arguments");
535 resource = luaL_checkstring(L, 1);
536 rid = string2resource(resource);
538 if (getrlimit(rid, &lim)) {
539 lua_pushboolean(L, 0);
540 lua_pushstring(L, "getrlimit-failed.");
544 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
545 lua_pushboolean(L, 0);
546 lua_pushstring(L, "invalid-resource");
549 lua_pushboolean(L, 1);
550 lua_pushnumber(L, lim.rlim_cur);
551 lua_pushnumber(L, lim.rlim_max);
555 int lc_abort(lua_State* L)
561 int lc_uname(lua_State* L)
563 struct utsname uname_info;
564 if(uname(&uname_info) != 0)
567 lua_pushstring(L, strerror(errno));
571 lua_pushstring(L, uname_info.sysname);
572 lua_setfield(L, -2, "sysname");
573 lua_pushstring(L, uname_info.nodename);
574 lua_setfield(L, -2, "nodename");
575 lua_pushstring(L, uname_info.release);
576 lua_setfield(L, -2, "release");
577 lua_pushstring(L, uname_info.version);
578 lua_setfield(L, -2, "version");
579 lua_pushstring(L, uname_info.machine);
580 lua_setfield(L, -2, "machine");
584 /* Register functions */
586 int luaopen_util_pposix(lua_State *L)
588 luaL_Reg exports[] = {
589 { "abort", lc_abort },
591 { "daemonize", lc_daemonize },
593 { "syslog_open", lc_syslog_open },
594 { "syslog_close", lc_syslog_close },
595 { "syslog_log", lc_syslog_log },
596 { "syslog_setminlevel", lc_syslog_setmask },
598 { "getpid", lc_getpid },
599 { "getuid", lc_getuid },
600 { "getgid", lc_getgid },
602 { "setuid", lc_setuid },
603 { "setgid", lc_setgid },
604 { "initgroups", lc_initgroups },
606 { "umask", lc_umask },
608 { "mkdir", lc_mkdir },
610 { "setrlimit", lc_setrlimit },
611 { "getrlimit", lc_getrlimit },
613 { "uname", lc_uname },
618 luaL_register(L, "pposix", exports);
620 lua_pushliteral(L, "pposix");
621 lua_setfield(L, -2, "_NAME");
623 lua_pushliteral(L, MODULE_VERSION);
624 lua_setfield(L, -2, "_VERSION");