2 -- Copyright (C) 2008-2009 Matthew Wild
3 -- Copyright (C) 2008-2009 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.3"
22 #include <sys/resource.h>
23 #include <sys/types.h>
36 /* Daemonization support */
38 static int lc_daemonize(lua_State *L)
45 lua_pushboolean(L, 0);
46 lua_pushstring(L, "already-daemonized");
50 /* Attempt initial fork */
51 if((pid = fork()) < 0)
54 lua_pushboolean(L, 0);
55 lua_pushstring(L, "fork-failed");
60 /* We are the parent process */
61 lua_pushboolean(L, 1);
62 lua_pushnumber(L, pid);
66 /* and we are the child process */
69 /* We failed to become session leader */
70 /* (we probably already were) */
71 lua_pushboolean(L, 0);
72 lua_pushstring(L, "setsid-failed");
76 /* Close stdin, stdout, stderr */
81 /* Final fork, use it wisely */
85 /* Show's over, let's continue */
86 lua_pushboolean(L, 1);
93 const char * const facility_strings[] = {
95 #if !(defined(sun) || defined(__sun))
100 #if !(defined(sun) || defined(__sun))
119 int facility_constants[] = {
121 #if !(defined(sun) || defined(__sun))
126 #if !(defined(sun) || defined(__sun))
148 The parameter ident in the call of openlog() is probably stored as-is.
149 Thus, if the string it points to is changed, syslog() may start
150 prepending the changed string, and if the string it points to ceases to
151 exist, the results are undefined. Most portable is to use a string
155 char* syslog_ident = NULL;
157 int lc_syslog_open(lua_State* L)
159 int facility = luaL_checkoption(L, 2, "daemon", facility_strings);
160 facility = facility_constants[facility];
162 luaL_checkstring(L, 1);
167 syslog_ident = strdup(lua_tostring(L, 1));
169 openlog(syslog_ident, LOG_PID, facility);
173 const char * const level_strings[] = {
181 int level_constants[] = {
189 int lc_syslog_log(lua_State* L)
191 int level = luaL_checkoption(L, 1, "notice", level_strings);
192 level = level_constants[level];
194 luaL_checkstring(L, 2);
196 syslog(level, "%s", lua_tostring(L, 2));
200 int lc_syslog_close(lua_State* L)
211 int lc_syslog_setmask(lua_State* L)
213 int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
217 mask |= LOG_MASK(level_constants[level_idx]);
218 } while (++level_idx<=4);
226 int lc_getpid(lua_State* L)
228 lua_pushinteger(L, getpid());
232 /* UID/GID functions */
234 int lc_getuid(lua_State* L)
236 lua_pushinteger(L, getuid());
240 int lc_getgid(lua_State* L)
242 lua_pushinteger(L, getgid());
246 int lc_setuid(lua_State* L)
249 if(lua_gettop(L) < 1)
251 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
253 /* Passed UID is actually a string, so look up the UID */
255 p = getpwnam(lua_tostring(L, 1));
258 lua_pushboolean(L, 0);
259 lua_pushstring(L, "no-such-user");
266 uid = lua_tonumber(L, 1);
271 /* Ok, attempt setuid */
276 lua_pushboolean(L, 0);
280 lua_pushstring(L, "invalid-uid");
283 lua_pushstring(L, "permission-denied");
286 lua_pushstring(L, "unknown-error");
293 lua_pushboolean(L, 1);
298 /* Seems we couldn't find a valid UID to switch to */
299 lua_pushboolean(L, 0);
300 lua_pushstring(L, "invalid-uid");
304 int lc_setgid(lua_State* L)
307 if(lua_gettop(L) < 1)
309 if(!lua_isnumber(L, 1) && lua_tostring(L, 1))
311 /* Passed GID is actually a string, so look up the GID */
313 g = getgrnam(lua_tostring(L, 1));
316 lua_pushboolean(L, 0);
317 lua_pushstring(L, "no-such-group");
324 gid = lua_tonumber(L, 1);
329 /* Ok, attempt setgid */
334 lua_pushboolean(L, 0);
338 lua_pushstring(L, "invalid-gid");
341 lua_pushstring(L, "permission-denied");
344 lua_pushstring(L, "unknown-error");
351 lua_pushboolean(L, 1);
356 /* Seems we couldn't find a valid GID to switch to */
357 lua_pushboolean(L, 0);
358 lua_pushstring(L, "invalid-gid");
362 int lc_umask(lua_State* L)
364 char old_mode_string[7];
365 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8));
367 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode);
368 old_mode_string[sizeof(old_mode_string)-1] = 0;
369 lua_pushstring(L, old_mode_string);
374 int lc_mkdir(lua_State* L)
376 int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR
377 | S_IRGRP | S_IWGRP | S_IXGRP
378 | S_IROTH | S_IXOTH); /* mode 775 */
380 lua_pushboolean(L, ret==0);
383 lua_pushstring(L, strerror(errno));
389 /* Like POSIX's setrlimit()/getrlimit() API functions.
392 * pposix.setrlimit( resource, soft limit, hard limit)
394 * Any negative limit will be replace with the current limit by an additional call of getrlimit().
397 * pposix.setrlimit("NOFILE", 1000, 2000)
399 int string2resource(const char *s) {
400 if (!strcmp(s, "CORE")) return RLIMIT_CORE;
401 if (!strcmp(s, "CPU")) return RLIMIT_CPU;
402 if (!strcmp(s, "DATA")) return RLIMIT_DATA;
403 if (!strcmp(s, "FSIZE")) return RLIMIT_FSIZE;
404 if (!strcmp(s, "NOFILE")) return RLIMIT_NOFILE;
405 if (!strcmp(s, "STACK")) return RLIMIT_STACK;
406 #if !(defined(sun) || defined(__sun))
407 if (!strcmp(s, "MEMLOCK")) return RLIMIT_MEMLOCK;
408 if (!strcmp(s, "NPROC")) return RLIMIT_NPROC;
409 if (!strcmp(s, "RSS")) return RLIMIT_RSS;
414 int lc_setrlimit(lua_State *L) {
415 int arguments = lua_gettop(L);
418 const char *resource = NULL;
420 if(arguments < 1 || arguments > 3) {
421 lua_pushboolean(L, 0);
422 lua_pushstring(L, "incorrect-arguments");
425 resource = luaL_checkstring(L, 1);
426 softlimit = luaL_checkinteger(L, 2);
427 hardlimit = luaL_checkinteger(L, 3);
429 rid = string2resource(resource);
432 struct rlimit lim_current;
434 if (softlimit < 0 || hardlimit < 0) {
435 if (getrlimit(rid, &lim_current)) {
436 lua_pushboolean(L, 0);
437 lua_pushstring(L, "getrlimit-failed");
442 if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur;
443 else lim.rlim_cur = softlimit;
444 if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max;
445 else lim.rlim_max = hardlimit;
447 if (setrlimit(rid, &lim)) {
448 lua_pushboolean(L, 0);
449 lua_pushstring(L, "setrlimit-failed");
453 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
454 lua_pushboolean(L, 0);
455 lua_pushstring(L, "invalid-resource");
458 lua_pushboolean(L, 1);
462 int lc_getrlimit(lua_State *L) {
463 int arguments = lua_gettop(L);
464 const char *resource = NULL;
468 if (arguments != 1) {
469 lua_pushboolean(L, 0);
470 lua_pushstring(L, "invalid-arguments");
474 resource = luaL_checkstring(L, 1);
475 rid = string2resource(resource);
477 if (getrlimit(rid, &lim)) {
478 lua_pushboolean(L, 0);
479 lua_pushstring(L, "getrlimit-failed.");
483 /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */
484 lua_pushboolean(L, 0);
485 lua_pushstring(L, "invalid-resource");
488 lua_pushboolean(L, 1);
489 lua_pushnumber(L, lim.rlim_cur);
490 lua_pushnumber(L, lim.rlim_max);
494 int lc_abort(lua_State* L)
500 /* Register functions */
502 int luaopen_util_pposix(lua_State *L)
504 luaL_Reg exports[] = {
505 { "abort", lc_abort },
507 { "daemonize", lc_daemonize },
509 { "syslog_open", lc_syslog_open },
510 { "syslog_close", lc_syslog_close },
511 { "syslog_log", lc_syslog_log },
512 { "syslog_setminlevel", lc_syslog_setmask },
514 { "getpid", lc_getpid },
515 { "getuid", lc_getuid },
516 { "getgid", lc_getgid },
518 { "setuid", lc_setuid },
519 { "setgid", lc_setgid },
521 { "umask", lc_umask },
523 { "mkdir", lc_mkdir },
525 { "setrlimit", lc_setrlimit },
526 { "getrlimit", lc_getrlimit },
531 luaL_register(L, "pposix", exports);
533 lua_pushliteral(L, "pposix");
534 lua_setfield(L, -2, "_NAME");
536 lua_pushliteral(L, MODULE_VERSION);
537 lua_setfield(L, -2, "_VERSION");