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