1 /*
2 * Copyright 2016 GitHub, Inc
3 *
4 * Based on lua.c, the Lua C Interpreter
5 * Copyright (C) 1994-2012 Lua.org, PUC-Rio. All rights reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26 #include <signal.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #include "lauxlib.h"
33 #include "lua.h"
34 #include "lualib.h"
35
36 static lua_State *globalL = NULL;
37 static const char *progname = NULL;
38
lstop(lua_State * L,lua_Debug * ar)39 static void lstop(lua_State *L, lua_Debug *ar) {
40 (void)ar; /* unused arg. */
41 lua_sethook(L, NULL, 0, 0);
42 luaL_error(L, "interrupted!");
43 }
44
laction(int i)45 static void laction(int i) {
46 signal(i, SIG_DFL);
47 lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
48 }
49
l_message(const char * pname,const char * msg)50 static void l_message(const char *pname, const char *msg) {
51 if (pname)
52 fprintf(stderr, "%s: ", pname);
53 fprintf(stderr, "%s\n", msg);
54 fflush(stderr);
55 }
56
report(lua_State * L,int status)57 static int report(lua_State *L, int status) {
58 if (status && !lua_isnil(L, -1)) {
59 const char *msg = lua_tostring(L, -1);
60 if (msg == NULL)
61 msg = "(error object is not a string)";
62 l_message(progname, msg);
63 lua_pop(L, 1);
64 }
65 return status;
66 }
67
traceback(lua_State * L)68 static int traceback(lua_State *L) {
69 if (!lua_isstring(L, 1)) /* 'message' not a string? */
70 return 1; /* keep it intact */
71 lua_getglobal(L, "debug");
72 if (!lua_istable(L, -1)) {
73 lua_pop(L, 1);
74 return 1;
75 }
76 lua_getfield(L, -1, "traceback");
77 if (!lua_isfunction(L, -1)) {
78 lua_pop(L, 2);
79 return 1;
80 }
81 lua_pushvalue(L, 1); /* pass error message */
82 lua_pushinteger(L, 2); /* skip this function and traceback */
83 lua_call(L, 2, 1); /* call debug.traceback */
84 return 1;
85 }
86
docall(lua_State * L,int narg,int clear)87 static int docall(lua_State *L, int narg, int clear) {
88 int status;
89 int base = lua_gettop(L) - narg; /* function index */
90 lua_pushcfunction(L, traceback); /* push traceback function */
91 lua_insert(L, base); /* put it under chunk and args */
92 signal(SIGINT, laction);
93 status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
94 signal(SIGINT, SIG_DFL);
95 lua_remove(L, base); /* remove traceback function */
96 /* force a complete garbage collection in case of errors */
97 if (status != 0)
98 lua_gc(L, LUA_GCCOLLECT, 0);
99 return status;
100 }
101
dolibrary(lua_State * L,const char * name,int clear)102 static int dolibrary(lua_State *L, const char *name, int clear) {
103 lua_getglobal(L, "require");
104 lua_pushstring(L, name);
105 return report(L, docall(L, 1, clear));
106 }
107
108 struct Smain {
109 int argc;
110 char **argv;
111 int status;
112 };
113
pushargv(lua_State * L,char ** argv,int argc,int offset)114 static void pushargv(lua_State *L, char **argv, int argc, int offset) {
115 int i, j;
116 lua_createtable(L, argc, 0);
117 for (i = offset, j = 1; i < argc; i++, j++) {
118 lua_pushstring(L, argv[i]);
119 lua_rawseti(L, -2, j);
120 }
121 }
122
pmain(lua_State * L)123 static int pmain(lua_State *L) {
124 struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
125 globalL = L;
126
127 lua_gc(L, LUA_GCSTOP, 0);
128 luaL_openlibs(L);
129 lua_gc(L, LUA_GCRESTART, 0);
130
131 s->status = dolibrary(L, "bcc", 0);
132 if (s->status)
133 return 0;
134
135 lua_pushstring(L, progname);
136 lua_setglobal(L, "BCC_STANDALONE");
137
138 pushargv(L, s->argv, s->argc, 1);
139 lua_setglobal(L, "arg");
140
141 s->status = report(L, docall(L, 0, 1));
142 return 0;
143 }
144
main(int argc,char ** argv)145 int main(int argc, char **argv) {
146 int status;
147 struct Smain s;
148 lua_State *L = lua_open(); /* create state */
149
150 if (L == NULL) {
151 l_message(argv[0], "cannot create state: not enough memory");
152 return EXIT_FAILURE;
153 }
154
155 if (geteuid() != 0) {
156 l_message(argv[0], "bcc-lua must be ran as root");
157 return EXIT_FAILURE;
158 }
159
160 progname = argv[0];
161 s.argc = argc;
162 s.argv = argv;
163 s.status = 0;
164
165 status = lua_cpcall(L, &pmain, &s);
166 report(L, status);
167 lua_close(L);
168
169 return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
170 }
171