lua.c
1 /* 2 * Copyright (c) 2021 Baptiste Daroussin <bapt@FreeBSD.org> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer 9 * in this position and unchanged. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include <sys/stat.h> 27 28 #include <atf-c.h> 29 #include <err.h> 30 #include <unistd.h> 31 #include <pkg.h> 32 #include <private/lua.h> 33 #include <fcntl.h> 34 #include <stdlib.h> 35 #include <errno.h> 36 37 38 // Some Lua tests are reported on macOS/aarch64 to poison addresses 39 // e.g. 40 // AddressSanitizer: CHECK failed: asan_poisoning.cpp:40 "((AddrIsInMem(addr + size - (1ULL << 3)))) != (0)" (0x0, 0x0) (tid=78712) 41 // #0 0x000101cf086c in __asan::CheckUnwind()+0x20 (libclang_rt.asan_osx_dynamic.dylib:arm64+0x5c86c) 42 // #1 0x000101d0b318 in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long)+0x90 (libclang_rt.asan_osx_dynamic.dylib:arm64+0x77318) 43 // #2 0x000101ce7ed4 in __asan::PoisonShadow(unsigned long, unsigned long, unsigned char)+0x28c (libclang_rt.asan_osx_dynamic.dylib:arm64+0x53ed4) 44 // #3 0x000101ce9e74 in __asan::PlatformUnpoisonStacks()+0x50 (libclang_rt.asan_osx_dynamic.dylib:arm64+0x55e74) 45 // #4 0x000101cf04c0 in __asan_handle_no_return+0x28 (libclang_rt.asan_osx_dynamic.dylib:arm64+0x5c4c0) 46 // #5 0x00010046cf98 in atfu_execute_body lua.c:193 47 // #6 0x0001010a70c4 in atf_tc_run+0x58 (libatf-c.1.dylib:arm64+0x30c4) 48 // #7 0x0001010ad49c in atf_tp_main+0x8a0 (libatf-c.1.dylib:arm64+0x949c) 49 // #8 0x00010046af48 in main lua.c:491 50 // #9 0x000187ee4270 () 51 // Use this attribute to silence the report until it is better understood. The code itself seems legit. 52 #if defined(__clang__) || defined (__GNUC__) 53 # define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) 54 #else 55 # define ATTRIBUTE_NO_SANITIZE_ADDRESS 56 #endif 57 58 ATF_TC_WITHOUT_HEAD(readdir); 59 ATF_TC_WITHOUT_HEAD(stat); 60 ATF_TC_WITHOUT_HEAD(print_msg); 61 ATF_TC_WITHOUT_HEAD(execute); 62 ATF_TC_WITHOUT_HEAD(override); 63 ATF_TC_WITHOUT_HEAD(fileops); 64 ATF_TC_WITHOUT_HEAD(prefix_path); 65 66 ATF_TC_BODY(readdir, tc) 67 { 68 char *cwd = getcwd(NULL, 0); 69 int rootfd = open(cwd, O_DIRECTORY); 70 free(cwd); 71 lua_State *L = luaL_newstate(); 72 static const luaL_Reg test_lib[] = { 73 { "readdir", lua_readdir }, 74 { NULL, NULL }, 75 }; 76 luaL_openlibs(L); 77 lua_override_ios(L, false); 78 luaL_newlib(L, test_lib); 79 lua_setglobal(L, "test"); 80 lua_pushinteger(L, rootfd); 81 lua_setglobal(L, "rootfd"); 82 83 ATF_REQUIRE(luaL_dostring(L, "test.readdir(\".\", \"plop\")") != 0); 84 ATF_REQUIRE_STREQ(lua_tostring(L, -1), "[string \"test.readdir(\".\", \"plop\")\"]:1: bad argument #2 to 'readdir' (pkg.readdir takes exactly one argument)"); 85 ATF_REQUIRE_EQ(lua_tonumber(L, -1), 0); 86 87 ATF_REQUIRE(luaL_dostring(L, "test.readdir()") != 0); 88 ATF_REQUIRE_STREQ(lua_tostring(L, -1), "[string \"test.readdir()\"]:1: bad argument #0 to 'readdir' (pkg.readdir takes exactly one argument)"); 89 ATF_REQUIRE_EQ(lua_tonumber(L, -1), 0); 90 91 ATF_REQUIRE(luaL_dostring(L, "res = test.readdir(\".\")\n gr = #res\n") == 0); 92 lua_getglobal(L, "res"); 93 ATF_REQUIRE(lua_istable(L, -1)); 94 ATF_REQUIRE_EQ(luaL_len(L, -1), 0); 95 96 ATF_REQUIRE(luaL_dostring(L, "res = test.readdir(\"nonexistent\")") == 0); 97 lua_getglobal(L, "res"); 98 ATF_REQUIRE(lua_isnil(L, -1)); 99 100 ATF_REQUIRE(luaL_dostring(L, "res = test.readdir(\"/\")") == 0); 101 lua_getglobal(L, "res"); 102 ATF_REQUIRE(!lua_isnil(L, -1)); 103 104 close(open("testfile", O_CREAT|O_TRUNC, 0644)); 105 ATF_REQUIRE(luaL_dostring(L, "res = test.readdir(\".\")\n gr = #res\n") == 0); 106 lua_getglobal(L, "res"); 107 ATF_REQUIRE(lua_istable(L, -1)); 108 ATF_REQUIRE_EQ(luaL_len(L, -1), 1); 109 110 ATF_REQUIRE(luaL_dostring(L, "res = test.readdir(\"testfile\")") == 0); 111 lua_getglobal(L, "res"); 112 ATF_REQUIRE(lua_isnil(L, -1)); 113 } 114 115 ATF_TC_BODY(stat, tc) 116 { 117 char *cwd = getcwd(NULL, 0); 118 int rootfd = open(cwd, O_DIRECTORY); 119 free(cwd); 120 lua_State *L = luaL_newstate(); 121 static const luaL_Reg test_lib[] = { 122 { "stat", lua_stat }, 123 { NULL, NULL }, 124 }; 125 luaL_openlibs(L); 126 lua_override_ios(L, false); 127 luaL_newlib(L, test_lib); 128 lua_setglobal(L, "test"); 129 lua_pushinteger(L, rootfd); 130 lua_setglobal(L, "rootfd"); 131 132 ATF_REQUIRE(luaL_dostring(L, "test.stat(\".\", \"plop\")") != 0); 133 ATF_REQUIRE_STREQ(lua_tostring(L, -1), "[string \"test.stat(\".\", \"plop\")\"]:1: bad argument #2 to 'stat' (pkg.stat takes exactly one argument)"); 134 ATF_REQUIRE_EQ(lua_tonumber(L, -1), 0); 135 136 ATF_REQUIRE(luaL_dostring(L, "test.stat()") != 0); 137 ATF_REQUIRE_STREQ(lua_tostring(L, -1), "[string \"test.stat()\"]:1: bad argument #0 to 'stat' (pkg.stat takes exactly one argument)"); 138 ATF_REQUIRE_EQ(lua_tonumber(L, -1), 0); 139 140 ATF_REQUIRE(luaL_dostring(L, "st = test.stat(\".\")\nres = st.type") == 0); 141 lua_getglobal(L, "res"); 142 ATF_REQUIRE(lua_isstring(L, -1)); 143 ATF_REQUIRE_STREQ(lua_tostring(L,-1), "dir"); 144 145 close(open("testfile", O_CREAT|O_TRUNC, 0644)); 146 ATF_REQUIRE(luaL_dostring(L, "st = test.stat(\"testfile\")\nres = st.type") == 0); 147 lua_getglobal(L, "res"); 148 ATF_REQUIRE(lua_isstring(L, -1)); 149 ATF_REQUIRE_STREQ(lua_tostring(L,-1), "reg"); 150 151 symlink("testfile", "plop"); 152 ATF_REQUIRE(luaL_dostring(L, "st = test.stat(\"plop\")\nres = st.type") == 0); 153 lua_getglobal(L, "res"); 154 ATF_REQUIRE(lua_isstring(L, -1)); 155 ATF_REQUIRE_STREQ(lua_tostring(L,-1), "lnk"); 156 157 lua_pushinteger(L, -1); 158 lua_setglobal(L, "rootfd"); 159 ATF_REQUIRE(luaL_dostring(L, "res = test.stat(\".\")\n") == 0); 160 lua_getglobal(L, "res"); 161 ATF_REQUIRE(lua_isnil(L, -1)); 162 } 163 164 ATF_TC_BODY(print_msg, tc) 165 { 166 lua_State *L = luaL_newstate(); 167 static const luaL_Reg test_lib[] = { 168 { "print_msg", lua_print_msg }, 169 { NULL, NULL }, 170 }; 171 int fd = open("testfile", O_CREAT|O_TRUNC|O_WRONLY, 0644); 172 173 ATF_REQUIRE_MSG(-1 != fd, "open failed (%d,%s)", errno, strerror(errno)); 174 175 luaL_openlibs(L); 176 lua_override_ios(L, false); 177 luaL_newlib(L, test_lib); 178 lua_setglobal(L, "test"); 179 lua_pushinteger(L, fd); 180 lua_setglobal(L, "msgfd"); 181 182 ATF_REQUIRE(luaL_dostring(L, "test.print_msg()") != 0); 183 ATF_REQUIRE_STREQ(lua_tostring(L, -1), "[string \"test.print_msg()\"]:1: bad argument #0 to 'print_msg' (pkg.print_msg takes exactly one argument)"); 184 ATF_REQUIRE_EQ(lua_tonumber(L, -1), 0); 185 186 ATF_REQUIRE(luaL_dostring(L, "test.print_msg(1, 2)") != 0); 187 ATF_REQUIRE_STREQ(lua_tostring(L, -1), "[string \"test.print_msg(1, 2)\"]:1: bad argument #2 to 'print_msg' (pkg.print_msg takes exactly one argument)"); 188 ATF_REQUIRE_EQ(lua_tonumber(L, -1), 0); 189 190 ATF_REQUIRE(luaL_dostring(L, "test.print_msg(\"bla\")") == 0); 191 int err = close(fd); 192 ATF_REQUIRE_MSG(0 == err, "close failed (%d,%s)", errno, strerror(errno)); 193 194 atf_utils_compare_file("testfile", "bla\n"); 195 } 196 197 ATTRIBUTE_NO_SANITIZE_ADDRESS ATF_TC_BODY(execute, tc) 198 { 199 lua_State *L = luaL_newstate(); 200 static const luaL_Reg test_lib[] = { 201 { "exec", lua_exec }, 202 { NULL, NULL }, 203 }; 204 luaL_openlibs(L); 205 lua_override_ios(L, false); 206 luaL_newlib(L, test_lib); 207 lua_setglobal(L, "test"); 208 209 pid_t p = atf_utils_fork(); 210 if (p == 0) { 211 if (luaL_dostring(L, "test.exec()")) { 212 printf("%s\n", lua_tostring(L, -1)); 213 } 214 exit(lua_tonumber(L, -1)); 215 } 216 atf_utils_wait(p, 0, "[string \"test.exec()\"]:1: bad argument #0 to 'exec' (pkg.exec takes exactly one argument)\n", ""); 217 218 p = atf_utils_fork(); 219 if (p == 0) { 220 if (luaL_dostring(L, "test.exec(plop)")) { 221 printf("%s\n", lua_tostring(L, -1)); 222 } 223 exit(lua_tonumber(L, -1)); 224 } 225 atf_utils_wait(p, 0, "[string \"test.exec(plop)\"]:1: bad argument #1 to 'exec' (table expected, got nil)\n", ""); 226 227 p = atf_utils_fork(); 228 if (p == 0) { 229 if (luaL_dostring(L, "test.exec(plop, meh)")) { 230 printf("%s\n", lua_tostring(L, -1)); 231 } 232 exit(lua_tonumber(L, -1)); 233 } 234 atf_utils_wait(p, 0, "[string \"test.exec(plop, meh)\"]:1: bad argument #2 to 'exec' (pkg.exec takes exactly one argument)\n", ""); 235 236 p = atf_utils_fork(); 237 if (p == 0) { 238 if (luaL_dostring(L, "test.exec({\"/bin/echo\", \"1\"})")) { 239 printf("%s\n", lua_tostring(L, -1)); 240 } 241 exit(lua_tonumber(L, -1)); 242 } 243 atf_utils_wait(p, 0, "1\n", ""); 244 } 245 246 ATTRIBUTE_NO_SANITIZE_ADDRESS ATF_TC_BODY(override, tc) 247 { 248 lua_State *L = luaL_newstate(); 249 luaL_openlibs(L); 250 lua_override_ios(L, true); 251 252 pid_t p = atf_utils_fork(); 253 if (p == 0) { 254 if (luaL_dostring(L, "os.execute(\"/usr/bin/true\")")) { 255 printf("%s\n", lua_tostring(L, -1)); 256 } 257 exit(lua_tonumber(L, -1)); 258 } 259 atf_utils_wait(p, 0, "[string \"os.execute(\"/usr/bin/true\")\"]:1: os.execute not available\n", ""); 260 261 p = atf_utils_fork(); 262 if (p == 0) { 263 if (luaL_dostring(L, "os.exit(1)")) { 264 printf("%s\n", lua_tostring(L, -1)); 265 } 266 exit(lua_tonumber(L, -1)); 267 } 268 atf_utils_wait(p, 0, "[string \"os.exit(1)\"]:1: os.exit not available\n", ""); 269 270 char *cwd = getcwd(NULL, 0); 271 int rootfd = open(cwd, O_DIRECTORY); 272 free(cwd); 273 lua_pushinteger(L, rootfd); 274 lua_setglobal(L, "rootfd"); 275 p = atf_utils_fork(); 276 if (p == 0) { 277 if (luaL_dostring(L, "io.close(io.open(\"/plop\", \"w+\"))")) { 278 printf("%s\n", lua_tostring(L, -1)); 279 } 280 exit(lua_tonumber(L, -1)); 281 } 282 atf_utils_wait(p, 0, "", ""); 283 atf_utils_file_exists("plop"); 284 285 p = atf_utils_fork(); 286 if (p == 0) { 287 if (luaL_dostring(L, "os.rename(\"/plop\", \"/bob\")")) { 288 printf("%s\n", lua_tostring(L, -1)); 289 } 290 exit(lua_tonumber(L, -1)); 291 } 292 atf_utils_wait(p, 0, "", ""); 293 atf_utils_file_exists("bob"); 294 295 p = atf_utils_fork(); 296 if (p == 0) { 297 if (luaL_dostring(L, "os.remove(\"/bob\")\nassert(io.open(\"/bob\", \"r\"))")) { 298 printf("%s\n", lua_tostring(L, -1)); 299 } 300 exit(lua_tonumber(L, -1)); 301 } 302 atf_utils_wait(p, 0, "[string \"os.remove(\"/bob\")...\"]:2: /bob: No such file or directory\n", ""); 303 } 304 305 ATF_TC_BODY(fileops, tc) 306 { 307 char b[1024]; 308 char *cwd = getcwd(NULL, 0); 309 int rootfd = open(cwd, O_DIRECTORY); 310 free(cwd); 311 lua_State *L = luaL_newstate(); 312 luaL_openlibs(L); 313 lua_pushinteger(L, rootfd); 314 lua_setglobal(L, "rootfd"); 315 lua_override_ios(L, true); 316 static const luaL_Reg test_lib[] = { 317 { "copy", lua_pkg_copy }, 318 { "cmp", lua_pkg_filecmp}, 319 { "symlink", lua_pkg_symlink}, 320 { NULL, NULL }, 321 }; 322 luaL_newlib(L, test_lib); 323 lua_setglobal(L, "test"); 324 pid_t p; 325 326 FILE *f1 = fopen("test1", "w+"); 327 FILE *f2 = fopen("test2", "w+"); 328 FILE *f3 = fopen("test3", "w+"); 329 330 fputs("test", f1); 331 fputs("test2", f2); 332 fputs("test", f3); 333 fclose(f1); 334 fclose(f2); 335 fclose(f3); 336 337 p = atf_utils_fork(); 338 if (p == 0) { 339 if (luaL_dostring(L, "test.cmp(1)")) { 340 printf("%s\n", lua_tostring(L, -1)); 341 } 342 exit(lua_tonumber(L, -1)); 343 } 344 atf_utils_wait(p, 0, "[string \"test.cmp(1)\"]:1: bad argument #1 to 'cmp' (pkg.filecmp takes exactly two arguments)\n", ""); 345 346 p = atf_utils_fork(); 347 if (p == 0) { 348 if (luaL_dostring(L, "test.cmp(1, 2, 3)")) { 349 printf("%s\n", lua_tostring(L, -1)); 350 } 351 exit(lua_tonumber(L, -1)); 352 } 353 atf_utils_wait(p, 0, "[string \"test.cmp(1, 2, 3)\"]:1: bad argument #3 to 'cmp' (pkg.filecmp takes exactly two arguments)\n", ""); 354 355 p = atf_utils_fork(); 356 if (p == 0) { 357 if (luaL_dostring(L, "return test.cmp(1, 2)")) { 358 printf("%s\n", lua_tostring(L, -1)); 359 } 360 exit(lua_tonumber(L, -1)); 361 } 362 atf_utils_wait(p, 2, "", ""); 363 364 p = atf_utils_fork(); 365 if (p == 0) { 366 if (luaL_dostring(L, "return test.cmp(\"test1\", 2)")) { 367 printf("%s\n", lua_tostring(L, -1)); 368 } 369 exit(lua_tonumber(L, -1)); 370 } 371 atf_utils_wait(p, 2, "", ""); 372 373 p = atf_utils_fork(); 374 if (p == 0) { 375 if (luaL_dostring(L, "return test.cmp(\"test1\", \"test2\")")) { 376 printf("%s\n", lua_tostring(L, -1)); 377 } 378 exit(lua_tonumber(L, -1)); 379 } 380 atf_utils_wait(p, 1, "", ""); 381 382 p = atf_utils_fork(); 383 if (p == 0) { 384 if (luaL_dostring(L, "return test.cmp(\"test1\", \"test3\")")) { 385 printf("%s\n", lua_tostring(L, -1)); 386 } 387 exit(lua_tonumber(L, -1)); 388 } 389 atf_utils_wait(p, 0, "", ""); 390 391 p = atf_utils_fork(); 392 if (p == 0) { 393 if (luaL_dostring(L, "return(test.copy(1, 2))")) { 394 printf("%s\n", lua_tostring(L, -1)); 395 } 396 exit(lua_tonumber(L, -1)); 397 } 398 atf_utils_wait(p, 2, "", ""); 399 400 p = atf_utils_fork(); 401 if (p == 0) { 402 if (luaL_dostring(L, "return(test.copy(\"test1\", \"nonexistent/2\"))")) { 403 printf("%s\n", lua_tostring(L, -1)); 404 } 405 exit(lua_tonumber(L, -1)); 406 } 407 atf_utils_wait(p, 2, "", ""); 408 409 p = atf_utils_fork(); 410 if (p == 0) { 411 if (luaL_dostring(L, "test.copy(\"test1\", \"test4\")\nreturn test.cmp(\"test1\", \"test4\")")) { 412 printf("%s\n", lua_tostring(L, -1)); 413 } 414 exit(lua_tonumber(L, -1)); 415 } 416 atf_utils_wait(p, 0, "", ""); 417 418 p = atf_utils_fork(); 419 if (p == 0) { 420 if (luaL_dostring(L, "test.symlink(\"a\", \"b\", \"meh\")\n")) { 421 printf("%s\n", lua_tostring(L, -1)); 422 } 423 exit(lua_tonumber(L, -1)); 424 } 425 atf_utils_wait(p, 0, "[string \"test.symlink(\"a\", \"b\", \"meh\")...\"]:1: bad argument #3 to 'symlink' (pkg.symlink takes exactly two arguments)\n", ""); 426 427 p = atf_utils_fork(); 428 if (p == 0) { 429 if (luaL_dostring(L, "test.symlink(\"a\")\n")) { 430 printf("%s\n", lua_tostring(L, -1)); 431 } 432 exit(lua_tonumber(L, -1)); 433 } 434 atf_utils_wait(p, 0, "[string \"test.symlink(\"a\")...\"]:1: bad argument #1 to 'symlink' (pkg.symlink takes exactly two arguments)\n", ""); 435 436 p = atf_utils_fork(); 437 if (p == 0) { 438 if (luaL_dostring(L, "test.symlink(\"a\", \"b\")\n")) { 439 printf("%s\n", lua_tostring(L, -1)); 440 } 441 exit(lua_tonumber(L, -1)); 442 } 443 atf_utils_wait(p, 0, "", ""); 444 struct stat st; 445 if (lstat("b", &st) != 0) 446 atf_tc_fail("File 'b' not created"); 447 if (!S_ISLNK(st.st_mode)) 448 atf_tc_fail("File 'b' is not a symlink"); 449 memset(b, 0, sizeof(b)); 450 readlink("b", b, sizeof(b)); 451 ATF_REQUIRE_STREQ(b, "a"); 452 453 } 454 455 ATF_TC_BODY(prefix_path, tc) 456 { 457 struct pkg *pkg = NULL; 458 pkg_new(&pkg, PKG_INSTALLED); 459 pkg_set(pkg, PKG_ATTR_PREFIX, "/myprefix"); 460 lua_State *L = luaL_newstate(); 461 static const luaL_Reg test_lib[] = { 462 { "prefix_path", lua_prefix_path }, 463 { NULL, NULL }, 464 }; 465 luaL_openlibs(L); 466 lua_override_ios(L, false); 467 luaL_newlib(L, test_lib); 468 lua_setglobal(L, "test"); 469 lua_pushlightuserdata(L, pkg); 470 lua_setglobal(L, "package"); 471 pid_t p; 472 473 p = atf_utils_fork(); 474 if (p == 0) { 475 if (luaL_dostring(L, "print(test.prefix_path())")) { 476 printf("%s\n", lua_tostring(L, -1)); 477 } 478 exit(lua_tonumber(L, -1)); 479 } 480 atf_utils_wait(p, 0, "[string \"print(test.prefix_path())\"]:1: bad argument #0 to 'prefix_path' (pkg.prefix_path takes exactly one argument)\n", ""); 481 482 p = atf_utils_fork(); 483 if (p == 0) { 484 if (luaL_dostring(L, "print(test.prefix_path(1, 2))")) { 485 printf("%s\n", lua_tostring(L, -1)); 486 } 487 exit(lua_tonumber(L, -1)); 488 } 489 atf_utils_wait(p, 0, "[string \"print(test.prefix_path(1, 2))\"]:1: bad argument #2 to 'prefix_path' (pkg.prefix_path takes exactly one argument)\n", ""); 490 491 p = atf_utils_fork(); 492 if (p == 0) { 493 if (luaL_dostring(L, "print(test.prefix_path(1))")) { 494 printf("%s\n", lua_tostring(L, -1)); 495 } 496 exit(lua_tonumber(L, -1)); 497 } 498 atf_utils_wait(p, 0, "/myprefix/1\n", ""); 499 500 p = atf_utils_fork(); 501 if (p == 0) { 502 if (luaL_dostring(L, "print(test.prefix_path(\"/1\"))")) { 503 printf("%s\n", lua_tostring(L, -1)); 504 } 505 exit(lua_tonumber(L, -1)); 506 } 507 atf_utils_wait(p, 0, "/1\n", ""); 508 } 509 510 ATF_TP_ADD_TCS(tp) 511 { 512 ATF_TP_ADD_TC(tp, readdir); 513 ATF_TP_ADD_TC(tp, stat); 514 ATF_TP_ADD_TC(tp, print_msg); 515 ATF_TP_ADD_TC(tp, execute); 516 ATF_TP_ADD_TC(tp, override); 517 ATF_TP_ADD_TC(tp, fileops); 518 ATF_TP_ADD_TC(tp, prefix_path); 519 520 return (atf_no_error()); 521 }