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