LCOV - code coverage report
Current view: top level - libpkg - lua.c (source / functions) Hit Total Coverage
Test: plop Lines: 256 326 78.5 %
Date: 2024-12-28 18:40:32 Functions: 18 19 94.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 106 172 61.6 %

           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 : }

Generated by: LCOV version 1.15