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 <errno.h> 12 #include <fnmatch.h> 13 #include <grp.h> 14 #include <libgen.h> 15 #include <pwd.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <unistd.h> 19 20 #include <lua.h> 21 #include "lauxlib.h" 22 #include "lposix.h" 23 24 /* 25 * Minimal implementation of luaposix needed for internal FreeBSD bits. 26 */ 27 static int 28 lua__exit(lua_State *L) 29 { 30 int code, narg; 31 32 narg = lua_gettop(L); 33 luaL_argcheck(L, narg == 1, 1, "_exit takes exactly one argument"); 34 35 code = luaL_checkinteger(L, 1); 36 _exit(code); 37 } 38 39 static int 40 lua_basename(lua_State *L) 41 { 42 char *inpath, *outpath; 43 int narg; 44 45 narg = lua_gettop(L); 46 luaL_argcheck(L, narg > 0, 1, "at least one argument required"); 47 inpath = strdup(luaL_checkstring(L, 1)); 48 if (inpath == NULL) { 49 lua_pushnil(L); 50 lua_pushstring(L, strerror(ENOMEM)); 51 lua_pushinteger(L, ENOMEM); 52 return (3); 53 } 54 55 outpath = basename(inpath); 56 lua_pushstring(L, outpath); 57 free(inpath); 58 return (1); 59 } 60 61 static int 62 lua_chmod(lua_State *L) 63 { 64 int n; 65 const char *path; 66 mode_t mode; 67 68 n = lua_gettop(L); 69 luaL_argcheck(L, n == 2, n > 2 ? 3 : n, 70 "chmod takes exactly two arguments"); 71 path = luaL_checkstring(L, 1); 72 mode = (mode_t)luaL_checkinteger(L, 2); 73 if (chmod(path, mode) == -1) { 74 lua_pushnil(L); 75 lua_pushstring(L, strerror(errno)); 76 lua_pushinteger(L, errno); 77 return (3); 78 } 79 lua_pushinteger(L, 0); 80 return (1); 81 } 82 83 static int 84 lua_chown(lua_State *L) 85 { 86 int n; 87 const char *path; 88 uid_t owner = (uid_t) -1; 89 gid_t group = (gid_t) -1; 90 91 n = lua_gettop(L); 92 luaL_argcheck(L, n > 1, n, 93 "chown takes at least two arguments"); 94 path = luaL_checkstring(L, 1); 95 if (lua_isinteger(L, 2)) 96 owner = (uid_t) lua_tointeger(L, 2); 97 else if (lua_isstring(L, 2)) { 98 struct passwd *p = getpwnam(lua_tostring(L, 2)); 99 if (p != NULL) 100 owner = p->pw_uid; 101 else 102 return (luaL_argerror(L, 2, 103 lua_pushfstring(L, "unknown user %s", 104 lua_tostring(L, 2)))); 105 } else if (!lua_isnoneornil(L, 2)) { 106 const char *type = luaL_typename(L, 2); 107 return (luaL_argerror(L, 2, 108 lua_pushfstring(L, "integer or string expected, got %s", 109 type))); 110 } 111 112 if (lua_isinteger(L, 3)) 113 group = (gid_t) lua_tointeger(L, 3); 114 else if (lua_isstring(L, 3)) { 115 struct group *g = getgrnam(lua_tostring(L, 3)); 116 if (g != NULL) 117 group = g->gr_gid; 118 else 119 return (luaL_argerror(L, 3, 120 lua_pushfstring(L, "unknown group %s", 121 lua_tostring(L, 3)))); 122 } else if (!lua_isnoneornil(L, 3)) { 123 const char *type = luaL_typename(L, 3); 124 return (luaL_argerror(L, 3, 125 lua_pushfstring(L, "integer or string expected, got %s", 126 type))); 127 } 128 129 if (chown(path, owner, group) == -1) { 130 lua_pushnil(L); 131 lua_pushstring(L, strerror(errno)); 132 lua_pushinteger(L, errno); 133 return (3); 134 } 135 lua_pushinteger(L, 0); 136 return (1); 137 } 138 139 static int 140 lua_pclose(lua_State *L) 141 { 142 int error, fd, n; 143 144 n = lua_gettop(L); 145 luaL_argcheck(L, n == 1, 1, 146 "close takes exactly one argument (fd)"); 147 148 fd = luaL_checkinteger(L, 1); 149 if (fd < 0) { 150 error = EBADF; 151 goto err; 152 } 153 154 if (close(fd) == 0) { 155 lua_pushinteger(L, 0); 156 return (1); 157 } 158 159 error = errno; 160 err: 161 lua_pushnil(L); 162 lua_pushstring(L, strerror(error)); 163 lua_pushinteger(L, error); 164 return (3); 165 166 } 167 168 static int 169 lua_fnmatch(lua_State *L) 170 { 171 const char *pattern, *string; 172 int flags, n; 173 174 n = lua_gettop(L); 175 luaL_argcheck(L, n == 2 || n == 3, 4, "need 2 or 3 arguments"); 176 177 pattern = luaL_checkstring(L, 1); 178 string = luaL_checkstring(L, 2); 179 flags = luaL_optinteger(L, 3, 0); 180 lua_pushinteger(L, fnmatch(pattern, string, flags)); 181 182 return (1); 183 } 184 185 static int 186 lua_uname(lua_State *L) 187 { 188 struct utsname name; 189 int error, n; 190 191 n = lua_gettop(L); 192 luaL_argcheck(L, n == 0, 1, "too many arguments"); 193 194 error = uname(&name); 195 if (error != 0) { 196 error = errno; 197 lua_pushnil(L); 198 lua_pushstring(L, strerror(error)); 199 lua_pushinteger(L, error); 200 return (3); 201 } 202 203 lua_newtable(L); 204 #define setkv(f) do { \ 205 lua_pushstring(L, name.f); \ 206 lua_setfield(L, -2, #f); \ 207 } while (0) 208 setkv(sysname); 209 setkv(nodename); 210 setkv(release); 211 setkv(version); 212 setkv(machine); 213 #undef setkv 214 215 return (1); 216 } 217 218 static int 219 lua_dirname(lua_State *L) 220 { 221 char *inpath, *outpath; 222 int narg; 223 224 narg = lua_gettop(L); 225 luaL_argcheck(L, narg > 0, 1, 226 "dirname takes at least one argument (path)"); 227 inpath = strdup(luaL_checkstring(L, 1)); 228 if (inpath == NULL) { 229 lua_pushnil(L); 230 lua_pushstring(L, strerror(ENOMEM)); 231 lua_pushinteger(L, ENOMEM); 232 return (3); 233 } 234 235 outpath = dirname(inpath); 236 lua_pushstring(L, outpath); 237 free(inpath); 238 return (1); 239 } 240 241 static int 242 lua_fork(lua_State *L) 243 { 244 pid_t pid; 245 int narg; 246 247 narg = lua_gettop(L); 248 luaL_argcheck(L, narg == 0, 1, "too many arguments"); 249 250 pid = fork(); 251 if (pid < 0) { 252 lua_pushnil(L); 253 lua_pushstring(L, strerror(errno)); 254 lua_pushinteger(L, errno); 255 return (3); 256 } 257 258 lua_pushinteger(L, pid); 259 return (1); 260 } 261 262 static int 263 lua_getpid(lua_State *L) 264 { 265 int narg; 266 267 narg = lua_gettop(L); 268 luaL_argcheck(L, narg == 0, 1, "too many arguments"); 269 lua_pushinteger(L, getpid()); 270 return (1); 271 } 272 273 static int 274 lua_pipe(lua_State *L) 275 { 276 int error, fd[2], narg; 277 278 narg = lua_gettop(L); 279 luaL_argcheck(L, narg == 0, 1, "too many arguments"); 280 281 error = pipe(fd); 282 if (error != 0) { 283 lua_pushnil(L); 284 lua_pushstring(L, strerror(errno)); 285 lua_pushinteger(L, errno); 286 return (1); 287 } 288 289 lua_pushinteger(L, fd[0]); 290 lua_pushinteger(L, fd[1]); 291 return (2); 292 } 293 294 static int 295 lua_read(lua_State *L) 296 { 297 char *buf; 298 ssize_t ret; 299 size_t sz; 300 int error, fd, narg; 301 302 narg = lua_gettop(L); 303 luaL_argcheck(L, narg == 2, 1, 304 "read takes exactly two arguments (fd, size)"); 305 306 fd = luaL_checkinteger(L, 1); 307 sz = luaL_checkinteger(L, 2); 308 309 if (fd < 0) { 310 error = EBADF; 311 goto err; 312 } 313 314 buf = malloc(sz); 315 if (buf == NULL) 316 goto err; 317 318 /* 319 * For 0-byte reads, we'll still push the empty string and let the 320 * caller deal with EOF to match lposix semantics. 321 */ 322 ret = read(fd, buf, sz); 323 if (ret >= 0) 324 lua_pushlstring(L, buf, ret); 325 else if (ret < 0) 326 error = errno; /* Save to avoid clobber by free() */ 327 328 free(buf); 329 if (error != 0) 330 goto err; 331 332 /* Just the string pushed. */ 333 return (1); 334 err: 335 lua_pushnil(L); 336 lua_pushstring(L, strerror(error)); 337 lua_pushinteger(L, error); 338 return (3); 339 } 340 341 static int 342 lua_realpath(lua_State *L) 343 { 344 const char *inpath; 345 char *outpath; 346 int narg; 347 348 narg = lua_gettop(L); 349 luaL_argcheck(L, narg > 0, 1, "at least one argument required"); 350 inpath = luaL_checkstring(L, 1); 351 352 outpath = realpath(inpath, NULL); 353 if (outpath == NULL) { 354 lua_pushnil(L); 355 lua_pushstring(L, strerror(errno)); 356 lua_pushinteger(L, errno); 357 return (3); 358 } 359 360 lua_pushstring(L, outpath); 361 free(outpath); 362 return (1); 363 } 364 365 static int 366 lua_wait(lua_State *L) 367 { 368 pid_t pid; 369 int options, status; 370 int narg; 371 372 narg = lua_gettop(L); 373 374 pid = -1; 375 status = options = 0; 376 if (narg >= 1 && !lua_isnil(L, 1)) 377 pid = luaL_checkinteger(L, 1); 378 if (narg >= 2 && !lua_isnil(L, 2)) 379 options = luaL_checkinteger(L, 2); 380 381 pid = waitpid(pid, &status, options); 382 if (pid < 0) { 383 lua_pushnil(L); 384 lua_pushstring(L, strerror(errno)); 385 lua_pushinteger(L, errno); 386 return (3); 387 } 388 389 lua_pushinteger(L, pid); 390 if (pid == 0) { 391 lua_pushliteral(L, "running"); 392 return (2); 393 } 394 395 if (WIFCONTINUED(status)) { 396 lua_pushliteral(L, "continued"); 397 return (2); 398 } else if(WIFSTOPPED(status)) { 399 lua_pushliteral(L, "stopped"); 400 lua_pushinteger(L, WSTOPSIG(status)); 401 return (3); 402 } else if (WIFEXITED(status)) { 403 lua_pushliteral(L, "exited"); 404 lua_pushinteger(L, WEXITSTATUS(status)); 405 return (3); 406 } else if (WIFSIGNALED(status)) { 407 lua_pushliteral(L, "killed"); 408 lua_pushinteger(L, WTERMSIG(status)); 409 return (3); 410 } 411 412 return (1); 413 } 414 415 static int 416 lua_write(lua_State *L) 417 { 418 const char *buf; 419 size_t bufsz, sz; 420 ssize_t ret; 421 off_t offset; 422 int error, fd, narg; 423 424 narg = lua_gettop(L); 425 luaL_argcheck(L, narg >= 2, 1, 426 "write takes at least two arguments (fd, buf, sz, off)"); 427 luaL_argcheck(L, narg <= 4, 5, 428 "write takes no more than four arguments (fd, buf, sz, off)"); 429 430 fd = luaL_checkinteger(L, 1); 431 if (fd < 0) { 432 error = EBADF; 433 goto err; 434 } 435 436 buf = luaL_checkstring(L, 2); 437 438 bufsz = sz = lua_rawlen(L, 2); 439 if (narg >= 3 && !lua_isnil(L, 3)) 440 sz = luaL_checkinteger(L, 3); 441 442 offset = 0; 443 if (narg >= 4 && !lua_isnil(L, 4)) 444 offset = luaL_checkinteger(L, 4); 445 446 if ((size_t)offset > bufsz || offset + sz > bufsz) { 447 lua_pushnil(L); 448 lua_pushfstring(L, 449 "write: invalid access offset %zu, size %zu in a buffer size %zu", 450 offset, sz, bufsz); 451 lua_pushinteger(L, EINVAL); 452 return (3); 453 } 454 455 ret = write(fd, buf + offset, sz); 456 if (ret < 0) { 457 error = errno; 458 goto err; 459 } 460 461 lua_pushinteger(L, ret); 462 return (1); 463 err: 464 lua_pushnil(L); 465 lua_pushstring(L, strerror(error)); 466 lua_pushinteger(L, error); 467 return (3); 468 } 469 470 #define REG_DEF(n, func) { #n, func } 471 #define REG_SIMPLE(n) REG_DEF(n, lua_ ## n) 472 static const struct luaL_Reg libgenlib[] = { 473 REG_SIMPLE(basename), 474 REG_SIMPLE(dirname), 475 { NULL, NULL }, 476 }; 477 478 static const struct luaL_Reg stdliblib[] = { 479 REG_SIMPLE(realpath), 480 { NULL, NULL }, 481 }; 482 483 static const struct luaL_Reg fnmatchlib[] = { 484 REG_SIMPLE(fnmatch), 485 { NULL, NULL }, 486 }; 487 488 static const struct luaL_Reg sys_statlib[] = { 489 REG_SIMPLE(chmod), 490 { NULL, NULL }, 491 }; 492 493 static const struct luaL_Reg sys_utsnamelib[] = { 494 REG_SIMPLE(uname), 495 { NULL, NULL }, 496 }; 497 498 static const struct luaL_Reg sys_waitlib[] = { 499 REG_SIMPLE(wait), 500 {NULL, NULL}, 501 }; 502 503 static const struct luaL_Reg unistdlib[] = { 504 REG_SIMPLE(_exit), 505 REG_SIMPLE(chown), 506 REG_DEF(close, lua_pclose), 507 REG_SIMPLE(fork), 508 REG_SIMPLE(getpid), 509 REG_SIMPLE(pipe), 510 REG_SIMPLE(read), 511 REG_SIMPLE(write), 512 { NULL, NULL }, 513 }; 514 515 #undef REG_SIMPLE 516 #undef REG_DEF 517 518 int 519 luaopen_posix_libgen(lua_State *L) 520 { 521 luaL_newlib(L, libgenlib); 522 return (1); 523 } 524 525 int 526 luaopen_posix_stdlib(lua_State *L) 527 { 528 luaL_newlib(L, stdliblib); 529 return (1); 530 } 531 532 int 533 luaopen_posix_fnmatch(lua_State *L) 534 { 535 luaL_newlib(L, fnmatchlib); 536 537 #define setkv(f) do { \ 538 lua_pushinteger(L, f); \ 539 lua_setfield(L, -2, #f); \ 540 } while (0) 541 setkv(FNM_PATHNAME); 542 setkv(FNM_NOESCAPE); 543 setkv(FNM_NOMATCH); 544 setkv(FNM_PERIOD); 545 #undef setkv 546 547 return 1; 548 } 549 550 int 551 luaopen_posix_sys_stat(lua_State *L) 552 { 553 luaL_newlib(L, sys_statlib); 554 return (1); 555 } 556 557 int 558 luaopen_posix_sys_wait(lua_State *L) 559 { 560 luaL_newlib(L, sys_waitlib); 561 562 #define lua_pushflag(L, flag) do { \ 563 lua_pushinteger(L, flag); \ 564 lua_setfield(L, -2, #flag); \ 565 } while(0) 566 567 /* Only these two exported by lposix */ 568 lua_pushflag(L, WNOHANG); 569 lua_pushflag(L, WUNTRACED); 570 571 lua_pushflag(L, WCONTINUED); 572 lua_pushflag(L, WSTOPPED); 573 #ifdef WTRAPPED 574 lua_pushflag(L, WTRAPPED); 575 #endif 576 lua_pushflag(L, WEXITED); 577 lua_pushflag(L, WNOWAIT); 578 #undef lua_pushflag 579 580 return (1); 581 } 582 583 int 584 luaopen_posix_sys_utsname(lua_State *L) 585 { 586 luaL_newlib(L, sys_utsnamelib); 587 return 1; 588 } 589 590 int 591 luaopen_posix_unistd(lua_State *L) 592 { 593 luaL_newlib(L, unistdlib); 594 return (1); 595 } 596