1 /* Prosody IM
2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
4 -- Copyright (C) 2009 Tobias Markmann
5 --
6 -- This project is MIT/X11 licensed. Please see the
7 -- COPYING file in the source package for more information.
8 --
9 */
10 
11 /*
12 * pposix.c
13 * POSIX support functions for Lua
14 */
15 
16 #define MODULE_VERSION "0.4.0"
17 
18 
19 #if defined(__linux__)
20 #ifndef _GNU_SOURCE
21 #define _GNU_SOURCE
22 #endif
23 #else
24 #ifndef _DEFAULT_SOURCE
25 #define _DEFAULT_SOURCE
26 #endif
27 #endif
28 #if defined(__APPLE__)
29 #ifndef _DARWIN_C_SOURCE
30 #define _DARWIN_C_SOURCE
31 #endif
32 #endif
33 
34 #include <stdlib.h>
35 #include <math.h>
36 #include <unistd.h>
37 #include <libgen.h>
38 #include <sys/resource.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/utsname.h>
42 #include <fcntl.h>
43 
44 #include <syslog.h>
45 #include <pwd.h>
46 #include <grp.h>
47 
48 #include <string.h>
49 #include <errno.h>
50 #include "lua.h"
51 #include "lualib.h"
52 #include "lauxlib.h"
53 
54 #if (LUA_VERSION_NUM == 501)
55 #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
56 #endif
57 
58 #include <fcntl.h>
59 #if defined(__linux__)
60 #include <linux/falloc.h>
61 #endif
62 
63 #if !defined(WITHOUT_MALLINFO) && defined(__linux__) && defined(__GLIBC__)
64 #include <malloc.h>
65 #define WITH_MALLINFO
66 #endif
67 
68 #if defined(__FreeBSD__) && defined(RFPROC)
69 /*
70  * On FreeBSD, calling fork() is equivalent to rfork(RFPROC | RFFDG).
71  *
72  * RFFDG being set means that the file descriptor table is copied,
73  * otherwise it's shared. We want the later, otherwise libevent gets
74  * messed up.
75  *
76  * See issue #412
77  */
78 #define fork() rfork(RFPROC)
79 #endif
80 
81 /* Daemonization support */
82 
lc_daemonize(lua_State * L)83 static int lc_daemonize(lua_State *L) {
84 
85 	pid_t pid;
86 
87 	if(getppid() == 1) {
88 		lua_pushboolean(L, 0);
89 		lua_pushstring(L, "already-daemonized");
90 		return 2;
91 	}
92 
93 	/* Attempt initial fork */
94 	if((pid = fork()) < 0) {
95 		/* Forking failed */
96 		lua_pushboolean(L, 0);
97 		lua_pushstring(L, "fork-failed");
98 		return 2;
99 	} else if(pid != 0) {
100 		/* We are the parent process */
101 		lua_pushboolean(L, 1);
102 		lua_pushnumber(L, pid);
103 		return 2;
104 	}
105 
106 	/* and we are the child process */
107 	if(setsid() == -1) {
108 		/* We failed to become session leader */
109 		/* (we probably already were) */
110 		lua_pushboolean(L, 0);
111 		lua_pushstring(L, "setsid-failed");
112 		return 2;
113 	}
114 
115 	/* Make sure accidental use of FDs 0, 1, 2 don't cause weirdness */
116 	freopen("/dev/null", "r", stdin);
117 	freopen("/dev/null", "w", stdout);
118 	freopen("/dev/null", "w", stderr);
119 
120 	/* Final fork, use it wisely */
121 	if(fork()) {
122 		exit(0);
123 	}
124 
125 	/* Show's over, let's continue */
126 	lua_pushboolean(L, 1);
127 	lua_pushnil(L);
128 	return 2;
129 }
130 
131 /* Syslog support */
132 
133 const char *const facility_strings[] = {
134 	"auth",
135 #if !(defined(sun) || defined(__sun))
136 	"authpriv",
137 #endif
138 	"cron",
139 	"daemon",
140 #if !(defined(sun) || defined(__sun))
141 	"ftp",
142 #endif
143 	"kern",
144 	"local0",
145 	"local1",
146 	"local2",
147 	"local3",
148 	"local4",
149 	"local5",
150 	"local6",
151 	"local7",
152 	"lpr",
153 	"mail",
154 	"syslog",
155 	"user",
156 	"uucp",
157 	NULL
158 };
159 int facility_constants[] =	{
160 	LOG_AUTH,
161 #if !(defined(sun) || defined(__sun))
162 	LOG_AUTHPRIV,
163 #endif
164 	LOG_CRON,
165 	LOG_DAEMON,
166 #if !(defined(sun) || defined(__sun))
167 	LOG_FTP,
168 #endif
169 	LOG_KERN,
170 	LOG_LOCAL0,
171 	LOG_LOCAL1,
172 	LOG_LOCAL2,
173 	LOG_LOCAL3,
174 	LOG_LOCAL4,
175 	LOG_LOCAL5,
176 	LOG_LOCAL6,
177 	LOG_LOCAL7,
178 	LOG_LPR,
179 	LOG_MAIL,
180 	LOG_NEWS,
181 	LOG_SYSLOG,
182 	LOG_USER,
183 	LOG_UUCP,
184 	-1
185 };
186 
187 /* "
188        The parameter ident in the call of openlog() is probably stored  as-is.
189        Thus,  if  the  string  it  points  to  is  changed, syslog() may start
190        prepending the changed string, and if the string it points to ceases to
191        exist,  the  results  are  undefined.  Most portable is to use a string
192        constant.
193    " -- syslog manpage
194 */
195 char *syslog_ident = NULL;
196 
lc_syslog_open(lua_State * L)197 int lc_syslog_open(lua_State *L) {
198 	int facility = luaL_checkoption(L, 2, "daemon", facility_strings);
199 	facility = facility_constants[facility];
200 
201 	luaL_checkstring(L, 1);
202 
203 	if(syslog_ident) {
204 		free(syslog_ident);
205 	}
206 
207 	syslog_ident = strdup(lua_tostring(L, 1));
208 
209 	openlog(syslog_ident, LOG_PID, facility);
210 	return 0;
211 }
212 
213 const char *const level_strings[] = {
214 	"debug",
215 	"info",
216 	"notice",
217 	"warn",
218 	"error",
219 	NULL
220 };
221 int level_constants[] = 	{
222 	LOG_DEBUG,
223 	LOG_INFO,
224 	LOG_NOTICE,
225 	LOG_WARNING,
226 	LOG_CRIT,
227 	-1
228 };
lc_syslog_log(lua_State * L)229 int lc_syslog_log(lua_State *L) {
230 	int level = level_constants[luaL_checkoption(L, 1, "notice", level_strings)];
231 
232 	if(lua_gettop(L) == 3) {
233 		syslog(level, "%s: %s", luaL_checkstring(L, 2), luaL_checkstring(L, 3));
234 	} else {
235 		syslog(level, "%s", lua_tostring(L, 2));
236 	}
237 
238 	return 0;
239 }
240 
lc_syslog_close(lua_State * L)241 int lc_syslog_close(lua_State *L) {
242 	(void)L;
243 	closelog();
244 
245 	if(syslog_ident) {
246 		free(syslog_ident);
247 		syslog_ident = NULL;
248 	}
249 
250 	return 0;
251 }
252 
lc_syslog_setmask(lua_State * L)253 int lc_syslog_setmask(lua_State *L) {
254 	int level_idx = luaL_checkoption(L, 1, "notice", level_strings);
255 	int mask = 0;
256 
257 	do {
258 		mask |= LOG_MASK(level_constants[level_idx]);
259 	} while(++level_idx <= 4);
260 
261 	setlogmask(mask);
262 	return 0;
263 }
264 
265 /* getpid */
266 
lc_getpid(lua_State * L)267 int lc_getpid(lua_State *L) {
268 	lua_pushinteger(L, getpid());
269 	return 1;
270 }
271 
272 /* UID/GID functions */
273 
lc_getuid(lua_State * L)274 int lc_getuid(lua_State *L) {
275 	lua_pushinteger(L, getuid());
276 	return 1;
277 }
278 
lc_getgid(lua_State * L)279 int lc_getgid(lua_State *L) {
280 	lua_pushinteger(L, getgid());
281 	return 1;
282 }
283 
lc_setuid(lua_State * L)284 int lc_setuid(lua_State *L) {
285 	int uid = -1;
286 
287 	if(lua_gettop(L) < 1) {
288 		return 0;
289 	}
290 
291 	if(!lua_isnumber(L, 1) && lua_tostring(L, 1)) {
292 		/* Passed UID is actually a string, so look up the UID */
293 		struct passwd *p;
294 		p = getpwnam(lua_tostring(L, 1));
295 
296 		if(!p) {
297 			lua_pushboolean(L, 0);
298 			lua_pushstring(L, "no-such-user");
299 			return 2;
300 		}
301 
302 		uid = p->pw_uid;
303 	} else {
304 		uid = lua_tonumber(L, 1);
305 	}
306 
307 	if(uid > -1) {
308 		/* Ok, attempt setuid */
309 		errno = 0;
310 
311 		if(setuid(uid)) {
312 			/* Fail */
313 			lua_pushboolean(L, 0);
314 
315 			switch(errno) {
316 				case EINVAL:
317 					lua_pushstring(L, "invalid-uid");
318 					break;
319 
320 				case EPERM:
321 					lua_pushstring(L, "permission-denied");
322 					break;
323 
324 				default:
325 					lua_pushstring(L, "unknown-error");
326 			}
327 
328 			return 2;
329 		} else {
330 			/* Success! */
331 			lua_pushboolean(L, 1);
332 			return 1;
333 		}
334 	}
335 
336 	/* Seems we couldn't find a valid UID to switch to */
337 	lua_pushboolean(L, 0);
338 	lua_pushstring(L, "invalid-uid");
339 	return 2;
340 }
341 
lc_setgid(lua_State * L)342 int lc_setgid(lua_State *L) {
343 	int gid = -1;
344 
345 	if(lua_gettop(L) < 1) {
346 		return 0;
347 	}
348 
349 	if(!lua_isnumber(L, 1) && lua_tostring(L, 1)) {
350 		/* Passed GID is actually a string, so look up the GID */
351 		struct group *g;
352 		g = getgrnam(lua_tostring(L, 1));
353 
354 		if(!g) {
355 			lua_pushboolean(L, 0);
356 			lua_pushstring(L, "no-such-group");
357 			return 2;
358 		}
359 
360 		gid = g->gr_gid;
361 	} else {
362 		gid = lua_tonumber(L, 1);
363 	}
364 
365 	if(gid > -1) {
366 		/* Ok, attempt setgid */
367 		errno = 0;
368 
369 		if(setgid(gid)) {
370 			/* Fail */
371 			lua_pushboolean(L, 0);
372 
373 			switch(errno) {
374 				case EINVAL:
375 					lua_pushstring(L, "invalid-gid");
376 					break;
377 
378 				case EPERM:
379 					lua_pushstring(L, "permission-denied");
380 					break;
381 
382 				default:
383 					lua_pushstring(L, "unknown-error");
384 			}
385 
386 			return 2;
387 		} else {
388 			/* Success! */
389 			lua_pushboolean(L, 1);
390 			return 1;
391 		}
392 	}
393 
394 	/* Seems we couldn't find a valid GID to switch to */
395 	lua_pushboolean(L, 0);
396 	lua_pushstring(L, "invalid-gid");
397 	return 2;
398 }
399 
lc_initgroups(lua_State * L)400 int lc_initgroups(lua_State *L) {
401 	int ret;
402 	gid_t gid;
403 	struct passwd *p;
404 
405 	if(!lua_isstring(L, 1)) {
406 		lua_pushnil(L);
407 		lua_pushstring(L, "invalid-username");
408 		return 2;
409 	}
410 
411 	p = getpwnam(lua_tostring(L, 1));
412 
413 	if(!p) {
414 		lua_pushnil(L);
415 		lua_pushstring(L, "no-such-user");
416 		return 2;
417 	}
418 
419 	if(lua_gettop(L) < 2) {
420 		lua_pushnil(L);
421 	}
422 
423 	switch(lua_type(L, 2)) {
424 		case LUA_TNIL:
425 			gid = p->pw_gid;
426 			break;
427 
428 		case LUA_TNUMBER:
429 			gid = lua_tointeger(L, 2);
430 			break;
431 
432 		default:
433 			lua_pushnil(L);
434 			lua_pushstring(L, "invalid-gid");
435 			return 2;
436 	}
437 
438 	ret = initgroups(lua_tostring(L, 1), gid);
439 
440 	if(ret) {
441 		switch(errno) {
442 			case ENOMEM:
443 				lua_pushnil(L);
444 				lua_pushstring(L, "no-memory");
445 				break;
446 
447 			case EPERM:
448 				lua_pushnil(L);
449 				lua_pushstring(L, "permission-denied");
450 				break;
451 
452 			default:
453 				lua_pushnil(L);
454 				lua_pushstring(L, "unknown-error");
455 		}
456 	} else {
457 		lua_pushboolean(L, 1);
458 		lua_pushnil(L);
459 	}
460 
461 	return 2;
462 }
463 
lc_umask(lua_State * L)464 int lc_umask(lua_State *L) {
465 	char old_mode_string[7];
466 	mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8));
467 
468 	snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode);
469 	old_mode_string[sizeof(old_mode_string) - 1] = 0;
470 	lua_pushstring(L, old_mode_string);
471 
472 	return 1;
473 }
474 
lc_mkdir(lua_State * L)475 int lc_mkdir(lua_State *L) {
476 	int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR
477 	                | S_IRGRP | S_IWGRP | S_IXGRP
478 	                | S_IROTH | S_IXOTH); /* mode 775 */
479 
480 	lua_pushboolean(L, ret == 0);
481 
482 	if(ret) {
483 		lua_pushstring(L, strerror(errno));
484 		return 2;
485 	}
486 
487 	return 1;
488 }
489 
490 /*	Like POSIX's setrlimit()/getrlimit() API functions.
491  *
492  *	Syntax:
493  *	pposix.setrlimit( resource, soft limit, hard limit)
494  *
495  *	Any negative limit will be replace with the current limit by an additional call of getrlimit().
496  *
497  *	Example usage:
498  *	pposix.setrlimit("NOFILE", 1000, 2000)
499  */
string2resource(const char * s)500 int string2resource(const char *s) {
501 	if(!strcmp(s, "CORE")) {
502 		return RLIMIT_CORE;
503 	}
504 
505 	if(!strcmp(s, "CPU")) {
506 		return RLIMIT_CPU;
507 	}
508 
509 	if(!strcmp(s, "DATA")) {
510 		return RLIMIT_DATA;
511 	}
512 
513 	if(!strcmp(s, "FSIZE")) {
514 		return RLIMIT_FSIZE;
515 	}
516 
517 	if(!strcmp(s, "NOFILE")) {
518 		return RLIMIT_NOFILE;
519 	}
520 
521 	if(!strcmp(s, "STACK")) {
522 		return RLIMIT_STACK;
523 	}
524 
525 #if !(defined(sun) || defined(__sun) || defined(__APPLE__))
526 
527 	if(!strcmp(s, "MEMLOCK")) {
528 		return RLIMIT_MEMLOCK;
529 	}
530 
531 	if(!strcmp(s, "NPROC")) {
532 		return RLIMIT_NPROC;
533 	}
534 
535 	if(!strcmp(s, "RSS")) {
536 		return RLIMIT_RSS;
537 	}
538 
539 #endif
540 #ifdef RLIMIT_NICE
541 
542 	if(!strcmp(s, "NICE")) {
543 		return RLIMIT_NICE;
544 	}
545 
546 #endif
547 	return -1;
548 }
549 
arg_to_rlimit(lua_State * L,int idx,rlim_t current)550 rlim_t arg_to_rlimit(lua_State *L, int idx, rlim_t current) {
551 	switch(lua_type(L, idx)) {
552 		case LUA_TSTRING:
553 
554 			if(strcmp(lua_tostring(L, idx), "unlimited") == 0) {
555 				return RLIM_INFINITY;
556 			}
557 			return luaL_argerror(L, idx, "unexpected type");
558 
559 		case LUA_TNUMBER:
560 			return lua_tointeger(L, idx);
561 
562 		case LUA_TNONE:
563 		case LUA_TNIL:
564 			return current;
565 
566 		default:
567 			return luaL_argerror(L, idx, "unexpected type");
568 	}
569 }
570 
lc_setrlimit(lua_State * L)571 int lc_setrlimit(lua_State *L) {
572 	struct rlimit lim;
573 	int arguments = lua_gettop(L);
574 	int rid = -1;
575 
576 	if(arguments < 1 || arguments > 3) {
577 		lua_pushboolean(L, 0);
578 		lua_pushstring(L, "incorrect-arguments");
579 		return 2;
580 	}
581 
582 	rid = string2resource(luaL_checkstring(L, 1));
583 
584 	if(rid == -1) {
585 		lua_pushboolean(L, 0);
586 		lua_pushstring(L, "invalid-resource");
587 		return 2;
588 	}
589 
590 	/* Fetch current values to use as defaults */
591 	if(getrlimit(rid, &lim)) {
592 		lua_pushboolean(L, 0);
593 		lua_pushstring(L, "getrlimit-failed");
594 		return 2;
595 	}
596 
597 	lim.rlim_cur = arg_to_rlimit(L, 2, lim.rlim_cur);
598 	lim.rlim_max = arg_to_rlimit(L, 3, lim.rlim_max);
599 
600 	if(setrlimit(rid, &lim)) {
601 		lua_pushboolean(L, 0);
602 		lua_pushstring(L, "setrlimit-failed");
603 		return 2;
604 	}
605 
606 	lua_pushboolean(L, 1);
607 	return 1;
608 }
609 
lc_getrlimit(lua_State * L)610 int lc_getrlimit(lua_State *L) {
611 	int arguments = lua_gettop(L);
612 	const char *resource = NULL;
613 	int rid = -1;
614 	struct rlimit lim;
615 
616 	if(arguments != 1) {
617 		lua_pushboolean(L, 0);
618 		lua_pushstring(L, "invalid-arguments");
619 		return 2;
620 	}
621 
622 	resource = luaL_checkstring(L, 1);
623 	rid = string2resource(resource);
624 
625 	if(rid != -1) {
626 		if(getrlimit(rid, &lim)) {
627 			lua_pushboolean(L, 0);
628 			lua_pushstring(L, "getrlimit-failed.");
629 			return 2;
630 		}
631 	} else {
632 		/* Unsupported resource. Sorry I'm pretty limited by POSIX standard. */
633 		lua_pushboolean(L, 0);
634 		lua_pushstring(L, "invalid-resource");
635 		return 2;
636 	}
637 
638 	lua_pushboolean(L, 1);
639 
640 	if(lim.rlim_cur == RLIM_INFINITY) {
641 		lua_pushstring(L, "unlimited");
642 	} else {
643 		lua_pushnumber(L, lim.rlim_cur);
644 	}
645 
646 	if(lim.rlim_max == RLIM_INFINITY) {
647 		lua_pushstring(L, "unlimited");
648 	} else {
649 		lua_pushnumber(L, lim.rlim_max);
650 	}
651 
652 	return 3;
653 }
654 
lc_abort(lua_State * L)655 int lc_abort(lua_State *L) {
656 	(void)L;
657 	abort();
658 	return 0;
659 }
660 
lc_uname(lua_State * L)661 int lc_uname(lua_State *L) {
662 	struct utsname uname_info;
663 
664 	if(uname(&uname_info) != 0) {
665 		lua_pushnil(L);
666 		lua_pushstring(L, strerror(errno));
667 		return 2;
668 	}
669 
670 	lua_createtable(L, 0, 6);
671 	lua_pushstring(L, uname_info.sysname);
672 	lua_setfield(L, -2, "sysname");
673 	lua_pushstring(L, uname_info.nodename);
674 	lua_setfield(L, -2, "nodename");
675 	lua_pushstring(L, uname_info.release);
676 	lua_setfield(L, -2, "release");
677 	lua_pushstring(L, uname_info.version);
678 	lua_setfield(L, -2, "version");
679 	lua_pushstring(L, uname_info.machine);
680 	lua_setfield(L, -2, "machine");
681 #ifdef __USE_GNU
682 	lua_pushstring(L, uname_info.domainname);
683 	lua_setfield(L, -2, "domainname");
684 #endif
685 	return 1;
686 }
687 
lc_setenv(lua_State * L)688 int lc_setenv(lua_State *L) {
689 	const char *var = luaL_checkstring(L, 1);
690 	const char *value;
691 
692 	/* If the second argument is nil or nothing, unset the var */
693 	if(lua_isnoneornil(L, 2)) {
694 		if(unsetenv(var) != 0) {
695 			lua_pushnil(L);
696 			lua_pushstring(L, strerror(errno));
697 			return 2;
698 		}
699 
700 		lua_pushboolean(L, 1);
701 		return 1;
702 	}
703 
704 	value = luaL_checkstring(L, 2);
705 
706 	if(setenv(var, value, 1) != 0) {
707 		lua_pushnil(L);
708 		lua_pushstring(L, strerror(errno));
709 		return 2;
710 	}
711 
712 	lua_pushboolean(L, 1);
713 	return 1;
714 }
715 
716 #ifdef WITH_MALLINFO
lc_meminfo(lua_State * L)717 int lc_meminfo(lua_State *L) {
718 	struct mallinfo info = mallinfo();
719 	lua_createtable(L, 0, 5);
720 	/* This is the total size of memory allocated with sbrk by malloc, in bytes. */
721 	lua_pushinteger(L, (unsigned)info.arena);
722 	lua_setfield(L, -2, "allocated");
723 	/* This is the total size of memory allocated with mmap, in bytes. */
724 	lua_pushinteger(L, (unsigned)info.hblkhd);
725 	lua_setfield(L, -2, "allocated_mmap");
726 	/* This is the total size of memory occupied by chunks handed out by malloc. */
727 	lua_pushinteger(L, (unsigned)info.uordblks);
728 	lua_setfield(L, -2, "used");
729 	/* This is the total size of memory occupied by free (not in use) chunks. */
730 	lua_pushinteger(L, (unsigned)info.fordblks);
731 	lua_setfield(L, -2, "unused");
732 	/* This is the size of the top-most releasable chunk that normally borders the
733 	   end of the heap (i.e., the high end of the virtual address space's data segment). */
734 	lua_pushinteger(L, (unsigned)info.keepcost);
735 	lua_setfield(L, -2, "returnable");
736 	return 1;
737 }
738 #endif
739 
740 /*
741  * Append some data to a file handle
742  * Attempt to allocate space first
743  * Truncate to original size on failure
744  */
lc_atomic_append(lua_State * L)745 int lc_atomic_append(lua_State *L) {
746 	int err;
747 	size_t len;
748 
749 	FILE *f = *(FILE **) luaL_checkudata(L, 1, LUA_FILEHANDLE);
750 	const char *data = luaL_checklstring(L, 2, &len);
751 
752 	off_t offset = ftell(f);
753 
754 #if defined(__linux__)
755 	/* Try to allocate space without changing the file size. */
756 	if((err = fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len))) {
757 		if(errno != 0) {
758 			/* Some old versions of Linux apparently use the return value instead of errno */
759 			err = errno;
760 		}
761 		switch(err) {
762 			case ENOSYS: /* Kernel doesn't implement fallocate */
763 			case EOPNOTSUPP: /* Filesystem doesn't support it */
764 				/* Ignore and proceed to try to write */
765 				break;
766 
767 			case ENOSPC: /* No space left */
768 			default: /* Other issues */
769 				lua_pushnil(L);
770 				lua_pushstring(L, strerror(err));
771 				lua_pushinteger(L, err);
772 				return 3;
773 		}
774 	}
775 #endif
776 
777 	if(fwrite(data, sizeof(char), len, f) == len) {
778 		if(fflush(f) == 0) {
779 			lua_pushboolean(L, 1); /* Great success! */
780 			return 1;
781 		} else {
782 			err = errno;
783 		}
784 	} else {
785 		err = ferror(f);
786 	}
787 
788 	fseek(f, offset, SEEK_SET);
789 
790 	/* Cut partially written data */
791 	if(ftruncate(fileno(f), offset)) {
792 		/* The file is now most likely corrupted, throw hard error */
793 		return luaL_error(L, "atomic_append() failed in ftruncate(): %s", strerror(errno));
794 	}
795 
796 	lua_pushnil(L);
797 	lua_pushstring(L, strerror(err));
798 	lua_pushinteger(L, err);
799 	return 3;
800 }
801 
802 /* Register functions */
803 
luaopen_util_pposix(lua_State * L)804 int luaopen_util_pposix(lua_State *L) {
805 #if (LUA_VERSION_NUM > 501)
806 	luaL_checkversion(L);
807 #endif
808 	luaL_Reg exports[] = {
809 		{ "abort", lc_abort },
810 
811 		{ "daemonize", lc_daemonize },
812 
813 		{ "syslog_open", lc_syslog_open },
814 		{ "syslog_close", lc_syslog_close },
815 		{ "syslog_log", lc_syslog_log },
816 		{ "syslog_setminlevel", lc_syslog_setmask },
817 
818 		{ "getpid", lc_getpid },
819 		{ "getuid", lc_getuid },
820 		{ "getgid", lc_getgid },
821 
822 		{ "setuid", lc_setuid },
823 		{ "setgid", lc_setgid },
824 		{ "initgroups", lc_initgroups },
825 
826 		{ "umask", lc_umask },
827 
828 		{ "mkdir", lc_mkdir },
829 
830 		{ "setrlimit", lc_setrlimit },
831 		{ "getrlimit", lc_getrlimit },
832 
833 		{ "uname", lc_uname },
834 
835 		{ "setenv", lc_setenv },
836 
837 #ifdef WITH_MALLINFO
838 		{ "meminfo", lc_meminfo },
839 #endif
840 
841 		{ "atomic_append", lc_atomic_append },
842 
843 		{ NULL, NULL }
844 	};
845 
846 	lua_newtable(L);
847 	luaL_setfuncs(L, exports, 0);
848 
849 #ifdef ENOENT
850 	lua_pushinteger(L, ENOENT);
851 	lua_setfield(L, -2, "ENOENT");
852 #endif
853 
854 	lua_pushliteral(L, "pposix");
855 	lua_setfield(L, -2, "_NAME");
856 
857 	lua_pushliteral(L, MODULE_VERSION);
858 	lua_setfield(L, -2, "_VERSION");
859 
860 	return 1;
861 }
862