Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2019-2022 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2023 Serenity Cyber Security, LLC
4 : : * Author: Gleb Popov <arrowd@FreeBSD.org>
5 : : * All rights reserved.
6 : : *
7 : : * Redistribution and use in source and binary forms, with or without
8 : : * modification, are permitted provided that the following conditions
9 : : * are met:
10 : : * 1. Redistributions of source code must retain the above copyright
11 : : * notice, this list of conditions and the following disclaimer
12 : : * in this position and unchanged.
13 : : * 2. Redistributions in binary form must reproduce the above copyright
14 : : * notice, this list of conditions and the following disclaimer in the
15 : : * documentation and/or other materials provided with the distribution.
16 : : *
17 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
18 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
21 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : : */
28 : :
29 : : #include "pkg_config.h"
30 : :
31 : : #ifdef HAVE_CAPSICUM
32 : : #include <sys/capsicum.h>
33 : : #endif
34 : :
35 : : #include <sys/stat.h>
36 : : #include <sys/mman.h>
37 : : #include <sys/wait.h>
38 : :
39 : : #include <dirent.h>
40 : : #include <errno.h>
41 : : #include <fcntl.h>
42 : : #include <spawn.h>
43 : : #include <stdbool.h>
44 : : #include <unistd.h>
45 : : #include <xstring.h>
46 : :
47 : : #include "private/pkg.h"
48 : : #include "private/event.h"
49 : : #include "private/lua.h"
50 : :
51 : : #ifndef DEFFILEMODE
52 : : #define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
53 : : #endif
54 : :
55 : : extern char **environ;
56 : :
57 : : lua_CFunction
58 : 0 : stack_dump(lua_State *L)
59 : : {
60 : : int i;
61 : 0 : int top = lua_gettop(L);
62 : : xstring *stack;
63 : : char *stackstr;
64 : :
65 : 0 : stack = xstring_new();
66 : :
67 : 0 : fputs("\nLua Stack\n---------\n"
68 : 0 : "\tType Data\n\t-----------\n", stack->fp);
69 : :
70 [ # # ]: 0 : for (i = 1; i <= top; i++) { /* repeat for each level */
71 : 0 : int t = lua_type(L, i);
72 : 0 : fprintf(stack->fp, "%i", i);
73 [ # # # # ]: 0 : switch (t) {
74 : : case LUA_TSTRING: /* strings */
75 : 0 : fprintf(stack->fp, "\tString: `%s'\n", lua_tostring(L, i));
76 : 0 : break;
77 : : case LUA_TBOOLEAN: /* booleans */
78 : 0 : fprintf(stack->fp, "\tBoolean: %s", lua_toboolean(L, i) ? "\ttrue\n" : "\tfalse\n");
79 : 0 : break;
80 : : case LUA_TNUMBER: /* numbers */
81 : 0 : fprintf(stack->fp, "\tNumber: %g\n", lua_tonumber(L, i));
82 : 0 : break;
83 : : default: /* other values */
84 : 0 : fprintf(stack->fp, "\tOther: %s\n", lua_typename(L, t));
85 : 0 : break;
86 : : }
87 : 0 : }
88 : 0 : stackstr = xstring_get(stack);
89 : 0 : pkg_emit_error("%s\n", stackstr);
90 : 0 : free(stackstr);
91 : :
92 : 0 : return (0);
93 : : }
94 : :
95 : : int
96 : 3 : lua_print_msg(lua_State *L)
97 : : {
98 : 3 : int n = lua_gettop(L);
99 [ + + + + : 3 : luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
+ - ]
100 : : "pkg.print_msg takes exactly one argument");
101 : 3 : const char* str = luaL_checkstring(L, 1);
102 : 3 : lua_getglobal(L, "msgfd");
103 : 3 : int fd = lua_tointeger(L, -1);
104 : :
105 : 3 : dprintf(fd, "%s\n", str);
106 : :
107 : 3 : return (0);
108 : : }
109 : :
110 : :
111 : : static const char**
112 : 2 : luaL_checkarraystrings(lua_State *L, int arg) {
113 : : const char **ret;
114 : : lua_Integer n, i;
115 : : int t;
116 : 2 : int abs_arg = lua_absindex(L, arg);
117 : 2 : luaL_checktype(L, abs_arg, LUA_TTABLE);
118 : 2 : n = lua_rawlen(L, abs_arg);
119 : 2 : ret = lua_newuserdata(L, (n+1)*sizeof(char*));
120 [ + + ]: 4 : for (i=0; i<n; i++) {
121 : 2 : t = lua_rawgeti(L, abs_arg, i+1);
122 [ - + ]: 2 : if (t == LUA_TNIL)
123 : 0 : break;
124 [ - + # # ]: 2 : luaL_argcheck(L, t == LUA_TSTRING, arg, "expected array of strings");
125 : 2 : ret[i] = lua_tostring(L, -1);
126 : 2 : lua_pop(L, 1);
127 : 2 : }
128 : 2 : ret[i] = NULL;
129 : 2 : return ret;
130 : : }
131 : :
132 : : int
133 : 3 : lua_exec(lua_State *L)
134 : : {
135 : : int r, pstat;
136 : : posix_spawn_file_actions_t action;
137 : 3 : int stdin_pipe[2] = {-1, -1};
138 : : pid_t pid;
139 : : const char **argv;
140 : 3 : int n = lua_gettop(L);
141 [ + + + + : 3 : luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
+ - ]
142 : : "pkg.exec takes exactly one argument");
143 : :
144 : : #ifdef HAVE_CAPSICUM
145 : : unsigned int capmode;
146 : : if (cap_getmode(&capmode) == 0 && capmode > 0) {
147 : : return (luaL_error(L, "pkg.exec not available in sandbox"));
148 : : }
149 : : #endif
150 [ + - ]: 3 : if (pipe(stdin_pipe) < 0)
151 : 0 : return (EPKG_FATAL);
152 : :
153 : 1 : posix_spawn_file_actions_init(&action);
154 : 1 : posix_spawn_file_actions_adddup2(&action, stdin_pipe[0], STDIN_FILENO);
155 : 1 : posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
156 : :
157 : 1 : argv = luaL_checkarraystrings(L, 1);
158 [ - + - + ]: 2 : if (0 != (r = posix_spawnp(&pid, argv[0], &action, NULL,
159 : 1 : (char*const*)argv, environ))) {
160 : 0 : lua_pushnil(L);
161 : 0 : lua_pushstring(L, strerror(r));
162 : 0 : lua_pushinteger(L, r);
163 : 0 : return 3;
164 : : }
165 [ - + ]: 1 : while (waitpid(pid, &pstat, 0) == -1) {
166 [ # # ]: 0 : if (errno != EINTR) {
167 : 0 : lua_pushnil(L);
168 : 0 : lua_pushstring(L, strerror(r));
169 : 0 : lua_pushinteger(L, r);
170 : 0 : return 3;
171 : : }
172 : : }
173 : :
174 [ - + ]: 1 : if (WEXITSTATUS(pstat) != 0) {
175 : 0 : lua_pushnil(L);
176 : 0 : lua_pushstring(L, "Abnormal termination");
177 : 0 : lua_pushinteger(L, r);
178 : 0 : return 3;
179 : : }
180 : :
181 : 1 : posix_spawn_file_actions_destroy(&action);
182 : :
183 [ - + ]: 1 : if (stdin_pipe[0] != -1)
184 : 1 : close(stdin_pipe[0]);
185 [ - + ]: 1 : if (stdin_pipe[1] != -1)
186 : 1 : close(stdin_pipe[1]);
187 : 1 : lua_pushinteger(L, pid);
188 : 1 : return 1;
189 : 1 : }
190 : :
191 : : int
192 : 3 : lua_pkg_copy(lua_State *L)
193 : : {
194 : 3 : int n = lua_gettop(L);
195 [ + - # # : 3 : luaL_argcheck(L, n == 2, n > 2 ? 3 : n,
# # ]
196 : : "pkg.copy takes exactly two arguments");
197 : 3 : const char* src = luaL_checkstring(L, 1);
198 : 3 : const char* dst = luaL_checkstring(L, 2);
199 : : struct stat s1;
200 : : int fd1, fd2;
201 : : struct timespec ts[2];
202 : :
203 : : #ifdef HAVE_CHFLAGSAT
204 : 3 : bool install_as_user = (getenv("INSTALL_AS_USER") != NULL);
205 : : #endif
206 : :
207 : 3 : lua_getglobal(L, "rootfd");
208 : 3 : int rootfd = lua_tointeger(L, -1);
209 : :
210 [ + + ]: 3 : if (fstatat(rootfd, RELATIVE_PATH(src), &s1, 0) == -1) {
211 : 1 : lua_pushinteger(L, 2);
212 : 1 : return (1);
213 : : }
214 : 2 : fd1 = openat(rootfd, RELATIVE_PATH(src), O_RDONLY, DEFFILEMODE);
215 [ + - ]: 2 : if (fd1 == -1) {
216 : 0 : lua_pushinteger(L, 2);
217 : 0 : return (1);
218 : : }
219 : :
220 : 2 : fd2 = openat(rootfd, RELATIVE_PATH(dst), O_RDWR | O_CREAT | O_TRUNC | O_EXCL, s1.st_mode);
221 [ + + ]: 2 : if (fd2 == -1) {
222 : 1 : lua_pushinteger(L, 2);
223 : 1 : return (1);
224 : : }
225 : :
226 [ + - ]: 1 : if (!pkg_copy_file(fd1, fd2)) {
227 : 0 : lua_pushinteger(L, 2);
228 : 0 : return (1);
229 : : }
230 [ + - ]: 1 : if (fchown(fd2, s1.st_uid, s1.st_gid) == -1) {
231 : 0 : lua_pushinteger(L, 2);
232 : 0 : return (1);
233 : : }
234 : :
235 : 1 : fsync(fd2);
236 : 1 : close(fd1);
237 : 1 : close(fd2);
238 : :
239 : : #ifdef HAVE_STRUCT_STAT_ST_MTIM
240 : 1 : ts[0] = s1.st_atim;
241 : 1 : ts[1] = s1.st_mtim;
242 : : #else
243 : : #if defined(_DARWIN_C_SOURCE) || defined(__APPLE__)
244 : : ts[0] = s1.st_atimespec;
245 : : ts[1] = s1.st_mtimespec;
246 : : #else
247 : : ts[0].tv_sec = s1.st_atime;
248 : : ts[0].tv_nsec = 0;
249 : : ts[1].tv_sec = s1.st_mtime;
250 : : ts[1].tv_nsec = 0;
251 : : #endif
252 : : #endif
253 : :
254 [ - + - + : 3 : if (set_attrsat(rootfd, RELATIVE_PATH(dst), s1.st_mode, s1.st_uid,
- + ]
255 : 2 : s1.st_gid, &ts[0], &ts[1]) != EPKG_OK) {
256 : 0 : lua_pushinteger(L, -1);
257 : 0 : return (1);
258 : : }
259 : :
260 : : #ifdef HAVE_CHFLAGSAT
261 [ + - - + ]: 1 : if (!install_as_user && s1.st_flags != 0) {
262 [ + - + - : 3 : if (chflagsat(rootfd, RELATIVE_PATH(dst),
+ - ]
263 : 2 : s1.st_flags, AT_SYMLINK_NOFOLLOW) == -1) {
264 : 0 : pkg_fatal_errno("Fail to chflags %s", dst);
265 : 0 : lua_pushinteger(L, -1);
266 : 0 : return (1);
267 : : }
268 : 1 : }
269 : : #endif
270 : 1 : return (0);
271 : 3 : }
272 : :
273 : : int
274 : 5 : lua_pkg_filecmp(lua_State *L)
275 : : {
276 : 5 : int n = lua_gettop(L);
277 [ + + + + : 5 : luaL_argcheck(L, n == 2, n > 2 ? 3 : n,
+ - ]
278 : : "pkg.filecmp takes exactly two arguments");
279 : 5 : const char* file1 = luaL_checkstring(L, 1);
280 : 5 : const char* file2 = luaL_checkstring(L, 2);
281 : : char *buf1, *buf2;
282 : : struct stat s1, s2;
283 : : int fd1, fd2;
284 : 5 : int ret = 0;
285 : :
286 : 5 : lua_getglobal(L, "rootfd");
287 : 5 : int rootfd = lua_tointeger(L, -1);
288 : :
289 [ + + ]: 5 : if (fstatat(rootfd, RELATIVE_PATH(file1), &s1, 0) == -1) {
290 : 1 : lua_pushinteger(L, 2);
291 : 1 : return (1);
292 : : }
293 [ + + ]: 4 : if (fstatat(rootfd, RELATIVE_PATH(file2), &s2, 0) == -1) {
294 : 1 : lua_pushinteger(L, 2);
295 : 1 : return (1);
296 : : }
297 [ + + ]: 3 : if (s1.st_size != s2.st_size) {
298 : 1 : lua_pushinteger(L, 1);
299 : 1 : return (1);
300 : : }
301 : 2 : fd1 = openat(rootfd, RELATIVE_PATH(file1), O_RDONLY, DEFFILEMODE);
302 [ + - ]: 2 : if (fd1 == -1) {
303 : 0 : lua_pushinteger(L, 2);
304 : 0 : return (1);
305 : : }
306 : 2 : buf1 = mmap(NULL, s1.st_size, PROT_READ, MAP_SHARED, fd1, 0);
307 : 2 : close(fd1);
308 [ + - ]: 2 : if (buf1 == NULL) {
309 : 0 : lua_pushinteger(L, -1);
310 : 0 : return (1);
311 : : }
312 : 2 : fd2 = openat(rootfd, RELATIVE_PATH(file2), O_RDONLY, DEFFILEMODE);
313 [ + - ]: 2 : if (fd2 == -1) {
314 : 0 : lua_pushinteger(L, 2);
315 : 0 : return (1);
316 : : }
317 : :
318 : 2 : buf2 = mmap(NULL, s2.st_size, PROT_READ, MAP_SHARED, fd2, 0);
319 : 2 : close(fd2);
320 [ + - ]: 2 : if (buf2 == NULL) {
321 : 0 : lua_pushinteger(L, -1);
322 : 0 : return (1);
323 : : }
324 [ + - ]: 2 : if (memcmp(buf1, buf2, s1.st_size) != 0)
325 : 0 : ret = 1;
326 : :
327 : 2 : munmap(buf1, s1.st_size);
328 : 2 : munmap(buf2, s2.st_size);
329 : :
330 : 2 : lua_pushinteger(L, ret);
331 : 2 : return (1);
332 : 5 : }
333 : :
334 : : int
335 : 3 : lua_pkg_symlink(lua_State *L)
336 : : {
337 : 3 : int n = lua_gettop(L);
338 [ + + + + : 3 : luaL_argcheck(L, n == 2, n > 2 ? 3 : n,
+ - ]
339 : : "pkg.symlink takes exactly two arguments");
340 : 3 : const char *from = luaL_checkstring(L, 1);
341 : 3 : const char *to = luaL_checkstring(L, 2);
342 : 3 : lua_getglobal(L, "rootfd");
343 : 3 : int rootfd = lua_tointeger(L, -1);
344 [ + - ]: 3 : if (symlinkat(from, rootfd, RELATIVE_PATH(to)) == -1)
345 : 0 : return (luaL_fileresult(L, 0, from));
346 : 1 : return (1);
347 : 1 : }
348 : :
349 : : int
350 : 2 : lua_prefix_path(lua_State *L)
351 : : {
352 : 2 : int n = lua_gettop(L);
353 [ - + + + : 2 : luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
+ - ]
354 : : "pkg.prefix_path takes exactly one argument");
355 : 2 : const char *str = luaL_checkstring(L, 1);
356 : 2 : lua_getglobal(L, "package");
357 : 2 : struct pkg *p = lua_touserdata(L, -1);
358 : :
359 : : char path[MAXPATHLEN];
360 : 2 : path[0] = '\0';
361 : :
362 [ + + ]: 2 : if (*str == '/') {
363 : 1 : strlcat(path, str, MAXPATHLEN);
364 : 1 : } else {
365 : 1 : strlcat(path, p->prefix, MAXPATHLEN);
366 : 1 : strlcat(path, "/", MAXPATHLEN);
367 : 1 : strlcat(path, str, MAXPATHLEN);
368 : : }
369 : :
370 : 2 : lua_pushstring(L, path);
371 : 2 : return (1);
372 : : }
373 : :
374 : : int
375 : 4 : lua_stat(lua_State *L)
376 : : {
377 : 4 : int n = lua_gettop(L);
378 [ + + + + : 4 : luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
+ - ]
379 : : "pkg.stat takes exactly one argument");
380 : 4 : const char *path = RELATIVE_PATH(luaL_checkstring(L, 1));
381 : 4 : lua_getglobal(L, "rootfd");
382 : 4 : int rootfd = lua_tointeger(L, -1);
383 : : struct stat s;
384 : 4 : const char *type = "unknown";
385 : :
386 [ + + ]: 4 : if (fstatat(rootfd, path, &s, AT_SYMLINK_NOFOLLOW) == -1) {
387 : 1 : return lua_pushnil(L), 1;
388 : : }
389 : :
390 : 3 : lua_settop(L, 2);
391 [ - + ]: 3 : if (!lua_istable(L, 2))
392 : 3 : lua_newtable(L);
393 : :
394 : 3 : lua_pushinteger(L, s.st_size);
395 : 3 : lua_setfield(L, -2, "size");
396 : 3 : lua_pushinteger(L, s.st_uid);
397 : 3 : lua_setfield(L, -2, "uid");
398 : 3 : lua_pushinteger(L, s.st_gid);
399 : 3 : lua_setfield(L, -2, "gid");
400 [ + + ]: 3 : if (S_ISREG(s.st_mode))
401 : 1 : type = "reg";
402 [ + + ]: 2 : else if (S_ISDIR(s.st_mode))
403 : 1 : type = "dir";
404 [ - + ]: 1 : else if (S_ISCHR(s.st_mode))
405 : 0 : type = "chr";
406 [ + - ]: 1 : else if (S_ISLNK(s.st_mode))
407 : 1 : type = "lnk";
408 [ # # ]: 0 : else if (S_ISSOCK(s.st_mode))
409 : 0 : type = "sock";
410 [ # # ]: 0 : else if (S_ISBLK(s.st_mode))
411 : 0 : type = "blk";
412 [ # # ]: 0 : else if (S_ISFIFO(s.st_mode))
413 : 0 : type = "fifo";
414 : 3 : lua_pushstring(L, type);
415 : 3 : lua_setfield(L, -2, "type");
416 : :
417 : 3 : return (1);
418 : 4 : }
419 : :
420 : : /* stolen from lua.c */
421 : : void
422 : 10 : lua_args_table(lua_State *L, char **argv, int argc)
423 : : {
424 : 10 : lua_createtable(L, argc, 1);
425 [ + + ]: 27 : for (int i = 0; i < argc; i++) {
426 : 17 : lua_pushstring(L, argv[i]);
427 : : /* lua starts counting by 1 */
428 : 17 : lua_rawseti(L, -2, i + 1);
429 : 17 : }
430 : 10 : lua_setglobal(L, "arg");
431 : 10 : }
432 : :
433 : :
434 : : /*
435 : : * this is a copy of lua code to be able to override open
436 : : * merge of newprefile and newfile
437 : : */
438 : :
439 : : static int
440 : 1 : my_iofclose(lua_State *L)
441 : : {
442 : 1 : luaL_Stream *p = ((luaL_Stream *)luaL_checkudata(L, 1, LUA_FILEHANDLE));
443 : 1 : int res = fclose(p->f);
444 : 1 : return (luaL_fileresult(L, (res == 0), NULL));
445 : : }
446 : :
447 : : static luaL_Stream *
448 : 2 : newfile(lua_State *L) {
449 : 2 : luaL_Stream *p = (luaL_Stream *)lua_newuserdata(L, sizeof(luaL_Stream));
450 : 2 : p->f = NULL;
451 : 2 : p->closef = &my_iofclose;
452 : 2 : luaL_setmetatable(L, LUA_FILEHANDLE);
453 : 2 : return (p);
454 : : }
455 : :
456 : : static int
457 : 2 : lua_io_open(lua_State *L)
458 : : {
459 : 2 : const char *filename = luaL_checkstring(L, 1);
460 : 2 : const char *mode = luaL_optstring(L, 2, "r");
461 : 2 : lua_getglobal(L, "rootfd");
462 : 2 : int rootfd = lua_tointeger(L, -1);
463 : : int oflags;
464 : 2 : luaL_Stream *p = newfile(L);
465 : 2 : const char *md = mode;
466 [ - + # # ]: 2 : luaL_argcheck(L, checkflags(md, &oflags), 2, "invalid mode");
467 : 2 : int fd = openat(rootfd, RELATIVE_PATH(filename), oflags, DEFFILEMODE);
468 [ + + ]: 2 : if (fd == -1)
469 : 1 : return (luaL_fileresult(L, 0, filename));
470 : 1 : p->f = fdopen(fd, mode);
471 [ + - ]: 1 : return ((p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1);
472 : 2 : }
473 : :
474 : : static int
475 : 1 : lua_os_remove(lua_State *L) {
476 : 1 : const char *filename = RELATIVE_PATH(luaL_checkstring(L, 1));
477 : 1 : lua_getglobal(L, "rootfd");
478 : 1 : int rootfd = lua_tointeger(L, -1);
479 : 1 : int flag = 0;
480 : : struct stat st;
481 : :
482 [ + - ]: 1 : if (fstatat(rootfd, filename, &st, AT_SYMLINK_NOFOLLOW) == -1)
483 : 0 : return (luaL_fileresult(L, 1, NULL));
484 : :
485 [ + - ]: 1 : if (S_ISDIR(st.st_mode))
486 : 0 : flag = AT_REMOVEDIR;
487 : :
488 : 1 : return (luaL_fileresult(L, unlinkat(rootfd, filename, flag) == 0, NULL));
489 : 1 : }
490 : :
491 : : static int
492 : 1 : lua_os_rename(lua_State *L)
493 : : {
494 : 1 : const char *fromname = RELATIVE_PATH(luaL_checkstring(L, 1));
495 : 1 : const char *toname = RELATIVE_PATH(luaL_checkstring(L, 2));
496 : 1 : lua_getglobal(L, "rootfd");
497 : 1 : int rootfd = lua_tointeger(L, -1);
498 : 1 : return luaL_fileresult(L, renameat(rootfd, fromname, rootfd, toname) == 0, NULL);
499 : : }
500 : :
501 : : static int
502 : 1 : lua_os_execute(lua_State *L)
503 : : {
504 : 1 : return (luaL_error(L, "os.execute not available"));
505 : : }
506 : :
507 : : static int
508 : 1 : lua_os_exit(lua_State *L)
509 : : {
510 : 1 : return (luaL_error(L, "os.exit not available"));
511 : : }
512 : :
513 : : void
514 : 42 : lua_override_ios(lua_State *L, bool sandboxed)
515 : : {
516 : 42 : lua_getglobal(L, "io");
517 : 42 : lua_pushcfunction(L, lua_io_open);
518 : 42 : lua_setfield(L, -2, "open");
519 : :
520 : 42 : lua_getglobal(L, "os");
521 : 42 : lua_pushcfunction(L, lua_os_remove);
522 : 42 : lua_setfield(L, -2, "remove");
523 : 42 : lua_pushcfunction(L, lua_os_rename);
524 : 42 : lua_setfield(L, -2, "rename");
525 [ + + ]: 42 : if (sandboxed) {
526 : 19 : lua_pushcfunction(L, lua_os_execute);
527 : 19 : lua_setfield(L, -2, "execute");
528 : 19 : }
529 : 42 : lua_pushcfunction(L, lua_os_exit);
530 : 42 : lua_setfield(L, -2, "exit");
531 : 42 : }
532 : :
533 : : int
534 : 5 : lua_readdir(lua_State *L)
535 : : {
536 : 5 : int n = lua_gettop(L);
537 [ + + + + : 5 : luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
+ - ]
538 : : "pkg.readdir takes exactly one argument");
539 : 5 : const char *path = luaL_checkstring(L, 1);
540 : 5 : int fd = -1;
541 : :
542 [ + + ]: 5 : if (*path == '/') {
543 : 1 : lua_getglobal(L, "rootfd");
544 : 1 : int rootfd = lua_tointeger(L, -1);
545 [ - + ]: 1 : if (strlen(path) > 1) {
546 : 0 : fd = openat(rootfd, path +1, O_DIRECTORY);
547 : 0 : } else {
548 : 1 : fd = dup(rootfd);
549 : : }
550 : 1 : } else {
551 : 4 : fd = open(path, O_DIRECTORY);
552 : : }
553 [ + + ]: 5 : if (fd == -1)
554 : 2 : return (luaL_fileresult(L, 0, path));
555 : :
556 : 3 : DIR *dir = fdopendir(fd);
557 [ + - ]: 3 : if (!dir)
558 : 0 : return (luaL_fileresult(L, 0, path));
559 : 3 : lua_newtable(L);
560 : : struct dirent *e;
561 : 3 : int i = 0;
562 [ + + ]: 10 : while ((e = readdir(dir))) {
563 : 7 : char *name = e->d_name;
564 [ + + + + ]: 7 : if (STREQ(name, ".") || STREQ(name, ".."))
565 : 6 : continue;
566 : 1 : lua_pushinteger(L, ++i);
567 : 1 : lua_pushstring(L, name);
568 : 1 : lua_settable(L, -3);
569 : : }
570 : 3 : return 1;
571 : 5 : }
|