3 * POSIX library for Lua 5.0. Based on original by Claudio Terra for Lua 3.x.
4 * Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
18 #include <sys/times.h>
19 #include <sys/types.h>
20 #include <sys/utsname.h>
26 #define MYNAME "posix"
27 #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2003"
38 #include "modemuncher.c"
40 static const char *filetype(mode_t m)
42 if (S_ISREG(m)) return "regular";
43 else if (S_ISLNK(m)) return "link";
44 else if (S_ISDIR(m)) return "directory";
45 else if (S_ISCHR(m)) return "character device";
46 else if (S_ISBLK(m)) return "block device";
47 else if (S_ISFIFO(m)) return "fifo";
48 else if (S_ISSOCK(m)) return "socket";
52 typedef int (*Selector)(lua_State *L, int i, const void *data);
54 static int doselection(lua_State *L, int i, const char *const S[], Selector F, const void *data)
59 for (i=0; S[i]!=NULL; i++)
61 lua_pushstring(L, S[i]);
69 int j=luaL_checkoption(L, i, NULL, S);
70 if (j==-1) luaL_argerror(L, i, "unknown selector");
75 static void storeindex(lua_State *L, int i, const char *value)
77 lua_pushstring(L, value);
78 lua_rawseti(L, -2, i);
81 static void storestring(lua_State *L, const char *name, const char *value)
83 lua_pushstring(L, name);
84 lua_pushstring(L, value);
88 static void storenumber(lua_State *L, const char *name, lua_Number value)
90 lua_pushstring(L, name);
91 lua_pushnumber(L, value);
95 static int pusherror(lua_State *L, const char *info)
99 lua_pushstring(L, strerror(errno));
101 lua_pushfstring(L, "%s: %s", info, strerror(errno));
102 lua_pushnumber(L, errno);
106 static int pushresult(lua_State *L, int i, const char *info)
110 lua_pushnumber(L, i);
114 return pusherror(L, info);
117 static void badoption(lua_State *L, int i, const char *what, int option)
120 lua_pushfstring(L, "unknown %s option `%c'", what, option));
123 static uid_t mygetuid(lua_State *L, int i)
125 if (lua_isnone(L, i))
127 else if (lua_isnumber(L, i))
128 return (uid_t) lua_tonumber(L, i);
129 else if (lua_isstring(L, i))
131 struct passwd *p=getpwnam(lua_tostring(L, i));
132 return (p==NULL) ? -1 : p->pw_uid;
135 return luaL_typerror(L, i, "string or number");
138 static gid_t mygetgid(lua_State *L, int i)
140 if (lua_isnone(L, i))
142 else if (lua_isnumber(L, i))
143 return (gid_t) lua_tonumber(L, i);
144 else if (lua_isstring(L, i))
146 struct group *g=getgrnam(lua_tostring(L, i));
147 return (g==NULL) ? -1 : g->gr_gid;
150 return luaL_typerror(L, i, "string or number");
155 static int Perrno(lua_State *L) /** errno() */
157 lua_pushstring(L, strerror(errno));
158 lua_pushnumber(L, errno);
163 static int Pdir(lua_State *L) /** dir([path]) */
165 const char *path = luaL_optstring(L, 1, ".");
166 DIR *d = opendir(path);
168 return pusherror(L, path);
172 struct dirent *entry;
174 for (i=1; (entry = readdir(d)) != NULL; i++)
175 storeindex(L, i, entry->d_name);
182 static int aux_files(lua_State *L)
184 DIR *d = lua_touserdata(L, lua_upvalueindex(1));
185 struct dirent *entry;
186 if (d == NULL) return luaL_error(L, "attempt to use closed dir");
192 lua_replace(L, lua_upvalueindex(1));
197 lua_pushstring(L, entry->d_name);
199 #ifdef _DIRENT_HAVE_D_TYPE
200 lua_pushstring(L, filetype(DTTOIF(entry->d_type)));
208 static int Pfiles(lua_State *L) /** files([path]) */
210 const char *path = luaL_optstring(L, 1, ".");
211 DIR *d = opendir(path);
213 return pusherror(L, path);
216 lua_pushlightuserdata(L, d);
217 lua_pushcclosure(L, aux_files, 1);
223 static int Pgetcwd(lua_State *L) /** getcwd() */
226 if (getcwd(buf, sizeof(buf)) == NULL)
227 return pusherror(L, ".");
230 lua_pushstring(L, buf);
236 static int Pmkdir(lua_State *L) /** mkdir(path) */
238 const char *path = luaL_checkstring(L, 1);
239 return pushresult(L, mkdir(path, 0777), path);
243 static int Pchdir(lua_State *L) /** chdir(path) */
245 const char *path = luaL_checkstring(L, 1);
246 return pushresult(L, chdir(path), path);
250 static int Prmdir(lua_State *L) /** rmdir(path) */
252 const char *path = luaL_checkstring(L, 1);
253 return pushresult(L, rmdir(path), path);
257 static int Punlink(lua_State *L) /** unlink(path) */
259 const char *path = luaL_checkstring(L, 1);
260 return pushresult(L, unlink(path), path);
264 static int Plink(lua_State *L) /** link(oldpath,newpath) */
266 const char *oldpath = luaL_checkstring(L, 1);
267 const char *newpath = luaL_checkstring(L, 2);
268 return pushresult(L, link(oldpath, newpath), NULL);
272 static int Psymlink(lua_State *L) /** symlink(oldpath,newpath) */
274 const char *oldpath = luaL_checkstring(L, 1);
275 const char *newpath = luaL_checkstring(L, 2);
276 return pushresult(L, symlink(oldpath, newpath), NULL);
280 static int Preadlink(lua_State *L) /** readlink(path) */
283 const char *path = luaL_checkstring(L, 1);
284 int n = readlink(path, buf, sizeof(buf));
285 if (n==-1) return pusherror(L, path);
286 lua_pushlstring(L, buf, n);
291 static int Paccess(lua_State *L) /** access(path,[mode]) */
294 const char *path=luaL_checkstring(L, 1);
296 for (s=luaL_optstring(L, 2, "f"); *s!=0 ; s++)
300 case 'r': mode |= R_OK; break;
301 case 'w': mode |= W_OK; break;
302 case 'x': mode |= X_OK; break;
303 case 'f': mode |= F_OK; break;
304 default: badoption(L, 2, "mode", *s); break;
306 return pushresult(L, access(path, mode), path);
310 static int Pmkfifo(lua_State *L) /** mkfifo(path) */
312 const char *path = luaL_checkstring(L, 1);
313 return pushresult(L, mkfifo(path, 0777), path);
317 static int Pexec(lua_State *L) /** exec(path,[args]) */
319 const char *path = luaL_checkstring(L, 1);
320 int i,n=lua_gettop(L);
321 char **argv = malloc((n+1)*sizeof(char*));
322 if (argv==NULL) return luaL_error(L,"not enough memory");
323 argv[0] = (char*)path;
324 for (i=1; i<n; i++) argv[i] = (char*)luaL_checkstring(L, i+1);
327 return pusherror(L, path);
331 static int Pfork(lua_State *L) /** fork() */
333 return pushresult(L, fork(), NULL);
337 static int Pwait(lua_State *L) /** wait([pid]) */
339 pid_t pid = luaL_optint(L, 1, -1);
340 return pushresult(L, waitpid(pid, NULL, 0), NULL);
344 static int Pkill(lua_State *L) /** kill(pid,[sig]) */
346 pid_t pid = luaL_checkint(L, 1);
347 int sig = luaL_optint(L, 2, SIGTERM);
348 return pushresult(L, kill(pid, sig), NULL);
352 static int Psleep(lua_State *L) /** sleep(seconds) */
354 unsigned int seconds = luaL_checkint(L, 1);
355 lua_pushnumber(L, sleep(seconds));
360 static int Pputenv(lua_State *L) /** putenv(string) */
363 const char *s=luaL_checklstring(L, 1, &l);
365 return pushresult(L, (e==NULL) ? -1 : putenv(memcpy(e,s,l)), s);
369 static int Psetenv(lua_State *L) /** setenv(name,value,[over]) */
371 const char *name=luaL_checkstring(L, 1);
372 const char *value=luaL_checkstring(L, 2);
373 int overwrite=lua_isnoneornil(L, 3) || lua_toboolean(L, 3);
374 return pushresult(L, setenv(name,value,overwrite), name);
378 static int Punsetenv(lua_State *L) /** unsetenv(name) */
380 const char *name=luaL_checkstring(L, 1);
385 static int Pgetenv(lua_State *L) /** getenv([name]) */
387 if (lua_isnone(L, 1))
390 #include <crt_externs.h>
391 #define environ (*_NSGetEnviron())
393 extern char **environ;
394 #endif /* __APPLE__ */
396 if (*environ==NULL) lua_pushnil(L); else lua_newtable(L);
397 for (e=environ; *e!=NULL; e++)
400 char *eq=strchr(s, '=');
401 if (eq==NULL) /* will this ever happen? */
404 lua_pushboolean(L,0);
408 lua_pushlstring(L,s,eq-s);
409 lua_pushstring(L,eq+1);
415 lua_pushstring(L, getenv(luaL_checkstring(L, 1)));
420 static int Pumask(lua_State *L) /** umask([mode]) */
424 umask(mode=umask(0));
426 if (!lua_isnone(L, 1))
428 if (mode_munch(&mode, luaL_checkstring(L, 1)))
436 modechopper(mode, m);
437 lua_pushstring(L, m);
442 static int Pchmod(lua_State *L) /** chmod(path,mode) */
446 const char *path = luaL_checkstring(L, 1);
447 const char *modestr = luaL_checkstring(L, 2);
448 if (stat(path, &s)) return pusherror(L, path);
450 if (mode_munch(&mode, modestr)) luaL_argerror(L, 2, "bad mode");
451 return pushresult(L, chmod(path, mode), path);
455 static int Pchown(lua_State *L) /** chown(path,uid,gid) */
457 const char *path = luaL_checkstring(L, 1);
458 uid_t uid = mygetuid(L, 2);
459 gid_t gid = mygetgid(L, 3);
460 return pushresult(L, chown(path, uid, gid), path);
464 static int Putime(lua_State *L) /** utime(path,[mtime,atime]) */
466 struct utimbuf times;
467 time_t currtime = time(NULL);
468 const char *path = luaL_checkstring(L, 1);
469 times.modtime = luaL_optnumber(L, 2, currtime);
470 times.actime = luaL_optnumber(L, 3, currtime);
471 return pushresult(L, utime(path, ×), path);
475 static int FgetID(lua_State *L, int i, const void *data)
479 case 0: lua_pushnumber(L, getegid()); break;
480 case 1: lua_pushnumber(L, geteuid()); break;
481 case 2: lua_pushnumber(L, getgid()); break;
482 case 3: lua_pushnumber(L, getuid()); break;
483 case 4: lua_pushnumber(L, getpgrp()); break;
484 case 5: lua_pushnumber(L, getpid()); break;
485 case 6: lua_pushnumber(L, getppid()); break;
490 static const char *const SgetID[] =
492 "egid", "euid", "gid", "uid", "pgrp", "pid", "ppid", NULL
495 static int Pgetprocessid(lua_State *L) /** getprocessid([selector]) */
497 return doselection(L, 1, SgetID, FgetID, NULL);
501 static int Pttyname(lua_State *L) /** ttyname(fd) */
503 int fd=luaL_optint(L, 1, 0);
504 lua_pushstring(L, ttyname(fd));
508 static int Pctermid(lua_State *L) /** ctermid() */
511 lua_pushstring(L, ctermid(b));
516 static int Pgetlogin(lua_State *L) /** getlogin() */
518 lua_pushstring(L, getlogin());
523 static int Fgetpasswd(lua_State *L, int i, const void *data)
525 const struct passwd *p=data;
528 case 0: lua_pushstring(L, p->pw_name); break;
529 case 1: lua_pushnumber(L, p->pw_uid); break;
530 case 2: lua_pushnumber(L, p->pw_gid); break;
531 case 3: lua_pushstring(L, p->pw_dir); break;
532 case 4: lua_pushstring(L, p->pw_shell); break;
533 /* not strictly POSIX */
534 case 5: lua_pushstring(L, p->pw_gecos); break;
535 case 6: lua_pushstring(L, p->pw_passwd); break;
540 static const char *const Sgetpasswd[] =
542 "name", "uid", "gid", "dir", "shell", "gecos", "passwd", NULL
546 static int Pgetpasswd(lua_State *L) /** getpasswd(name or id) */
548 struct passwd *p=NULL;
549 if (lua_isnoneornil(L, 1))
550 p = getpwuid(geteuid());
551 else if (lua_isnumber(L, 1))
552 p = getpwuid((uid_t)lua_tonumber(L, 1));
553 else if (lua_isstring(L, 1))
554 p = getpwnam(lua_tostring(L, 1));
556 luaL_typerror(L, 1, "string or number");
560 doselection(L, 2, Sgetpasswd, Fgetpasswd, p);
565 static int Pgetgroup(lua_State *L) /** getgroup(name or id) */
567 struct group *g=NULL;
568 if (lua_isnumber(L, 1))
569 g = getgrgid((gid_t)lua_tonumber(L, 1));
570 else if (lua_isstring(L, 1))
571 g = getgrnam(lua_tostring(L, 1));
573 luaL_typerror(L, 1, "string or number");
580 storestring(L, "name", g->gr_name);
581 storenumber(L, "gid", g->gr_gid);
582 for (i=0; g->gr_mem[i] != NULL; i++)
583 storeindex(L, i+1, g->gr_mem[i]);
589 static int Psetuid(lua_State *L) /** setuid(name or id) */
591 return pushresult(L, setuid(mygetuid(L, 1)), NULL);
595 static int Psetgid(lua_State *L) /** setgid(name or id) */
597 return pushresult(L, setgid(mygetgid(L, 1)), NULL);
606 #define pushtime(L,x) lua_pushnumber(L,((lua_Number)x)/CLOCKS_PER_SEC)
608 static int Ftimes(lua_State *L, int i, const void *data)
610 const struct mytimes *t=data;
613 case 0: pushtime(L, t->t.tms_utime); break;
614 case 1: pushtime(L, t->t.tms_stime); break;
615 case 2: pushtime(L, t->t.tms_cutime); break;
616 case 3: pushtime(L, t->t.tms_cstime); break;
617 case 4: pushtime(L, t->elapsed); break;
622 static const char *const Stimes[] =
624 "utime", "stime", "cutime", "cstime", "elapsed", NULL
627 #define storetime(L,name,x) storenumber(L,name,(lua_Number)x/CLOCKS_PER_SEC)
629 static int Ptimes(lua_State *L) /** times() */
632 t.elapsed = times(&t.t);
633 return doselection(L, 1, Stimes, Ftimes, &t);
644 static int Fstat(lua_State *L, int i, const void *data)
646 const struct mystat *s=data;
649 case 0: lua_pushstring(L, s->mode); break;
650 case 1: lua_pushnumber(L, s->s.st_ino); break;
651 case 2: lua_pushnumber(L, s->s.st_dev); break;
652 case 3: lua_pushnumber(L, s->s.st_nlink); break;
653 case 4: lua_pushnumber(L, s->s.st_uid); break;
654 case 5: lua_pushnumber(L, s->s.st_gid); break;
655 case 6: lua_pushnumber(L, s->s.st_size); break;
656 case 7: lua_pushnumber(L, s->s.st_atime); break;
657 case 8: lua_pushnumber(L, s->s.st_mtime); break;
658 case 9: lua_pushnumber(L, s->s.st_ctime); break;
659 case 10:lua_pushstring(L, s->type); break;
660 case 11:lua_pushnumber(L, s->s.st_mode); break;
665 static const char *const Sstat[] =
667 "mode", "ino", "dev", "nlink", "uid", "gid",
668 "size", "atime", "mtime", "ctime", "type", "_mode",
672 static int Pstat(lua_State *L) /** stat(path,[selector]) */
675 const char *path=luaL_checkstring(L, 1);
676 if (lstat(path,&s.s)==-1) return pusherror(L, path);
677 s.type=filetype(s.s.st_mode);
678 modechopper(s.s.st_mode, s.mode);
679 return doselection(L, 2, Sstat, Fstat, &s);
683 static int Puname(lua_State *L) /** uname([string]) */
688 if (uname(&u) == -1) return pusherror(L, NULL);
689 luaL_buffinit(L, &b);
690 for (s=luaL_optstring(L, 1, "%s %n %r %v %m"); *s; s++)
692 luaL_putchar(&b, *s);
695 case '%': luaL_putchar(&b, *s); break;
696 case 'm': luaL_addstring(&b,u.machine); break;
697 case 'n': luaL_addstring(&b,u.nodename); break;
698 case 'r': luaL_addstring(&b,u.release); break;
699 case 's': luaL_addstring(&b,u.sysname); break;
700 case 'v': luaL_addstring(&b,u.version); break;
701 default: badoption(L, 2, "format", *s); break;
708 static const int Kpathconf[] =
710 _PC_LINK_MAX, _PC_MAX_CANON, _PC_MAX_INPUT, _PC_NAME_MAX, _PC_PATH_MAX,
711 _PC_PIPE_BUF, _PC_CHOWN_RESTRICTED, _PC_NO_TRUNC, _PC_VDISABLE,
715 static int Fpathconf(lua_State *L, int i, const void *data)
717 const char *path=data;
718 lua_pushnumber(L, pathconf(path, Kpathconf[i]));
722 static const char *const Spathconf[] =
724 "link_max", "max_canon", "max_input", "name_max", "path_max",
725 "pipe_buf", "chown_restricted", "no_trunc", "vdisable",
729 static int Ppathconf(lua_State *L) /** pathconf(path,[selector]) */
731 const char *path=luaL_checkstring(L, 1);
732 return doselection(L, 2, Spathconf, Fpathconf, path);
736 static const int Ksysconf[] =
738 _SC_ARG_MAX, _SC_CHILD_MAX, _SC_CLK_TCK, _SC_NGROUPS_MAX, _SC_STREAM_MAX,
739 _SC_TZNAME_MAX, _SC_OPEN_MAX, _SC_JOB_CONTROL, _SC_SAVED_IDS, _SC_VERSION,
743 static int Fsysconf(lua_State *L, int i, const void *data)
745 lua_pushnumber(L, sysconf(Ksysconf[i]));
749 static const char *const Ssysconf[] =
751 "arg_max", "child_max", "clk_tck", "ngroups_max", "stream_max",
752 "tzname_max", "open_max", "job_control", "saved_ids", "version",
756 static int Psysconf(lua_State *L) /** sysconf([selector]) */
758 return doselection(L, 1, Ssysconf, Fsysconf, NULL);
761 static int Pmkstemp(lua_State *L)
768 path = luaL_checkstring(L, 1);
771 dynpath = strdup(path);
772 fd = mkstemp(dynpath);
773 f = (FILE**)lua_newuserdata(L, sizeof(FILE*));
779 *f = fdopen(fd, "a+");
780 lua_pushstring(L, dynpath);
782 luaL_getmetatable(L, "FILE*");
783 if (lua_isnil(L, -1)) {
785 return luaL_error(L, "FILE* metatable not available "
788 lua_setmetatable(L, -3);
793 static const luaL_reg R[] =
799 {"ctermid", Pctermid},
807 {"getgroup", Pgetgroup},
808 {"getlogin", Pgetlogin},
809 {"getpasswd", Pgetpasswd},
810 {"getprocessid", Pgetprocessid},
815 {"mkstemp", Pmkstemp},
816 {"pathconf", Ppathconf},
818 {"readlink", Preadlink},
824 {"symlink", Psymlink},
825 {"sysconf", Psysconf},
827 {"ttyname", Pttyname},
834 {"unsetenv", Punsetenv},
838 LUALIB_API int luaopen_posix (lua_State *L)
840 luaL_openlib(L, MYNAME, R, 0);
841 lua_pushliteral(L,"version"); /** version */
842 lua_pushliteral(L,MYVERSION);