xref: /aosp_15_r20/external/bcc/src/lua/src/main.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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