use lua_mem(L, +-size) to track your additional userdata sizes. keep it balanced...
[blua.git] / src / lposix.c
blobfaf71a66f762d6129d0a6e4b90230d54b9c4edae
1 #if defined(LUA_USE_POSIX) || defined(LUA_USE_LINUX)
3 /*
4 * lposix.c
5 * POSIX library for Lua 5.0. Based on original by Claudio Terra for Lua 3.x.
6 * Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
7 * 05 Nov 2003 22:09:10
9 */
11 #include <dirent.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <grp.h>
15 #include <pwd.h>
16 #include <signal.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/stat.h>
21 #include <sys/times.h>
22 #include <sys/types.h>
23 #include <sys/utsname.h>
24 #include <sys/wait.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <utime.h>
29 #define MYNAME "posix"
30 #define MYVERSION MYNAME " library for " LUA_VERSION " / Nov 2003"
32 #include "lua.h"
33 #include "lauxlib.h"
35 #ifndef MYBUFSIZ
36 #define MYBUFSIZ 512
37 #endif
39 /*
40 Mode Muncher -- modemuncher.c
41 961110 Claudio Terra
43 munch vb
44 [ME monchen, perh. influenced by MF mangier to eat --more at MANGER]
45 :to chew with a crunching sound: eat with relish
46 :to chew food with a crunching sound: eat food with relish
47 --munch-er n
49 The NeXT Digital Edition of Webster's Ninth New Collegiate Dictionary
50 and Webster's Collegiate Thesaurus
53 /* struct for rwx <-> POSIX constant lookup tables */
54 struct modeLookup
56 char rwx;
57 mode_t bits;
60 typedef struct modeLookup modeLookup;
62 static modeLookup modesel[] =
64 /* RWX char Posix Constant */
65 {'r', S_IRUSR},
66 {'w', S_IWUSR},
67 {'x', S_IXUSR},
69 {'r', S_IRGRP},
70 {'w', S_IWGRP},
71 {'x', S_IXGRP},
73 {'r', S_IROTH},
74 {'w', S_IWOTH},
75 {'x', S_IXOTH},
76 {0, (mode_t)-1} /* do not delete this line */
81 static int rwxrwxrwx(mode_t *mode, const char *p)
83 int count;
84 mode_t tmp_mode = *mode;
86 tmp_mode &= ~(S_ISUID | S_ISGID); /* turn off suid and sgid flags */
87 for (count=0; count<9; count ++)
89 if (*p == modesel[count].rwx) tmp_mode |= modesel[count].bits; /* set a bit */
90 else if (*p == '-') tmp_mode &= ~modesel[count].bits; /* clear a bit */
91 else if (*p=='s') switch(count)
93 case 2: /* turn on suid flag */
94 tmp_mode |= S_ISUID | S_IXUSR;
95 break;
97 case 5: /* turn on sgid flag */
98 tmp_mode |= S_ISGID | S_IXGRP;
99 break;
101 default:
102 return -4; /* failed! -- bad rwxrwxrwx mode change */
103 break;
105 p++;
107 *mode = tmp_mode;
108 return 0;
111 static void modechopper(mode_t mode, char *p)
113 /* requires char p[10] */
114 int count;
115 char *pp;
117 pp=p;
119 for (count=0; count<9; count ++)
121 if (mode & modesel[count].bits) *p = modesel[count].rwx;
122 else *p='-';
124 p++;
126 *p=0; /* to finish the string */
128 /* dealing with suid and sgid flags */
129 if (mode & S_ISUID) pp[2] = (mode & S_IXUSR) ? 's' : 'S';
130 if (mode & S_ISGID) pp[5] = (mode & S_IXGRP) ? 's' : 'S';
134 static int mode_munch(mode_t *mode, const char* p)
137 char op=0;
138 mode_t affected_bits, ch_mode;
139 int doneFlag = 0;
140 #ifdef DEBUG
141 char tmp[10];
142 #endif
144 #ifdef DEBUG
145 modechopper(*mode, tmp);
146 printf("modemuncher: got base mode = %s\n", tmp);
147 #endif
149 while (!doneFlag)
151 /* step 0 -- clear temporary variables */
152 affected_bits=0;
153 ch_mode=0;
155 /* step 1 -- who's affected? */
157 #ifdef DEBUG
158 printf("modemuncher step 1\n");
159 #endif
161 /* mode string given in rwxrwxrwx format */
162 if (*p== 'r' || *p == '-') return rwxrwxrwx(mode, p);
164 /* mode string given in ugoa+-=rwx format */
165 for ( ; ; p++)
166 switch (*p)
168 case 'u':
169 affected_bits |= 04700;
170 break;
172 case 'g':
173 affected_bits |= 02070;
174 break;
176 case 'o':
177 affected_bits |= 01007;
178 break;
180 case 'a':
181 affected_bits |= 07777;
182 break;
184 /* ignore spaces */
185 case ' ':
186 break;
189 default:
190 goto no_more_affected;
193 no_more_affected:
194 /* If none specified, affect all bits. */
195 if (affected_bits == 0) affected_bits = 07777;
197 /* step 2 -- how is it changed? */
199 #ifdef DEBUG
200 printf("modemuncher step 2 (*p='%c')\n", *p);
201 #endif
203 switch (*p)
205 case '+':
206 case '-':
207 case '=':
208 op = *p;
209 break;
211 /* ignore spaces */
212 case ' ':
213 break;
215 default:
216 return -1; /* failed! -- bad operator */
220 /* step 3 -- what are the changes? */
222 #ifdef DEBUG
223 printf("modemuncher step 3\n");
224 #endif
226 for (p++ ; *p!=0 ; p++)
227 switch (*p)
229 case 'r':
230 ch_mode |= 00444;
231 break;
233 case 'w':
234 ch_mode |= 00222;
235 break;
237 case 'x':
238 ch_mode |= 00111;
239 break;
241 case 's':
242 /* Set the setuid/gid bits if `u' or `g' is selected. */
243 ch_mode |= 06000;
244 break;
246 /* ignore spaces */
247 case ' ':
248 break;
250 default:
251 goto specs_done;
254 specs_done:
255 /* step 4 -- apply the changes */
257 #ifdef DEBUG
258 printf("modemuncher step 4\n");
259 #endif
260 if (*p != ',') doneFlag = 1;
261 if (*p != 0 && *p != ' ' && *p != ',')
264 #ifdef DEBUG
265 printf("modemuncher: comma error!\n");
266 printf("modemuncher: doneflag = %u\n", doneFlag);
267 #endif
268 return -2; /* failed! -- bad mode change */
271 p++;
272 /*if (!ch_mode) return -2;*/ /* failed! -- bad mode change */
273 if (ch_mode) switch (op)
275 case '+':
276 *mode = *mode |= ch_mode & affected_bits;
277 break;
279 case '-':
280 *mode = *mode &= ~(ch_mode & affected_bits);
281 break;
283 case '=':
284 *mode = ch_mode & affected_bits;
285 break;
287 default:
288 return -3; /* failed! -- unknown error */
291 #ifdef DEBUG
292 modechopper(*mode, tmp);
293 printf("modemuncher: returning mode = %s\n", tmp);
294 #endif
296 return 0; /* successful call */
300 static const char *filetype(mode_t m)
302 if (S_ISREG(m)) return "regular";
303 else if (S_ISLNK(m)) return "link";
304 else if (S_ISDIR(m)) return "directory";
305 else if (S_ISCHR(m)) return "character device";
306 else if (S_ISBLK(m)) return "block device";
307 else if (S_ISFIFO(m)) return "fifo";
308 else if (S_ISSOCK(m)) return "socket";
309 else return "?";
312 typedef int (*Selector)(lua_State *L, int i, const void *data);
314 static int doselection(lua_State *L, int i, const char *const S[], Selector F, const void *data)
316 if (lua_isnone(L, i))
318 lua_newtable(L);
319 for (i=0; S[i]!=NULL; i++)
321 lua_pushstring(L, S[i]);
322 F(L, i, data);
323 lua_settable(L, -3);
325 return 1;
327 else
329 int j;
330 const char *s=luaL_checkstring(L, i);
331 for (j=0;S[j];j++) if (!strcmp(S[j],s)) break;
332 if (!S[j]) luaL_argerror(L, i, "unknown selector");
333 return F(L, j, data);
337 static void storeindex(lua_State *L, int i, const char *value)
339 lua_pushstring(L, value);
340 lua_rawseti(L, -2, i);
343 static void storestring(lua_State *L, const char *name, const char *value)
345 lua_pushstring(L, name);
346 lua_pushstring(L, value);
347 lua_settable(L, -3);
350 static void storenumber(lua_State *L, const char *name, lua_Number value)
352 lua_pushstring(L, name);
353 lua_pushnumber(L, value);
354 lua_settable(L, -3);
357 static int pusherror(lua_State *L, const char *info)
359 lua_pushnil(L);
360 if (info==NULL)
361 lua_pushstring(L, strerror(errno));
362 else
363 lua_pushfstring(L, "%s: %s", info, strerror(errno));
364 lua_pushnumber(L, errno);
365 return 3;
368 static int pushresult(lua_State *L, int i, const char *info)
370 if (i != -1)
372 lua_pushnumber(L, i);
373 return 1;
375 else
376 return pusherror(L, info);
379 static void badoption(lua_State *L, int i, const char *what, int option)
381 luaL_argerror(L, 2,
382 lua_pushfstring(L, "unknown %s option `%c'", what, option));
385 static uid_t mygetuid(lua_State *L, int i)
387 if (lua_isnone(L, i))
388 return -1;
389 else if (lua_isnumber(L, i))
390 return (uid_t) lua_tonumber(L, i);
391 else if (lua_isstring(L, i))
393 struct passwd *p=getpwnam(lua_tostring(L, i));
394 return (p==NULL) ? -1 : p->pw_uid;
396 else
397 return luaL_typerror(L, i, "string or number");
400 static gid_t mygetgid(lua_State *L, int i)
402 if (lua_isnone(L, i))
403 return -1;
404 else if (lua_isnumber(L, i))
405 return (gid_t) lua_tonumber(L, i);
406 else if (lua_isstring(L, i))
408 struct group *g=getgrnam(lua_tostring(L, i));
409 return (g==NULL) ? -1 : g->gr_gid;
411 else
412 return luaL_typerror(L, i, "string or number");
417 static int Perrno(lua_State *L) /** errno() */
419 lua_pushstring(L, strerror(errno));
420 lua_pushnumber(L, errno);
421 return 2;
425 static int Pdir(lua_State *L) /** dir([path]) */
427 const char *path = luaL_optstring(L, 1, ".");
428 DIR *d = opendir(path);
429 if (d == NULL)
430 return pusherror(L, path);
431 else
433 int i;
434 struct dirent *entry;
435 lua_newtable(L);
436 for (i=1; (entry = readdir(d)) != NULL; i++)
437 storeindex(L, i, entry->d_name);
438 closedir(d);
439 return 1;
444 static int aux_files(lua_State *L)
446 DIR *d = lua_touserdata(L, lua_upvalueindex(1));
447 struct dirent *entry;
448 if (d == NULL) luaL_error(L, "attempt to use closed dir");
449 entry = readdir(d);
450 if (entry == NULL)
452 closedir(d);
453 lua_pushnil(L);
454 lua_replace(L, lua_upvalueindex(1));
455 lua_pushnil(L);
457 else
459 lua_pushstring(L, entry->d_name);
460 #if 0
461 #ifdef _DIRENT_HAVE_D_TYPE
462 lua_pushstring(L, filetype(DTTOIF(entry->d_type)));
463 return 2;
464 #endif
465 #endif
467 return 1;
470 static int Pfiles(lua_State *L) /** files([path]) */
472 const char *path = luaL_optstring(L, 1, ".");
473 DIR *d = opendir(path);
474 if (d == NULL)
475 return pusherror(L, path);
476 else
478 lua_pushlightuserdata(L, d);
479 lua_pushcclosure(L, aux_files, 1);
480 return 1;
485 static int Pgetcwd(lua_State *L) /** getcwd() */
487 char buf[MYBUFSIZ];
488 if (getcwd(buf, sizeof(buf)) == NULL)
489 return pusherror(L, ".");
490 else
492 lua_pushstring(L, buf);
493 return 1;
498 static int Pmkdir(lua_State *L) /** mkdir(path) */
500 const char *path = luaL_checkstring(L, 1);
501 return pushresult(L, mkdir(path, 0777), path);
505 static int Pchdir(lua_State *L) /** chdir(path) */
507 const char *path = luaL_checkstring(L, 1);
508 return pushresult(L, chdir(path), path);
512 static int Prmdir(lua_State *L) /** rmdir(path) */
514 const char *path = luaL_checkstring(L, 1);
515 return pushresult(L, rmdir(path), path);
519 static int Punlink(lua_State *L) /** unlink(path) */
521 const char *path = luaL_checkstring(L, 1);
522 return pushresult(L, unlink(path), path);
526 static int Plink(lua_State *L) /** link(oldpath,newpath) */
528 const char *oldpath = luaL_checkstring(L, 1);
529 const char *newpath = luaL_checkstring(L, 2);
530 return pushresult(L, link(oldpath, newpath), NULL);
534 static int Psymlink(lua_State *L) /** symlink(oldpath,newpath) */
536 const char *oldpath = luaL_checkstring(L, 1);
537 const char *newpath = luaL_checkstring(L, 2);
538 return pushresult(L, symlink(oldpath, newpath), NULL);
542 static int Preadlink(lua_State *L) /** readlink(path) */
544 char buf[MYBUFSIZ];
545 const char *path = luaL_checkstring(L, 1);
546 int n = readlink(path, buf, sizeof(buf));
547 if (n==-1) return pusherror(L, path);
548 lua_pushlstring(L, buf, n);
549 return 1;
553 static int Paccess(lua_State *L) /** access(path,[mode]) */
555 int mode=F_OK;
556 const char *path=luaL_checkstring(L, 1);
557 const char *s;
558 for (s=luaL_optstring(L, 2, "f"); *s!=0 ; s++)
559 switch (*s)
561 case ' ': break;
562 case 'r': mode |= R_OK; break;
563 case 'w': mode |= W_OK; break;
564 case 'x': mode |= X_OK; break;
565 case 'f': mode |= F_OK; break;
566 default: badoption(L, 2, "mode", *s); break;
568 return pushresult(L, access(path, mode), path);
572 static int Pmkfifo(lua_State *L) /** mkfifo(path) */
574 const char *path = luaL_checkstring(L, 1);
575 return pushresult(L, mkfifo(path, 0777), path);
579 static int Pexec(lua_State *L) /** exec(path,[args]) */
581 const char *path = luaL_checkstring(L, 1);
582 int i,n=lua_gettop(L);
583 char **argv = malloc((n+1)*sizeof(char*));
584 if (argv==NULL) luaL_error(L,"not enough memory");
585 argv[0] = (char*)path;
586 for (i=1; i<n; i++) argv[i] = (char*)luaL_checkstring(L, i+1);
587 argv[i] = NULL;
588 execvp(path,argv);
589 return pusherror(L, path);
593 static int Pfork(lua_State *L) /** fork() */
595 return pushresult(L, fork(), NULL);
599 static int Pwait(lua_State *L) /** wait([pid]) */
601 pid_t pid = luaL_optint(L, 1, -1);
602 return pushresult(L, waitpid(pid, NULL, 0), NULL);
606 static int Pkill(lua_State *L) /** kill(pid,[sig]) */
608 pid_t pid = luaL_checkint(L, 1);
609 int sig = luaL_optint(L, 2, SIGTERM);
610 return pushresult(L, kill(pid, sig), NULL);
614 static int Psleep(lua_State *L) /** sleep(seconds) */
616 unsigned int seconds = luaL_checkint(L, 1);
617 lua_pushnumber(L, sleep(seconds));
618 return 1;
622 static int Pputenv(lua_State *L) /** putenv(string) */
624 size_t l;
625 const char *s=luaL_checklstring(L, 1, &l);
626 char *e=malloc(++l);
627 return pushresult(L, (e==NULL) ? -1 : putenv(memcpy(e,s,l)), s);
631 #ifdef linux
632 static int Psetenv(lua_State *L) /** setenv(name,value,[over]) */
634 const char *name=luaL_checkstring(L, 1);
635 const char *value=luaL_checkstring(L, 2);
636 int overwrite=lua_isnoneornil(L, 3) || lua_toboolean(L, 3);
637 return pushresult(L, setenv(name,value,overwrite), name);
641 static int Punsetenv(lua_State *L) /** unsetenv(name) */
643 const char *name=luaL_checkstring(L, 1);
644 unsetenv(name);
645 return 0;
647 #endif
650 static int Pgetenv(lua_State *L) /** getenv([name]) */
652 if (lua_isnone(L, 1))
654 extern char **environ;
655 char **e;
656 if (*environ==NULL) lua_pushnil(L); else lua_newtable(L);
657 for (e=environ; *e!=NULL; e++)
659 char *s=*e;
660 char *eq=strchr(s, '=');
661 if (eq==NULL) /* will this ever happen? */
663 lua_pushstring(L,s);
664 lua_pushboolean(L,0);
666 else
668 lua_pushlstring(L,s,eq-s);
669 lua_pushstring(L,eq+1);
671 lua_settable(L,-3);
674 else
675 lua_pushstring(L, getenv(luaL_checkstring(L, 1)));
676 return 1;
680 static int Pumask(lua_State *L) /** umask([mode]) */
682 char m[10];
683 mode_t mode;
684 umask(mode=umask(0));
685 mode=(~mode)&0777;
686 if (!lua_isnone(L, 1))
688 if (mode_munch(&mode, luaL_checkstring(L, 1)))
690 lua_pushnil(L);
691 return 1;
693 mode&=0777;
694 umask(~mode);
696 modechopper(mode, m);
697 lua_pushstring(L, m);
698 return 1;
702 static int Pchmod(lua_State *L) /** chmod(path,mode) */
704 mode_t mode;
705 struct stat s;
706 const char *path = luaL_checkstring(L, 1);
707 const char *modestr = luaL_checkstring(L, 2);
708 if (stat(path, &s)) return pusherror(L, path);
709 mode = s.st_mode;
710 if (mode_munch(&mode, modestr)) luaL_argerror(L, 2, "bad mode");
711 return pushresult(L, chmod(path, mode), path);
715 static int Pchown(lua_State *L) /** chown(path,uid,gid) */
717 const char *path = luaL_checkstring(L, 1);
718 uid_t uid = mygetuid(L, 2);
719 gid_t gid = mygetgid(L, 3);
720 return pushresult(L, chown(path, uid, gid), path);
724 static int Putime(lua_State *L) /** utime(path,[mtime,atime]) */
726 struct utimbuf times;
727 time_t currtime = time(NULL);
728 const char *path = luaL_checkstring(L, 1);
729 times.modtime = luaL_optnumber(L, 2, currtime);
730 times.actime = luaL_optnumber(L, 3, currtime);
731 return pushresult(L, utime(path, &times), path);
735 static int FgetID(lua_State *L, int i, const void *data)
737 switch (i)
739 case 0: lua_pushnumber(L, getegid()); break;
740 case 1: lua_pushnumber(L, geteuid()); break;
741 case 2: lua_pushnumber(L, getgid()); break;
742 case 3: lua_pushnumber(L, getuid()); break;
743 case 4: lua_pushnumber(L, getpgrp()); break;
744 case 5: lua_pushnumber(L, getpid()); break;
745 case 6: lua_pushnumber(L, getppid()); break;
747 return 1;
750 static const char *const SgetID[] =
752 "egid", "euid", "gid", "uid", "pgrp", "pid", "ppid", NULL
755 static int Pgetprocessid(lua_State *L) /** getprocessid([selector]) */
757 return doselection(L, 1, SgetID, FgetID, NULL);
761 static int Pttyname(lua_State *L) /** ttyname(fd) */
763 int fd=luaL_optint(L, 1, 0);
764 lua_pushstring(L, ttyname(fd));
765 return 1;
768 static int Pctermid(lua_State *L) /** ctermid() */
770 char b[L_ctermid];
771 lua_pushstring(L, ctermid(b));
772 return 1;
776 static int Pgetlogin(lua_State *L) /** getlogin() */
778 lua_pushstring(L, getlogin());
779 return 1;
783 static int Fgetpasswd(lua_State *L, int i, const void *data)
785 const struct passwd *p=data;
786 switch (i)
788 case 0: lua_pushstring(L, p->pw_name); break;
789 case 1: lua_pushnumber(L, p->pw_uid); break;
790 case 2: lua_pushnumber(L, p->pw_gid); break;
791 case 3: lua_pushstring(L, p->pw_dir); break;
792 case 4: lua_pushstring(L, p->pw_shell); break;
793 /* not strictly POSIX */
794 case 5: lua_pushstring(L, p->pw_gecos); break;
795 case 6: lua_pushstring(L, p->pw_passwd); break;
797 return 1;
800 static const char *const Sgetpasswd[] =
802 "name", "uid", "gid", "dir", "shell", "gecos", "passwd", NULL
806 static int Pgetpasswd(lua_State *L) /** getpasswd(name or id) */
808 struct passwd *p=NULL;
809 if (lua_isnoneornil(L, 1))
810 p = getpwuid(geteuid());
811 else if (lua_isnumber(L, 1))
812 p = getpwuid((uid_t)lua_tonumber(L, 1));
813 else if (lua_isstring(L, 1))
814 p = getpwnam(lua_tostring(L, 1));
815 else
816 luaL_typerror(L, 1, "string or number");
817 if (p==NULL)
818 lua_pushnil(L);
819 else
820 doselection(L, 2, Sgetpasswd, Fgetpasswd, p);
821 return 1;
825 static int Pgetgroup(lua_State *L) /** getgroup(name or id) */
827 struct group *g=NULL;
828 if (lua_isnumber(L, 1))
829 g = getgrgid((gid_t)lua_tonumber(L, 1));
830 else if (lua_isstring(L, 1))
831 g = getgrnam(lua_tostring(L, 1));
832 else
833 luaL_typerror(L, 1, "string or number");
834 if (g==NULL)
835 lua_pushnil(L);
836 else
838 int i;
839 lua_newtable(L);
840 storestring(L, "name", g->gr_name);
841 storenumber(L, "gid", g->gr_gid);
842 for (i=0; g->gr_mem[i] != NULL; i++)
843 storeindex(L, i+1, g->gr_mem[i]);
845 return 1;
849 static int Psetuid(lua_State *L) /** setuid(name or id) */
851 return pushresult(L, setuid(mygetuid(L, 1)), NULL);
855 static int Psetgid(lua_State *L) /** setgid(name or id) */
857 return pushresult(L, setgid(mygetgid(L, 1)), NULL);
860 struct mytimes
862 struct tms t;
863 clock_t elapsed;
866 #define pushtime(L,x) lua_pushnumber(L,((lua_Number)x)/CLK_TCK)
868 #ifndef CLK_TCK
869 #define CLK_TCK CLOCKS_PER_SEC
870 #endif
872 static int Ftimes(lua_State *L, int i, const void *data)
874 const struct mytimes *t=data;
875 switch (i)
877 case 0: pushtime(L, t->t.tms_utime); break;
878 case 1: pushtime(L, t->t.tms_stime); break;
879 case 2: pushtime(L, t->t.tms_cutime); break;
880 case 3: pushtime(L, t->t.tms_cstime); break;
881 case 4: pushtime(L, t->elapsed); break;
883 return 1;
886 static const char *const Stimes[] =
888 "utime", "stime", "cutime", "cstime", "elapsed", NULL
891 #define storetime(L,name,x) storenumber(L,name,(lua_Number)x/CLK_TCK)
893 static int Ptimes(lua_State *L) /** times() */
895 struct mytimes t;
896 t.elapsed = times(&t.t);
897 return doselection(L, 1, Stimes, Ftimes, &t);
901 struct mystat
903 struct stat s;
904 char mode[10];
905 const char *type;
908 static int Fstat(lua_State *L, int i, const void *data)
910 const struct mystat *s=data;
911 switch (i)
913 case 0: lua_pushstring(L, s->mode); break;
914 case 1: lua_pushnumber(L, s->s.st_ino); break;
915 case 2: lua_pushnumber(L, s->s.st_dev); break;
916 case 3: lua_pushnumber(L, s->s.st_nlink); break;
917 case 4: lua_pushnumber(L, s->s.st_uid); break;
918 case 5: lua_pushnumber(L, s->s.st_gid); break;
919 case 6: lua_pushnumber(L, s->s.st_size); break;
920 case 7: lua_pushnumber(L, s->s.st_atime); break;
921 case 8: lua_pushnumber(L, s->s.st_mtime); break;
922 case 9: lua_pushnumber(L, s->s.st_ctime); break;
923 case 10:lua_pushstring(L, s->type); break;
924 case 11:lua_pushnumber(L, s->s.st_mode); break;
926 return 1;
929 static const char *const Sstat[] =
931 "mode", "ino", "dev", "nlink", "uid", "gid",
932 "size", "atime", "mtime", "ctime", "type", "_mode",
933 NULL
936 static int Pstat(lua_State *L) /** stat(path,[selector]) */
938 struct mystat s;
939 const char *path=luaL_checkstring(L, 1);
940 if (lstat(path,&s.s)==-1) return pusherror(L, path);
941 s.type=filetype(s.s.st_mode);
942 modechopper(s.s.st_mode, s.mode);
943 return doselection(L, 2, Sstat, Fstat, &s);
947 static int Puname(lua_State *L) /** uname([string]) */
949 struct utsname u;
950 luaL_Buffer b;
951 const char *s;
952 if (uname(&u) == -1) return pusherror(L, NULL);
953 luaL_buffinit(L, &b);
954 for (s=luaL_optstring(L, 1, "%s %n %r %v %m"); *s; s++)
955 if (*s!='%')
956 luaL_putchar(&b, *s);
957 else switch (*++s)
959 case '%': luaL_putchar(&b, *s); break;
960 case 'm': luaL_addstring(&b,u.machine); break;
961 case 'n': luaL_addstring(&b,u.nodename); break;
962 case 'r': luaL_addstring(&b,u.release); break;
963 case 's': luaL_addstring(&b,u.sysname); break;
964 case 'v': luaL_addstring(&b,u.version); break;
965 default: badoption(L, 2, "format", *s); break;
967 luaL_pushresult(&b);
968 return 1;
972 static const int Kpathconf[] =
974 _PC_LINK_MAX, _PC_MAX_CANON, _PC_MAX_INPUT, _PC_NAME_MAX, _PC_PATH_MAX,
975 _PC_PIPE_BUF, _PC_CHOWN_RESTRICTED, _PC_NO_TRUNC, _PC_VDISABLE,
979 static int Fpathconf(lua_State *L, int i, const void *data)
981 const char *path=data;
982 lua_pushnumber(L, pathconf(path, Kpathconf[i]));
983 return 1;
986 static const char *const Spathconf[] =
988 "link_max", "max_canon", "max_input", "name_max", "path_max",
989 "pipe_buf", "chown_restricted", "no_trunc", "vdisable",
990 NULL
993 static int Ppathconf(lua_State *L) /** pathconf(path,[selector]) */
995 const char *path=luaL_checkstring(L, 1);
996 return doselection(L, 2, Spathconf, Fpathconf, path);
1000 static const int Ksysconf[] =
1002 _SC_ARG_MAX, _SC_CHILD_MAX, _SC_CLK_TCK, _SC_NGROUPS_MAX, _SC_STREAM_MAX,
1003 _SC_TZNAME_MAX, _SC_OPEN_MAX, _SC_JOB_CONTROL, _SC_SAVED_IDS, _SC_VERSION,
1007 static int Fsysconf(lua_State *L, int i, const void *data)
1009 lua_pushnumber(L, sysconf(Ksysconf[i]));
1010 return 1;
1013 static const char *const Ssysconf[] =
1015 "arg_max", "child_max", "clk_tck", "ngroups_max", "stream_max",
1016 "tzname_max", "open_max", "job_control", "saved_ids", "version",
1017 NULL
1020 static int Psysconf(lua_State *L) /** sysconf([selector]) */
1022 return doselection(L, 1, Ssysconf, Fsysconf, NULL);
1026 static const luaL_reg R[] =
1028 {"access", Paccess},
1029 {"chdir", Pchdir},
1030 {"chmod", Pchmod},
1031 {"chown", Pchown},
1032 {"ctermid", Pctermid},
1033 {"dir", Pdir},
1034 {"errno", Perrno},
1035 {"exec", Pexec},
1036 {"files", Pfiles},
1037 {"fork", Pfork},
1038 {"getcwd", Pgetcwd},
1039 {"getenv", Pgetenv},
1040 {"getgroup", Pgetgroup},
1041 {"getlogin", Pgetlogin},
1042 {"getpasswd", Pgetpasswd},
1043 {"getprocessid", Pgetprocessid},
1044 {"kill", Pkill},
1045 {"link", Plink},
1046 {"mkdir", Pmkdir},
1047 {"mkfifo", Pmkfifo},
1048 {"pathconf", Ppathconf},
1049 {"putenv", Pputenv},
1050 {"readlink", Preadlink},
1051 {"rmdir", Prmdir},
1052 {"setgid", Psetgid},
1053 {"setuid", Psetuid},
1054 {"sleep", Psleep},
1055 {"stat", Pstat},
1056 {"symlink", Psymlink},
1057 {"sysconf", Psysconf},
1058 {"times", Ptimes},
1059 {"ttyname", Pttyname},
1060 {"umask", Pumask},
1061 {"uname", Puname},
1062 {"unlink", Punlink},
1063 {"utime", Putime},
1064 {"wait", Pwait},
1066 #ifdef linux
1067 {"setenv", Psetenv},
1068 {"unsetenv", Punsetenv},
1069 #endif
1070 {NULL, NULL}
1073 LUALIB_API int luaopen_posix (lua_State *L)
1075 luaL_openlib(L, MYNAME, R, 0);
1076 lua_pushliteral(L,"version"); /** version */
1077 lua_pushliteral(L,MYVERSION);
1078 lua_settable(L,-3);
1079 return 1;
1083 #endif