Imported Upstream version 4.14.1
[platform/upstream/rpm.git] / luaext / lposix.c
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 */
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <dirent.h>
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <grp.h>
16 #include <pwd.h>
17 #include <signal.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/stat.h>
22 #include <sys/times.h>
23 #include <sys/types.h>
24 #include <sys/utsname.h>
25 #include <sys/wait.h>
26 #include <time.h>
27 #include <unistd.h>
28 #include <utime.h>
29 #include <rpm/rpmutil.h>
30
31 #define MYNAME          "posix"
32 #define MYVERSION       MYNAME " library for " LUA_VERSION " / Nov 2003"
33
34 #include "lua.h"
35 #include "lauxlib.h"
36 #include "lposix.h"
37
38
39 #ifndef MYBUFSIZ
40 #define MYBUFSIZ 512
41 #endif
42
43 #include "modemuncher.c"
44
45 static int have_forked = 0;
46
47 static const char *filetype(mode_t m)
48 {
49         if (S_ISREG(m))         return "regular";
50         else if (S_ISLNK(m))    return "link";
51         else if (S_ISDIR(m))    return "directory";
52         else if (S_ISCHR(m))    return "character device";
53         else if (S_ISBLK(m))    return "block device";
54         else if (S_ISFIFO(m))   return "fifo";
55         else if (S_ISSOCK(m))   return "socket";
56         else                    return "?";
57 }
58
59 typedef int (*Selector)(lua_State *L, int i, const void *data);
60
61 /* implemented as luaL_typerror until lua 5.1, dropped in 5.2
62  * (C) 1994-2012 Lua.org, PUC-Rio. MIT license
63  */
64 static int typerror (lua_State *L, int narg, const char *tname) {
65         const char *msg = lua_pushfstring(L, "%s expected, got %s",
66                                           tname, luaL_typename(L, narg));
67         return luaL_argerror(L, narg, msg);
68 }
69
70 static int doselection(lua_State *L, int i, const char *const S[], Selector F, const void *data)
71 {
72         if (lua_isnone(L, i))
73         {
74                 lua_newtable(L);
75                 for (i=0; S[i]!=NULL; i++)
76                 {
77                         lua_pushstring(L, S[i]);
78                         F(L, i, data);
79                         lua_settable(L, -3);
80                 }
81                 return 1;
82         }
83         else
84         {
85                 int j=luaL_checkoption(L, i, NULL, S);
86                 if (j==-1) luaL_argerror(L, i, "unknown selector");
87                 return F(L, j, data);
88         }
89 }
90
91 static void storeindex(lua_State *L, int i, const char *value)
92 {
93         lua_pushstring(L, value);
94         lua_rawseti(L, -2, i);
95 }
96
97 static void storestring(lua_State *L, const char *name, const char *value)
98 {
99         lua_pushstring(L, name);
100         lua_pushstring(L, value);
101         lua_settable(L, -3);
102 }
103
104 static void storenumber(lua_State *L, const char *name, lua_Number value)
105 {
106         lua_pushstring(L, name);
107         lua_pushnumber(L, value);
108         lua_settable(L, -3);
109 }
110
111 static int pusherror(lua_State *L, const char *info)
112 {
113         lua_pushnil(L);
114         if (info==NULL)
115                 lua_pushstring(L, strerror(errno));
116         else
117                 lua_pushfstring(L, "%s: %s", info, strerror(errno));
118         lua_pushnumber(L, errno);
119         return 3;
120 }
121
122 static int pushresult(lua_State *L, int i, const char *info)
123 {
124         if (i != -1)
125         {
126                 lua_pushnumber(L, i);
127                 return 1;
128         }
129         else
130                 return pusherror(L, info);
131 }
132
133 static void badoption(lua_State *L, int i, const char *what, int option)
134 {
135         luaL_argerror(L, 2,
136                 lua_pushfstring(L, "unknown %s option `%c'", what, option));
137 }
138
139 static uid_t mygetuid(lua_State *L, int i)
140 {
141         if (lua_isnone(L, i))
142                 return -1;
143         else if (lua_isnumber(L, i))
144                 return (uid_t) lua_tonumber(L, i);
145         else if (lua_isstring(L, i))
146         {
147                 struct passwd *p=getpwnam(lua_tostring(L, i));
148                 return (p==NULL) ? -1 : p->pw_uid;
149         }
150         else
151                 return typerror(L, i, "string or number");
152 }
153
154 static gid_t mygetgid(lua_State *L, int i)
155 {
156         if (lua_isnone(L, i))
157                 return -1;
158         else if (lua_isnumber(L, i))
159                 return (gid_t) lua_tonumber(L, i);
160         else if (lua_isstring(L, i))
161         {
162                 struct group *g=getgrnam(lua_tostring(L, i));
163                 return (g==NULL) ? -1 : g->gr_gid;
164         }
165         else
166                 return typerror(L, i, "string or number");
167 }
168
169
170
171 static int Perrno(lua_State *L)                 /** errno() */
172 {
173         lua_pushstring(L, strerror(errno));
174         lua_pushnumber(L, errno);
175         return 2;
176 }
177
178
179 static int Pdir(lua_State *L)                   /** dir([path]) */
180 {
181         const char *path = luaL_optstring(L, 1, ".");
182         DIR *d = opendir(path);
183         if (d == NULL)
184                 return pusherror(L, path);
185         else
186         {
187                 int i;
188                 struct dirent *entry;
189                 lua_newtable(L);
190                 for (i=1; (entry = readdir(d)) != NULL; i++)
191                         storeindex(L, i, entry->d_name);
192                 closedir(d);
193                 return 1;
194         }
195 }
196
197
198 static int aux_files(lua_State *L)
199 {
200         DIR *d = lua_touserdata(L, lua_upvalueindex(1));
201         struct dirent *entry;
202         if (d == NULL) return luaL_error(L, "attempt to use closed dir");
203         entry = readdir(d);
204         if (entry == NULL)
205         {
206                 closedir(d);
207                 lua_pushnil(L);
208                 lua_replace(L, lua_upvalueindex(1));
209                 lua_pushnil(L);
210         }
211         else
212         {
213                 lua_pushstring(L, entry->d_name);
214 #if 0
215 #ifdef _DIRENT_HAVE_D_TYPE
216                 lua_pushstring(L, filetype(DTTOIF(entry->d_type)));
217                 return 2;
218 #endif
219 #endif
220         }
221         return 1;
222 }
223
224 static int Pfiles(lua_State *L)                 /** files([path]) */
225 {
226         const char *path = luaL_optstring(L, 1, ".");
227         DIR *d = opendir(path);
228         if (d == NULL)
229                 return pusherror(L, path);
230         else
231         {
232                 lua_pushlightuserdata(L, d);
233                 lua_pushcclosure(L, aux_files, 1);
234                 return 1;
235         }
236 }
237
238
239 static int Pgetcwd(lua_State *L)                /** getcwd() */
240 {
241         char buf[MYBUFSIZ];
242         if (getcwd(buf, sizeof(buf)) == NULL)
243                 return pusherror(L, ".");
244         else
245         {
246                 lua_pushstring(L, buf);
247                 return 1;
248         }
249 }
250
251
252 static int Pmkdir(lua_State *L)                 /** mkdir(path) */
253 {
254         const char *path = luaL_checkstring(L, 1);
255         return pushresult(L, mkdir(path, 0777), path);
256 }
257
258
259 static int Pchdir(lua_State *L)                 /** chdir(path) */
260 {
261         const char *path = luaL_checkstring(L, 1);
262         return pushresult(L, chdir(path), path);
263 }
264
265
266 static int Prmdir(lua_State *L)                 /** rmdir(path) */
267 {
268         const char *path = luaL_checkstring(L, 1);
269         return pushresult(L, rmdir(path), path);
270 }
271
272
273 static int Punlink(lua_State *L)                /** unlink(path) */
274 {
275         const char *path = luaL_checkstring(L, 1);
276         return pushresult(L, unlink(path), path);
277 }
278
279
280 static int Plink(lua_State *L)                  /** link(oldpath,newpath) */
281 {
282         const char *oldpath = luaL_checkstring(L, 1);
283         const char *newpath = luaL_checkstring(L, 2);
284         return pushresult(L, link(oldpath, newpath), NULL);
285 }
286
287
288 static int Psymlink(lua_State *L)               /** symlink(oldpath,newpath) */
289 {
290         const char *oldpath = luaL_checkstring(L, 1);
291         const char *newpath = luaL_checkstring(L, 2);
292         return pushresult(L, symlink(oldpath, newpath), NULL);
293 }
294
295
296 static int Preadlink(lua_State *L)              /** readlink(path) */
297 {
298         char buf[MYBUFSIZ];
299         const char *path = luaL_checkstring(L, 1);
300         int n = readlink(path, buf, sizeof(buf));
301         if (n==-1) return pusherror(L, path);
302         lua_pushlstring(L, buf, n);
303         return 1;
304 }
305
306
307 static int Paccess(lua_State *L)                /** access(path,[mode]) */
308 {
309         int mode=F_OK;
310         const char *path=luaL_checkstring(L, 1);
311         const char *s;
312         for (s=luaL_optstring(L, 2, "f"); *s!=0 ; s++)
313                 switch (*s)
314                 {
315                         case ' ': break;
316                         case 'r': mode |= R_OK; break;
317                         case 'w': mode |= W_OK; break;
318                         case 'x': mode |= X_OK; break;
319                         case 'f': mode |= F_OK; break;
320                         default: badoption(L, 2, "mode", *s); break;
321                 }
322         return pushresult(L, access(path, mode), path);
323 }
324
325
326 static int Pmkfifo(lua_State *L)                /** mkfifo(path) */
327 {
328         const char *path = luaL_checkstring(L, 1);
329         return pushresult(L, mkfifo(path, 0777), path);
330 }
331
332
333 static int Pexec(lua_State *L)                  /** exec(path,[args]) */
334 {
335         const char *path = luaL_checkstring(L, 1);
336         int i,n=lua_gettop(L);
337         char **argv;
338         int flag, fdno, open_max;
339
340         if (!have_forked)
341             return luaL_error(L, "exec not permitted in this context");
342
343         open_max = sysconf(_SC_OPEN_MAX);
344         if (open_max == -1) {
345             open_max = 1024;
346         }
347         for (fdno = 3; fdno < open_max; fdno++) {
348             flag = fcntl(fdno, F_GETFD);
349             if (flag == -1 || (flag & FD_CLOEXEC))
350                 continue;
351             fcntl(fdno, F_SETFD, FD_CLOEXEC);
352         }
353
354         argv = malloc((n+1)*sizeof(char*));
355         if (argv==NULL) return luaL_error(L,"not enough memory");
356         argv[0] = (char*)path;
357         for (i=1; i<n; i++) argv[i] = (char*)luaL_checkstring(L, i+1);
358         argv[i] = NULL;
359         execvp(path,argv);
360         return pusherror(L, path);
361 }
362
363
364 static int Pfork(lua_State *L)                  /** fork() */
365 {
366         pid_t pid = fork();
367         if (pid == 0) {
368             have_forked = 1;
369         }
370         return pushresult(L, pid, NULL);
371 }
372
373
374 static int Pwait(lua_State *L)                  /** wait([pid]) */
375 {
376         pid_t pid = luaL_optinteger(L, 1, -1);
377         return pushresult(L, waitpid(pid, NULL, 0), NULL);
378 }
379
380
381 static int Pkill(lua_State *L)                  /** kill(pid,[sig]) */
382 {
383         pid_t pid = luaL_checkinteger(L, 1);
384         int sig = luaL_optinteger(L, 2, SIGTERM);
385         return pushresult(L, kill(pid, sig), NULL);
386 }
387
388
389 static int Psleep(lua_State *L)                 /** sleep(seconds) */
390 {
391         unsigned int seconds = luaL_checkinteger(L, 1);
392         lua_pushnumber(L, sleep(seconds));
393         return 1;
394 }
395
396
397 static int Pputenv(lua_State *L)                /** putenv(string) */
398 {
399 #if HAVE_PUTENV
400         size_t l;
401         const char *s=luaL_checklstring(L, 1, &l);
402         char *e=malloc(++l);
403         return pushresult(L, (e==NULL) ? -1 : putenv(memcpy(e,s,l)), s);
404 #else
405         return -1;
406 #endif
407 }
408
409
410 static int Psetenv(lua_State *L)                /** setenv(name,value,[over]) */
411 {
412         const char *name=luaL_checkstring(L, 1);
413         const char *value=luaL_checkstring(L, 2);
414         int overwrite=lua_isnoneornil(L, 3) || lua_toboolean(L, 3);
415         return pushresult(L, setenv(name,value,overwrite), name);
416 }
417
418
419 static int Punsetenv(lua_State *L)              /** unsetenv(name) */
420 {
421         const char *name=luaL_checkstring(L, 1);
422         unsetenv(name);
423         return 0;
424 }
425
426 static int Pgetenv(lua_State *L)                /** getenv([name]) */
427 {
428         if (lua_isnone(L, 1))
429         {
430         #ifdef __APPLE__
431                 #include <crt_externs.h>
432                 #define environ (*_NSGetEnviron())
433         #else
434                 extern char **environ;
435         #endif /* __APPLE__ */
436                 char **e;
437                 if (*environ==NULL) lua_pushnil(L); else lua_newtable(L);
438                 for (e=environ; *e!=NULL; e++)
439                 {
440                         char *s=*e;
441                         char *eq=strchr(s, '=');
442                         if (eq==NULL)           /* will this ever happen? */
443                         {
444                                 lua_pushstring(L,s);
445                                 lua_pushboolean(L,0);
446                         }
447                         else
448                         {
449                                 lua_pushlstring(L,s,eq-s);
450                                 lua_pushstring(L,eq+1);
451                         }
452                         lua_settable(L,-3);
453                 }
454         }
455         else
456                 lua_pushstring(L, getenv(luaL_checkstring(L, 1)));
457         return 1;
458 }
459
460
461 static int Pumask(lua_State *L)                 /** umask([mode]) */
462 {
463         char m[10];
464         mode_t mode;
465         umask(mode=umask(0));
466         mode=(~mode)&0777;
467         if (!lua_isnone(L, 1))
468         {
469                 if (mode_munch(&mode, luaL_checkstring(L, 1)))
470                 {
471                         lua_pushnil(L);
472                         return 1;
473                 }
474                 mode&=0777;
475                 umask(~mode);
476         }
477         modechopper(mode, m);
478         lua_pushstring(L, m);
479         return 1;
480 }
481
482
483 static int Pchmod(lua_State *L)                 /** chmod(path,mode) */
484 {
485         mode_t mode;
486         struct stat s;
487         const char *path = luaL_checkstring(L, 1);
488         const char *modestr = luaL_checkstring(L, 2);
489         if (stat(path, &s)) return pusherror(L, path);
490         mode = s.st_mode;
491         if (mode_munch(&mode, modestr)) luaL_argerror(L, 2, "bad mode");
492         return pushresult(L, chmod(path, mode), path);
493 }
494
495
496 static int Pchown(lua_State *L)                 /** chown(path,uid,gid) */
497 {
498         const char *path = luaL_checkstring(L, 1);
499         uid_t uid = mygetuid(L, 2);
500         gid_t gid = mygetgid(L, 3);
501         return pushresult(L, chown(path, uid, gid), path);
502 }
503
504
505 static int Putime(lua_State *L)                 /** utime(path,[mtime,atime]) */
506 {
507         struct utimbuf times;
508         time_t currtime = time(NULL);
509         const char *path = luaL_checkstring(L, 1);
510         times.modtime = luaL_optnumber(L, 2, currtime);
511         times.actime  = luaL_optnumber(L, 3, currtime);
512         return pushresult(L, utime(path, &times), path);
513 }
514
515
516 static int FgetID(lua_State *L, int i, const void *data)
517 {
518         switch (i)
519         {
520                 case 0: lua_pushnumber(L, getegid());   break;
521                 case 1: lua_pushnumber(L, geteuid());   break;
522                 case 2: lua_pushnumber(L, getgid());    break;
523                 case 3: lua_pushnumber(L, getuid());    break;
524                 case 4: lua_pushnumber(L, getpgrp());   break;
525                 case 5: lua_pushnumber(L, getpid());    break;
526                 case 6: lua_pushnumber(L, getppid());   break;
527         }
528         return 1;
529 }
530
531 static const char *const SgetID[] =
532 {
533         "egid", "euid", "gid", "uid", "pgrp", "pid", "ppid", NULL
534 };
535
536 static int Pgetprocessid(lua_State *L)          /** getprocessid([selector]) */
537 {
538         return doselection(L, 1, SgetID, FgetID, NULL);
539 }
540
541
542 static int Pttyname(lua_State *L)               /** ttyname(fd) */
543 {
544         int fd=luaL_optinteger(L, 1, 0);
545         lua_pushstring(L, ttyname(fd));
546         return 1;
547 }
548
549 static int Pctermid(lua_State *L)               /** ctermid() */
550 {
551         char b[L_ctermid];
552         lua_pushstring(L, ctermid(b));
553         return 1;
554 }
555
556
557 static int Pgetlogin(lua_State *L)              /** getlogin() */
558 {
559         lua_pushstring(L, getlogin());
560         return 1;
561 }
562
563
564 static int Fgetpasswd(lua_State *L, int i, const void *data)
565 {
566         const struct passwd *p=data;
567         switch (i)
568         {
569                 case 0: lua_pushstring(L, p->pw_name); break;
570                 case 1: lua_pushnumber(L, p->pw_uid); break;
571                 case 2: lua_pushnumber(L, p->pw_gid); break;
572                 case 3: lua_pushstring(L, p->pw_dir); break;
573                 case 4: lua_pushstring(L, p->pw_shell); break;
574 /* not strictly POSIX */
575                 case 5: lua_pushstring(L, p->pw_gecos); break;
576                 case 6: lua_pushstring(L, p->pw_passwd); break;
577         }
578         return 1;
579 }
580
581 static const char *const Sgetpasswd[] =
582 {
583         "name", "uid", "gid", "dir", "shell", "gecos", "passwd", NULL
584 };
585
586
587 static int Pgetpasswd(lua_State *L)             /** getpasswd(name or id) */
588 {
589         struct passwd *p=NULL;
590         if (lua_isnoneornil(L, 1))
591                 p = getpwuid(geteuid());
592         else if (lua_isnumber(L, 1))
593                 p = getpwuid((uid_t)lua_tonumber(L, 1));
594         else if (lua_isstring(L, 1))
595                 p = getpwnam(lua_tostring(L, 1));
596         else
597                 typerror(L, 1, "string or number");
598         if (p==NULL)
599                 lua_pushnil(L);
600         else
601                 doselection(L, 2, Sgetpasswd, Fgetpasswd, p);
602         return 1;
603 }
604
605
606 static int Pgetgroup(lua_State *L)              /** getgroup(name or id) */
607 {
608         struct group *g=NULL;
609         if (lua_isnumber(L, 1))
610                 g = getgrgid((gid_t)lua_tonumber(L, 1));
611         else if (lua_isstring(L, 1))
612                 g = getgrnam(lua_tostring(L, 1));
613         else
614                 typerror(L, 1, "string or number");
615         if (g==NULL)
616                 lua_pushnil(L);
617         else
618         {
619                 int i;
620                 lua_newtable(L);
621                 storestring(L, "name", g->gr_name);
622                 storenumber(L, "gid", g->gr_gid);
623                 for (i=0; g->gr_mem[i] != NULL; i++)
624                         storeindex(L, i+1, g->gr_mem[i]);
625         }
626         return 1;
627 }
628
629
630 static int Psetuid(lua_State *L)                /** setuid(name or id) */
631 {
632         return pushresult(L, setuid(mygetuid(L, 1)), NULL);
633 }
634
635
636 static int Psetgid(lua_State *L)                /** setgid(name or id) */
637 {
638         return pushresult(L, setgid(mygetgid(L, 1)), NULL);
639 }
640
641 struct mytimes
642 {
643  struct tms t;
644  clock_t elapsed;
645 };
646
647 #define pushtime(L,x)           lua_pushnumber(L,((lua_Number)x)/CLOCKS_PER_SEC)
648
649 static int Ftimes(lua_State *L, int i, const void *data)
650 {
651         const struct mytimes *t=data;
652         switch (i)
653         {
654                 case 0: pushtime(L, t->t.tms_utime); break;
655                 case 1: pushtime(L, t->t.tms_stime); break;
656                 case 2: pushtime(L, t->t.tms_cutime); break;
657                 case 3: pushtime(L, t->t.tms_cstime); break;
658                 case 4: pushtime(L, t->elapsed); break;
659         }
660         return 1;
661 }
662
663 static const char *const Stimes[] =
664 {
665         "utime", "stime", "cutime", "cstime", "elapsed", NULL
666 };
667
668 #define storetime(L,name,x)     storenumber(L,name,(lua_Number)x/CLOCKS_PER_SEC)
669
670 static int Ptimes(lua_State *L)                 /** times() */
671 {
672         struct mytimes t;
673         t.elapsed = times(&t.t);
674         return doselection(L, 1, Stimes, Ftimes, &t);
675 }
676
677
678 struct mystat
679 {
680         struct stat s;
681         char mode[10];
682         const char *type;
683 };
684
685 static int Fstat(lua_State *L, int i, const void *data)
686 {
687         const struct mystat *s=data;
688         switch (i)
689         {
690                 case 0: lua_pushstring(L, s->mode); break;
691                 case 1: lua_pushnumber(L, s->s.st_ino); break;
692                 case 2: lua_pushnumber(L, s->s.st_dev); break;
693                 case 3: lua_pushnumber(L, s->s.st_nlink); break;
694                 case 4: lua_pushnumber(L, s->s.st_uid); break;
695                 case 5: lua_pushnumber(L, s->s.st_gid); break;
696                 case 6: lua_pushnumber(L, s->s.st_size); break;
697                 case 7: lua_pushnumber(L, s->s.st_atime); break;
698                 case 8: lua_pushnumber(L, s->s.st_mtime); break;
699                 case 9: lua_pushnumber(L, s->s.st_ctime); break;
700                 case 10:lua_pushstring(L, s->type); break;
701                 case 11:lua_pushnumber(L, s->s.st_mode); break;
702         }
703         return 1;
704 }
705
706 static const char *const Sstat[] =
707 {
708         "mode", "ino", "dev", "nlink", "uid", "gid",
709         "size", "atime", "mtime", "ctime", "type", "_mode",
710         NULL
711 };
712
713 static int Pstat(lua_State *L)                  /** stat(path,[selector]) */
714 {
715         struct mystat s;
716         const char *path=luaL_checkstring(L, 1);
717         if (lstat(path,&s.s)==-1) return pusherror(L, path);
718         s.type=filetype(s.s.st_mode);
719         modechopper(s.s.st_mode, s.mode);
720         return doselection(L, 2, Sstat, Fstat, &s);
721 }
722
723
724 static int Puname(lua_State *L)                 /** uname([string]) */
725 {
726         struct utsname u;
727         luaL_Buffer b;
728         const char *s;
729         if (uname(&u) == -1) return pusherror(L, NULL);
730         luaL_buffinit(L, &b);
731         for (s=luaL_optstring(L, 1, "%s %n %r %v %m"); *s; s++)
732                 if (*s!='%')
733                         luaL_addchar(&b, *s);
734                 else switch (*++s)
735                 {
736                         case '%': luaL_addchar(&b, *s); break;
737                         case 'm': luaL_addstring(&b,u.machine); break;
738                         case 'n': luaL_addstring(&b,u.nodename); break;
739                         case 'r': luaL_addstring(&b,u.release); break;
740                         case 's': luaL_addstring(&b,u.sysname); break;
741                         case 'v': luaL_addstring(&b,u.version); break;
742                         default: badoption(L, 2, "format", *s); break;
743                 }
744         luaL_pushresult(&b);
745         return 1;
746 }
747
748
749 static const int Kpathconf[] =
750 {
751         _PC_LINK_MAX, _PC_MAX_CANON, _PC_MAX_INPUT, _PC_NAME_MAX, _PC_PATH_MAX,
752         _PC_PIPE_BUF, _PC_CHOWN_RESTRICTED, _PC_NO_TRUNC, _PC_VDISABLE,
753         -1
754 };
755
756 static int Fpathconf(lua_State *L, int i, const void *data)
757 {
758         const char *path=data;
759         lua_pushnumber(L, pathconf(path, Kpathconf[i]));
760         return 1;
761 }
762
763 static const char *const Spathconf[] =
764 {
765         "link_max", "max_canon", "max_input", "name_max", "path_max",
766         "pipe_buf", "chown_restricted", "no_trunc", "vdisable",
767         NULL
768 };
769
770 static int Ppathconf(lua_State *L)              /** pathconf(path,[selector]) */
771 {
772         const char *path=luaL_checkstring(L, 1);
773         return doselection(L, 2, Spathconf, Fpathconf, path);
774 }
775
776
777 static const int Ksysconf[] =
778 {
779         _SC_ARG_MAX, _SC_CHILD_MAX, _SC_CLK_TCK, _SC_NGROUPS_MAX, _SC_STREAM_MAX,
780         _SC_TZNAME_MAX, _SC_OPEN_MAX, _SC_JOB_CONTROL, _SC_SAVED_IDS, _SC_VERSION,
781         -1
782 };
783
784 static int Fsysconf(lua_State *L, int i, const void *data)
785 {
786         lua_pushnumber(L, sysconf(Ksysconf[i]));
787         return 1;
788 }
789
790 static const char *const Ssysconf[] =
791 {
792         "arg_max", "child_max", "clk_tck", "ngroups_max", "stream_max",
793         "tzname_max", "open_max", "job_control", "saved_ids", "version",
794         NULL
795 };
796
797 static int Psysconf(lua_State *L)               /** sysconf([selector]) */
798 {
799         return doselection(L, 1, Ssysconf, Fsysconf, NULL);
800 }
801
802 static int Pmkstemp(lua_State *L)
803 {
804         const char *path;
805         char *dynpath;
806         int fd;
807         FILE **f;
808
809         path = luaL_checkstring(L, 1);
810         if (path == NULL)
811                 return 0;
812         dynpath = rstrdup(path);
813         fd = mkstemp(dynpath);
814         f = (FILE**)lua_newuserdata(L, sizeof(FILE*));
815         if (f == NULL) {
816                 close(fd);
817                 free(dynpath);
818                 return 0;
819         }
820         *f = fdopen(fd, "a+");
821         lua_pushstring(L, dynpath);
822         free(dynpath);
823         luaL_getmetatable(L, "FILE*");
824         if (lua_isnil(L, -1)) {
825                 lua_pop(L, 1);
826                 return luaL_error(L, "FILE* metatable not available "
827                               "(io not loaded?)");
828         } else {
829                 lua_setmetatable(L, -3);
830         }
831         return 2;
832 }
833
834 static int Predirect2null(lua_State *L)
835 {
836     int target_fd, fd, r, e;
837
838     if (!have_forked)
839         return luaL_error(L, "silence_file_descriptor not permitted in this context");
840
841     target_fd = luaL_checkinteger(L, 1);
842
843     r = fd = open("/dev/null", O_WRONLY);
844     if (fd >= 0 && fd != target_fd) {
845         r = dup2(fd, target_fd);
846         e = errno;
847         (void) close(fd);
848         errno = e;
849     }
850     return pushresult(L, r, NULL);
851 }
852
853 static const luaL_Reg R[] =
854 {
855         {"access",              Paccess},
856         {"chdir",               Pchdir},
857         {"chmod",               Pchmod},
858         {"chown",               Pchown},
859         {"ctermid",             Pctermid},
860         {"dir",                 Pdir},
861         {"errno",               Perrno},
862         {"exec",                Pexec},
863         {"files",               Pfiles},
864         {"fork",                Pfork},
865         {"getcwd",              Pgetcwd},
866         {"getenv",              Pgetenv},
867         {"getgroup",            Pgetgroup},
868         {"getlogin",            Pgetlogin},
869         {"getpasswd",           Pgetpasswd},
870         {"getprocessid",        Pgetprocessid},
871         {"kill",                Pkill},
872         {"link",                Plink},
873         {"mkdir",               Pmkdir},
874         {"mkfifo",              Pmkfifo},
875         {"mkstemp",             Pmkstemp},
876         {"pathconf",            Ppathconf},
877         {"putenv",              Pputenv},
878         {"readlink",            Preadlink},
879         {"rmdir",               Prmdir},
880         {"setgid",              Psetgid},
881         {"setuid",              Psetuid},
882         {"sleep",               Psleep},
883         {"stat",                Pstat},
884         {"symlink",             Psymlink},
885         {"sysconf",             Psysconf},
886         {"times",               Ptimes},
887         {"ttyname",             Pttyname},
888         {"umask",               Pumask},
889         {"uname",               Puname},
890         {"unlink",              Punlink},
891         {"utime",               Putime},
892         {"wait",                Pwait},
893         {"setenv",              Psetenv},
894         {"unsetenv",            Punsetenv},
895         {"redirect2null",       Predirect2null},
896         {NULL,                  NULL}
897 };
898
899 LUALIB_API int luaopen_posix (lua_State *L)
900 {
901         luaL_openlib(L, MYNAME, R, 0);
902         lua_pushliteral(L,"version");           /** version */
903         lua_pushliteral(L,MYVERSION);
904         lua_settable(L,-3);
905         return 1;
906 }
907
908 /* RPM specific overrides for Lua standard library */
909
910 static int exit_override(lua_State *L)
911 {
912     if (!have_forked)
913         return luaL_error(L, "exit not permitted in this context");
914
915     exit(luaL_optinteger(L, 1, EXIT_SUCCESS));
916 }
917
918 static const luaL_Reg os_overrides[] =
919 {
920     {"exit",    exit_override},
921     {NULL,      NULL}
922 };
923
924 #ifndef lua_pushglobaltable
925 #define lua_pushglobaltable(L) lua_pushvalue(L, LUA_GLOBALSINDEX)
926 #endif
927
928 int luaopen_rpm_os(lua_State *L)
929 {
930     lua_pushglobaltable(L);
931     luaL_openlib(L, "os", os_overrides, 0);
932     return 0;
933 }
934