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;
490 int lc_setrlimit(lua_State *L) {
491 int arguments = lua_gettop(L);
494 const char *resource = NULL;
496 if(arguments < 1 || arguments > 3) {
497 lua_pushboolean(L, 0);
498 lua_pushstring(L, "incorrect-arguments");
501 resource = luaL_checkstring(L, 1);
502 softlimit = luaL_checkinteger(L, 2);
503 hardlimit = luaL_checkinteger(L, 3);
505 rid = string2resource(resource);
508 struct rlimit lim_current;
510 if (softlimit < 0 || hardlimit < 0) {
511 if (getrlimit(rid, &lim_current)) {
512 lua_pushboolean(L, 0);
513 lua_pushstring(L, "getrlimit-failed");
518 if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur;
519 else lim.rlim_cur = softlimit;
520 if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max;
521 else lim.rlim_max = hardlimit;
523 if (setrlimit(rid, &lim)) {
524 lua_pushboolean(L, 0);
525 lua_pushstring(L, "setrlimit-failed");
529 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
530 lua_pushboolean(L, 0);
531 lua_pushstring(L, "invalid-resource");
534 lua_pushboolean(L, 1);
538 int lc_getrlimit(lua_State *L) {
539 int arguments = lua_gettop(L);
540 const char *resource = NULL;
544 if (arguments != 1) {
545 lua_pushboolean(L, 0);
546 lua_pushstring(L, "invalid-arguments");
550 resource = luaL_checkstring(L, 1);
551 rid = string2resource(resource);
553 if (getrlimit(rid, &lim)) {
554 lua_pushboolean(L, 0);
555 lua_pushstring(L, "getrlimit-failed.");
559 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
560 lua_pushboolean(L, 0);
561 lua_pushstring(L, "invalid-resource");
564 lua_pushboolean(L, 1);
565 lua_pushnumber(L, lim.rlim_cur);
566 lua_pushnumber(L, lim.rlim_max);
570 int lc_abort(lua_State* L)
576 int lc_uname(lua_State* L)
578 struct utsname uname_info;
579 if(uname(&uname_info) != 0)
582 lua_pushstring(L, strerror(errno));
586 lua_pushstring(L, uname_info.sysname);
587 lua_setfield(L, -2, "sysname");
588 lua_pushstring(L, uname_info.nodename);
589 lua_setfield(L, -2, "nodename");
590 lua_pushstring(L, uname_info.release);
591 lua_setfield(L, -2, "release");
592 lua_pushstring(L, uname_info.version);
593 lua_setfield(L, -2, "version");
594 lua_pushstring(L, uname_info.machine);
595 lua_setfield(L, -2, "machine");
599 int lc_setenv(lua_State* L)
601 const char *var = luaL_checkstring(L, 1);
604 /* If the second argument is nil or nothing, unset the var */
605 if(lua_isnoneornil(L, 2))
607 if(unsetenv(var) != 0)
610 lua_pushstring(L, strerror(errno));
613 lua_pushboolean(L, 1);
617 value = luaL_checkstring(L, 2);
619 if(setenv(var, value, 1) != 0)
622 lua_pushstring(L, strerror(errno));
626 lua_pushboolean(L, 1);
631 int lc_meminfo(lua_State* L)
633 struct mallinfo info = mallinfo();
635 /* This is the total size of memory allocated with sbrk by malloc, in bytes. */
636 lua_pushinteger(L, info.arena);
637 lua_setfield(L, -2, "allocated");
638 /* This is the total size of memory allocated with mmap, in bytes. */
639 lua_pushinteger(L, info.hblkhd);
640 lua_setfield(L, -2, "allocated_mmap");
641 /* This is the total size of memory occupied by chunks handed out by malloc. */
642 lua_pushinteger(L, info.uordblks);
643 lua_setfield(L, -2, "used");
644 /* This is the total size of memory occupied by free (not in use) chunks. */
645 lua_pushinteger(L, info.fordblks);
646 lua_setfield(L, -2, "unused");
647 /* This is the size of the top-most releasable chunk that normally borders the
648 end of the heap (i.e., the high end of the virtual address space's data segment). */
649 lua_pushinteger(L, info.keepcost);
650 lua_setfield(L, -2, "returnable");
655 /* File handle extraction blatantly stolen from
656 * https://github.com/rrthomas/luaposix/blob/master/lposix.c#L631
659 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
660 int lc_fallocate(lua_State* L)
663 FILE *f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE);
665 offset = luaL_checkinteger(L, 2);
666 len = luaL_checkinteger(L, 3);
668 #if defined(_GNU_SOURCE)
669 if(fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len) == 0)
671 lua_pushboolean(L, 1);
675 if(errno != ENOSYS && errno != EOPNOTSUPP)
678 lua_pushstring(L, strerror(errno));
682 #warning Only using posix_fallocate() fallback.
683 #warning Linux fallocate() is strongly recommended if available: recompile with -D_GNU_SOURCE
684 #warning Note that posix_fallocate() will still be used on filesystems that dont support fallocate()
687 if(posix_fallocate(fileno(f), offset, len) == 0)
689 lua_pushboolean(L, 1);
695 lua_pushstring(L, strerror(errno));
696 /* posix_fallocate() can leave a bunch of NULs at the end, so we cut that
697 * this assumes that offset == length of the file */
698 ftruncate(fileno(f), offset);
704 /* Register functions */
706 int luaopen_util_pposix(lua_State *L)
708 luaL_Reg exports[] = {
709 { "abort", lc_abort },
711 { "daemonize", lc_daemonize },
713 { "syslog_open", lc_syslog_open },
714 { "syslog_close", lc_syslog_close },
715 { "syslog_log", lc_syslog_log },
716 { "syslog_setminlevel", lc_syslog_setmask },
718 { "getpid", lc_getpid },
719 { "getuid", lc_getuid },
720 { "getgid", lc_getgid },
722 { "setuid", lc_setuid },
723 { "setgid", lc_setgid },
724 { "initgroups", lc_initgroups },
726 { "umask", lc_umask },
728 { "mkdir", lc_mkdir },
730 { "setrlimit", lc_setrlimit },
731 { "getrlimit", lc_getrlimit },
733 { "uname", lc_uname },
735 { "setenv", lc_setenv },
738 { "meminfo", lc_meminfo },
741 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
742 { "fallocate", lc_fallocate },
748 luaL_register(L, "pposix", exports);
750 lua_pushliteral(L, "pposix");
751 lua_setfield(L, -2, "_NAME");
753 lua_pushliteral(L, MODULE_VERSION);
754 lua_setfield(L, -2, "_VERSION");