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