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 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");
505 resource = luaL_checkstring(L, 1);
506 softlimit = luaL_checkinteger(L, 2);
507 hardlimit = luaL_checkinteger(L, 3);
509 rid = string2resource(resource);
512 struct rlimit lim_current;
514 if (softlimit < 0 || hardlimit < 0) {
515 if (getrlimit(rid, &lim_current)) {
516 lua_pushboolean(L, 0);
517 lua_pushstring(L, "getrlimit-failed");
522 if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur;
523 else lim.rlim_cur = softlimit;
524 if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max;
525 else lim.rlim_max = hardlimit;
527 if (setrlimit(rid, &lim)) {
528 lua_pushboolean(L, 0);
529 lua_pushstring(L, "setrlimit-failed");
533 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
534 lua_pushboolean(L, 0);
535 lua_pushstring(L, "invalid-resource");
538 lua_pushboolean(L, 1);
542 int lc_getrlimit(lua_State *L) {
543 int arguments = lua_gettop(L);
544 const char *resource = NULL;
548 if (arguments != 1) {
549 lua_pushboolean(L, 0);
550 lua_pushstring(L, "invalid-arguments");
554 resource = luaL_checkstring(L, 1);
555 rid = string2resource(resource);
557 if (getrlimit(rid, &lim)) {
558 lua_pushboolean(L, 0);
559 lua_pushstring(L, "getrlimit-failed.");
563 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
564 lua_pushboolean(L, 0);
565 lua_pushstring(L, "invalid-resource");
568 lua_pushboolean(L, 1);
569 lua_pushnumber(L, lim.rlim_cur);
570 lua_pushnumber(L, lim.rlim_max);
574 int lc_abort(lua_State* L)
580 int lc_uname(lua_State* L)
582 struct utsname uname_info;
583 if(uname(&uname_info) != 0)
586 lua_pushstring(L, strerror(errno));
590 lua_pushstring(L, uname_info.sysname);
591 lua_setfield(L, -2, "sysname");
592 lua_pushstring(L, uname_info.nodename);
593 lua_setfield(L, -2, "nodename");
594 lua_pushstring(L, uname_info.release);
595 lua_setfield(L, -2, "release");
596 lua_pushstring(L, uname_info.version);
597 lua_setfield(L, -2, "version");
598 lua_pushstring(L, uname_info.machine);
599 lua_setfield(L, -2, "machine");
603 int lc_setenv(lua_State* L)
605 const char *var = luaL_checkstring(L, 1);
608 /* If the second argument is nil or nothing, unset the var */
609 if(lua_isnoneornil(L, 2))
611 if(unsetenv(var) != 0)
614 lua_pushstring(L, strerror(errno));
617 lua_pushboolean(L, 1);
621 value = luaL_checkstring(L, 2);
623 if(setenv(var, value, 1) != 0)
626 lua_pushstring(L, strerror(errno));
630 lua_pushboolean(L, 1);
635 int lc_meminfo(lua_State* L)
637 struct mallinfo info = mallinfo();
639 /* This is the total size of memory allocated with sbrk by malloc, in bytes. */
640 lua_pushinteger(L, info.arena);
641 lua_setfield(L, -2, "allocated");
642 /* This is the total size of memory allocated with mmap, in bytes. */
643 lua_pushinteger(L, info.hblkhd);
644 lua_setfield(L, -2, "allocated_mmap");
645 /* This is the total size of memory occupied by chunks handed out by malloc. */
646 lua_pushinteger(L, info.uordblks);
647 lua_setfield(L, -2, "used");
648 /* This is the total size of memory occupied by free (not in use) chunks. */
649 lua_pushinteger(L, info.fordblks);
650 lua_setfield(L, -2, "unused");
651 /* This is the size of the top-most releasable chunk that normally borders the
652 end of the heap (i.e., the high end of the virtual address space's data segment). */
653 lua_pushinteger(L, info.keepcost);
654 lua_setfield(L, -2, "returnable");
659 /* File handle extraction blatantly stolen from
660 * https://github.com/rrthomas/luaposix/blob/master/lposix.c#L631
663 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
664 int lc_fallocate(lua_State* L)
667 FILE *f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE);
669 offset = luaL_checkinteger(L, 2);
670 len = luaL_checkinteger(L, 3);
672 #if defined(_GNU_SOURCE)
673 if(fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len) == 0)
675 lua_pushboolean(L, 1);
679 if(errno != ENOSYS && errno != EOPNOTSUPP)
682 lua_pushstring(L, strerror(errno));
686 #warning Only using posix_fallocate() fallback.
687 #warning Linux fallocate() is strongly recommended if available: recompile with -D_GNU_SOURCE
688 #warning Note that posix_fallocate() will still be used on filesystems that dont support fallocate()
691 if(posix_fallocate(fileno(f), offset, len) == 0)
693 lua_pushboolean(L, 1);
699 lua_pushstring(L, strerror(errno));
700 /* posix_fallocate() can leave a bunch of NULs at the end, so we cut that
701 * this assumes that offset == length of the file */
702 ftruncate(fileno(f), offset);
708 /* Register functions */
710 int luaopen_util_pposix(lua_State *L)
712 luaL_Reg exports[] = {
713 { "abort", lc_abort },
715 { "daemonize", lc_daemonize },
717 { "syslog_open", lc_syslog_open },
718 { "syslog_close", lc_syslog_close },
719 { "syslog_log", lc_syslog_log },
720 { "syslog_setminlevel", lc_syslog_setmask },
722 { "getpid", lc_getpid },
723 { "getuid", lc_getuid },
724 { "getgid", lc_getgid },
726 { "setuid", lc_setuid },
727 { "setgid", lc_setgid },
728 { "initgroups", lc_initgroups },
730 { "umask", lc_umask },
732 { "mkdir", lc_mkdir },
734 { "setrlimit", lc_setrlimit },
735 { "getrlimit", lc_getrlimit },
737 { "uname", lc_uname },
739 { "setenv", lc_setenv },
742 { "meminfo", lc_meminfo },
745 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE)
746 { "fallocate", lc_fallocate },
752 luaL_register(L, "pposix", exports);
754 lua_pushliteral(L, "pposix");
755 lua_setfield(L, -2, "_NAME");
757 lua_pushliteral(L, MODULE_VERSION);
758 lua_setfield(L, -2, "_VERSION");