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>
39 #if defined(_GNU_SOURCE)
40 #include <linux/falloc.h>
43 #if (defined(_SVID_SOURCE) && !defined(WITHOUT_MALLINFO))
48 /* Daemonization support */
50 static int lc_daemonize(lua_State *L)
57 lua_pushboolean(L, 0);
58 lua_pushstring(L, "already-daemonized");
62 /* Attempt initial fork */
63 if((pid = fork()) < 0)
66 lua_pushboolean(L, 0);
67 lua_pushstring(L, "fork-failed");
72 /* We are the parent process */
73 lua_pushboolean(L, 1);
74 lua_pushnumber(L, pid);
78 /* and we are the child process */
81 /* We failed to become session leader */
82 /* (we probably already were) */
83 lua_pushboolean(L, 0);
84 lua_pushstring(L, "setsid-failed");
88 /* Close stdin, stdout, stderr */
93 /* Final fork, use it wisely */
97 /* Show's over, let's continue */
98 lua_pushboolean(L, 1);
105 const char * const facility_strings[] = {
107 #if !(defined(sun) || defined(__sun))
112 #if !(defined(sun) || defined(__sun))
131 int facility_constants[] = {
133 #if !(defined(sun) || defined(__sun))
138 #if !(defined(sun) || defined(__sun))
160 The parameter ident in the call of openlog() is probably stored as-is.
161 Thus, if the string it points to is changed, syslog() may start
162 prepending the changed string, and if the string it points to ceases to
163 exist, the results are undefined. Most portable is to use a string
167 char* syslog_ident = NULL;
169 int lc_syslog_open(lua_State* L)
171 int facility = luaL_checkoption(L, 2, "daemon", facility_strings);
172 facility = facility_constants[facility];
174 luaL_checkstring(L, 1);
179 syslog_ident = strdup(lua_tostring(L, 1));
181 openlog(syslog_ident, LOG_PID, facility);
185 const char * const level_strings[] = {
193 int level_constants[] = {
201 int lc_syslog_log(lua_State* L)
203 int level = luaL_checkoption(L, 1, "notice", level_strings);
204 level = level_constants[level];
206 luaL_checkstring(L, 2);
208 syslog(level, "%s", lua_tostring(L, 2));
212 int lc_syslog_close(lua_State* L)
223 int lc_syslog_setmask(lua_State* L)
225 int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
229 mask |= LOG_MASK(level_constants[level_idx]);
230 } while (++level_idx<=4);
238 int lc_getpid(lua_State* L)
240 lua_pushinteger(L, getpid());
244 /* UID/GID functions */
246 int lc_getuid(lua_State* L)
248 lua_pushinteger(L, getuid());
252 int lc_getgid(lua_State* L)
254 lua_pushinteger(L, getgid());
258 int lc_setuid(lua_State* L)
261 if(lua_gettop(L) < 1)
263 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
265 /* Passed UID is actually a string, so look up the UID */
267 p = getpwnam(lua_tostring(L, 1));
270 lua_pushboolean(L, 0);
271 lua_pushstring(L, "no-such-user");
278 uid = lua_tonumber(L, 1);
283 /* Ok, attempt setuid */
288 lua_pushboolean(L, 0);
292 lua_pushstring(L, "invalid-uid");
295 lua_pushstring(L, "permission-denied");
298 lua_pushstring(L, "unknown-error");
305 lua_pushboolean(L, 1);
310 /* Seems we couldn't find a valid UID to switch to */
311 lua_pushboolean(L, 0);
312 lua_pushstring(L, "invalid-uid");
316 int lc_setgid(lua_State* L)
319 if(lua_gettop(L) < 1)
321 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
323 /* Passed GID is actually a string, so look up the GID */
325 g = getgrnam(lua_tostring(L, 1));
328 lua_pushboolean(L, 0);
329 lua_pushstring(L, "no-such-group");
336 gid = lua_tonumber(L, 1);
341 /* Ok, attempt setgid */
346 lua_pushboolean(L, 0);
350 lua_pushstring(L, "invalid-gid");
353 lua_pushstring(L, "permission-denied");
356 lua_pushstring(L, "unknown-error");
363 lua_pushboolean(L, 1);
368 /* Seems we couldn't find a valid GID to switch to */
369 lua_pushboolean(L, 0);
370 lua_pushstring(L, "invalid-gid");
374 int lc_initgroups(lua_State* L)
380 if(!lua_isstring(L, 1))
383 lua_pushstring(L, "invalid-username");
386 p = getpwnam(lua_tostring(L, 1));
390 lua_pushstring(L, "no-such-user");
393 if(lua_gettop(L) < 2)
395 switch(lua_type(L, 2))
401 gid = lua_tointeger(L, 2);
405 lua_pushstring(L, "invalid-gid");
408 ret = initgroups(lua_tostring(L, 1), gid);
415 lua_pushstring(L, "no-memory");
419 lua_pushstring(L, "permission-denied");
423 lua_pushstring(L, "unknown-error");
428 lua_pushboolean(L, 1);
434 int lc_umask(lua_State* L)
436 char old_mode_string[7];
437 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8));
439 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode);
440 old_mode_string[sizeof(old_mode_string)-1] = 0;
441 lua_pushstring(L, old_mode_string);
446 int lc_mkdir(lua_State* L)
448 int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR
449 | S_IRGRP | S_IWGRP | S_IXGRP
450 | S_IROTH | S_IXOTH); /* mode 775 */
452 lua_pushboolean(L, ret==0);
455 lua_pushstring(L, strerror(errno));
461 /* Like POSIX's setrlimit()/getrlimit() API functions.
464 * pposix.setrlimit( resource, soft limit, hard limit)
466 * Any negative limit will be replace with the current limit by an additional call of getrlimit().
469 * pposix.setrlimit("NOFILE", 1000, 2000)
471 int string2resource(const char *s) {
472 if (!strcmp(s, "CORE")) return RLIMIT_CORE;
473 if (!strcmp(s, "CPU")) return RLIMIT_CPU;
474 if (!strcmp(s, "DATA")) return RLIMIT_DATA;
475 if (!strcmp(s, "FSIZE")) return RLIMIT_FSIZE;
476 if (!strcmp(s, "NOFILE")) return RLIMIT_NOFILE;
477 if (!strcmp(s, "STACK")) return RLIMIT_STACK;
478 #if !(defined(sun) || defined(__sun))
479 if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK;
480 if (!strcmp(s, "NPROC")) return RLIMIT_NPROC;
481 if (!strcmp(s, "RSS")) return RLIMIT_RSS;
486 int lc_setrlimit(lua_State *L) {
487 int arguments = lua_gettop(L);
490 const char *resource = NULL;
492 if(arguments < 1 || arguments > 3) {
493 lua_pushboolean(L, 0);
494 lua_pushstring(L, "incorrect-arguments");
497 resource = luaL_checkstring(L, 1);
498 softlimit = luaL_checkinteger(L, 2);
499 hardlimit = luaL_checkinteger(L, 3);
501 rid = string2resource(resource);
504 struct rlimit lim_current;
506 if (softlimit < 0 || hardlimit < 0) {
507 if (getrlimit(rid, &lim_current)) {
508 lua_pushboolean(L, 0);
509 lua_pushstring(L, "getrlimit-failed");
514 if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur;
515 else lim.rlim_cur = softlimit;
516 if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max;
517 else lim.rlim_max = hardlimit;
519 if (setrlimit(rid, &lim)) {
520 lua_pushboolean(L, 0);
521 lua_pushstring(L, "setrlimit-failed");
525 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
526 lua_pushboolean(L, 0);
527 lua_pushstring(L, "invalid-resource");
530 lua_pushboolean(L, 1);
534 int lc_getrlimit(lua_State *L) {
535 int arguments = lua_gettop(L);
536 const char *resource = NULL;
540 if (arguments != 1) {
541 lua_pushboolean(L, 0);
542 lua_pushstring(L, "invalid-arguments");
546 resource = luaL_checkstring(L, 1);
547 rid = string2resource(resource);
549 if (getrlimit(rid, &lim)) {
550 lua_pushboolean(L, 0);
551 lua_pushstring(L, "getrlimit-failed.");
555 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
556 lua_pushboolean(L, 0);
557 lua_pushstring(L, "invalid-resource");
560 lua_pushboolean(L, 1);
561 lua_pushnumber(L, lim.rlim_cur);
562 lua_pushnumber(L, lim.rlim_max);
566 int lc_abort(lua_State* L)
572 int lc_uname(lua_State* L)
574 struct utsname uname_info;
575 if(uname(&uname_info) != 0)
578 lua_pushstring(L, strerror(errno));
582 lua_pushstring(L, uname_info.sysname);
583 lua_setfield(L, -2, "sysname");
584 lua_pushstring(L, uname_info.nodename);
585 lua_setfield(L, -2, "nodename");
586 lua_pushstring(L, uname_info.release);
587 lua_setfield(L, -2, "release");
588 lua_pushstring(L, uname_info.version);
589 lua_setfield(L, -2, "version");
590 lua_pushstring(L, uname_info.machine);
591 lua_setfield(L, -2, "machine");
595 int lc_setenv(lua_State* L)
597 const char *var = luaL_checkstring(L, 1);
600 /* If the second argument is nil or nothing, unset the var */
601 if(lua_isnoneornil(L, 2))
603 if(unsetenv(var) != 0)
606 lua_pushstring(L, strerror(errno));
609 lua_pushboolean(L, 1);
613 value = luaL_checkstring(L, 2);
615 if(setenv(var, value, 1) != 0)
618 lua_pushstring(L, strerror(errno));
622 lua_pushboolean(L, 1);
627 int lc_meminfo(lua_State* L)
629 struct mallinfo info = mallinfo();
631 /* This is the total size of memory allocated with sbrk by malloc, in bytes. */
632 lua_pushinteger(L, info.arena);
633 lua_setfield(L, -2, "allocated");
634 /* This is the total size of memory allocated with mmap, in bytes. */
635 lua_pushinteger(L, info.hblkhd);
636 lua_setfield(L, -2, "allocated_mmap");
637 /* This is the total size of memory occupied by chunks handed out by malloc. */
638 lua_pushinteger(L, info.uordblks);
639 lua_setfield(L, -2, "used");
640 /* This is the total size of memory occupied by free (not in use) chunks. */
641 lua_pushinteger(L, info.fordblks);
642 lua_setfield(L, -2, "unused");
643 /* This is the size of the top-most releasable chunk that normally borders the
644 end of the heap (i.e., the high end of the virtual address space's data segment). */
645 lua_pushinteger(L, info.keepcost);
646 lua_setfield(L, -2, "returnable");
651 /* File handle extraction blatantly stolen from
652 * https://github.com/rrthomas/luaposix/blob/master/lposix.c#L631
655 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
656 int lc_fallocate(lua_State* L)
659 FILE *f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE);
661 offset = luaL_checkinteger(L, 2);
662 len = luaL_checkinteger(L, 3);
664 #if defined(_GNU_SOURCE)
665 if(fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len) == 0)
667 lua_pushboolean(L, 1);
671 if(errno != ENOSYS && errno != EOPNOTSUPP)
674 lua_pushstring(L, strerror(errno));
679 if(posix_fallocate(fileno(f), offset, len) == 0)
681 lua_pushboolean(L, 1);
687 lua_pushstring(L, strerror(errno));
688 /* posix_fallocate() can leave a bunch of NULs at the end, so we cut that
689 * this assumes that offset == length of the file */
690 ftruncate(fileno(f), offset);
696 /* Register functions */
698 int luaopen_util_pposix(lua_State *L)
700 luaL_Reg exports[] = {
701 { "abort", lc_abort },
703 { "daemonize", lc_daemonize },
705 { "syslog_open", lc_syslog_open },
706 { "syslog_close", lc_syslog_close },
707 { "syslog_log", lc_syslog_log },
708 { "syslog_setminlevel", lc_syslog_setmask },
710 { "getpid", lc_getpid },
711 { "getuid", lc_getuid },
712 { "getgid", lc_getgid },
714 { "setuid", lc_setuid },
715 { "setgid", lc_setgid },
716 { "initgroups", lc_initgroups },
718 { "umask", lc_umask },
720 { "mkdir", lc_mkdir },
722 { "setrlimit", lc_setrlimit },
723 { "getrlimit", lc_getrlimit },
725 { "uname", lc_uname },
727 { "setenv", lc_setenv },
730 { "meminfo", lc_meminfo },
733 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
734 { "fallocate", lc_fallocate },
740 luaL_register(L, "pposix", exports);
742 lua_pushliteral(L, "pposix");
743 lua_setfield(L, -2, "_NAME");
745 lua_pushliteral(L, MODULE_VERSION);
746 lua_setfield(L, -2, "_VERSION");