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.6"
22 #include <sys/resource.h>
23 #include <sys/types.h>
25 #include <sys/utsname.h>
38 #if (LUA_VERSION_NUM == 501)
39 #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
43 #if defined(__linux__) && defined(_GNU_SOURCE)
44 #include <linux/falloc.h>
47 #if (defined(_SVID_SOURCE) && !defined(WITHOUT_MALLINFO))
52 #if defined(RFPROC) && defined(EV_SET)
54 * On *BSD, calling fork() is equivalent to rfork(RFPROC | RFFDG).
56 * RFFDG being set means that the file descriptor table is copied,
57 * otherwise it's shared. We want the later, otherwise libevent gets
62 #define fork() rfork(RFPROC)
65 /* Daemonization support */
67 static int lc_daemonize(lua_State* L) {
72 lua_pushboolean(L, 0);
73 lua_pushstring(L, "already-daemonized");
77 /* Attempt initial fork */
78 if((pid = fork()) < 0) {
80 lua_pushboolean(L, 0);
81 lua_pushstring(L, "fork-failed");
84 /* We are the parent process */
85 lua_pushboolean(L, 1);
86 lua_pushnumber(L, pid);
90 /* and we are the child process */
92 /* We failed to become session leader */
93 /* (we probably already were) */
94 lua_pushboolean(L, 0);
95 lua_pushstring(L, "setsid-failed");
99 /* Close stdin, stdout, stderr */
103 /* Make sure accidental use of FDs 0, 1, 2 don't cause weirdness */
104 open("/dev/null", O_RDONLY);
105 open("/dev/null", O_WRONLY);
106 open("/dev/null", O_WRONLY);
108 /* Final fork, use it wisely */
113 /* Show's over, let's continue */
114 lua_pushboolean(L, 1);
121 const char* const facility_strings[] = {
123 #if !(defined(sun) || defined(__sun))
128 #if !(defined(sun) || defined(__sun))
147 int facility_constants[] = {
149 #if !(defined(sun) || defined(__sun))
154 #if !(defined(sun) || defined(__sun))
176 The parameter ident in the call of openlog() is probably stored as-is.
177 Thus, if the string it points to is changed, syslog() may start
178 prepending the changed string, and if the string it points to ceases to
179 exist, the results are undefined. Most portable is to use a string
183 char* syslog_ident = NULL;
185 int lc_syslog_open(lua_State* L) {
186 int facility = luaL_checkoption(L, 2, "daemon", facility_strings);
187 facility = facility_constants[facility];
189 luaL_checkstring(L, 1);
195 syslog_ident = strdup(lua_tostring(L, 1));
197 openlog(syslog_ident, LOG_PID, facility);
201 const char* const level_strings[] = {
209 int level_constants[] = {
217 int lc_syslog_log(lua_State* L) {
218 int level = level_constants[luaL_checkoption(L, 1, "notice", level_strings)];
220 if(lua_gettop(L) == 3) {
221 syslog(level, "%s: %s", luaL_checkstring(L, 2), luaL_checkstring(L, 3));
223 syslog(level, "%s", lua_tostring(L, 2));
229 int lc_syslog_close(lua_State* L) {
240 int lc_syslog_setmask(lua_State* L) {
241 int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
245 mask |= LOG_MASK(level_constants[level_idx]);
246 } while(++level_idx <= 4);
254 int lc_getpid(lua_State* L) {
255 lua_pushinteger(L, getpid());
259 /* UID/GID functions */
261 int lc_getuid(lua_State* L) {
262 lua_pushinteger(L, getuid());
266 int lc_getgid(lua_State* L) {
267 lua_pushinteger(L, getgid());
271 int lc_setuid(lua_State* L) {
274 if(lua_gettop(L) < 1) {
278 if(!lua_isnumber(L, 1) && lua_tostring(L, 1)) {
279 /* Passed UID is actually a string, so look up the UID */
281 p = getpwnam(lua_tostring(L, 1));
284 lua_pushboolean(L, 0);
285 lua_pushstring(L, "no-such-user");
291 uid = lua_tonumber(L, 1);
295 /* Ok, attempt setuid */
300 lua_pushboolean(L, 0);
304 lua_pushstring(L, "invalid-uid");
307 lua_pushstring(L, "permission-denied");
310 lua_pushstring(L, "unknown-error");
316 lua_pushboolean(L, 1);
321 /* Seems we couldn't find a valid UID to switch to */
322 lua_pushboolean(L, 0);
323 lua_pushstring(L, "invalid-uid");
327 int lc_setgid(lua_State* L) {
330 if(lua_gettop(L) < 1) {
334 if(!lua_isnumber(L, 1) && lua_tostring(L, 1)) {
335 /* Passed GID is actually a string, so look up the GID */
337 g = getgrnam(lua_tostring(L, 1));
340 lua_pushboolean(L, 0);
341 lua_pushstring(L, "no-such-group");
347 gid = lua_tonumber(L, 1);
351 /* Ok, attempt setgid */
356 lua_pushboolean(L, 0);
360 lua_pushstring(L, "invalid-gid");
363 lua_pushstring(L, "permission-denied");
366 lua_pushstring(L, "unknown-error");
372 lua_pushboolean(L, 1);
377 /* Seems we couldn't find a valid GID to switch to */
378 lua_pushboolean(L, 0);
379 lua_pushstring(L, "invalid-gid");
383 int lc_initgroups(lua_State* L) {
388 if(!lua_isstring(L, 1)) {
390 lua_pushstring(L, "invalid-username");
394 p = getpwnam(lua_tostring(L, 1));
398 lua_pushstring(L, "no-such-user");
402 if(lua_gettop(L) < 2) {
406 switch(lua_type(L, 2)) {
411 gid = lua_tointeger(L, 2);
415 lua_pushstring(L, "invalid-gid");
419 ret = initgroups(lua_tostring(L, 1), gid);
425 lua_pushstring(L, "no-memory");
429 lua_pushstring(L, "permission-denied");
433 lua_pushstring(L, "unknown-error");
436 lua_pushboolean(L, 1);
443 int lc_umask(lua_State* L) {
444 char old_mode_string[7];
445 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8));
447 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode);
448 old_mode_string[sizeof(old_mode_string) - 1] = 0;
449 lua_pushstring(L, old_mode_string);
454 int lc_mkdir(lua_State* L) {
455 int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR
456 | S_IRGRP | S_IWGRP | S_IXGRP
457 | S_IROTH | S_IXOTH); /* mode 775 */
459 lua_pushboolean(L, ret == 0);
462 lua_pushstring(L, strerror(errno));
469 /* Like POSIX's setrlimit()/getrlimit() API functions.
472 * pposix.setrlimit( resource, soft limit, hard limit)
474 * Any negative limit will be replace with the current limit by an additional call of getrlimit().
477 * pposix.setrlimit("NOFILE", 1000, 2000)
479 int string2resource(const char* s) {
480 if(!strcmp(s, "CORE")) {
484 if(!strcmp(s, "CPU")) {
488 if(!strcmp(s, "DATA")) {
492 if(!strcmp(s, "FSIZE")) {
496 if(!strcmp(s, "NOFILE")) {
497 return RLIMIT_NOFILE;
500 if(!strcmp(s, "STACK")) {
504 #if !(defined(sun) || defined(__sun))
506 if(!strcmp(s, "MEMLOCK")) {
507 return RLIMIT_MEMLOCK;
510 if(!strcmp(s, "NPROC")) {
514 if(!strcmp(s, "RSS")) {
521 if(!strcmp(s, "NICE")) {
529 unsigned long int arg_to_rlimit(lua_State* L, int idx, rlim_t current) {
530 switch(lua_type(L, idx)) {
533 if(strcmp(lua_tostring(L, idx), "unlimited") == 0) {
534 return RLIM_INFINITY;
538 return lua_tointeger(L, idx);
543 return luaL_argerror(L, idx, "unexpected type");
547 int lc_setrlimit(lua_State* L) {
549 int arguments = lua_gettop(L);
552 if(arguments < 1 || arguments > 3) {
553 lua_pushboolean(L, 0);
554 lua_pushstring(L, "incorrect-arguments");
558 rid = string2resource(luaL_checkstring(L, 1));
561 lua_pushboolean(L, 0);
562 lua_pushstring(L, "invalid-resource");
566 /* Fetch current values to use as defaults */
567 if(getrlimit(rid, &lim)) {
568 lua_pushboolean(L, 0);
569 lua_pushstring(L, "getrlimit-failed");
573 lim.rlim_cur = arg_to_rlimit(L, 2, lim.rlim_cur);
574 lim.rlim_max = arg_to_rlimit(L, 3, lim.rlim_max);
576 if(setrlimit(rid, &lim)) {
577 lua_pushboolean(L, 0);
578 lua_pushstring(L, "setrlimit-failed");
582 lua_pushboolean(L, 1);
586 int lc_getrlimit(lua_State* L) {
587 int arguments = lua_gettop(L);
588 const char* resource = NULL;
593 lua_pushboolean(L, 0);
594 lua_pushstring(L, "invalid-arguments");
600 resource = luaL_checkstring(L, 1);
601 rid = string2resource(resource);
604 if(getrlimit(rid, &lim)) {
605 lua_pushboolean(L, 0);
606 lua_pushstring(L, "getrlimit-failed.");
610 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
611 lua_pushboolean(L, 0);
612 lua_pushstring(L, "invalid-resource");
616 lua_pushboolean(L, 1);
618 if(lim.rlim_cur == RLIM_INFINITY) {
619 lua_pushstring(L, "unlimited");
621 lua_pushnumber(L, lim.rlim_cur);
624 if(lim.rlim_max == RLIM_INFINITY) {
625 lua_pushstring(L, "unlimited");
627 lua_pushnumber(L, lim.rlim_max);
633 int lc_abort(lua_State* L) {
638 int lc_uname(lua_State* L) {
639 struct utsname uname_info;
641 if(uname(&uname_info) != 0) {
643 lua_pushstring(L, strerror(errno));
648 lua_pushstring(L, uname_info.sysname);
649 lua_setfield(L, -2, "sysname");
650 lua_pushstring(L, uname_info.nodename);
651 lua_setfield(L, -2, "nodename");
652 lua_pushstring(L, uname_info.release);
653 lua_setfield(L, -2, "release");
654 lua_pushstring(L, uname_info.version);
655 lua_setfield(L, -2, "version");
656 lua_pushstring(L, uname_info.machine);
657 lua_setfield(L, -2, "machine");
659 lua_pushstring(L, uname_info.domainname);
660 lua_setfield(L, -2, "domainname");
665 int lc_setenv(lua_State* L) {
666 const char* var = luaL_checkstring(L, 1);
669 /* If the second argument is nil or nothing, unset the var */
670 if(lua_isnoneornil(L, 2)) {
671 if(unsetenv(var) != 0) {
673 lua_pushstring(L, strerror(errno));
677 lua_pushboolean(L, 1);
681 value = luaL_checkstring(L, 2);
683 if(setenv(var, value, 1) != 0) {
685 lua_pushstring(L, strerror(errno));
689 lua_pushboolean(L, 1);
694 int lc_meminfo(lua_State* L) {
695 struct mallinfo info = mallinfo();
697 /* This is the total size of memory allocated with sbrk by malloc, in bytes. */
698 lua_pushinteger(L, info.arena);
699 lua_setfield(L, -2, "allocated");
700 /* This is the total size of memory allocated with mmap, in bytes. */
701 lua_pushinteger(L, info.hblkhd);
702 lua_setfield(L, -2, "allocated_mmap");
703 /* This is the total size of memory occupied by chunks handed out by malloc. */
704 lua_pushinteger(L, info.uordblks);
705 lua_setfield(L, -2, "used");
706 /* This is the total size of memory occupied by free (not in use) chunks. */
707 lua_pushinteger(L, info.fordblks);
708 lua_setfield(L, -2, "unused");
709 /* This is the size of the top-most releasable chunk that normally borders the
710 end of the heap (i.e., the high end of the virtual address space's data segment). */
711 lua_pushinteger(L, info.keepcost);
712 lua_setfield(L, -2, "returnable");
717 /* File handle extraction blatantly stolen from
718 * https://github.com/rrthomas/luaposix/blob/master/lposix.c#L631
721 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
722 int lc_fallocate(lua_State* L) {
725 FILE* f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE);
728 return luaL_error(L, "attempt to use a closed file");
731 offset = luaL_checkinteger(L, 2);
732 len = luaL_checkinteger(L, 3);
734 #if defined(__linux__) && defined(_GNU_SOURCE)
736 ret = fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len);
739 lua_pushboolean(L, 1);
743 /* Some old versions of Linux apparently use the return value instead of errno */
748 if(errno != ENOSYS && errno != EOPNOTSUPP) {
750 lua_pushstring(L, strerror(errno));
755 #warning Only using posix_fallocate() fallback.
756 #warning Linux fallocate() is strongly recommended if available: recompile with -D_GNU_SOURCE
757 #warning Note that posix_fallocate() will still be used on filesystems that dont support fallocate()
760 ret = posix_fallocate(fileno(f), offset, len);
763 lua_pushboolean(L, 1);
767 lua_pushstring(L, strerror(ret));
768 /* posix_fallocate() can leave a bunch of NULs at the end, so we cut that
769 * this assumes that offset == length of the file */
770 if(ftruncate(fileno(f), offset) != 0) {
771 lua_pushstring(L, strerror(errno));
779 /* Register functions */
781 int luaopen_util_pposix(lua_State* L) {
782 luaL_Reg exports[] = {
783 { "abort", lc_abort },
785 { "daemonize", lc_daemonize },
787 { "syslog_open", lc_syslog_open },
788 { "syslog_close", lc_syslog_close },
789 { "syslog_log", lc_syslog_log },
790 { "syslog_setminlevel", lc_syslog_setmask },
792 { "getpid", lc_getpid },
793 { "getuid", lc_getuid },
794 { "getgid", lc_getgid },
796 { "setuid", lc_setuid },
797 { "setgid", lc_setgid },
798 { "initgroups", lc_initgroups },
800 { "umask", lc_umask },
802 { "mkdir", lc_mkdir },
804 { "setrlimit", lc_setrlimit },
805 { "getrlimit", lc_getrlimit },
807 { "uname", lc_uname },
809 { "setenv", lc_setenv },
812 { "meminfo", lc_meminfo },
815 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
816 { "fallocate", lc_fallocate },
823 luaL_setfuncs(L, exports, 0);
825 lua_pushliteral(L, "pposix");
826 lua_setfield(L, -2, "_NAME");
828 lua_pushliteral(L, MODULE_VERSION);
829 lua_setfield(L, -2, "_VERSION");