1 /*- 2 * Copyright (c) 2019, 2023 Kyle Evans <kevans@FreeBSD.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #include <sys/stat.h> 8 #include <sys/utsname.h> 9 #include <sys/wait.h> 10 11 #include <assert.h> 12 #include <errno.h> 13 #include <fnmatch.h> 14 #include <grp.h> 15 #include <libgen.h> 16 #include <pwd.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <unistd.h> 20 21 #include <lua.h> 22 #include "lauxlib.h" 23 #include "lposix.h" 24 25 static void 26 enforce_max_args(lua_State *L, int max) 27 { 28 int narg; 29 30 narg = lua_gettop(L); 31 luaL_argcheck(L, narg <= max, max + 1, "too many arguments"); 32 } 33 34 /* 35 * Minimal implementation of luaposix needed for internal FreeBSD bits. 36 */ 37 static int 38 lua__exit(lua_State *L) 39 { 40 int code; 41 42 enforce_max_args(L, 1); 43 code = luaL_checkinteger(L, 1); 44 45 _exit(code); 46 } 47 48 static int 49 lua_basename(lua_State *L) 50 { 51 char *inpath, *outpath; 52 53 enforce_max_args(L, 1); 54 inpath = strdup(luaL_checkstring(L, 1)); 55 if (inpath == NULL) { 56 lua_pushnil(L); 57 lua_pushstring(L, strerror(ENOMEM)); 58 lua_pushinteger(L, ENOMEM); 59 return (3); 60 } 61 62 outpath = basename(inpath); 63 lua_pushstring(L, outpath); 64 free(inpath); 65 return (1); 66 } 67 68 static int 69 lua_chmod(lua_State *L) 70 { 71 const char *path; 72 mode_t mode; 73 74 enforce_max_args(L, 2); 75 path = luaL_checkstring(L, 1); 76 mode = (mode_t)luaL_checkinteger(L, 2); 77 78 if (chmod(path, mode) == -1) { 79 lua_pushnil(L); 80 lua_pushstring(L, strerror(errno)); 81 lua_pushinteger(L, errno); 82 return (3); 83 } 84 lua_pushinteger(L, 0); 85 return (1); 86 } 87 88 static int 89 lua_chown(lua_State *L) 90 { 91 const char *path; 92 uid_t owner = (uid_t)-1; 93 gid_t group = (gid_t)-1; 94 int error; 95 96 enforce_max_args(L, 3); 97 98 path = luaL_checkstring(L, 1); 99 if (lua_isinteger(L, 2)) 100 owner = (uid_t)lua_tointeger(L, 2); 101 else if (lua_isstring(L, 2)) { 102 char buf[4096]; 103 struct passwd passwd, *pwd = NULL; 104 105 error = getpwnam_r(lua_tostring(L, 2), &passwd, 106 buf, sizeof(buf), &pwd); 107 if (pwd != NULL && error == 0) 108 owner = pwd->pw_uid; 109 else 110 return (luaL_argerror(L, 2, 111 lua_pushfstring(L, "unknown user %s", 112 lua_tostring(L, 2)))); 113 } else if (!lua_isnoneornil(L, 2)) { 114 const char *type = luaL_typename(L, 2); 115 return (luaL_argerror(L, 2, 116 lua_pushfstring(L, "integer or string expected, got %s", 117 type))); 118 } 119 120 if (lua_isinteger(L, 3)) 121 group = (gid_t)lua_tointeger(L, 3); 122 else if (lua_isstring(L, 3)) { 123 char buf[4096]; 124 struct group gr, *grp = NULL; 125 126 error = getgrnam_r(lua_tostring(L, 3), &gr, buf, sizeof(buf), 127 &grp); 128 if (grp != NULL && error == 0) 129 group = grp->gr_gid; 130 else 131 return (luaL_argerror(L, 3, 132 lua_pushfstring(L, "unknown group %s", 133 lua_tostring(L, 3)))); 134 } else if (!lua_isnoneornil(L, 3)) { 135 const char *type = luaL_typename(L, 3); 136 return (luaL_argerror(L, 3, 137 lua_pushfstring(L, "integer or string expected, got %s", 138 type))); 139 } 140 141 if (chown(path, owner, group) == -1) { 142 lua_pushnil(L); 143 lua_pushstring(L, strerror(errno)); 144 lua_pushinteger(L, errno); 145 return (3); 146 } 147 lua_pushinteger(L, 0); 148 return (1); 149 } 150 151 static int 152 lua_pclose(lua_State *L) 153 { 154 int error, fd; 155 156 enforce_max_args(L, 1); 157 158 fd = luaL_checkinteger(L, 1); 159 if (fd < 0) { 160 error = EBADF; 161 goto err; 162 } 163 164 if (close(fd) == 0) { 165 lua_pushinteger(L, 0); 166 return (1); 167 } 168 169 error = errno; 170 err: 171 lua_pushnil(L); 172 lua_pushstring(L, strerror(error)); 173 lua_pushinteger(L, error); 174 return (3); 175 176 } 177 178 static int 179 lua_dup2(lua_State *L) 180 { 181 int error, oldd, newd; 182 183 enforce_max_args(L, 2); 184 185 oldd = luaL_checkinteger(L, 1); 186 if (oldd < 0) { 187 error = EBADF; 188 goto err; 189 } 190 191 newd = luaL_checkinteger(L, 2); 192 if (newd < 0) { 193 error = EBADF; 194 goto err; 195 } 196 197 error = dup2(oldd, newd); 198 if (error >= 0) { 199 lua_pushinteger(L, error); 200 return (1); 201 } 202 203 error = errno; 204 err: 205 lua_pushnil(L); 206 lua_pushstring(L, strerror(error)); 207 lua_pushinteger(L, error); 208 return (3); 209 } 210 211 static int 212 lua_execp(lua_State *L) 213 { 214 int argc, error; 215 const char *file; 216 const char **argv; 217 218 enforce_max_args(L, 2); 219 220 file = luaL_checkstring(L, 1); 221 luaL_checktype(L, 2, LUA_TTABLE); 222 223 lua_len(L, 2); 224 argc = lua_tointeger(L, -1); 225 226 /* 227 * Use lua_newuserdatauv() to allocate a scratch buffer that is tracked 228 * and freed by lua's GC. This avoid any chance of a leak if a lua error 229 * is raised later in this function (e.g. by luaL_argerror()). 230 * The (argc + 2) size gives enough space in the buffer for argv[0] and 231 * the terminating NULL. 232 */ 233 argv = lua_newuserdatauv(L, (argc + 2) * sizeof(char *), 0); 234 235 /* 236 * Sequential tables in lua start at index 1 by convention. 237 * If there happens to be a string at index 0, use that to 238 * override the default argv[0]. This matches the lposix API. 239 */ 240 lua_pushinteger(L, 0); 241 lua_gettable(L, 2); 242 argv[0] = lua_tostring(L, -1); 243 if (argv[0] == NULL) { 244 argv[0] = file; 245 } 246 247 for (int i = 1; i <= argc; i++) { 248 lua_pushinteger(L, i); 249 lua_gettable(L, 2); 250 argv[i] = lua_tostring(L, -1); 251 if (argv[i] == NULL) { 252 luaL_argerror(L, 2, 253 "argv table must contain only strings"); 254 } 255 } 256 argv[argc + 1] = NULL; 257 258 execvp(file, __DECONST(char **, argv)); 259 error = errno; 260 261 lua_pushnil(L); 262 lua_pushstring(L, strerror(error)); 263 lua_pushinteger(L, error); 264 return (3); 265 } 266 267 static int 268 lua_fnmatch(lua_State *L) 269 { 270 const char *pattern, *string; 271 int flags; 272 273 enforce_max_args(L, 3); 274 pattern = luaL_checkstring(L, 1); 275 string = luaL_checkstring(L, 2); 276 flags = luaL_optinteger(L, 3, 0); 277 278 lua_pushinteger(L, fnmatch(pattern, string, flags)); 279 280 return (1); 281 } 282 283 static int 284 lua_uname(lua_State *L) 285 { 286 struct utsname name; 287 int error; 288 289 enforce_max_args(L, 0); 290 291 error = uname(&name); 292 if (error != 0) { 293 error = errno; 294 lua_pushnil(L); 295 lua_pushstring(L, strerror(error)); 296 lua_pushinteger(L, error); 297 return (3); 298 } 299 300 lua_newtable(L); 301 #define setkv(f) do { \ 302 lua_pushstring(L, name.f); \ 303 lua_setfield(L, -2, #f); \ 304 } while (0) 305 setkv(sysname); 306 setkv(nodename); 307 setkv(release); 308 setkv(version); 309 setkv(machine); 310 #undef setkv 311 312 return (1); 313 } 314 315 static int 316 lua_dirname(lua_State *L) 317 { 318 char *inpath, *outpath; 319 320 enforce_max_args(L, 1); 321 322 inpath = strdup(luaL_checkstring(L, 1)); 323 if (inpath == NULL) { 324 lua_pushnil(L); 325 lua_pushstring(L, strerror(ENOMEM)); 326 lua_pushinteger(L, ENOMEM); 327 return (3); 328 } 329 330 outpath = dirname(inpath); 331 lua_pushstring(L, outpath); 332 free(inpath); 333 return (1); 334 } 335 336 static int 337 lua_fork(lua_State *L) 338 { 339 pid_t pid; 340 341 enforce_max_args(L, 0); 342 343 pid = fork(); 344 if (pid < 0) { 345 lua_pushnil(L); 346 lua_pushstring(L, strerror(errno)); 347 lua_pushinteger(L, errno); 348 return (3); 349 } 350 351 lua_pushinteger(L, pid); 352 return (1); 353 } 354 355 static int 356 lua_getpid(lua_State *L) 357 { 358 enforce_max_args(L, 0); 359 360 lua_pushinteger(L, getpid()); 361 return (1); 362 } 363 364 static int 365 lua_pipe(lua_State *L) 366 { 367 int error, fd[2]; 368 369 enforce_max_args(L, 0); 370 371 error = pipe(fd); 372 if (error != 0) { 373 lua_pushnil(L); 374 lua_pushstring(L, strerror(errno)); 375 lua_pushinteger(L, errno); 376 return (1); 377 } 378 379 lua_pushinteger(L, fd[0]); 380 lua_pushinteger(L, fd[1]); 381 return (2); 382 } 383 384 static int 385 lua_read(lua_State *L) 386 { 387 char *buf; 388 ssize_t ret; 389 size_t sz; 390 int error = 0, fd; 391 392 enforce_max_args(L, 2); 393 fd = luaL_checkinteger(L, 1); 394 sz = luaL_checkinteger(L, 2); 395 396 if (fd < 0) { 397 error = EBADF; 398 goto err; 399 } 400 401 buf = malloc(sz); 402 if (buf == NULL) { 403 error = errno; 404 goto err; 405 } 406 407 /* 408 * For 0-byte reads, we'll still push the empty string and let the 409 * caller deal with EOF to match lposix semantics. 410 */ 411 ret = read(fd, buf, sz); 412 if (ret >= 0) 413 lua_pushlstring(L, buf, ret); 414 else if (ret < 0) 415 error = errno; /* Save to avoid clobber by free() */ 416 417 free(buf); 418 if (ret < 0) 419 goto err; 420 421 /* Just the string pushed. */ 422 return (1); 423 err: 424 assert(error != 0); 425 lua_pushnil(L); 426 lua_pushstring(L, strerror(error)); 427 lua_pushinteger(L, error); 428 return (3); 429 } 430 431 static int 432 lua_realpath(lua_State *L) 433 { 434 const char *inpath; 435 char *outpath; 436 437 enforce_max_args(L, 1); 438 inpath = luaL_checkstring(L, 1); 439 440 outpath = realpath(inpath, NULL); 441 if (outpath == NULL) { 442 lua_pushnil(L); 443 lua_pushstring(L, strerror(errno)); 444 lua_pushinteger(L, errno); 445 return (3); 446 } 447 448 lua_pushstring(L, outpath); 449 free(outpath); 450 return (1); 451 } 452 453 static int 454 lua_wait(lua_State *L) 455 { 456 pid_t pid; 457 int options, status; 458 459 enforce_max_args(L, 2); 460 pid = luaL_optinteger(L, 1, -1); 461 options = luaL_optinteger(L, 2, 0); 462 463 status = 0; 464 pid = waitpid(pid, &status, options); 465 if (pid < 0) { 466 lua_pushnil(L); 467 lua_pushstring(L, strerror(errno)); 468 lua_pushinteger(L, errno); 469 return (3); 470 } 471 472 lua_pushinteger(L, pid); 473 if (pid == 0) { 474 lua_pushliteral(L, "running"); 475 return (2); 476 } 477 478 if (WIFCONTINUED(status)) { 479 lua_pushliteral(L, "continued"); 480 return (2); 481 } else if(WIFSTOPPED(status)) { 482 lua_pushliteral(L, "stopped"); 483 lua_pushinteger(L, WSTOPSIG(status)); 484 return (3); 485 } else if (WIFEXITED(status)) { 486 lua_pushliteral(L, "exited"); 487 lua_pushinteger(L, WEXITSTATUS(status)); 488 return (3); 489 } else if (WIFSIGNALED(status)) { 490 lua_pushliteral(L, "killed"); 491 lua_pushinteger(L, WTERMSIG(status)); 492 return (3); 493 } 494 495 return (1); 496 } 497 498 static int 499 lua_write(lua_State *L) 500 { 501 const char *buf; 502 size_t bufsz, sz; 503 ssize_t ret; 504 off_t offset; 505 int error, fd; 506 507 enforce_max_args(L, 4); 508 509 fd = luaL_checkinteger(L, 1); 510 if (fd < 0) { 511 error = EBADF; 512 goto err; 513 } 514 515 buf = luaL_checkstring(L, 2); 516 517 bufsz = lua_rawlen(L, 2); 518 sz = luaL_optinteger(L, 3, bufsz); 519 520 offset = luaL_optinteger(L, 4, 0); 521 522 523 if ((size_t)offset > bufsz || offset + sz > bufsz) { 524 lua_pushnil(L); 525 lua_pushfstring(L, 526 "write: invalid access offset %zu, size %zu in a buffer size %zu", 527 offset, sz, bufsz); 528 lua_pushinteger(L, EINVAL); 529 return (3); 530 } 531 532 ret = write(fd, buf + offset, sz); 533 if (ret < 0) { 534 error = errno; 535 goto err; 536 } 537 538 lua_pushinteger(L, ret); 539 return (1); 540 err: 541 lua_pushnil(L); 542 lua_pushstring(L, strerror(error)); 543 lua_pushinteger(L, error); 544 return (3); 545 } 546 547 #define REG_DEF(n, func) { #n, func } 548 #define REG_SIMPLE(n) REG_DEF(n, lua_ ## n) 549 static const struct luaL_Reg libgenlib[] = { 550 REG_SIMPLE(basename), 551 REG_SIMPLE(dirname), 552 { NULL, NULL }, 553 }; 554 555 static const struct luaL_Reg stdliblib[] = { 556 REG_SIMPLE(realpath), 557 { NULL, NULL }, 558 }; 559 560 static const struct luaL_Reg fnmatchlib[] = { 561 REG_SIMPLE(fnmatch), 562 { NULL, NULL }, 563 }; 564 565 static const struct luaL_Reg sys_statlib[] = { 566 REG_SIMPLE(chmod), 567 { NULL, NULL }, 568 }; 569 570 static const struct luaL_Reg sys_utsnamelib[] = { 571 REG_SIMPLE(uname), 572 { NULL, NULL }, 573 }; 574 575 static const struct luaL_Reg sys_waitlib[] = { 576 REG_SIMPLE(wait), 577 {NULL, NULL}, 578 }; 579 580 static const struct luaL_Reg unistdlib[] = { 581 REG_SIMPLE(_exit), 582 REG_SIMPLE(chown), 583 REG_DEF(close, lua_pclose), 584 REG_SIMPLE(dup2), 585 REG_SIMPLE(execp), 586 REG_SIMPLE(fork), 587 REG_SIMPLE(getpid), 588 REG_SIMPLE(pipe), 589 REG_SIMPLE(read), 590 REG_SIMPLE(write), 591 { NULL, NULL }, 592 }; 593 594 #undef REG_SIMPLE 595 #undef REG_DEF 596 597 static int 598 luaopen_posix_libgen(lua_State *L) 599 { 600 luaL_newlib(L, libgenlib); 601 return (1); 602 } 603 604 static int 605 luaopen_posix_stdlib(lua_State *L) 606 { 607 luaL_newlib(L, stdliblib); 608 return (1); 609 } 610 611 static int 612 luaopen_posix_fnmatch(lua_State *L) 613 { 614 luaL_newlib(L, fnmatchlib); 615 616 #define setkv(f) do { \ 617 lua_pushinteger(L, f); \ 618 lua_setfield(L, -2, #f); \ 619 } while (0) 620 setkv(FNM_PATHNAME); 621 setkv(FNM_NOESCAPE); 622 setkv(FNM_NOMATCH); 623 setkv(FNM_PERIOD); 624 #undef setkv 625 626 return 1; 627 } 628 629 static int 630 luaopen_posix_sys_stat(lua_State *L) 631 { 632 luaL_newlib(L, sys_statlib); 633 return (1); 634 } 635 636 static int 637 luaopen_posix_sys_utsname(lua_State *L) 638 { 639 luaL_newlib(L, sys_utsnamelib); 640 return 1; 641 } 642 643 static int 644 luaopen_posix_sys_wait(lua_State *L) 645 { 646 luaL_newlib(L, sys_waitlib); 647 648 #define lua_pushflag(L, flag) do { \ 649 lua_pushinteger(L, flag); \ 650 lua_setfield(L, -2, #flag); \ 651 } while(0) 652 653 /* Only these two exported by lposix */ 654 lua_pushflag(L, WNOHANG); 655 lua_pushflag(L, WUNTRACED); 656 657 lua_pushflag(L, WCONTINUED); 658 lua_pushflag(L, WSTOPPED); 659 #ifdef WTRAPPED 660 lua_pushflag(L, WTRAPPED); 661 #endif 662 lua_pushflag(L, WEXITED); 663 lua_pushflag(L, WNOWAIT); 664 #undef lua_pushflag 665 666 return (1); 667 } 668 669 static int 670 luaopen_posix_unistd(lua_State *L) 671 { 672 luaL_newlib(L, unistdlib); 673 return (1); 674 } 675 676 int 677 luaopen_posix(lua_State *L) 678 { 679 lua_newtable(L); /* posix */ 680 681 luaL_requiref(L, "posix.fnmatch", luaopen_posix_fnmatch, 0); 682 lua_setfield(L, -2, "fnmatch"); 683 684 luaL_requiref(L, "posix.libgen", luaopen_posix_libgen, 0); 685 lua_setfield(L, -2, "libgen"); 686 687 luaL_requiref(L, "posix.stdlib", luaopen_posix_stdlib, 0); 688 lua_setfield(L, -2, "stdlib"); 689 690 lua_newtable(L); /* posix.sys */ 691 luaL_requiref(L, "posix.sys.stat", luaopen_posix_sys_stat, 0); 692 lua_setfield(L, -2, "stat"); 693 luaL_requiref(L, "posix.sys.utsname", luaopen_posix_sys_utsname, 0); 694 lua_setfield(L, -2, "utsname"); 695 luaL_requiref(L, "posix.sys.wait", luaopen_posix_sys_wait, 0); 696 lua_setfield(L, -2, "wait"); 697 lua_setfield(L, -2, "sys"); 698 699 luaL_requiref(L, "posix.unistd", luaopen_posix_unistd, 0); 700 lua_setfield(L, -2, "unistd"); 701 702 return (1); 703 } 704