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