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 /* 81 * Accepts a space-delimited loader command and runs it through the standard 82 * loader parsing, as if it were executed at the loader prompt by the user. 83 */ 84 static int 85 lua_interpret(lua_State *L) 86 { 87 const char *interp_string; 88 89 if (lua_gettop(L) != 1) { 90 lua_pushnil(L); 91 return 1; 92 } 93 94 interp_string = luaL_checkstring(L, 1); 95 lua_pushinteger(L, interp_run(interp_string)); 96 return 1; 97 } 98 99 static int 100 lua_getchar(lua_State *L) 101 { 102 103 lua_pushinteger(L, getchar()); 104 return 1; 105 } 106 107 static int 108 lua_ischar(lua_State *L) 109 { 110 111 lua_pushboolean(L, ischar()); 112 return 1; 113 } 114 115 static int 116 lua_gets(lua_State *L) 117 { 118 char buf[129]; 119 120 ngets(buf, 128); 121 lua_pushstring(L, buf); 122 return 1; 123 } 124 125 static int 126 lua_time(lua_State *L) 127 { 128 129 lua_pushinteger(L, time(NULL)); 130 return 1; 131 } 132 133 static int 134 lua_delay(lua_State *L) 135 { 136 137 delay((int)luaL_checknumber(L, 1)); 138 return 0; 139 } 140 141 static int 142 lua_getenv(lua_State *L) 143 { 144 lua_pushstring(L, getenv(luaL_checkstring(L, 1))); 145 146 return 1; 147 } 148 149 static int 150 lua_setenv(lua_State *L) 151 { 152 const char *key, *val; 153 154 key = luaL_checkstring(L, 1); 155 val = luaL_checkstring(L, 2); 156 lua_pushinteger(L, setenv(key, val, 1)); 157 158 return 1; 159 } 160 161 static int 162 lua_unsetenv(lua_State *L) 163 { 164 const char *ev; 165 166 ev = luaL_checkstring(L, 1); 167 lua_pushinteger(L, unsetenv(ev)); 168 169 return 1; 170 } 171 172 static int 173 lua_printc(lua_State *L) 174 { 175 ssize_t cur, l; 176 const char *s = luaL_checklstring(L, 1, &l); 177 178 for (cur = 0; cur < l; ++cur) 179 putchar((unsigned char)*(s++)); 180 181 return 1; 182 } 183 184 static int 185 lua_openfile(lua_State *L) 186 { 187 const char *mode, *str; 188 int nargs; 189 190 nargs = lua_gettop(L); 191 if (nargs < 1 || nargs > 2) { 192 lua_pushnil(L); 193 return 1; 194 } 195 str = lua_tostring(L, 1); 196 mode = "r"; 197 if (nargs > 1) { 198 mode = lua_tostring(L, 2); 199 if (mode == NULL) { 200 lua_pushnil(L); 201 return 1; 202 } 203 } 204 FILE * f = fopen(str, mode); 205 if (f != NULL) { 206 FILE ** ptr = (FILE**)lua_newuserdata(L, sizeof(FILE**)); 207 *ptr = f; 208 } else 209 lua_pushnil(L); 210 return 1; 211 } 212 213 static int 214 lua_closefile(lua_State *L) 215 { 216 FILE ** f; 217 if (lua_gettop(L) != 1) { 218 lua_pushboolean(L, 0); 219 return 1; 220 } 221 222 f = (FILE**)lua_touserdata(L, 1); 223 if (f != NULL && *f != NULL) { 224 lua_pushboolean(L, fclose(*f) == 0 ? 1 : 0); 225 *f = NULL; 226 } else 227 lua_pushboolean(L, 0); 228 229 return 1; 230 } 231 232 static int 233 lua_readfile(lua_State *L) 234 { 235 FILE **f; 236 size_t size, r; 237 char * buf; 238 239 if (lua_gettop(L) < 1 || lua_gettop(L) > 2) { 240 lua_pushnil(L); 241 lua_pushinteger(L, 0); 242 return 2; 243 } 244 245 f = (FILE**)lua_touserdata(L, 1); 246 247 if (f == NULL || *f == NULL) { 248 lua_pushnil(L); 249 lua_pushinteger(L, 0); 250 return 2; 251 } 252 253 if (lua_gettop(L) == 2) 254 size = (size_t)lua_tonumber(L, 2); 255 else 256 size = (*f)->size; 257 258 259 buf = (char*)malloc(size); 260 r = fread(buf, 1, size, *f); 261 lua_pushlstring(L, buf, r); 262 free(buf); 263 lua_pushinteger(L, r); 264 265 return 2; 266 } 267 268 /* 269 * Implements io.write(file, ...) 270 * Any number of string and number arguments may be passed to it, 271 * and it will return the number of bytes written, or nil, an error string, and 272 * the errno. 273 */ 274 static int 275 lua_writefile(lua_State *L) 276 { 277 FILE **f; 278 const char *buf; 279 int i, nargs; 280 size_t bufsz, w, wrsz; 281 282 buf = NULL; 283 bufsz = 0; 284 w = 0; 285 wrsz = 0; 286 nargs = lua_gettop(L); 287 if (nargs < 2) { 288 errno = EINVAL; 289 return luaL_fileresult(L, 0, NULL); 290 } 291 292 f = (FILE**)lua_touserdata(L, 1); 293 294 if (f == NULL || *f == NULL) { 295 errno = EINVAL; 296 return luaL_fileresult(L, 0, NULL); 297 } 298 299 /* Do a validation pass first */ 300 for (i = 0; i < nargs - 1; i++) { 301 /* 302 * With Lua's API, lua_isstring really checks if the argument 303 * is a string or a number. The latter will be implicitly 304 * converted to a string by our later call to lua_tolstring. 305 */ 306 if (!lua_isstring(L, i + 2)) { 307 errno = EINVAL; 308 return luaL_fileresult(L, 0, NULL); 309 } 310 } 311 for (i = 0; i < nargs - 1; i++) { 312 /* We've already validated; there's no chance of failure */ 313 buf = lua_tolstring(L, i + 2, &bufsz); 314 wrsz = fwrite(buf, 1, bufsz, *f); 315 if (wrsz < bufsz) 316 return luaL_fileresult(L, 0, NULL); 317 w += wrsz; 318 } 319 lua_pushinteger(L, w); 320 return 1; 321 } 322 323 #define REG_SIMPLE(n) { #n, lua_ ## n } 324 static const struct luaL_Reg loaderlib[] = { 325 REG_SIMPLE(delay), 326 REG_SIMPLE(command), 327 REG_SIMPLE(interpret), 328 REG_SIMPLE(getenv), 329 REG_SIMPLE(perform), 330 /* Also registered as the global 'printc' */ 331 REG_SIMPLE(printc), 332 REG_SIMPLE(setenv), 333 REG_SIMPLE(time), 334 REG_SIMPLE(unsetenv), 335 { NULL, NULL }, 336 }; 337 338 static const struct luaL_Reg iolib[] = { 339 { "close", lua_closefile }, 340 REG_SIMPLE(getchar), 341 REG_SIMPLE(gets), 342 REG_SIMPLE(ischar), 343 { "open", lua_openfile }, 344 { "read", lua_readfile }, 345 { "write", lua_writefile }, 346 { NULL, NULL }, 347 }; 348 #undef REG_SIMPLE 349 350 int 351 luaopen_loader(lua_State *L) 352 { 353 luaL_newlib(L, loaderlib); 354 /* Add loader.machine and loader.machine_arch properties */ 355 lua_pushstring(L, MACHINE); 356 lua_setfield(L, -2, "machine"); 357 lua_pushstring(L, MACHINE_ARCH); 358 lua_setfield(L, -2, "machine_arch"); 359 /* Set global printc to loader.printc */ 360 lua_register(L, "printc", lua_printc); 361 return 1; 362 } 363 364 int 365 luaopen_io(lua_State *L) 366 { 367 luaL_newlib(L, iolib); 368 return 1; 369 } 370