File: | luaext/lposix.c |
Warning: | line 360, column 9 Potential leak of memory pointed to by 'argv' |
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_H1 | |||
9 | #include <config.h> | |||
10 | #endif | |||
11 | ||||
12 | #include <dirent.h> | |||
13 | #include <errno(*__errno_location ()).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" "posix" | |||
32 | #define MYVERSION"posix" " library for " "Lua " "5" "." "3" " / Nov 2003" MYNAME"posix" " library for " LUA_VERSION"Lua " "5" "." "3" " / Nov 2003" | |||
33 | ||||
34 | #include "lua.h" | |||
35 | #include "lauxlib.h" | |||
36 | #include "lposix.h" | |||
37 | ||||
38 | ||||
39 | #ifndef MYBUFSIZ512 | |||
40 | #define MYBUFSIZ512 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)((((m)) & 0170000) == (0100000))) return "regular"; | |||
50 | else if (S_ISLNK(m)((((m)) & 0170000) == (0120000))) return "link"; | |||
51 | else if (S_ISDIR(m)((((m)) & 0170000) == (0040000))) return "directory"; | |||
52 | else if (S_ISCHR(m)((((m)) & 0170000) == (0020000))) return "character device"; | |||
53 | else if (S_ISBLK(m)((((m)) & 0170000) == (0060000))) return "block device"; | |||
54 | else if (S_ISFIFO(m)((((m)) & 0170000) == (0010000))) return "fifo"; | |||
55 | else if (S_ISSOCK(m)((((m)) & 0170000) == (0140000))) 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)lua_typename(L, lua_type(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)(lua_type(L, (i)) == (-1))) | |||
73 | { | |||
74 | lua_newtable(L)lua_createtable(L, 0, 0); | |||
75 | for (i=0; S[i]!=NULL((void*)0); 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((void*)0), 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((void*)0)) | |||
115 | lua_pushstring(L, strerror(errno(*__errno_location ()))); | |||
116 | else | |||
117 | lua_pushfstring(L, "%s: %s", info, strerror(errno(*__errno_location ()))); | |||
118 | lua_pushnumber(L, errno(*__errno_location ())); | |||
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)(lua_type(L, (i)) == (-1))) | |||
142 | return -1; | |||
143 | else if (lua_isnumber(L, i)) | |||
144 | return (uid_t) lua_tonumber(L, i)lua_tonumberx(L,(i),((void*)0)); | |||
145 | else if (lua_isstring(L, i)) | |||
146 | { | |||
147 | struct passwd *p=getpwnam(lua_tostring(L, i)lua_tolstring(L, (i), ((void*)0))); | |||
148 | return (p==NULL((void*)0)) ? -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)(lua_type(L, (i)) == (-1))) | |||
157 | return -1; | |||
158 | else if (lua_isnumber(L, i)) | |||
159 | return (gid_t) lua_tonumber(L, i)lua_tonumberx(L,(i),((void*)0)); | |||
160 | else if (lua_isstring(L, i)) | |||
161 | { | |||
162 | struct group *g=getgrnam(lua_tostring(L, i)lua_tolstring(L, (i), ((void*)0))); | |||
163 | return (g==NULL((void*)0)) ? -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(*__errno_location ()))); | |||
174 | lua_pushnumber(L, errno(*__errno_location ())); | |||
175 | return 2; | |||
176 | } | |||
177 | ||||
178 | ||||
179 | static int Pdir(lua_State *L) /** dir([path]) */ | |||
180 | { | |||
181 | const char *path = luaL_optstring(L, 1, ".")(luaL_optlstring(L, (1), ("."), ((void*)0))); | |||
182 | DIR *d = opendir(path); | |||
183 | if (d == NULL((void*)0)) | |||
184 | return pusherror(L, path); | |||
185 | else | |||
186 | { | |||
187 | int i; | |||
188 | struct dirent *entry; | |||
189 | lua_newtable(L)lua_createtable(L, 0, 0); | |||
190 | for (i=1; (entry = readdir(d)) != NULL((void*)0); 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)((-1000000 - 1000) - (1))); | |||
201 | struct dirent *entry; | |||
202 | if (d == NULL((void*)0)) return luaL_error(L, "attempt to use closed dir"); | |||
203 | entry = readdir(d); | |||
204 | if (entry == NULL((void*)0)) | |||
205 | { | |||
206 | closedir(d); | |||
207 | lua_pushnil(L); | |||
208 | lua_replace(L, lua_upvalueindex(1))(lua_copy(L, -1, (((-1000000 - 1000) - (1)))), lua_settop(L, - (1)-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)((entry->d_type) << 12))); | |||
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, ".")(luaL_optlstring(L, (1), ("."), ((void*)0))); | |||
227 | DIR *d = opendir(path); | |||
228 | if (d == NULL((void*)0)) | |||
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[MYBUFSIZ512]; | |||
242 | if (getcwd(buf, sizeof(buf)) == NULL((void*)0)) | |||
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)(luaL_checklstring(L, (1), ((void*)0))); | |||
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)(luaL_checklstring(L, (1), ((void*)0))); | |||
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)(luaL_checklstring(L, (1), ((void*)0))); | |||
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)(luaL_checklstring(L, (1), ((void*)0))); | |||
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)(luaL_checklstring(L, (1), ((void*)0))); | |||
283 | const char *newpath = luaL_checkstring(L, 2)(luaL_checklstring(L, (2), ((void*)0))); | |||
284 | return pushresult(L, link(oldpath, newpath), NULL((void*)0)); | |||
285 | } | |||
286 | ||||
287 | ||||
288 | static int Psymlink(lua_State *L) /** symlink(oldpath,newpath) */ | |||
289 | { | |||
290 | const char *oldpath = luaL_checkstring(L, 1)(luaL_checklstring(L, (1), ((void*)0))); | |||
291 | const char *newpath = luaL_checkstring(L, 2)(luaL_checklstring(L, (2), ((void*)0))); | |||
292 | return pushresult(L, symlink(oldpath, newpath), NULL((void*)0)); | |||
293 | } | |||
294 | ||||
295 | ||||
296 | static int Preadlink(lua_State *L) /** readlink(path) */ | |||
297 | { | |||
298 | char buf[MYBUFSIZ512]; | |||
299 | const char *path = luaL_checkstring(L, 1)(luaL_checklstring(L, (1), ((void*)0))); | |||
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_OK0; | |||
310 | const char *path=luaL_checkstring(L, 1)(luaL_checklstring(L, (1), ((void*)0))); | |||
311 | const char *s; | |||
312 | for (s=luaL_optstring(L, 2, "f")(luaL_optlstring(L, (2), ("f"), ((void*)0))); *s!=0 ; s++) | |||
313 | switch (*s) | |||
314 | { | |||
315 | case ' ': break; | |||
316 | case 'r': mode |= R_OK4; break; | |||
317 | case 'w': mode |= W_OK2; break; | |||
318 | case 'x': mode |= X_OK1; break; | |||
319 | case 'f': mode |= F_OK0; 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)(luaL_checklstring(L, (1), ((void*)0))); | |||
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)(luaL_checklstring(L, (1), ((void*)0))); | |||
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_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_GETFD1); | |||
349 | if (flag == -1 || (flag & FD_CLOEXEC1)) | |||
350 | continue; | |||
351 | fcntl(fdno, F_SETFD2, FD_CLOEXEC1); | |||
352 | } | |||
353 | ||||
354 | argv = malloc((n+1)*sizeof(char*)); | |||
355 | if (argv==NULL((void*)0)) 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)(luaL_checklstring(L, (i+1), ((void*)0))); | |||
358 | argv[i] = NULL((void*)0); | |||
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((void*)0)); | |||
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((void*)0), 0), NULL((void*)0)); | |||
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, SIGTERM15); | |||
385 | return pushresult(L, kill(pid, sig), NULL((void*)0)); | |||
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_PUTENV1 | |||
400 | size_t l; | |||
401 | const char *s=luaL_checklstring(L, 1, &l); | |||
402 | char *e=malloc(++l); | |||
403 | return pushresult(L, (e==NULL((void*)0)) ? -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)(luaL_checklstring(L, (1), ((void*)0))); | |||
413 | const char *value=luaL_checkstring(L, 2)(luaL_checklstring(L, (2), ((void*)0))); | |||
414 | int overwrite=lua_isnoneornil(L, 3)(lua_type(L, (3)) <= 0) || 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)(luaL_checklstring(L, (1), ((void*)0))); | |||
422 | unsetenv(name); | |||
423 | return 0; | |||
424 | } | |||
425 | ||||
426 | static int Pgetenv(lua_State *L) /** getenv([name]) */ | |||
427 | { | |||
428 | if (lua_isnone(L, 1)(lua_type(L, (1)) == (-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((void*)0)) lua_pushnil(L); else lua_newtable(L)lua_createtable(L, 0, 0); | |||
438 | for (e=environ; *e!=NULL((void*)0); e++) | |||
439 | { | |||
440 | char *s=*e; | |||
441 | char *eq=strchr(s, '='); | |||
442 | if (eq==NULL((void*)0)) /* 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)(luaL_checklstring(L, (1), ((void*)0))))); | |||
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)(lua_type(L, (1)) == (-1))) | |||
468 | { | |||
469 | if (mode_munch(&mode, luaL_checkstring(L, 1)(luaL_checklstring(L, (1), ((void*)0))))) | |||
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)(luaL_checklstring(L, (1), ((void*)0))); | |||
488 | const char *modestr = luaL_checkstring(L, 2)(luaL_checklstring(L, (2), ((void*)0))); | |||
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)(luaL_checklstring(L, (1), ((void*)0))); | |||
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((void*)0)); | |||
509 | const char *path = luaL_checkstring(L, 1)(luaL_checklstring(L, (1), ((void*)0))); | |||
510 | times.modtime = luaL_optnumber(L, 2, currtime); | |||
511 | times.actime = luaL_optnumber(L, 3, currtime); | |||
512 | return pushresult(L, utime(path, ×), 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((void*)0) | |||
534 | }; | |||
535 | ||||
536 | static int Pgetprocessid(lua_State *L) /** getprocessid([selector]) */ | |||
537 | { | |||
538 | return doselection(L, 1, SgetID, FgetID, NULL((void*)0)); | |||
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_ctermid9]; | |||
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((void*)0) | |||
584 | }; | |||
585 | ||||
586 | ||||
587 | static int Pgetpasswd(lua_State *L) /** getpasswd(name or id) */ | |||
588 | { | |||
589 | struct passwd *p=NULL((void*)0); | |||
590 | if (lua_isnoneornil(L, 1)(lua_type(L, (1)) <= 0)) | |||
591 | p = getpwuid(geteuid()); | |||
592 | else if (lua_isnumber(L, 1)) | |||
593 | p = getpwuid((uid_t)lua_tonumber(L, 1)lua_tonumberx(L,(1),((void*)0))); | |||
594 | else if (lua_isstring(L, 1)) | |||
595 | p = getpwnam(lua_tostring(L, 1)lua_tolstring(L, (1), ((void*)0))); | |||
596 | else | |||
597 | typerror(L, 1, "string or number"); | |||
598 | if (p==NULL((void*)0)) | |||
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((void*)0); | |||
609 | if (lua_isnumber(L, 1)) | |||
610 | g = getgrgid((gid_t)lua_tonumber(L, 1)lua_tonumberx(L,(1),((void*)0))); | |||
611 | else if (lua_isstring(L, 1)) | |||
612 | g = getgrnam(lua_tostring(L, 1)lua_tolstring(L, (1), ((void*)0))); | |||
613 | else | |||
614 | typerror(L, 1, "string or number"); | |||
615 | if (g==NULL((void*)0)) | |||
616 | lua_pushnil(L); | |||
617 | else | |||
618 | { | |||
619 | int i; | |||
620 | lua_newtable(L)lua_createtable(L, 0, 0); | |||
621 | storestring(L, "name", g->gr_name); | |||
622 | storenumber(L, "gid", g->gr_gid); | |||
623 | for (i=0; g->gr_mem[i] != NULL((void*)0); 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((void*)0)); | |||
633 | } | |||
634 | ||||
635 | ||||
636 | static int Psetgid(lua_State *L) /** setgid(name or id) */ | |||
637 | { | |||
638 | return pushresult(L, setgid(mygetgid(L, 1)), NULL((void*)0)); | |||
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)/((__clock_t) 1000000)) lua_pushnumber(L,((lua_Number)x)/CLOCKS_PER_SEC((__clock_t) 1000000)) | |||
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)lua_pushnumber(L,((lua_Number)t->t.tms_utime)/((__clock_t) 1000000)); break; | |||
655 | case 1: pushtime(L, t->t.tms_stime)lua_pushnumber(L,((lua_Number)t->t.tms_stime)/((__clock_t) 1000000)); break; | |||
656 | case 2: pushtime(L, t->t.tms_cutime)lua_pushnumber(L,((lua_Number)t->t.tms_cutime)/((__clock_t ) 1000000)); break; | |||
657 | case 3: pushtime(L, t->t.tms_cstime)lua_pushnumber(L,((lua_Number)t->t.tms_cstime)/((__clock_t ) 1000000)); break; | |||
658 | case 4: pushtime(L, t->elapsed)lua_pushnumber(L,((lua_Number)t->elapsed)/((__clock_t) 1000000 )); break; | |||
659 | } | |||
660 | return 1; | |||
661 | } | |||
662 | ||||
663 | static const char *const Stimes[] = | |||
664 | { | |||
665 | "utime", "stime", "cutime", "cstime", "elapsed", NULL((void*)0) | |||
666 | }; | |||
667 | ||||
668 | #define storetime(L,name,x)storenumber(L,name,(lua_Number)x/((__clock_t) 1000000)) storenumber(L,name,(lua_Number)x/CLOCKS_PER_SEC((__clock_t) 1000000)) | |||
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_atimest_atim.tv_sec); break; | |||
698 | case 8: lua_pushnumber(L, s->s.st_mtimest_mtim.tv_sec); break; | |||
699 | case 9: lua_pushnumber(L, s->s.st_ctimest_ctim.tv_sec); 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((void*)0) | |||
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)(luaL_checklstring(L, (1), ((void*)0))); | |||
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((void*)0)); | |||
730 | luaL_buffinit(L, &b); | |||
731 | for (s=luaL_optstring(L, 1, "%s %n %r %v %m")(luaL_optlstring(L, (1), ("%s %n %r %v %m"), ((void*)0))); *s; s++) | |||
732 | if (*s!='%') | |||
733 | luaL_addchar(&b, *s)((void)((&b)->n < (&b)->size || luaL_prepbuffsize ((&b), 1)), ((&b)->b[(&b)->n++] = (*s))); | |||
734 | else switch (*++s) | |||
735 | { | |||
736 | case '%': luaL_addchar(&b, *s)((void)((&b)->n < (&b)->size || luaL_prepbuffsize ((&b), 1)), ((&b)->b[(&b)->n++] = (*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_LINK_MAX, _PC_MAX_CANON_PC_MAX_CANON, _PC_MAX_INPUT_PC_MAX_INPUT, _PC_NAME_MAX_PC_NAME_MAX, _PC_PATH_MAX_PC_PATH_MAX, | |||
752 | _PC_PIPE_BUF_PC_PIPE_BUF, _PC_CHOWN_RESTRICTED_PC_CHOWN_RESTRICTED, _PC_NO_TRUNC_PC_NO_TRUNC, _PC_VDISABLE_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((void*)0) | |||
768 | }; | |||
769 | ||||
770 | static int Ppathconf(lua_State *L) /** pathconf(path,[selector]) */ | |||
771 | { | |||
772 | const char *path=luaL_checkstring(L, 1)(luaL_checklstring(L, (1), ((void*)0))); | |||
773 | return doselection(L, 2, Spathconf, Fpathconf, path); | |||
774 | } | |||
775 | ||||
776 | ||||
777 | static const int Ksysconf[] = | |||
778 | { | |||
779 | _SC_ARG_MAX_SC_ARG_MAX, _SC_CHILD_MAX_SC_CHILD_MAX, _SC_CLK_TCK_SC_CLK_TCK, _SC_NGROUPS_MAX_SC_NGROUPS_MAX, _SC_STREAM_MAX_SC_STREAM_MAX, | |||
780 | _SC_TZNAME_MAX_SC_TZNAME_MAX, _SC_OPEN_MAX_SC_OPEN_MAX, _SC_JOB_CONTROL_SC_JOB_CONTROL, _SC_SAVED_IDS_SC_SAVED_IDS, _SC_VERSION_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((void*)0) | |||
795 | }; | |||
796 | ||||
797 | static int Psysconf(lua_State *L) /** sysconf([selector]) */ | |||
798 | { | |||
799 | return doselection(L, 1, Ssysconf, Fsysconf, NULL((void*)0)); | |||
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)(luaL_checklstring(L, (1), ((void*)0))); | |||
810 | if (path == NULL((void*)0)) | |||
811 | return 0; | |||
812 | dynpath = rstrdup(path); | |||
813 | fd = mkstemp(dynpath); | |||
814 | f = (FILE**)lua_newuserdata(L, sizeof(FILE*)); | |||
815 | if (f == NULL((void*)0)) { | |||
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*")(lua_getfield(L, (-1000000 - 1000), ("FILE*"))); | |||
824 | if (lua_isnil(L, -1)(lua_type(L, (-1)) == 0)) { | |||
825 | lua_pop(L, 1)lua_settop(L, -(1)-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_WRONLY01); | |||
844 | if (fd >= 0 && fd != target_fd) { | |||
845 | r = dup2(fd, target_fd); | |||
846 | e = errno(*__errno_location ()); | |||
847 | (void) close(fd); | |||
848 | errno(*__errno_location ()) = e; | |||
849 | } | |||
850 | return pushresult(L, r, NULL((void*)0)); | |||
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((void*)0), NULL((void*)0)} | |||
897 | }; | |||
898 | ||||
899 | LUALIB_APIextern int luaopen_posix (lua_State *L) | |||
900 | { | |||
901 | luaL_openlib(L, MYNAME"posix", R, 0); | |||
902 | lua_pushliteral(L,"version")lua_pushstring(L, "" "version"); /** version */ | |||
903 | lua_pushliteral(L,MYVERSION)lua_pushstring(L, "" "posix" " library for " "Lua " "5" "." "3" " / Nov 2003"); | |||
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_SUCCESS0)); | |||
916 | } | |||
917 | ||||
918 | static const luaL_Reg os_overrides[] = | |||
919 | { | |||
920 | {"exit", exit_override}, | |||
921 | {NULL((void*)0), NULL((void*)0)} | |||
922 | }; | |||
923 | ||||
924 | #ifndef lua_pushglobaltable | |||
925 | #define lua_pushglobaltable(L)((void)lua_rawgeti(L, (-1000000 - 1000), 2)) lua_pushvalue(L, LUA_GLOBALSINDEX) | |||
926 | #endif | |||
927 | ||||
928 | int luaopen_rpm_os(lua_State *L) | |||
929 | { | |||
930 | lua_pushglobaltable(L)((void)lua_rawgeti(L, (-1000000 - 1000), 2)); | |||
931 | luaL_openlib(L, "os", os_overrides, 0); | |||
932 | return 0; | |||
933 | } | |||
934 |