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 */
92 /* Make sure accidental use of FDs 0, 1, 2 don't cause weirdness */
93 open("/dev/null", O_RDONLY);
94 open("/dev/null", O_WRONLY);
95 open("/dev/null", O_WRONLY);
97 /* Final fork, use it wisely */
101 /* Show's over, let's continue */
102 lua_pushboolean(L, 1);
109 const char * const facility_strings[] = {
111 #if !(defined(sun) || defined(__sun))
116 #if !(defined(sun) || defined(__sun))
135 int facility_constants[] = {
137 #if !(defined(sun) || defined(__sun))
142 #if !(defined(sun) || defined(__sun))
164 The parameter ident in the call of openlog() is probably stored as-is.
165 Thus, if the string it points to is changed, syslog() may start
166 prepending the changed string, and if the string it points to ceases to
167 exist, the results are undefined. Most portable is to use a string
171 char* syslog_ident = NULL;
173 int lc_syslog_open(lua_State* L)
175 int facility = luaL_checkoption(L, 2, "daemon", facility_strings);
176 facility = facility_constants[facility];
178 luaL_checkstring(L, 1);
183 syslog_ident = strdup(lua_tostring(L, 1));
185 openlog(syslog_ident, LOG_PID, facility);
189 const char * const level_strings[] = {
197 int level_constants[] = {
205 int lc_syslog_log(lua_State* L)
207 int level = luaL_checkoption(L, 1, "notice", level_strings);
208 level = level_constants[level];
210 luaL_checkstring(L, 2);
212 syslog(level, "%s", lua_tostring(L, 2));
216 int lc_syslog_close(lua_State* L)
227 int lc_syslog_setmask(lua_State* L)
229 int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
233 mask |= LOG_MASK(level_constants[level_idx]);
234 } while (++level_idx<=4);
242 int lc_getpid(lua_State* L)
244 lua_pushinteger(L, getpid());
248 /* UID/GID functions */
250 int lc_getuid(lua_State* L)
252 lua_pushinteger(L, getuid());
256 int lc_getgid(lua_State* L)
258 lua_pushinteger(L, getgid());
262 int lc_setuid(lua_State* L)
265 if(lua_gettop(L) < 1)
267 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
269 /* Passed UID is actually a string, so look up the UID */
271 p = getpwnam(lua_tostring(L, 1));
274 lua_pushboolean(L, 0);
275 lua_pushstring(L, "no-such-user");
282 uid = lua_tonumber(L, 1);
287 /* Ok, attempt setuid */
292 lua_pushboolean(L, 0);
296 lua_pushstring(L, "invalid-uid");
299 lua_pushstring(L, "permission-denied");
302 lua_pushstring(L, "unknown-error");
309 lua_pushboolean(L, 1);
314 /* Seems we couldn't find a valid UID to switch to */
315 lua_pushboolean(L, 0);
316 lua_pushstring(L, "invalid-uid");
320 int lc_setgid(lua_State* L)
323 if(lua_gettop(L) < 1)
325 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
327 /* Passed GID is actually a string, so look up the GID */
329 g = getgrnam(lua_tostring(L, 1));
332 lua_pushboolean(L, 0);
333 lua_pushstring(L, "no-such-group");
340 gid = lua_tonumber(L, 1);
345 /* Ok, attempt setgid */
350 lua_pushboolean(L, 0);
354 lua_pushstring(L, "invalid-gid");
357 lua_pushstring(L, "permission-denied");
360 lua_pushstring(L, "unknown-error");
367 lua_pushboolean(L, 1);
372 /* Seems we couldn't find a valid GID to switch to */
373 lua_pushboolean(L, 0);
374 lua_pushstring(L, "invalid-gid");
378 int lc_initgroups(lua_State* L)
384 if(!lua_isstring(L, 1))
387 lua_pushstring(L, "invalid-username");
390 p = getpwnam(lua_tostring(L, 1));
394 lua_pushstring(L, "no-such-user");
397 if(lua_gettop(L) < 2)
399 switch(lua_type(L, 2))
405 gid = lua_tointeger(L, 2);
409 lua_pushstring(L, "invalid-gid");
412 ret = initgroups(lua_tostring(L, 1), gid);
419 lua_pushstring(L, "no-memory");
423 lua_pushstring(L, "permission-denied");
427 lua_pushstring(L, "unknown-error");
432 lua_pushboolean(L, 1);
438 int lc_umask(lua_State* L)
440 char old_mode_string[7];
441 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8));
443 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode);
444 old_mode_string[sizeof(old_mode_string)-1] = 0;
445 lua_pushstring(L, old_mode_string);
450 int lc_mkdir(lua_State* L)
452 int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR
453 | S_IRGRP | S_IWGRP | S_IXGRP
454 | S_IROTH | S_IXOTH); /* mode 775 */
456 lua_pushboolean(L, ret==0);
459 lua_pushstring(L, strerror(errno));
465 /* Like POSIX's setrlimit()/getrlimit() API functions.
468 * pposix.setrlimit( resource, soft limit, hard limit)
470 * Any negative limit will be replace with the current limit by an additional call of getrlimit().
473 * pposix.setrlimit("NOFILE", 1000, 2000)
475 int string2resource(const char *s) {
476 if (!strcmp(s, "CORE")) return RLIMIT_CORE;
477 if (!strcmp(s, "CPU")) return RLIMIT_CPU;
478 if (!strcmp(s, "DATA")) return RLIMIT_DATA;
479 if (!strcmp(s, "FSIZE")) return RLIMIT_FSIZE;
480 if (!strcmp(s, "NOFILE")) return RLIMIT_NOFILE;
481 if (!strcmp(s, "STACK")) return RLIMIT_STACK;
482 #if !(defined(sun) || defined(__sun))
483 if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK;
484 if (!strcmp(s, "NPROC")) return RLIMIT_NPROC;
485 if (!strcmp(s, "RSS")) return RLIMIT_RSS;
488 if (!strcmp(s, "NICE")) return RLIMIT_NICE;
493 int lc_setrlimit(lua_State *L) {
494 int arguments = lua_gettop(L);
497 const char *resource = NULL;
499 if(arguments < 1 || arguments > 3) {
500 lua_pushboolean(L, 0);
501 lua_pushstring(L, "incorrect-arguments");
504 resource = luaL_checkstring(L, 1);
505 softlimit = luaL_checkinteger(L, 2);
506 hardlimit = luaL_checkinteger(L, 3);
508 rid = string2resource(resource);
511 struct rlimit lim_current;
513 if (softlimit < 0 || hardlimit < 0) {
514 if (getrlimit(rid, &lim_current)) {
515 lua_pushboolean(L, 0);
516 lua_pushstring(L, "getrlimit-failed");
521 if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur;
522 else lim.rlim_cur = softlimit;
523 if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max;
524 else lim.rlim_max = hardlimit;
526 if (setrlimit(rid, &lim)) {
527 lua_pushboolean(L, 0);
528 lua_pushstring(L, "setrlimit-failed");
532 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
533 lua_pushboolean(L, 0);
534 lua_pushstring(L, "invalid-resource");
537 lua_pushboolean(L, 1);
541 int lc_getrlimit(lua_State *L) {
542 int arguments = lua_gettop(L);
543 const char *resource = NULL;
547 if (arguments != 1) {
548 lua_pushboolean(L, 0);
549 lua_pushstring(L, "invalid-arguments");
553 resource = luaL_checkstring(L, 1);
554 rid = string2resource(resource);
556 if (getrlimit(rid, &lim)) {
557 lua_pushboolean(L, 0);
558 lua_pushstring(L, "getrlimit-failed.");
562 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
563 lua_pushboolean(L, 0);
564 lua_pushstring(L, "invalid-resource");
567 lua_pushboolean(L, 1);
568 lua_pushnumber(L, lim.rlim_cur);
569 lua_pushnumber(L, lim.rlim_max);
573 int lc_abort(lua_State* L)
579 int lc_uname(lua_State* L)
581 struct utsname uname_info;
582 if(uname(&uname_info) != 0)
585 lua_pushstring(L, strerror(errno));
589 lua_pushstring(L, uname_info.sysname);
590 lua_setfield(L, -2, "sysname");
591 lua_pushstring(L, uname_info.nodename);
592 lua_setfield(L, -2, "nodename");
593 lua_pushstring(L, uname_info.release);
594 lua_setfield(L, -2, "release");
595 lua_pushstring(L, uname_info.version);
596 lua_setfield(L, -2, "version");
597 lua_pushstring(L, uname_info.machine);
598 lua_setfield(L, -2, "machine");
602 int lc_setenv(lua_State* L)
604 const char *var = luaL_checkstring(L, 1);
607 /* If the second argument is nil or nothing, unset the var */
608 if(lua_isnoneornil(L, 2))
610 if(unsetenv(var) != 0)
613 lua_pushstring(L, strerror(errno));
616 lua_pushboolean(L, 1);
620 value = luaL_checkstring(L, 2);
622 if(setenv(var, value, 1) != 0)
625 lua_pushstring(L, strerror(errno));
629 lua_pushboolean(L, 1);
634 int lc_meminfo(lua_State* L)
636 struct mallinfo info = mallinfo();
638 /* This is the total size of memory allocated with sbrk by malloc, in bytes. */
639 lua_pushinteger(L, info.arena);
640 lua_setfield(L, -2, "allocated");
641 /* This is the total size of memory allocated with mmap, in bytes. */
642 lua_pushinteger(L, info.hblkhd);
643 lua_setfield(L, -2, "allocated_mmap");
644 /* This is the total size of memory occupied by chunks handed out by malloc. */
645 lua_pushinteger(L, info.uordblks);
646 lua_setfield(L, -2, "used");
647 /* This is the total size of memory occupied by free (not in use) chunks. */
648 lua_pushinteger(L, info.fordblks);
649 lua_setfield(L, -2, "unused");
650 /* This is the size of the top-most releasable chunk that normally borders the
651 end of the heap (i.e., the high end of the virtual address space's data segment). */
652 lua_pushinteger(L, info.keepcost);
653 lua_setfield(L, -2, "returnable");
658 /* File handle extraction blatantly stolen from
659 * https://github.com/rrthomas/luaposix/blob/master/lposix.c#L631
662 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
663 int lc_fallocate(lua_State* L)
666 FILE *f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE);
668 offset = luaL_checkinteger(L, 2);
669 len = luaL_checkinteger(L, 3);
671 #if defined(_GNU_SOURCE)
672 if(fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len) == 0)
674 lua_pushboolean(L, 1);
678 if(errno != ENOSYS && errno != EOPNOTSUPP)
681 lua_pushstring(L, strerror(errno));
685 #warning Only using posix_fallocate() fallback.
686 #warning Linux fallocate() is strongly recommended if available: recompile with -D_GNU_SOURCE
687 #warning Note that posix_fallocate() will still be used on filesystems that dont support fallocate()
690 if(posix_fallocate(fileno(f), offset, len) == 0)
692 lua_pushboolean(L, 1);
698 lua_pushstring(L, strerror(errno));
699 /* posix_fallocate() can leave a bunch of NULs at the end, so we cut that
700 * this assumes that offset == length of the file */
701 ftruncate(fileno(f), offset);
707 /* Register functions */
709 int luaopen_util_pposix(lua_State *L)
711 luaL_Reg exports[] = {
712 { "abort", lc_abort },
714 { "daemonize", lc_daemonize },
716 { "syslog_open", lc_syslog_open },
717 { "syslog_close", lc_syslog_close },
718 { "syslog_log", lc_syslog_log },
719 { "syslog_setminlevel", lc_syslog_setmask },
721 { "getpid", lc_getpid },
722 { "getuid", lc_getuid },
723 { "getgid", lc_getgid },
725 { "setuid", lc_setuid },
726 { "setgid", lc_setgid },
727 { "initgroups", lc_initgroups },
729 { "umask", lc_umask },
731 { "mkdir", lc_mkdir },
733 { "setrlimit", lc_setrlimit },
734 { "getrlimit", lc_getrlimit },
736 { "uname", lc_uname },
738 { "setenv", lc_setenv },
741 { "meminfo", lc_meminfo },
744 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
745 { "fallocate", lc_fallocate },
751 luaL_register(L, "pposix", exports);
753 lua_pushliteral(L, "pposix");
754 lua_setfield(L, -2, "_NAME");
756 lua_pushliteral(L, MODULE_VERSION);
757 lua_setfield(L, -2, "_VERSION");