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 #if (defined(_SVID_SOURCE) && !defined(WITHOUT_MALLINFO))
42 /* Daemonization support */
44 static int lc_daemonize(lua_State *L)
51 lua_pushboolean(L, 0);
52 lua_pushstring(L, "already-daemonized");
56 /* Attempt initial fork */
57 if((pid = fork()) < 0)
60 lua_pushboolean(L, 0);
61 lua_pushstring(L, "fork-failed");
66 /* We are the parent process */
67 lua_pushboolean(L, 1);
68 lua_pushnumber(L, pid);
72 /* and we are the child process */
75 /* We failed to become session leader */
76 /* (we probably already were) */
77 lua_pushboolean(L, 0);
78 lua_pushstring(L, "setsid-failed");
82 /* Close stdin, stdout, stderr */
87 /* Final fork, use it wisely */
91 /* Show's over, let's continue */
92 lua_pushboolean(L, 1);
99 const char * const facility_strings[] = {
101 #if !(defined(sun) || defined(__sun))
106 #if !(defined(sun) || defined(__sun))
125 int facility_constants[] = {
127 #if !(defined(sun) || defined(__sun))
132 #if !(defined(sun) || defined(__sun))
154 The parameter ident in the call of openlog() is probably stored as-is.
155 Thus, if the string it points to is changed, syslog() may start
156 prepending the changed string, and if the string it points to ceases to
157 exist, the results are undefined. Most portable is to use a string
161 char* syslog_ident = NULL;
163 int lc_syslog_open(lua_State* L)
165 int facility = luaL_checkoption(L, 2, "daemon", facility_strings);
166 facility = facility_constants[facility];
168 luaL_checkstring(L, 1);
173 syslog_ident = strdup(lua_tostring(L, 1));
175 openlog(syslog_ident, LOG_PID, facility);
179 const char * const level_strings[] = {
187 int level_constants[] = {
195 int lc_syslog_log(lua_State* L)
197 int level = luaL_checkoption(L, 1, "notice", level_strings);
198 level = level_constants[level];
200 luaL_checkstring(L, 2);
202 syslog(level, "%s", lua_tostring(L, 2));
206 int lc_syslog_close(lua_State* L)
217 int lc_syslog_setmask(lua_State* L)
219 int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
223 mask |= LOG_MASK(level_constants[level_idx]);
224 } while (++level_idx<=4);
232 int lc_getpid(lua_State* L)
234 lua_pushinteger(L, getpid());
238 /* UID/GID functions */
240 int lc_getuid(lua_State* L)
242 lua_pushinteger(L, getuid());
246 int lc_getgid(lua_State* L)
248 lua_pushinteger(L, getgid());
252 int lc_setuid(lua_State* L)
255 if(lua_gettop(L) < 1)
257 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
259 /* Passed UID is actually a string, so look up the UID */
261 p = getpwnam(lua_tostring(L, 1));
264 lua_pushboolean(L, 0);
265 lua_pushstring(L, "no-such-user");
272 uid = lua_tonumber(L, 1);
277 /* Ok, attempt setuid */
282 lua_pushboolean(L, 0);
286 lua_pushstring(L, "invalid-uid");
289 lua_pushstring(L, "permission-denied");
292 lua_pushstring(L, "unknown-error");
299 lua_pushboolean(L, 1);
304 /* Seems we couldn't find a valid UID to switch to */
305 lua_pushboolean(L, 0);
306 lua_pushstring(L, "invalid-uid");
310 int lc_setgid(lua_State* L)
313 if(lua_gettop(L) < 1)
315 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
317 /* Passed GID is actually a string, so look up the GID */
319 g = getgrnam(lua_tostring(L, 1));
322 lua_pushboolean(L, 0);
323 lua_pushstring(L, "no-such-group");
330 gid = lua_tonumber(L, 1);
335 /* Ok, attempt setgid */
340 lua_pushboolean(L, 0);
344 lua_pushstring(L, "invalid-gid");
347 lua_pushstring(L, "permission-denied");
350 lua_pushstring(L, "unknown-error");
357 lua_pushboolean(L, 1);
362 /* Seems we couldn't find a valid GID to switch to */
363 lua_pushboolean(L, 0);
364 lua_pushstring(L, "invalid-gid");
368 int lc_initgroups(lua_State* L)
374 if(!lua_isstring(L, 1))
377 lua_pushstring(L, "invalid-username");
380 p = getpwnam(lua_tostring(L, 1));
384 lua_pushstring(L, "no-such-user");
387 if(lua_gettop(L) < 2)
389 switch(lua_type(L, 2))
395 gid = lua_tointeger(L, 2);
399 lua_pushstring(L, "invalid-gid");
402 ret = initgroups(lua_tostring(L, 1), gid);
409 lua_pushstring(L, "no-memory");
413 lua_pushstring(L, "permission-denied");
417 lua_pushstring(L, "unknown-error");
422 lua_pushboolean(L, 1);
428 int lc_umask(lua_State* L)
430 char old_mode_string[7];
431 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8));
433 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode);
434 old_mode_string[sizeof(old_mode_string)-1] = 0;
435 lua_pushstring(L, old_mode_string);
440 int lc_mkdir(lua_State* L)
442 int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR
443 | S_IRGRP | S_IWGRP | S_IXGRP
444 | S_IROTH | S_IXOTH); /* mode 775 */
446 lua_pushboolean(L, ret==0);
449 lua_pushstring(L, strerror(errno));
455 /* Like POSIX's setrlimit()/getrlimit() API functions.
458 * pposix.setrlimit( resource, soft limit, hard limit)
460 * Any negative limit will be replace with the current limit by an additional call of getrlimit().
463 * pposix.setrlimit("NOFILE", 1000, 2000)
465 int string2resource(const char *s) {
466 if (!strcmp(s, "CORE")) return RLIMIT_CORE;
467 if (!strcmp(s, "CPU")) return RLIMIT_CPU;
468 if (!strcmp(s, "DATA")) return RLIMIT_DATA;
469 if (!strcmp(s, "FSIZE")) return RLIMIT_FSIZE;
470 if (!strcmp(s, "NOFILE")) return RLIMIT_NOFILE;
471 if (!strcmp(s, "STACK")) return RLIMIT_STACK;
472 #if !(defined(sun) || defined(__sun))
473 if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK;
474 if (!strcmp(s, "NPROC")) return RLIMIT_NPROC;
475 if (!strcmp(s, "RSS")) return RLIMIT_RSS;
480 int lc_setrlimit(lua_State *L) {
481 int arguments = lua_gettop(L);
484 const char *resource = NULL;
486 if(arguments < 1 || arguments > 3) {
487 lua_pushboolean(L, 0);
488 lua_pushstring(L, "incorrect-arguments");
491 resource = luaL_checkstring(L, 1);
492 softlimit = luaL_checkinteger(L, 2);
493 hardlimit = luaL_checkinteger(L, 3);
495 rid = string2resource(resource);
498 struct rlimit lim_current;
500 if (softlimit < 0 || hardlimit < 0) {
501 if (getrlimit(rid, &lim_current)) {
502 lua_pushboolean(L, 0);
503 lua_pushstring(L, "getrlimit-failed");
508 if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur;
509 else lim.rlim_cur = softlimit;
510 if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max;
511 else lim.rlim_max = hardlimit;
513 if (setrlimit(rid, &lim)) {
514 lua_pushboolean(L, 0);
515 lua_pushstring(L, "setrlimit-failed");
519 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
520 lua_pushboolean(L, 0);
521 lua_pushstring(L, "invalid-resource");
524 lua_pushboolean(L, 1);
528 int lc_getrlimit(lua_State *L) {
529 int arguments = lua_gettop(L);
530 const char *resource = NULL;
534 if (arguments != 1) {
535 lua_pushboolean(L, 0);
536 lua_pushstring(L, "invalid-arguments");
540 resource = luaL_checkstring(L, 1);
541 rid = string2resource(resource);
543 if (getrlimit(rid, &lim)) {
544 lua_pushboolean(L, 0);
545 lua_pushstring(L, "getrlimit-failed.");
549 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
550 lua_pushboolean(L, 0);
551 lua_pushstring(L, "invalid-resource");
554 lua_pushboolean(L, 1);
555 lua_pushnumber(L, lim.rlim_cur);
556 lua_pushnumber(L, lim.rlim_max);
560 int lc_abort(lua_State* L)
566 int lc_uname(lua_State* L)
568 struct utsname uname_info;
569 if(uname(&uname_info) != 0)
572 lua_pushstring(L, strerror(errno));
576 lua_pushstring(L, uname_info.sysname);
577 lua_setfield(L, -2, "sysname");
578 lua_pushstring(L, uname_info.nodename);
579 lua_setfield(L, -2, "nodename");
580 lua_pushstring(L, uname_info.release);
581 lua_setfield(L, -2, "release");
582 lua_pushstring(L, uname_info.version);
583 lua_setfield(L, -2, "version");
584 lua_pushstring(L, uname_info.machine);
585 lua_setfield(L, -2, "machine");
589 int lc_setenv(lua_State* L)
591 const char *var = luaL_checkstring(L, 1);
594 /* If the second argument is nil or nothing, unset the var */
595 if(lua_isnoneornil(L, 2))
597 if(unsetenv(var) != 0)
600 lua_pushstring(L, strerror(errno));
603 lua_pushboolean(L, 1);
607 value = luaL_checkstring(L, 2);
609 if(setenv(var, value, 1) != 0)
612 lua_pushstring(L, strerror(errno));
616 lua_pushboolean(L, 1);
621 int lc_meminfo(lua_State* L)
623 struct mallinfo info = mallinfo();
625 /* This is the total size of memory allocated with sbrk by malloc, in bytes. */
626 lua_pushinteger(L, info.arena);
627 lua_setfield(L, -2, "allocated");
628 /* This is the total size of memory allocated with mmap, in bytes. */
629 lua_pushinteger(L, info.hblkhd);
630 lua_setfield(L, -2, "allocated_mmap");
631 /* This is the total size of memory occupied by chunks handed out by malloc. */
632 lua_pushinteger(L, info.uordblks);
633 lua_setfield(L, -2, "used");
634 /* This is the total size of memory occupied by free (not in use) chunks. */
635 lua_pushinteger(L, info.fordblks);
636 lua_setfield(L, -2, "unused");
637 /* This is the size of the top-most releasable chunk that normally borders the
638 end of the heap (i.e., the high end of the virtual address space's data segment). */
639 lua_pushinteger(L, info.keepcost);
640 lua_setfield(L, -2, "returnable");
645 /* Register functions */
647 int luaopen_util_pposix(lua_State *L)
649 luaL_Reg exports[] = {
650 { "abort", lc_abort },
652 { "daemonize", lc_daemonize },
654 { "syslog_open", lc_syslog_open },
655 { "syslog_close", lc_syslog_close },
656 { "syslog_log", lc_syslog_log },
657 { "syslog_setminlevel", lc_syslog_setmask },
659 { "getpid", lc_getpid },
660 { "getuid", lc_getuid },
661 { "getgid", lc_getgid },
663 { "setuid", lc_setuid },
664 { "setgid", lc_setgid },
665 { "initgroups", lc_initgroups },
667 { "umask", lc_umask },
669 { "mkdir", lc_mkdir },
671 { "setrlimit", lc_setrlimit },
672 { "getrlimit", lc_getrlimit },
674 { "uname", lc_uname },
676 { "setenv", lc_setenv },
679 { "meminfo", lc_meminfo },
685 luaL_register(L, "pposix", exports);
687 lua_pushliteral(L, "pposix");
688 lua_setfield(L, -2, "_NAME");
690 lua_pushliteral(L, MODULE_VERSION);
691 lua_setfield(L, -2, "_VERSION");