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(_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 arg_to_rlimit(lua_State* L, int idx, rlim_t current) {
495 switch(lua_type(L, idx)) {
497 if(strcmp(lua_tostring(L, idx), "unlimited") == 0)
498 return RLIM_INFINITY;
500 return lua_tointeger(L, idx);
505 return luaL_argerror(L, idx, "unexpected type");
509 int lc_setrlimit(lua_State *L) {
511 int arguments = lua_gettop(L);
513 if(arguments < 1 || arguments > 3) {
514 lua_pushboolean(L, 0);
515 lua_pushstring(L, "incorrect-arguments");
519 rid = string2resource(luaL_checkstring(L, 1));
521 lua_pushboolean(L, 0);
522 lua_pushstring(L, "invalid-resource");
526 /* Fetch current values to use as defaults */
527 if (getrlimit(rid, &lim)) {
528 lua_pushboolean(L, 0);
529 lua_pushstring(L, "getrlimit-failed");
533 lim.rlim_cur = arg_to_rlimit(L, 2, lim.rlim_cur);
534 lim.rlim_max = arg_to_rlimit(L, 3, lim.rlim_max);
536 if (setrlimit(rid, &lim)) {
537 lua_pushboolean(L, 0);
538 lua_pushstring(L, "setrlimit-failed");
541 lua_pushboolean(L, 1);
545 int lc_getrlimit(lua_State *L) {
546 int arguments = lua_gettop(L);
547 const char *resource = NULL;
551 if (arguments != 1) {
552 lua_pushboolean(L, 0);
553 lua_pushstring(L, "invalid-arguments");
559 resource = luaL_checkstring(L, 1);
560 rid = string2resource(resource);
562 if (getrlimit(rid, &lim)) {
563 lua_pushboolean(L, 0);
564 lua_pushstring(L, "getrlimit-failed.");
568 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
569 lua_pushboolean(L, 0);
570 lua_pushstring(L, "invalid-resource");
573 lua_pushboolean(L, 1);
574 if(lim.rlim_cur == RLIM_INFINITY)
575 lua_pushstring(L, "unlimited");
577 lua_pushnumber(L, lim.rlim_cur);
578 if(lim.rlim_max == RLIM_INFINITY)
579 lua_pushstring(L, "unlimited");
581 lua_pushnumber(L, lim.rlim_max);
585 int lc_abort(lua_State* L)
591 int lc_uname(lua_State* L)
593 struct utsname uname_info;
594 if(uname(&uname_info) != 0)
597 lua_pushstring(L, strerror(errno));
601 lua_pushstring(L, uname_info.sysname);
602 lua_setfield(L, -2, "sysname");
603 lua_pushstring(L, uname_info.nodename);
604 lua_setfield(L, -2, "nodename");
605 lua_pushstring(L, uname_info.release);
606 lua_setfield(L, -2, "release");
607 lua_pushstring(L, uname_info.version);
608 lua_setfield(L, -2, "version");
609 lua_pushstring(L, uname_info.machine);
610 lua_setfield(L, -2, "machine");
614 int lc_setenv(lua_State* L)
616 const char *var = luaL_checkstring(L, 1);
619 /* If the second argument is nil or nothing, unset the var */
620 if(lua_isnoneornil(L, 2))
622 if(unsetenv(var) != 0)
625 lua_pushstring(L, strerror(errno));
628 lua_pushboolean(L, 1);
632 value = luaL_checkstring(L, 2);
634 if(setenv(var, value, 1) != 0)
637 lua_pushstring(L, strerror(errno));
641 lua_pushboolean(L, 1);
646 int lc_meminfo(lua_State* L)
648 struct mallinfo info = mallinfo();
650 /* This is the total size of memory allocated with sbrk by malloc, in bytes. */
651 lua_pushinteger(L, info.arena);
652 lua_setfield(L, -2, "allocated");
653 /* This is the total size of memory allocated with mmap, in bytes. */
654 lua_pushinteger(L, info.hblkhd);
655 lua_setfield(L, -2, "allocated_mmap");
656 /* This is the total size of memory occupied by chunks handed out by malloc. */
657 lua_pushinteger(L, info.uordblks);
658 lua_setfield(L, -2, "used");
659 /* This is the total size of memory occupied by free (not in use) chunks. */
660 lua_pushinteger(L, info.fordblks);
661 lua_setfield(L, -2, "unused");
662 /* This is the size of the top-most releasable chunk that normally borders the
663 end of the heap (i.e., the high end of the virtual address space's data segment). */
664 lua_pushinteger(L, info.keepcost);
665 lua_setfield(L, -2, "returnable");
670 /* File handle extraction blatantly stolen from
671 * https://github.com/rrthomas/luaposix/blob/master/lposix.c#L631
674 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
675 int lc_fallocate(lua_State* L)
678 FILE *f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE);
680 offset = luaL_checkinteger(L, 2);
681 len = luaL_checkinteger(L, 3);
683 #if defined(_GNU_SOURCE)
684 if(fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len) == 0)
686 lua_pushboolean(L, 1);
690 if(errno != ENOSYS && errno != EOPNOTSUPP)
693 lua_pushstring(L, strerror(errno));
697 #warning Only using posix_fallocate() fallback.
698 #warning Linux fallocate() is strongly recommended if available: recompile with -D_GNU_SOURCE
699 #warning Note that posix_fallocate() will still be used on filesystems that dont support fallocate()
702 if(posix_fallocate(fileno(f), offset, len) == 0)
704 lua_pushboolean(L, 1);
710 lua_pushstring(L, strerror(errno));
711 /* posix_fallocate() can leave a bunch of NULs at the end, so we cut that
712 * this assumes that offset == length of the file */
713 ftruncate(fileno(f), offset);
719 /* Register functions */
721 int luaopen_util_pposix(lua_State *L)
723 luaL_Reg exports[] = {
724 { "abort", lc_abort },
726 { "daemonize", lc_daemonize },
728 { "syslog_open", lc_syslog_open },
729 { "syslog_close", lc_syslog_close },
730 { "syslog_log", lc_syslog_log },
731 { "syslog_setminlevel", lc_syslog_setmask },
733 { "getpid", lc_getpid },
734 { "getuid", lc_getuid },
735 { "getgid", lc_getgid },
737 { "setuid", lc_setuid },
738 { "setgid", lc_setgid },
739 { "initgroups", lc_initgroups },
741 { "umask", lc_umask },
743 { "mkdir", lc_mkdir },
745 { "setrlimit", lc_setrlimit },
746 { "getrlimit", lc_getrlimit },
748 { "uname", lc_uname },
750 { "setenv", lc_setenv },
753 { "meminfo", lc_meminfo },
756 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
757 { "fallocate", lc_fallocate },
763 luaL_register(L, "pposix", exports);
765 lua_pushliteral(L, "pposix");
766 lua_setfield(L, -2, "_NAME");
768 lua_pushliteral(L, MODULE_VERSION);
769 lua_setfield(L, -2, "_VERSION");