1 /*- 2 * Copyright (c) 2014 Pedro Souza <pedrosouza@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 * 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 AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 33 #include "lua.h" 34 #include "lauxlib.h" 35 #include "lstd.h" 36 #include "lutils.h" 37 #include "bootstrap.h" 38 39 /* 40 * Like loader.perform, except args are passed already parsed 41 * on the stack. 42 */ 43 static int 44 lua_command(lua_State *L) 45 { 46 int i; 47 int res = 1; 48 int argc = lua_gettop(L); 49 char **argv; 50 51 argv = malloc(sizeof(char *) * (argc + 1)); 52 if (argv == NULL) 53 return 0; 54 for (i = 0; i < argc; i++) 55 argv[i] = (char *)(intptr_t)luaL_checkstring(L, i + 1); 56 argv[argc] = NULL; 57 res = interp_builtin_cmd(argc, argv); 58 free(argv); 59 lua_pushinteger(L, res); 60 61 return 1; 62 } 63 64 static int 65 lua_perform(lua_State *L) 66 { 67 int argc; 68 char **argv; 69 int res = 1; 70 71 if (parse(&argc, &argv, luaL_checkstring(L, 1)) == 0) { 72 res = interp_builtin_cmd(argc, argv); 73 free(argv); 74 } 75 lua_pushinteger(L, res); 76 77 return 1; 78 } 79 80 static int 81 lua_command_error(lua_State *L) 82 { 83 84 lua_pushstring(L, command_errbuf); 85 return 1; 86 } 87 88 /* 89 * Accepts a space-delimited loader command and runs it through the standard 90 * loader parsing, as if it were executed at the loader prompt by the user. 91 */ 92 static int 93 lua_interpret(lua_State *L) 94 { 95 const char *interp_string; 96 97 if (lua_gettop(L) != 1) { 98 lua_pushnil(L); 99 return 1; 100 } 101 102 interp_string = luaL_checkstring(L, 1); 103 lua_pushinteger(L, interp_run(interp_string)); 104 return 1; 105 } 106 107 static int 108 lua_parse(lua_State *L) 109 { 110 int argc, nargc; 111 char **argv; 112 113 if (parse(&argc, &argv, luaL_checkstring(L, 1)) == 0) { 114 for (nargc = 0; nargc < argc; ++nargc) { 115 lua_pushstring(L, argv[nargc]); 116 } 117 free(argv); 118 return nargc; 119 } 120 121 lua_pushnil(L); 122 return 1; 123 } 124 125 static int 126 lua_getchar(lua_State *L) 127 { 128 129 lua_pushinteger(L, getchar()); 130 return 1; 131 } 132 133 static int 134 lua_ischar(lua_State *L) 135 { 136 137 lua_pushboolean(L, ischar()); 138 return 1; 139 } 140 141 static int 142 lua_gets(lua_State *L) 143 { 144 char buf[129]; 145 146 ngets(buf, 128); 147 lua_pushstring(L, buf); 148 return 1; 149 } 150 151 static int 152 lua_time(lua_State *L) 153 { 154 155 lua_pushinteger(L, time(NULL)); 156 return 1; 157 } 158 159 static int 160 lua_delay(lua_State *L) 161 { 162 163 delay((int)luaL_checknumber(L, 1)); 164 return 0; 165 } 166 167 static int 168 lua_getenv(lua_State *L) 169 { 170 lua_pushstring(L, getenv(luaL_checkstring(L, 1))); 171 172 return 1; 173 } 174 175 static int 176 lua_setenv(lua_State *L) 177 { 178 const char *key, *val; 179 180 key = luaL_checkstring(L, 1); 181 val = luaL_checkstring(L, 2); 182 lua_pushinteger(L, setenv(key, val, 1)); 183 184 return 1; 185 } 186 187 static int 188 lua_unsetenv(lua_State *L) 189 { 190 const char *ev; 191 192 ev = luaL_checkstring(L, 1); 193 lua_pushinteger(L, unsetenv(ev)); 194 195 return 1; 196 } 197 198 static int 199 lua_printc(lua_State *L) 200 { 201 ssize_t cur, l; 202 const char *s = luaL_checklstring(L, 1, &l); 203 204 for (cur = 0; cur < l; ++cur) 205 putchar((unsigned char)*(s++)); 206 207 return 1; 208 } 209 210 static int 211 lua_openfile(lua_State *L) 212 { 213 const char *mode, *str; 214 int nargs; 215 216 nargs = lua_gettop(L); 217 if (nargs < 1 || nargs > 2) { 218 lua_pushnil(L); 219 return 1; 220 } 221 str = lua_tostring(L, 1); 222 mode = "r"; 223 if (nargs > 1) { 224 mode = lua_tostring(L, 2); 225 if (mode == NULL) { 226 lua_pushnil(L); 227 return 1; 228 } 229 } 230 FILE * f = fopen(str, mode); 231 if (f != NULL) { 232 FILE ** ptr = (FILE**)lua_newuserdata(L, sizeof(FILE**)); 233 *ptr = f; 234 } else 235 lua_pushnil(L); 236 return 1; 237 } 238 239 static int 240 lua_closefile(lua_State *L) 241 { 242 FILE ** f; 243 if (lua_gettop(L) != 1) { 244 lua_pushboolean(L, 0); 245 return 1; 246 } 247 248 f = (FILE**)lua_touserdata(L, 1); 249 if (f != NULL && *f != NULL) { 250 lua_pushboolean(L, fclose(*f) == 0 ? 1 : 0); 251 *f = NULL; 252 } else 253 lua_pushboolean(L, 0); 254 255 return 1; 256 } 257 258 static int 259 lua_readfile(lua_State *L) 260 { 261 FILE **f; 262 size_t size, r; 263 char * buf; 264 265 if (lua_gettop(L) < 1 || lua_gettop(L) > 2) { 266 lua_pushnil(L); 267 lua_pushinteger(L, 0); 268 return 2; 269 } 270 271 f = (FILE**)lua_touserdata(L, 1); 272 273 if (f == NULL || *f == NULL) { 274 lua_pushnil(L); 275 lua_pushinteger(L, 0); 276 return 2; 277 } 278 279 if (lua_gettop(L) == 2) 280 size = (size_t)lua_tonumber(L, 2); 281 else 282 size = (*f)->size; 283 284 285 buf = (char*)malloc(size); 286 r = fread(buf, 1, size, *f); 287 lua_pushlstring(L, buf, r); 288 free(buf); 289 lua_pushinteger(L, r); 290 291 return 2; 292 } 293 294 /* 295 * Implements io.write(file, ...) 296 * Any number of string and number arguments may be passed to it, 297 * and it will return the number of bytes written, or nil, an error string, and 298 * the errno. 299 */ 300 static int 301 lua_writefile(lua_State *L) 302 { 303 FILE **f; 304 const char *buf; 305 int i, nargs; 306 size_t bufsz, w, wrsz; 307 308 buf = NULL; 309 bufsz = 0; 310 w = 0; 311 wrsz = 0; 312 nargs = lua_gettop(L); 313 if (nargs < 2) { 314 errno = EINVAL; 315 return luaL_fileresult(L, 0, NULL); 316 } 317 318 f = (FILE**)lua_touserdata(L, 1); 319 320 if (f == NULL || *f == NULL) { 321 errno = EINVAL; 322 return luaL_fileresult(L, 0, NULL); 323 } 324 325 /* Do a validation pass first */ 326 for (i = 0; i < nargs - 1; i++) { 327 /* 328 * With Lua's API, lua_isstring really checks if the argument 329 * is a string or a number. The latter will be implicitly 330 * converted to a string by our later call to lua_tolstring. 331 */ 332 if (!lua_isstring(L, i + 2)) { 333 errno = EINVAL; 334 return luaL_fileresult(L, 0, NULL); 335 } 336 } 337 for (i = 0; i < nargs - 1; i++) { 338 /* We've already validated; there's no chance of failure */ 339 buf = lua_tolstring(L, i + 2, &bufsz); 340 wrsz = fwrite(buf, 1, bufsz, *f); 341 if (wrsz < bufsz) 342 return luaL_fileresult(L, 0, NULL); 343 w += wrsz; 344 } 345 lua_pushinteger(L, w); 346 return 1; 347 } 348 349 #define REG_SIMPLE(n) { #n, lua_ ## n } 350 static const struct luaL_Reg loaderlib[] = { 351 REG_SIMPLE(delay), 352 REG_SIMPLE(command_error), 353 REG_SIMPLE(command), 354 REG_SIMPLE(interpret), 355 REG_SIMPLE(parse), 356 REG_SIMPLE(getenv), 357 REG_SIMPLE(perform), 358 /* Also registered as the global 'printc' */ 359 REG_SIMPLE(printc), 360 REG_SIMPLE(setenv), 361 REG_SIMPLE(time), 362 REG_SIMPLE(unsetenv), 363 { NULL, NULL }, 364 }; 365 366 static const struct luaL_Reg iolib[] = { 367 { "close", lua_closefile }, 368 REG_SIMPLE(getchar), 369 REG_SIMPLE(gets), 370 REG_SIMPLE(ischar), 371 { "open", lua_openfile }, 372 { "read", lua_readfile }, 373 { "write", lua_writefile }, 374 { NULL, NULL }, 375 }; 376 #undef REG_SIMPLE 377 378 int 379 luaopen_loader(lua_State *L) 380 { 381 luaL_newlib(L, loaderlib); 382 /* Add loader.machine and loader.machine_arch properties */ 383 lua_pushstring(L, MACHINE); 384 lua_setfield(L, -2, "machine"); 385 lua_pushstring(L, MACHINE_ARCH); 386 lua_setfield(L, -2, "machine_arch"); 387 lua_pushstring(L, LUA_PATH); 388 lua_setfield(L, -2, "lua_path"); 389 /* Set global printc to loader.printc */ 390 lua_register(L, "printc", lua_printc); 391 return 1; 392 } 393 394 int 395 luaopen_io(lua_State *L) 396 { 397 luaL_newlib(L, iolib); 398 return 1; 399 } 400