LCOV - code coverage report
Current view: top level - libpkg - lua.c (source / functions) Hit Total Coverage
Test: rapport Lines: 256 322 79.5 %
Date: 2021-12-10 16:22:55 Functions: 17 18 94.4 %
Branches: 99 150 66.0 %

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

Generated by: LCOV version 1.15