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>
39 #if defined(__linux__) && 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 = level_constants[luaL_checkoption(L, 1, "notice", level_strings)];
209 if(lua_gettop(L) == 3)
210 syslog(level, "%s: %s", luaL_checkstring(L, 2), luaL_checkstring(L, 3));
212 syslog(level, "%s", lua_tostring(L, 2));
217 int lc_syslog_close(lua_State* L)
228 int lc_syslog_setmask(lua_State* L)
230 int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
234 mask |= LOG_MASK(level_constants[level_idx]);
235 } while (++level_idx<=4);
243 int lc_getpid(lua_State* L)
245 lua_pushinteger(L, getpid());
249 /* UID/GID functions */
251 int lc_getuid(lua_State* L)
253 lua_pushinteger(L, getuid());
257 int lc_getgid(lua_State* L)
259 lua_pushinteger(L, getgid());
263 int lc_setuid(lua_State* L)
266 if(lua_gettop(L) < 1)
268 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
270 /* Passed UID is actually a string, so look up the UID */
272 p = getpwnam(lua_tostring(L, 1));
275 lua_pushboolean(L, 0);
276 lua_pushstring(L, "no-such-user");
283 uid = lua_tonumber(L, 1);
288 /* Ok, attempt setuid */
293 lua_pushboolean(L, 0);
297 lua_pushstring(L, "invalid-uid");
300 lua_pushstring(L, "permission-denied");
303 lua_pushstring(L, "unknown-error");
310 lua_pushboolean(L, 1);
315 /* Seems we couldn't find a valid UID to switch to */
316 lua_pushboolean(L, 0);
317 lua_pushstring(L, "invalid-uid");
321 int lc_setgid(lua_State* L)
324 if(lua_gettop(L) < 1)
326 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
328 /* Passed GID is actually a string, so look up the GID */
330 g = getgrnam(lua_tostring(L, 1));
333 lua_pushboolean(L, 0);
334 lua_pushstring(L, "no-such-group");
341 gid = lua_tonumber(L, 1);
346 /* Ok, attempt setgid */
351 lua_pushboolean(L, 0);
355 lua_pushstring(L, "invalid-gid");
358 lua_pushstring(L, "permission-denied");
361 lua_pushstring(L, "unknown-error");
368 lua_pushboolean(L, 1);
373 /* Seems we couldn't find a valid GID to switch to */
374 lua_pushboolean(L, 0);
375 lua_pushstring(L, "invalid-gid");
379 int lc_initgroups(lua_State* L)
385 if(!lua_isstring(L, 1))
388 lua_pushstring(L, "invalid-username");
391 p = getpwnam(lua_tostring(L, 1));
395 lua_pushstring(L, "no-such-user");
398 if(lua_gettop(L) < 2)
400 switch(lua_type(L, 2))
406 gid = lua_tointeger(L, 2);
410 lua_pushstring(L, "invalid-gid");
413 ret = initgroups(lua_tostring(L, 1), gid);
420 lua_pushstring(L, "no-memory");
424 lua_pushstring(L, "permission-denied");
428 lua_pushstring(L, "unknown-error");
433 lua_pushboolean(L, 1);
439 int lc_umask(lua_State* L)
441 char old_mode_string[7];
442 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8));
444 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode);
445 old_mode_string[sizeof(old_mode_string)-1] = 0;
446 lua_pushstring(L, old_mode_string);
451 int lc_mkdir(lua_State* L)
453 int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR
454 | S_IRGRP | S_IWGRP | S_IXGRP
455 | S_IROTH | S_IXOTH); /* mode 775 */
457 lua_pushboolean(L, ret==0);
460 lua_pushstring(L, strerror(errno));
466 /* Like POSIX's setrlimit()/getrlimit() API functions.
469 * pposix.setrlimit( resource, soft limit, hard limit)
471 * Any negative limit will be replace with the current limit by an additional call of getrlimit().
474 * pposix.setrlimit("NOFILE", 1000, 2000)
476 int string2resource(const char *s) {
477 if (!strcmp(s, "CORE")) return RLIMIT_CORE;
478 if (!strcmp(s, "CPU")) return RLIMIT_CPU;
479 if (!strcmp(s, "DATA")) return RLIMIT_DATA;
480 if (!strcmp(s, "FSIZE")) return RLIMIT_FSIZE;
481 if (!strcmp(s, "NOFILE")) return RLIMIT_NOFILE;
482 if (!strcmp(s, "STACK")) return RLIMIT_STACK;
483 #if !(defined(sun) || defined(__sun))
484 if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK;
485 if (!strcmp(s, "NPROC")) return RLIMIT_NPROC;
486 if (!strcmp(s, "RSS")) return RLIMIT_RSS;
489 if (!strcmp(s, "NICE")) return RLIMIT_NICE;
494 int lc_setrlimit(lua_State *L) {
495 int arguments = lua_gettop(L);
498 const char *resource = NULL;
500 if(arguments < 1 || arguments > 3) {
501 lua_pushboolean(L, 0);
502 lua_pushstring(L, "incorrect-arguments");
506 resource = luaL_checkstring(L, 1);
507 softlimit = luaL_checkinteger(L, 2);
508 hardlimit = luaL_checkinteger(L, 3);
510 rid = string2resource(resource);
513 struct rlimit lim_current;
515 if (softlimit < 0 || hardlimit < 0) {
516 if (getrlimit(rid, &lim_current)) {
517 lua_pushboolean(L, 0);
518 lua_pushstring(L, "getrlimit-failed");
523 if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur;
524 else lim.rlim_cur = softlimit;
525 if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max;
526 else lim.rlim_max = hardlimit;
528 if (setrlimit(rid, &lim)) {
529 lua_pushboolean(L, 0);
530 lua_pushstring(L, "setrlimit-failed");
534 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
535 lua_pushboolean(L, 0);
536 lua_pushstring(L, "invalid-resource");
539 lua_pushboolean(L, 1);
543 int lc_getrlimit(lua_State *L) {
544 int arguments = lua_gettop(L);
545 const char *resource = NULL;
549 if (arguments != 1) {
550 lua_pushboolean(L, 0);
551 lua_pushstring(L, "invalid-arguments");
555 resource = luaL_checkstring(L, 1);
556 rid = string2resource(resource);
558 if (getrlimit(rid, &lim)) {
559 lua_pushboolean(L, 0);
560 lua_pushstring(L, "getrlimit-failed.");
564 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
565 lua_pushboolean(L, 0);
566 lua_pushstring(L, "invalid-resource");
569 lua_pushboolean(L, 1);
570 lua_pushnumber(L, lim.rlim_cur);
571 lua_pushnumber(L, lim.rlim_max);
575 int lc_abort(lua_State* L)
581 int lc_uname(lua_State* L)
583 struct utsname uname_info;
584 if(uname(&uname_info) != 0)
587 lua_pushstring(L, strerror(errno));
591 lua_pushstring(L, uname_info.sysname);
592 lua_setfield(L, -2, "sysname");
593 lua_pushstring(L, uname_info.nodename);
594 lua_setfield(L, -2, "nodename");
595 lua_pushstring(L, uname_info.release);
596 lua_setfield(L, -2, "release");
597 lua_pushstring(L, uname_info.version);
598 lua_setfield(L, -2, "version");
599 lua_pushstring(L, uname_info.machine);
600 lua_setfield(L, -2, "machine");
604 int lc_setenv(lua_State* L)
606 const char *var = luaL_checkstring(L, 1);
609 /* If the second argument is nil or nothing, unset the var */
610 if(lua_isnoneornil(L, 2))
612 if(unsetenv(var) != 0)
615 lua_pushstring(L, strerror(errno));
618 lua_pushboolean(L, 1);
622 value = luaL_checkstring(L, 2);
624 if(setenv(var, value, 1) != 0)
627 lua_pushstring(L, strerror(errno));
631 lua_pushboolean(L, 1);
636 int lc_meminfo(lua_State* L)
638 struct mallinfo info = mallinfo();
640 /* This is the total size of memory allocated with sbrk by malloc, in bytes. */
641 lua_pushinteger(L, info.arena);
642 lua_setfield(L, -2, "allocated");
643 /* This is the total size of memory allocated with mmap, in bytes. */
644 lua_pushinteger(L, info.hblkhd);
645 lua_setfield(L, -2, "allocated_mmap");
646 /* This is the total size of memory occupied by chunks handed out by malloc. */
647 lua_pushinteger(L, info.uordblks);
648 lua_setfield(L, -2, "used");
649 /* This is the total size of memory occupied by free (not in use) chunks. */
650 lua_pushinteger(L, info.fordblks);
651 lua_setfield(L, -2, "unused");
652 /* This is the size of the top-most releasable chunk that normally borders the
653 end of the heap (i.e., the high end of the virtual address space's data segment). */
654 lua_pushinteger(L, info.keepcost);
655 lua_setfield(L, -2, "returnable");
660 /* File handle extraction blatantly stolen from
661 * https://github.com/rrthomas/luaposix/blob/master/lposix.c#L631
664 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
665 int lc_fallocate(lua_State* L)
669 FILE *f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE);
671 luaL_error(L, "attempt to use a closed file");
673 offset = luaL_checkinteger(L, 2);
674 len = luaL_checkinteger(L, 3);
676 #if defined(__linux__) && defined(_GNU_SOURCE)
678 ret = fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len);
681 lua_pushboolean(L, 1);
684 /* Some old versions of Linux apparently use the return value instead of errno */
685 if(errno == 0) errno = ret;
687 if(errno != ENOSYS && errno != EOPNOTSUPP)
690 lua_pushstring(L, strerror(errno));
694 #warning Only using posix_fallocate() fallback.
695 #warning Linux fallocate() is strongly recommended if available: recompile with -D_GNU_SOURCE
696 #warning Note that posix_fallocate() will still be used on filesystems that dont support fallocate()
699 ret = posix_fallocate(fileno(f), offset, len);
702 lua_pushboolean(L, 1);
708 lua_pushstring(L, strerror(ret));
709 /* posix_fallocate() can leave a bunch of NULs at the end, so we cut that
710 * this assumes that offset == length of the file */
711 ftruncate(fileno(f), offset);
717 /* Register functions */
719 int luaopen_util_pposix(lua_State *L)
721 luaL_Reg exports[] = {
722 { "abort", lc_abort },
724 { "daemonize", lc_daemonize },
726 { "syslog_open", lc_syslog_open },
727 { "syslog_close", lc_syslog_close },
728 { "syslog_log", lc_syslog_log },
729 { "syslog_setminlevel", lc_syslog_setmask },
731 { "getpid", lc_getpid },
732 { "getuid", lc_getuid },
733 { "getgid", lc_getgid },
735 { "setuid", lc_setuid },
736 { "setgid", lc_setgid },
737 { "initgroups", lc_initgroups },
739 { "umask", lc_umask },
741 { "mkdir", lc_mkdir },
743 { "setrlimit", lc_setrlimit },
744 { "getrlimit", lc_getrlimit },
746 { "uname", lc_uname },
748 { "setenv", lc_setenv },
751 { "meminfo", lc_meminfo },
754 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
755 { "fallocate", lc_fallocate },
761 luaL_register(L, "pposix", exports);
763 lua_pushliteral(L, "pposix");
764 lua_setfield(L, -2, "_NAME");
766 lua_pushliteral(L, MODULE_VERSION);
767 lua_setfield(L, -2, "_VERSION");