Dash:
[t2-trunk.git] / misc / luabash / posix / lposix.c
blob0c28b26039eb190e125b4e945a05a52d0ca4a31b
1 /*
2 * lposix.c
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>
5 * 05 Nov 2003 22:09:10
6 */
8 #include <dirent.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <grp.h>
12 #include <pwd.h>
13 #include <signal.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/stat.h>
18 #include <sys/times.h>
19 #include <sys/types.h>
20 #include <sys/utsname.h>
21 #include <sys/wait.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <utime.h>
25 #include <glob.h>
27 #define MYNAME "posix"
28 #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2003"
30 #include "lua.h"
31 #include "lauxlib.h"
33 #ifndef MYBUFSIZ
34 #define MYBUFSIZ 512
35 #endif
37 #include "modemuncher.c"
39 static const char *filetype(mode_t m)
41 if (S_ISREG(m)) return "regular";
42 else if (S_ISLNK(m)) return "link";
43 else if (S_ISDIR(m)) return "directory";
44 else if (S_ISCHR(m)) return "character device";
45 else if (S_ISBLK(m)) return "block device";
46 else if (S_ISFIFO(m)) return "fifo";
47 else if (S_ISSOCK(m)) return "socket";
48 else return "?";
51 typedef int (*Selector)(lua_State *L, int i, const void *data);
53 static int doselection(lua_State *L, int i, const char *const S[], Selector F, const void *data)
55 if (lua_isnone(L, i))
57 lua_newtable(L);
58 for (i=0; S[i]!=NULL; i++)
60 lua_pushstring(L, S[i]);
61 F(L, i, data);
62 lua_settable(L, -3);
64 return 1;
66 else
68 int j=luaL_checkoption(L, i, NULL, S);
69 if (j==-1) luaL_argerror(L, i, "unknown selector");
70 return F(L, j, data);
74 static void storeindex(lua_State *L, int i, const char *value)
76 lua_pushstring(L, value);
77 lua_rawseti(L, -2, i);
80 static void storestring(lua_State *L, const char *name, const char *value)
82 lua_pushstring(L, name);
83 lua_pushstring(L, value);
84 lua_settable(L, -3);
87 static void storenumber(lua_State *L, const char *name, lua_Number value)
89 lua_pushstring(L, name);
90 lua_pushnumber(L, value);
91 lua_settable(L, -3);
94 static int pusherror(lua_State *L, const char *info)
96 lua_pushnil(L);
97 if (info==NULL)
98 lua_pushstring(L, strerror(errno));
99 else
100 lua_pushfstring(L, "%s: %s", info, strerror(errno));
101 lua_pushnumber(L, errno);
102 return 3;
105 static int pushresult(lua_State *L, int i, const char *info)
107 if (i != -1)
109 lua_pushnumber(L, i);
110 return 1;
112 else
113 return pusherror(L, info);
116 static void badoption(lua_State *L, int i, const char *what, int option)
118 luaL_argerror(L, 2,
119 lua_pushfstring(L, "unknown %s option `%c'", what, option));
122 static uid_t mygetuid(lua_State *L, int i)
124 if (lua_isnone(L, i))
125 return -1;
126 else if (lua_isnumber(L, i))
127 return (uid_t) lua_tonumber(L, i);
128 else if (lua_isstring(L, i))
130 struct passwd *p=getpwnam(lua_tostring(L, i));
131 return (p==NULL) ? -1 : p->pw_uid;
133 else
134 return luaL_typerror(L, i, "string or number");
137 static gid_t mygetgid(lua_State *L, int i)
139 if (lua_isnone(L, i))
140 return -1;
141 else if (lua_isnumber(L, i))
142 return (gid_t) lua_tonumber(L, i);
143 else if (lua_isstring(L, i))
145 struct group *g=getgrnam(lua_tostring(L, i));
146 return (g==NULL) ? -1 : g->gr_gid;
148 else
149 return luaL_typerror(L, i, "string or number");
154 static int Perrno(lua_State *L) /** errno() */
156 lua_pushstring(L, strerror(errno));
157 lua_pushnumber(L, errno);
158 return 2;
162 static int Pdir(lua_State *L) /** dir([path]) */
164 const char *path = luaL_optstring(L, 1, ".");
165 DIR *d = opendir(path);
166 if (d == NULL)
167 return pusherror(L, path);
168 else
170 int i;
171 struct dirent *entry;
172 lua_newtable(L);
173 for (i=1; (entry = readdir(d)) != NULL; i++)
174 storeindex(L, i, entry->d_name);
175 closedir(d);
176 return 1;
181 static int Pglob(lua_State *L) /** glob(pattern) */
183 const char *pattern = luaL_optstring(L, 1, ".");
184 glob_t globres;
186 if (glob(pattern, 0, NULL, &globres))
187 return pusherror(L, pattern);
188 else
190 int i;
191 lua_newtable(L);
192 for (i=1; i<=globres.gl_pathc; i++)
193 storeindex(L, i, globres.gl_pathv[i-1]);
194 globfree(&globres);
195 return 1;
200 static int aux_files(lua_State *L)
202 DIR *d = lua_touserdata(L, lua_upvalueindex(1));
203 struct dirent *entry;
204 if (d == NULL) luaL_error(L, "attempt to use closed dir");
205 entry = readdir(d);
206 if (entry == NULL)
208 closedir(d);
209 lua_pushnil(L);
210 lua_replace(L, lua_upvalueindex(1));
211 lua_pushnil(L);
213 else
215 lua_pushstring(L, entry->d_name);
216 #if 0
217 #ifdef _DIRENT_HAVE_D_TYPE
218 lua_pushstring(L, filetype(DTTOIF(entry->d_type)));
219 return 2;
220 #endif
221 #endif
223 return 1;
226 static int Pfiles(lua_State *L) /** files([path]) */
228 const char *path = luaL_optstring(L, 1, ".");
229 DIR *d = opendir(path);
230 if (d == NULL)
231 return pusherror(L, path);
232 else
234 lua_pushlightuserdata(L, d);
235 lua_pushcclosure(L, aux_files, 1);
236 return 1;
241 static int Pgetcwd(lua_State *L) /** getcwd() */
243 char buf[MYBUFSIZ];
244 if (getcwd(buf, sizeof(buf)) == NULL)
245 return pusherror(L, ".");
246 else
248 lua_pushstring(L, buf);
249 return 1;
254 static int Pmkdir(lua_State *L) /** mkdir(path) */
256 const char *path = luaL_checkstring(L, 1);
257 return pushresult(L, mkdir(path, 0777), path);
261 static int Pchdir(lua_State *L) /** chdir(path) */
263 const char *path = luaL_checkstring(L, 1);
264 return pushresult(L, chdir(path), path);
268 static int Prmdir(lua_State *L) /** rmdir(path) */
270 const char *path = luaL_checkstring(L, 1);
271 return pushresult(L, rmdir(path), path);
275 static int Punlink(lua_State *L) /** unlink(path) */
277 const char *path = luaL_checkstring(L, 1);
278 return pushresult(L, unlink(path), path);
282 static int Plink(lua_State *L) /** link(oldpath,newpath) */
284 const char *oldpath = luaL_checkstring(L, 1);
285 const char *newpath = luaL_checkstring(L, 2);
286 return pushresult(L, link(oldpath, newpath), NULL);
290 static int Psymlink(lua_State *L) /** symlink(oldpath,newpath) */
292 const char *oldpath = luaL_checkstring(L, 1);
293 const char *newpath = luaL_checkstring(L, 2);
294 return pushresult(L, symlink(oldpath, newpath), NULL);
298 static int Preadlink(lua_State *L) /** readlink(path) */
300 char buf[MYBUFSIZ];
301 const char *path = luaL_checkstring(L, 1);
302 int n = readlink(path, buf, sizeof(buf));
303 if (n==-1) return pusherror(L, path);
304 lua_pushlstring(L, buf, n);
305 return 1;
309 static int Paccess(lua_State *L) /** access(path,[mode]) */
311 int mode=F_OK;
312 const char *path=luaL_checkstring(L, 1);
313 const char *s;
314 for (s=luaL_optstring(L, 2, "f"); *s!=0 ; s++)
315 switch (*s)
317 case ' ': break;
318 case 'r': mode |= R_OK; break;
319 case 'w': mode |= W_OK; break;
320 case 'x': mode |= X_OK; break;
321 case 'f': mode |= F_OK; break;
322 default: badoption(L, 2, "mode", *s); break;
324 return pushresult(L, access(path, mode), path);
328 static int Pmkfifo(lua_State *L) /** mkfifo(path) */
330 const char *path = luaL_checkstring(L, 1);
331 return pushresult(L, mkfifo(path, 0777), path);
335 static int Pexec(lua_State *L) /** exec(path,[args]) */
337 const char *path = luaL_checkstring(L, 1);
338 int i,n=lua_gettop(L);
339 char **argv = malloc((n+1)*sizeof(char*));
340 if (argv==NULL) luaL_error(L,"not enough memory");
341 argv[0] = (char*)path;
342 for (i=1; i<n; i++) argv[i] = (char*)luaL_checkstring(L, i+1);
343 argv[i] = NULL;
344 execvp(path,argv);
345 return pusherror(L, path);
349 static int Pfork(lua_State *L) /** fork() */
351 return pushresult(L, fork(), NULL);
355 static int Pwait(lua_State *L) /** wait([pid]) */
357 pid_t pid = luaL_optint(L, 1, -1);
358 return pushresult(L, waitpid(pid, NULL, 0), NULL);
362 static int Pkill(lua_State *L) /** kill(pid,[sig]) */
364 pid_t pid = luaL_checkint(L, 1);
365 int sig = luaL_optint(L, 2, SIGTERM);
366 return pushresult(L, kill(pid, sig), NULL);
370 static int Psleep(lua_State *L) /** sleep(seconds) */
372 unsigned int seconds = luaL_checkint(L, 1);
373 lua_pushnumber(L, sleep(seconds));
374 return 1;
378 static int Pputenv(lua_State *L) /** putenv(string) */
380 size_t l;
381 const char *s=luaL_checklstring(L, 1, &l);
382 char *e=malloc(++l);
383 return pushresult(L, (e==NULL) ? -1 : putenv(memcpy(e,s,l)), s);
387 #ifdef linux
388 static int Psetenv(lua_State *L) /** setenv(name,value,[over]) */
390 const char *name=luaL_checkstring(L, 1);
391 const char *value=luaL_checkstring(L, 2);
392 int overwrite=lua_isnoneornil(L, 3) || lua_toboolean(L, 3);
393 return pushresult(L, setenv(name,value,overwrite), name);
397 static int Punsetenv(lua_State *L) /** unsetenv(name) */
399 const char *name=luaL_checkstring(L, 1);
400 unsetenv(name);
401 return 0;
403 #endif
406 static int Pgetenv(lua_State *L) /** getenv([name]) */
408 if (lua_isnone(L, 1))
410 extern char **environ;
411 char **e;
412 if (*environ==NULL) lua_pushnil(L); else lua_newtable(L);
413 for (e=environ; *e!=NULL; e++)
415 char *s=*e;
416 char *eq=strchr(s, '=');
417 if (eq==NULL) /* will this ever happen? */
419 lua_pushstring(L,s);
420 lua_pushboolean(L,0);
422 else
424 lua_pushlstring(L,s,eq-s);
425 lua_pushstring(L,eq+1);
427 lua_settable(L,-3);
430 else
431 lua_pushstring(L, getenv(luaL_checkstring(L, 1)));
432 return 1;
436 static int Pumask(lua_State *L) /** umask([mode]) */
438 char m[10];
439 mode_t mode;
440 umask(mode=umask(0));
441 mode=(~mode)&0777;
442 if (!lua_isnone(L, 1))
444 if (mode_munch(&mode, luaL_checkstring(L, 1)))
446 lua_pushnil(L);
447 return 1;
449 mode&=0777;
450 umask(~mode);
452 modechopper(mode, m);
453 lua_pushstring(L, m);
454 return 1;
458 static int Pchmod(lua_State *L) /** chmod(path,mode) */
460 mode_t mode;
461 struct stat s;
462 const char *path = luaL_checkstring(L, 1);
463 const char *modestr = luaL_checkstring(L, 2);
464 if (stat(path, &s)) return pusherror(L, path);
465 mode = s.st_mode;
466 if (mode_munch(&mode, modestr)) luaL_argerror(L, 2, "bad mode");
467 return pushresult(L, chmod(path, mode), path);
471 static int Pchown(lua_State *L) /** chown(path,uid,gid) */
473 const char *path = luaL_checkstring(L, 1);
474 uid_t uid = mygetuid(L, 2);
475 gid_t gid = mygetgid(L, 3);
476 return pushresult(L, chown(path, uid, gid), path);
480 static int Putime(lua_State *L) /** utime(path,[mtime,atime]) */
482 struct utimbuf times;
483 time_t currtime = time(NULL);
484 const char *path = luaL_checkstring(L, 1);
485 times.modtime = luaL_optnumber(L, 2, currtime);
486 times.actime = luaL_optnumber(L, 3, currtime);
487 return pushresult(L, utime(path, &times), path);
491 static int FgetID(lua_State *L, int i, const void *data)
493 switch (i)
495 case 0: lua_pushnumber(L, getegid()); break;
496 case 1: lua_pushnumber(L, geteuid()); break;
497 case 2: lua_pushnumber(L, getgid()); break;
498 case 3: lua_pushnumber(L, getuid()); break;
499 case 4: lua_pushnumber(L, getpgrp()); break;
500 case 5: lua_pushnumber(L, getpid()); break;
501 case 6: lua_pushnumber(L, getppid()); break;
503 return 1;
506 static const char *const SgetID[] =
508 "egid", "euid", "gid", "uid", "pgrp", "pid", "ppid", NULL
511 static int Pgetprocessid(lua_State *L) /** getprocessid([selector]) */
513 return doselection(L, 1, SgetID, FgetID, NULL);
517 static int Pttyname(lua_State *L) /** ttyname(fd) */
519 int fd=luaL_optint(L, 1, 0);
520 lua_pushstring(L, ttyname(fd));
521 return 1;
524 static int Pctermid(lua_State *L) /** ctermid() */
526 char b[L_ctermid];
527 lua_pushstring(L, ctermid(b));
528 return 1;
532 static int Pgetlogin(lua_State *L) /** getlogin() */
534 lua_pushstring(L, getlogin());
535 return 1;
539 static int Fgetpasswd(lua_State *L, int i, const void *data)
541 const struct passwd *p=data;
542 switch (i)
544 case 0: lua_pushstring(L, p->pw_name); break;
545 case 1: lua_pushnumber(L, p->pw_uid); break;
546 case 2: lua_pushnumber(L, p->pw_gid); break;
547 case 3: lua_pushstring(L, p->pw_dir); break;
548 case 4: lua_pushstring(L, p->pw_shell); break;
549 /* not strictly POSIX */
550 case 5: lua_pushstring(L, p->pw_gecos); break;
551 case 6: lua_pushstring(L, p->pw_passwd); break;
553 return 1;
556 static const char *const Sgetpasswd[] =
558 "name", "uid", "gid", "dir", "shell", "gecos", "passwd", NULL
562 static int Pgetpasswd(lua_State *L) /** getpasswd(name or id) */
564 struct passwd *p=NULL;
565 if (lua_isnoneornil(L, 1))
566 p = getpwuid(geteuid());
567 else if (lua_isnumber(L, 1))
568 p = getpwuid((uid_t)lua_tonumber(L, 1));
569 else if (lua_isstring(L, 1))
570 p = getpwnam(lua_tostring(L, 1));
571 else
572 luaL_typerror(L, 1, "string or number");
573 if (p==NULL)
574 lua_pushnil(L);
575 else
576 doselection(L, 2, Sgetpasswd, Fgetpasswd, p);
577 return 1;
581 static int Pgetgroup(lua_State *L) /** getgroup(name or id) */
583 struct group *g=NULL;
584 if (lua_isnumber(L, 1))
585 g = getgrgid((gid_t)lua_tonumber(L, 1));
586 else if (lua_isstring(L, 1))
587 g = getgrnam(lua_tostring(L, 1));
588 else
589 luaL_typerror(L, 1, "string or number");
590 if (g==NULL)
591 lua_pushnil(L);
592 else
594 int i;
595 lua_newtable(L);
596 storestring(L, "name", g->gr_name);
597 storenumber(L, "gid", g->gr_gid);
598 for (i=0; g->gr_mem[i] != NULL; i++)
599 storeindex(L, i+1, g->gr_mem[i]);
601 return 1;
605 static int Psetuid(lua_State *L) /** setuid(name or id) */
607 return pushresult(L, setuid(mygetuid(L, 1)), NULL);
611 static int Psetgid(lua_State *L) /** setgid(name or id) */
613 return pushresult(L, setgid(mygetgid(L, 1)), NULL);
616 struct mytimes
618 struct tms t;
619 clock_t elapsed;
622 #define pushtime(L,x) lua_pushnumber(L,((lua_Number)x)/clk_tck)
624 static int Ftimes(lua_State *L, int i, const void *data)
626 const struct mytimes *t=data;
628 static clock_t clk_tck = 0;
629 if (!clk_tck) {
630 clk_tck = (clock_t) sysconf(_SC_CLK_TCK);
633 switch (i)
635 case 0: pushtime(L, t->t.tms_utime); break;
636 case 1: pushtime(L, t->t.tms_stime); break;
637 case 2: pushtime(L, t->t.tms_cutime); break;
638 case 3: pushtime(L, t->t.tms_cstime); break;
639 case 4: pushtime(L, t->elapsed); break;
641 return 1;
644 static const char *const Stimes[] =
646 "utime", "stime", "cutime", "cstime", "elapsed", NULL
649 static int Ptimes(lua_State *L) /** times() */
651 struct mytimes t;
652 t.elapsed = times(&t.t);
653 return doselection(L, 1, Stimes, Ftimes, &t);
657 struct mystat
659 struct stat s;
660 char mode[10];
661 const char *type;
664 static int Fstat(lua_State *L, int i, const void *data)
666 const struct mystat *s=data;
667 switch (i)
669 case 0: lua_pushstring(L, s->mode); break;
670 case 1: lua_pushnumber(L, s->s.st_ino); break;
671 case 2: lua_pushnumber(L, s->s.st_dev); break;
672 case 3: lua_pushnumber(L, s->s.st_nlink); break;
673 case 4: lua_pushnumber(L, s->s.st_uid); break;
674 case 5: lua_pushnumber(L, s->s.st_gid); break;
675 case 6: lua_pushnumber(L, s->s.st_size); break;
676 case 7: lua_pushnumber(L, s->s.st_atime); break;
677 case 8: lua_pushnumber(L, s->s.st_mtime); break;
678 case 9: lua_pushnumber(L, s->s.st_ctime); break;
679 case 10:lua_pushstring(L, s->type); break;
680 case 11:lua_pushnumber(L, s->s.st_mode); break;
682 return 1;
685 static const char *const Sstat[] =
687 "mode", "ino", "dev", "nlink", "uid", "gid",
688 "size", "atime", "mtime", "ctime", "type", "_mode",
689 NULL
692 static int Pstat(lua_State *L) /** stat(path,[selector]) */
694 struct mystat s;
695 const char *path=luaL_checkstring(L, 1);
696 if (lstat(path,&s.s)==-1) return pusherror(L, path);
697 s.type=filetype(s.s.st_mode);
698 modechopper(s.s.st_mode, s.mode);
699 return doselection(L, 2, Sstat, Fstat, &s);
703 static int Puname(lua_State *L) /** uname([string]) */
705 struct utsname u;
706 luaL_Buffer b;
707 const char *s;
708 if (uname(&u) == -1) return pusherror(L, NULL);
709 luaL_buffinit(L, &b);
710 for (s=luaL_optstring(L, 1, "%s %n %r %v %m"); *s; s++)
711 if (*s!='%')
712 luaL_putchar(&b, *s);
713 else switch (*++s)
715 case '%': luaL_putchar(&b, *s); break;
716 case 'm': luaL_addstring(&b,u.machine); break;
717 case 'n': luaL_addstring(&b,u.nodename); break;
718 case 'r': luaL_addstring(&b,u.release); break;
719 case 's': luaL_addstring(&b,u.sysname); break;
720 case 'v': luaL_addstring(&b,u.version); break;
721 default: badoption(L, 2, "format", *s); break;
723 luaL_pushresult(&b);
724 return 1;
728 static const int Kpathconf[] =
730 _PC_LINK_MAX, _PC_MAX_CANON, _PC_MAX_INPUT, _PC_NAME_MAX, _PC_PATH_MAX,
731 _PC_PIPE_BUF, _PC_CHOWN_RESTRICTED, _PC_NO_TRUNC, _PC_VDISABLE,
735 static int Fpathconf(lua_State *L, int i, const void *data)
737 const char *path=data;
738 lua_pushnumber(L, pathconf(path, Kpathconf[i]));
739 return 1;
742 static const char *const Spathconf[] =
744 "link_max", "max_canon", "max_input", "name_max", "path_max",
745 "pipe_buf", "chown_restricted", "no_trunc", "vdisable",
746 NULL
749 static int Ppathconf(lua_State *L) /** pathconf(path,[selector]) */
751 const char *path=luaL_checkstring(L, 1);
752 return doselection(L, 2, Spathconf, Fpathconf, path);
756 static const int Ksysconf[] =
758 _SC_ARG_MAX, _SC_CHILD_MAX, _SC_CLK_TCK, _SC_NGROUPS_MAX, _SC_STREAM_MAX,
759 _SC_TZNAME_MAX, _SC_OPEN_MAX, _SC_JOB_CONTROL, _SC_SAVED_IDS, _SC_VERSION,
763 static int Fsysconf(lua_State *L, int i, const void *data)
765 lua_pushnumber(L, sysconf(Ksysconf[i]));
766 return 1;
769 static const char *const Ssysconf[] =
771 "arg_max", "child_max", "clk_tck", "ngroups_max", "stream_max",
772 "tzname_max", "open_max", "job_control", "saved_ids", "version",
773 NULL
776 static int Psysconf(lua_State *L) /** sysconf([selector]) */
778 return doselection(L, 1, Ssysconf, Fsysconf, NULL);
782 static const luaL_reg R[] =
784 {"access", Paccess},
785 {"chdir", Pchdir},
786 {"chmod", Pchmod},
787 {"chown", Pchown},
788 {"ctermid", Pctermid},
789 {"dir", Pdir},
790 {"errno", Perrno},
791 {"exec", Pexec},
792 {"files", Pfiles},
793 {"fork", Pfork},
794 {"getcwd", Pgetcwd},
795 {"getenv", Pgetenv},
796 {"getgroup", Pgetgroup},
797 {"getlogin", Pgetlogin},
798 {"getpasswd", Pgetpasswd},
799 {"getprocessid", Pgetprocessid},
800 {"glob", Pglob},
801 {"kill", Pkill},
802 {"link", Plink},
803 {"mkdir", Pmkdir},
804 {"mkfifo", Pmkfifo},
805 {"pathconf", Ppathconf},
806 {"putenv", Pputenv},
807 {"readlink", Preadlink},
808 {"rmdir", Prmdir},
809 {"setgid", Psetgid},
810 {"setuid", Psetuid},
811 {"sleep", Psleep},
812 {"stat", Pstat},
813 {"symlink", Psymlink},
814 {"sysconf", Psysconf},
815 {"times", Ptimes},
816 {"ttyname", Pttyname},
817 {"umask", Pumask},
818 {"uname", Puname},
819 {"unlink", Punlink},
820 {"utime", Putime},
821 {"wait", Pwait},
823 #ifdef linux
824 {"setenv", Psetenv},
825 {"unsetenv", Punsetenv},
826 #endif
827 {NULL, NULL}
830 LUALIB_API int luaopen_lposix (lua_State *L)
832 luaL_openlib(L, MYNAME, R, 0);
833 lua_pushliteral(L,"version"); /** version */
834 lua_pushliteral(L,MYVERSION);
835 lua_settable(L,-3);
836 return 1;