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 == 502)
39 #define luaL_register(L, N, R) luaL_setfuncs(L, R, 0)
43 #if defined(__linux__) && defined(_GNU_SOURCE)
44 #include <linux/falloc.h>
47 #if (defined(_SVID_SOURCE) && !defined(WITHOUT_MALLINFO))
52 /* Daemonization support */
54 static int lc_daemonize(lua_State *L)
61 lua_pushboolean(L, 0);
62 lua_pushstring(L, "already-daemonized");
66 /* Attempt initial fork */
67 if((pid = fork()) < 0)
70 lua_pushboolean(L, 0);
71 lua_pushstring(L, "fork-failed");
76 /* We are the parent process */
77 lua_pushboolean(L, 1);
78 lua_pushnumber(L, pid);
82 /* and we are the child process */
85 /* We failed to become session leader */
86 /* (we probably already were) */
87 lua_pushboolean(L, 0);
88 lua_pushstring(L, "setsid-failed");
92 /* Close stdin, stdout, stderr */
96 /* Make sure accidental use of FDs 0, 1, 2 don't cause weirdness */
97 open("/dev/null", O_RDONLY);
98 open("/dev/null", O_WRONLY);
99 open("/dev/null", O_WRONLY);
101 /* Final fork, use it wisely */
105 /* Show's over, let's continue */
106 lua_pushboolean(L, 1);
113 const char * const facility_strings[] = {
115 #if !(defined(sun) || defined(__sun))
120 #if !(defined(sun) || defined(__sun))
139 int facility_constants[] = {
141 #if !(defined(sun) || defined(__sun))
146 #if !(defined(sun) || defined(__sun))
168 The parameter ident in the call of openlog() is probably stored as-is.
169 Thus, if the string it points to is changed, syslog() may start
170 prepending the changed string, and if the string it points to ceases to
171 exist, the results are undefined. Most portable is to use a string
175 char* syslog_ident = NULL;
177 int lc_syslog_open(lua_State* L)
179 int facility = luaL_checkoption(L, 2, "daemon", facility_strings);
180 facility = facility_constants[facility];
182 luaL_checkstring(L, 1);
187 syslog_ident = strdup(lua_tostring(L, 1));
189 openlog(syslog_ident, LOG_PID, facility);
193 const char * const level_strings[] = {
201 int level_constants[] = {
209 int lc_syslog_log(lua_State* L)
211 int level = level_constants[luaL_checkoption(L, 1, "notice", level_strings)];
213 if(lua_gettop(L) == 3)
214 syslog(level, "%s: %s", luaL_checkstring(L, 2), luaL_checkstring(L, 3));
216 syslog(level, "%s", lua_tostring(L, 2));
221 int lc_syslog_close(lua_State* L)
232 int lc_syslog_setmask(lua_State* L)
234 int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
238 mask |= LOG_MASK(level_constants[level_idx]);
239 } while (++level_idx<=4);
247 int lc_getpid(lua_State* L)
249 lua_pushinteger(L, getpid());
253 /* UID/GID functions */
255 int lc_getuid(lua_State* L)
257 lua_pushinteger(L, getuid());
261 int lc_getgid(lua_State* L)
263 lua_pushinteger(L, getgid());
267 int lc_setuid(lua_State* L)
270 if(lua_gettop(L) < 1)
272 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
274 /* Passed UID is actually a string, so look up the UID */
276 p = getpwnam(lua_tostring(L, 1));
279 lua_pushboolean(L, 0);
280 lua_pushstring(L, "no-such-user");
287 uid = lua_tonumber(L, 1);
292 /* Ok, attempt setuid */
297 lua_pushboolean(L, 0);
301 lua_pushstring(L, "invalid-uid");
304 lua_pushstring(L, "permission-denied");
307 lua_pushstring(L, "unknown-error");
314 lua_pushboolean(L, 1);
319 /* Seems we couldn't find a valid UID to switch to */
320 lua_pushboolean(L, 0);
321 lua_pushstring(L, "invalid-uid");
325 int lc_setgid(lua_State* L)
328 if(lua_gettop(L) < 1)
330 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
332 /* Passed GID is actually a string, so look up the GID */
334 g = getgrnam(lua_tostring(L, 1));
337 lua_pushboolean(L, 0);
338 lua_pushstring(L, "no-such-group");
345 gid = lua_tonumber(L, 1);
350 /* Ok, attempt setgid */
355 lua_pushboolean(L, 0);
359 lua_pushstring(L, "invalid-gid");
362 lua_pushstring(L, "permission-denied");
365 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)
389 if(!lua_isstring(L, 1))
392 lua_pushstring(L, "invalid-username");
395 p = getpwnam(lua_tostring(L, 1));
399 lua_pushstring(L, "no-such-user");
402 if(lua_gettop(L) < 2)
404 switch(lua_type(L, 2))
410 gid = lua_tointeger(L, 2);
414 lua_pushstring(L, "invalid-gid");
417 ret = initgroups(lua_tostring(L, 1), gid);
424 lua_pushstring(L, "no-memory");
428 lua_pushstring(L, "permission-denied");
432 lua_pushstring(L, "unknown-error");
437 lua_pushboolean(L, 1);
443 int lc_umask(lua_State* L)
445 char old_mode_string[7];
446 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8));
448 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode);
449 old_mode_string[sizeof(old_mode_string)-1] = 0;
450 lua_pushstring(L, old_mode_string);
455 int lc_mkdir(lua_State* L)
457 int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR
458 | S_IRGRP | S_IWGRP | S_IXGRP
459 | S_IROTH | S_IXOTH); /* mode 775 */
461 lua_pushboolean(L, ret==0);
464 lua_pushstring(L, strerror(errno));
470 /* Like POSIX's setrlimit()/getrlimit() API functions.
473 * pposix.setrlimit( resource, soft limit, hard limit)
475 * Any negative limit will be replace with the current limit by an additional call of getrlimit().
478 * pposix.setrlimit("NOFILE", 1000, 2000)
480 int string2resource(const char *s) {
481 if (!strcmp(s, "CORE")) return RLIMIT_CORE;
482 if (!strcmp(s, "CPU")) return RLIMIT_CPU;
483 if (!strcmp(s, "DATA")) return RLIMIT_DATA;
484 if (!strcmp(s, "FSIZE")) return RLIMIT_FSIZE;
485 if (!strcmp(s, "NOFILE")) return RLIMIT_NOFILE;
486 if (!strcmp(s, "STACK")) return RLIMIT_STACK;
487 #if !(defined(sun) || defined(__sun))
488 if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK;
489 if (!strcmp(s, "NPROC")) return RLIMIT_NPROC;
490 if (!strcmp(s, "RSS")) return RLIMIT_RSS;
493 if (!strcmp(s, "NICE")) return RLIMIT_NICE;
498 unsigned long int arg_to_rlimit(lua_State* L, int idx, rlim_t current) {
499 switch(lua_type(L, idx)) {
501 if(strcmp(lua_tostring(L, idx), "unlimited") == 0)
502 return RLIM_INFINITY;
504 return lua_tointeger(L, idx);
509 return luaL_argerror(L, idx, "unexpected type");
513 int lc_setrlimit(lua_State *L) {
515 int arguments = lua_gettop(L);
517 if(arguments < 1 || arguments > 3) {
518 lua_pushboolean(L, 0);
519 lua_pushstring(L, "incorrect-arguments");
523 rid = string2resource(luaL_checkstring(L, 1));
525 lua_pushboolean(L, 0);
526 lua_pushstring(L, "invalid-resource");
530 /* Fetch current values to use as defaults */
531 if (getrlimit(rid, &lim)) {
532 lua_pushboolean(L, 0);
533 lua_pushstring(L, "getrlimit-failed");
537 lim.rlim_cur = arg_to_rlimit(L, 2, lim.rlim_cur);
538 lim.rlim_max = arg_to_rlimit(L, 3, lim.rlim_max);
540 if (setrlimit(rid, &lim)) {
541 lua_pushboolean(L, 0);
542 lua_pushstring(L, "setrlimit-failed");
545 lua_pushboolean(L, 1);
549 int lc_getrlimit(lua_State *L) {
550 int arguments = lua_gettop(L);
551 const char *resource = NULL;
555 if (arguments != 1) {
556 lua_pushboolean(L, 0);
557 lua_pushstring(L, "invalid-arguments");
563 resource = luaL_checkstring(L, 1);
564 rid = string2resource(resource);
566 if (getrlimit(rid, &lim)) {
567 lua_pushboolean(L, 0);
568 lua_pushstring(L, "getrlimit-failed.");
572 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
573 lua_pushboolean(L, 0);
574 lua_pushstring(L, "invalid-resource");
577 lua_pushboolean(L, 1);
578 if(lim.rlim_cur == RLIM_INFINITY)
579 lua_pushstring(L, "unlimited");
581 lua_pushnumber(L, lim.rlim_cur);
582 if(lim.rlim_max == RLIM_INFINITY)
583 lua_pushstring(L, "unlimited");
585 lua_pushnumber(L, lim.rlim_max);
589 int lc_abort(lua_State* L)
595 int lc_uname(lua_State* L)
597 struct utsname uname_info;
598 if(uname(&uname_info) != 0)
601 lua_pushstring(L, strerror(errno));
605 lua_pushstring(L, uname_info.sysname);
606 lua_setfield(L, -2, "sysname");
607 lua_pushstring(L, uname_info.nodename);
608 lua_setfield(L, -2, "nodename");
609 lua_pushstring(L, uname_info.release);
610 lua_setfield(L, -2, "release");
611 lua_pushstring(L, uname_info.version);
612 lua_setfield(L, -2, "version");
613 lua_pushstring(L, uname_info.machine);
614 lua_setfield(L, -2, "machine");
618 int lc_setenv(lua_State* L)
620 const char *var = luaL_checkstring(L, 1);
623 /* If the second argument is nil or nothing, unset the var */
624 if(lua_isnoneornil(L, 2))
626 if(unsetenv(var) != 0)
629 lua_pushstring(L, strerror(errno));
632 lua_pushboolean(L, 1);
636 value = luaL_checkstring(L, 2);
638 if(setenv(var, value, 1) != 0)
641 lua_pushstring(L, strerror(errno));
645 lua_pushboolean(L, 1);
650 int lc_meminfo(lua_State* L)
652 struct mallinfo info = mallinfo();
654 /* This is the total size of memory allocated with sbrk by malloc, in bytes. */
655 lua_pushinteger(L, info.arena);
656 lua_setfield(L, -2, "allocated");
657 /* This is the total size of memory allocated with mmap, in bytes. */
658 lua_pushinteger(L, info.hblkhd);
659 lua_setfield(L, -2, "allocated_mmap");
660 /* This is the total size of memory occupied by chunks handed out by malloc. */
661 lua_pushinteger(L, info.uordblks);
662 lua_setfield(L, -2, "used");
663 /* This is the total size of memory occupied by free (not in use) chunks. */
664 lua_pushinteger(L, info.fordblks);
665 lua_setfield(L, -2, "unused");
666 /* This is the size of the top-most releasable chunk that normally borders the
667 end of the heap (i.e., the high end of the virtual address space's data segment). */
668 lua_pushinteger(L, info.keepcost);
669 lua_setfield(L, -2, "returnable");
674 /* File handle extraction blatantly stolen from
675 * https://github.com/rrthomas/luaposix/blob/master/lposix.c#L631
678 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
679 int lc_fallocate(lua_State* L)
683 FILE *f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE);
685 luaL_error(L, "attempt to use a closed file");
687 offset = luaL_checkinteger(L, 2);
688 len = luaL_checkinteger(L, 3);
690 #if defined(__linux__) && defined(_GNU_SOURCE)
692 ret = fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len);
695 lua_pushboolean(L, 1);
698 /* Some old versions of Linux apparently use the return value instead of errno */
699 if(errno == 0) errno = ret;
701 if(errno != ENOSYS && errno != EOPNOTSUPP)
704 lua_pushstring(L, strerror(errno));
708 #warning Only using posix_fallocate() fallback.
709 #warning Linux fallocate() is strongly recommended if available: recompile with -D_GNU_SOURCE
710 #warning Note that posix_fallocate() will still be used on filesystems that dont support fallocate()
713 ret = posix_fallocate(fileno(f), offset, len);
716 lua_pushboolean(L, 1);
722 lua_pushstring(L, strerror(ret));
723 /* posix_fallocate() can leave a bunch of NULs at the end, so we cut that
724 * this assumes that offset == length of the file */
725 ftruncate(fileno(f), offset);
731 /* Register functions */
733 int luaopen_util_pposix(lua_State *L)
735 luaL_Reg exports[] = {
736 { "abort", lc_abort },
738 { "daemonize", lc_daemonize },
740 { "syslog_open", lc_syslog_open },
741 { "syslog_close", lc_syslog_close },
742 { "syslog_log", lc_syslog_log },
743 { "syslog_setminlevel", lc_syslog_setmask },
745 { "getpid", lc_getpid },
746 { "getuid", lc_getuid },
747 { "getgid", lc_getgid },
749 { "setuid", lc_setuid },
750 { "setgid", lc_setgid },
751 { "initgroups", lc_initgroups },
753 { "umask", lc_umask },
755 { "mkdir", lc_mkdir },
757 { "setrlimit", lc_setrlimit },
758 { "getrlimit", lc_getrlimit },
760 { "uname", lc_uname },
762 { "setenv", lc_setenv },
765 { "meminfo", lc_meminfo },
768 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
769 { "fallocate", lc_fallocate },
776 luaL_register(L, NULL, exports);
778 lua_pushliteral(L, "pposix");
779 lua_setfield(L, -2, "_NAME");
781 lua_pushliteral(L, MODULE_VERSION);
782 lua_setfield(L, -2, "_VERSION");