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>
37 /* Daemonization support */
39 static int lc_daemonize(lua_State *L)
46 lua_pushboolean(L, 0);
47 lua_pushstring(L, "already-daemonized");
51 /* Attempt initial fork */
52 if((pid = fork()) < 0)
55 lua_pushboolean(L, 0);
56 lua_pushstring(L, "fork-failed");
61 /* We are the parent process */
62 lua_pushboolean(L, 1);
63 lua_pushnumber(L, pid);
67 /* and we are the child process */
70 /* We failed to become session leader */
71 /* (we probably already were) */
72 lua_pushboolean(L, 0);
73 lua_pushstring(L, "setsid-failed");
77 /* Close stdin, stdout, stderr */
82 /* Final fork, use it wisely */
86 /* Show's over, let's continue */
87 lua_pushboolean(L, 1);
94 const char * const facility_strings[] = {
96 #if !(defined(sun) || defined(__sun))
101 #if !(defined(sun) || defined(__sun))
120 int facility_constants[] = {
122 #if !(defined(sun) || defined(__sun))
127 #if !(defined(sun) || defined(__sun))
149 The parameter ident in the call of openlog() is probably stored as-is.
150 Thus, if the string it points to is changed, syslog() may start
151 prepending the changed string, and if the string it points to ceases to
152 exist, the results are undefined. Most portable is to use a string
156 char* syslog_ident = NULL;
158 int lc_syslog_open(lua_State* L)
160 int facility = luaL_checkoption(L, 2, "daemon", facility_strings);
161 facility = facility_constants[facility];
163 luaL_checkstring(L, 1);
168 syslog_ident = strdup(lua_tostring(L, 1));
170 openlog(syslog_ident, LOG_PID, facility);
174 const char * const level_strings[] = {
182 int level_constants[] = {
190 int lc_syslog_log(lua_State* L)
192 int level = luaL_checkoption(L, 1, "notice", level_strings);
193 level = level_constants[level];
195 luaL_checkstring(L, 2);
197 syslog(level, "%s", lua_tostring(L, 2));
201 int lc_syslog_close(lua_State* L)
212 int lc_syslog_setmask(lua_State* L)
214 int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
218 mask |= LOG_MASK(level_constants[level_idx]);
219 } while (++level_idx<=4);
227 int lc_getpid(lua_State* L)
229 lua_pushinteger(L, getpid());
233 /* UID/GID functions */
235 int lc_getuid(lua_State* L)
237 lua_pushinteger(L, getuid());
241 int lc_getgid(lua_State* L)
243 lua_pushinteger(L, getgid());
247 int lc_setuid(lua_State* L)
250 if(lua_gettop(L) < 1)
252 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
254 /* Passed UID is actually a string, so look up the UID */
256 p = getpwnam(lua_tostring(L, 1));
259 lua_pushboolean(L, 0);
260 lua_pushstring(L, "no-such-user");
267 uid = lua_tonumber(L, 1);
272 /* Ok, attempt setuid */
277 lua_pushboolean(L, 0);
281 lua_pushstring(L, "invalid-uid");
284 lua_pushstring(L, "permission-denied");
287 lua_pushstring(L, "unknown-error");
294 lua_pushboolean(L, 1);
299 /* Seems we couldn't find a valid UID to switch to */
300 lua_pushboolean(L, 0);
301 lua_pushstring(L, "invalid-uid");
305 int lc_setgid(lua_State* L)
308 if(lua_gettop(L) < 1)
310 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
312 /* Passed GID is actually a string, so look up the GID */
314 g = getgrnam(lua_tostring(L, 1));
317 lua_pushboolean(L, 0);
318 lua_pushstring(L, "no-such-group");
325 gid = lua_tonumber(L, 1);
330 /* Ok, attempt setgid */
335 lua_pushboolean(L, 0);
339 lua_pushstring(L, "invalid-gid");
342 lua_pushstring(L, "permission-denied");
345 lua_pushstring(L, "unknown-error");
352 lua_pushboolean(L, 1);
357 /* Seems we couldn't find a valid GID to switch to */
358 lua_pushboolean(L, 0);
359 lua_pushstring(L, "invalid-gid");
363 int lc_initgroups(lua_State* L)
369 if(!lua_isstring(L, 1))
372 lua_pushstring(L, "invalid-username");
375 p = getpwnam(lua_tostring(L, 1));
379 lua_pushstring(L, "no-such-user");
382 if(lua_gettop(L) < 2)
384 switch(lua_type(L, 2))
390 gid = lua_tointeger(L, 2);
394 lua_pushstring(L, "invalid-gid");
397 ret = initgroups(lua_tostring(L, 1), gid);
401 lua_pushboolean(L, 1);
406 lua_pushstring(L, "no-memory");
410 lua_pushstring(L, "permission-denied");
414 lua_pushstring(L, "unknown-error");
419 int lc_umask(lua_State* L)
421 char old_mode_string[7];
422 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8));
424 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode);
425 old_mode_string[sizeof(old_mode_string)-1] = 0;
426 lua_pushstring(L, old_mode_string);
431 int lc_mkdir(lua_State* L)
433 int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR
434 | S_IRGRP | S_IWGRP | S_IXGRP
435 | S_IROTH | S_IXOTH); /* mode 775 */
437 lua_pushboolean(L, ret==0);
440 lua_pushstring(L, strerror(errno));
446 /* Like POSIX's setrlimit()/getrlimit() API functions.
449 * pposix.setrlimit( resource, soft limit, hard limit)
451 * Any negative limit will be replace with the current limit by an additional call of getrlimit().
454 * pposix.setrlimit("NOFILE", 1000, 2000)
456 int string2resource(const char *s) {
457 if (!strcmp(s, "CORE")) return RLIMIT_CORE;
458 if (!strcmp(s, "CPU")) return RLIMIT_CPU;
459 if (!strcmp(s, "DATA")) return RLIMIT_DATA;
460 if (!strcmp(s, "FSIZE")) return RLIMIT_FSIZE;
461 if (!strcmp(s, "NOFILE")) return RLIMIT_NOFILE;
462 if (!strcmp(s, "STACK")) return RLIMIT_STACK;
463 #if !(defined(sun) || defined(__sun))
464 if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK;
465 if (!strcmp(s, "NPROC")) return RLIMIT_NPROC;
466 if (!strcmp(s, "RSS")) return RLIMIT_RSS;
471 int lc_setrlimit(lua_State *L) {
472 int arguments = lua_gettop(L);
475 const char *resource = NULL;
477 if(arguments < 1 || arguments > 3) {
478 lua_pushboolean(L, 0);
479 lua_pushstring(L, "incorrect-arguments");
482 resource = luaL_checkstring(L, 1);
483 softlimit = luaL_checkinteger(L, 2);
484 hardlimit = luaL_checkinteger(L, 3);
486 rid = string2resource(resource);
489 struct rlimit lim_current;
491 if (softlimit < 0 || hardlimit < 0) {
492 if (getrlimit(rid, &lim_current)) {
493 lua_pushboolean(L, 0);
494 lua_pushstring(L, "getrlimit-failed");
499 if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur;
500 else lim.rlim_cur = softlimit;
501 if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max;
502 else lim.rlim_max = hardlimit;
504 if (setrlimit(rid, &lim)) {
505 lua_pushboolean(L, 0);
506 lua_pushstring(L, "setrlimit-failed");
510 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
511 lua_pushboolean(L, 0);
512 lua_pushstring(L, "invalid-resource");
515 lua_pushboolean(L, 1);
519 int lc_getrlimit(lua_State *L) {
520 int arguments = lua_gettop(L);
521 const char *resource = NULL;
525 if (arguments != 1) {
526 lua_pushboolean(L, 0);
527 lua_pushstring(L, "invalid-arguments");
531 resource = luaL_checkstring(L, 1);
532 rid = string2resource(resource);
534 if (getrlimit(rid, &lim)) {
535 lua_pushboolean(L, 0);
536 lua_pushstring(L, "getrlimit-failed.");
540 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
541 lua_pushboolean(L, 0);
542 lua_pushstring(L, "invalid-resource");
545 lua_pushboolean(L, 1);
546 lua_pushnumber(L, lim.rlim_cur);
547 lua_pushnumber(L, lim.rlim_max);
551 int lc_abort(lua_State* L)
557 int lc_uname(lua_State* L)
559 struct utsname uname_info;
560 if(uname(&uname_info) != 0)
563 lua_pushstring(L, strerror(errno));
567 lua_pushstring(L, uname_info.sysname);
568 lua_setfield(L, -2, "sysname");
569 lua_pushstring(L, uname_info.nodename);
570 lua_setfield(L, -2, "nodename");
571 lua_pushstring(L, uname_info.release);
572 lua_setfield(L, -2, "release");
573 lua_pushstring(L, uname_info.version);
574 lua_setfield(L, -2, "version");
575 lua_pushstring(L, uname_info.machine);
576 lua_setfield(L, -2, "machine");
580 /* Register functions */
582 int luaopen_util_pposix(lua_State *L)
584 luaL_Reg exports[] = {
585 { "abort", lc_abort },
587 { "daemonize", lc_daemonize },
589 { "syslog_open", lc_syslog_open },
590 { "syslog_close", lc_syslog_close },
591 { "syslog_log", lc_syslog_log },
592 { "syslog_setminlevel", lc_syslog_setmask },
594 { "getpid", lc_getpid },
595 { "getuid", lc_getuid },
596 { "getgid", lc_getgid },
598 { "setuid", lc_setuid },
599 { "setgid", lc_setgid },
600 { "initgroups", lc_initgroups },
602 { "umask", lc_umask },
604 { "mkdir", lc_mkdir },
606 { "setrlimit", lc_setrlimit },
607 { "getrlimit", lc_getrlimit },
609 { "uname", lc_uname },
614 luaL_register(L, "pposix", exports);
616 lua_pushliteral(L, "pposix");
617 lua_setfield(L, -2, "_NAME");
619 lua_pushliteral(L, MODULE_VERSION);
620 lua_setfield(L, -2, "_VERSION");