99#include <stdio.h>
1010#include <string.h>
1111
12+ #if MII_ENABLE_LUA
13+ #include <lua.h>
14+ #include <lualib.h>
15+ #include <lauxlib.h>
16+
17+ /* After Lua 5.1, lua_objlen changed name and LUA_OK is defined */
18+ #if LUA_VERSION_NUM <= 501
19+ #define mii_lua_len lua_objlen
20+ #define LUA_OK 0
21+ #else
22+ #define mii_lua_len lua_rawlen
23+ #endif
24+
25+ #endif // MII_ENABLE_LUA
26+
1227#include <dirent.h>
1328#include <errno.h>
1429#include <regex.h>
1530#include <unistd.h>
1631#include <sys/stat.h>
1732#include <wordexp.h>
1833
34+ #if !MII_ENABLE_LUA
1935static const char * _mii_analysis_lmod_regex_src =
2036 "\\s*(prepend_path|append_path)\\s*\\(\\s*"
2137 "\"PATH\"\\s*,\\s*\"([^\"]+)\"" ;
2238
2339static regex_t _mii_analysis_lmod_regex ;
40+ #else
41+ /* Lua interpreter state */
42+ static lua_State * lua_state ;
43+
44+ /* run lua module code in a sandbox */
45+ int _mii_analysis_lua_run (lua_State * lua_state , const char * code , char * * * paths_out , int * num_paths_out );
46+ #endif
2447
2548/* word expansion functions */
2649char * _mii_analysis_expand (const char * expr );
@@ -32,6 +55,7 @@ int _mii_analysis_tcl(const char* path, char*** bins_out, int* num_bins_out);
3255/* path scanning functions */
3356int _mii_analysis_scan_path (char * path , char * * * bins_out , int * num_bins_out );
3457
58+ #if !MII_ENABLE_LUA
3559/*
3660 * compile regexes
3761 */
@@ -43,12 +67,49 @@ int mii_analysis_init() {
4367
4468 return 0 ;
4569}
70+ #else
71+ /*
72+ * initialize Lua interpreter
73+ */
74+ int mii_analysis_init () {
75+ lua_state = luaL_newstate ();
76+ luaL_openlibs (lua_state );
77+
78+ /* sandbox path when mii is installed */
79+ char * lua_path = mii_join_path (MII_PREFIX , "share/mii/lua/sandbox.luac" );
80+
81+ if (access (lua_path , F_OK ) == 0 ) {
82+ /* found file, try to execute it and return */
83+ if (luaL_dofile (lua_state , lua_path ) == LUA_OK ) {
84+ free (lua_path );
85+ return 0 ;
86+ }
87+ }
88+ free (lua_path );
89+
90+ lua_path = "./sandbox.luac" ;
91+ if (access (lua_path , F_OK ) == 0 ) {
92+ /* mii is not installed, but should work anyway */
93+ if (luaL_dofile (lua_state , lua_path ) == LUA_OK )
94+ return 0 ;
95+ }
96+
97+ mii_error ("failed to load Lua file" );
98+ lua_close (lua_state );
99+
100+ return -1 ;
101+ }
102+ #endif
46103
47104/*
48- * clean up regexes
105+ * cleanup regexes or Lua interpreter
49106 */
50107void mii_analysis_free () {
108+ #if !MII_ENABLE_LUA
51109 regfree (& _mii_analysis_lmod_regex );
110+ #else
111+ lua_close (lua_state );
112+ #endif
52113}
53114
54115/*
@@ -65,20 +126,57 @@ int mii_analysis_run(const char* modfile, int modtype, char*** bins_out, int* nu
65126 return 0 ;
66127}
67128
129+ #if MII_ENABLE_LUA
130+ /*
131+ * run a modulefile's code in a Lua sandbox
132+ */
133+ int _mii_analysis_lua_run (lua_State * lua_state , const char * code , char * * * paths_out , int * num_paths_out ) {
134+ /* execute modulefile */
135+ int res ;
136+ lua_getglobal (lua_state , "sandbox_run" );
137+ lua_pushstring (lua_state , code );
138+ res = lua_pcall (lua_state , 1 , 1 , 0 );
139+
140+ if (res != LUA_OK ) {
141+ mii_error ("Error occured in Lua sandbox : %s" , lua_tostring (lua_state , -1 ));
142+ lua_pop (lua_state , 1 );
143+ return -1 ;
144+ }
145+
146+ luaL_checktype (lua_state , 1 , LUA_TTABLE );
147+
148+ /* allocate memory for the paths */
149+ * num_paths_out = mii_lua_len (lua_state , -1 );
150+ * paths_out = malloc (* num_paths_out * sizeof (char * ));
151+
152+ /* retrieve paths from Lua stack */
153+ for (int i = 1 ; i <= * num_paths_out ; ++ i ) {
154+ lua_rawgeti (lua_state , - i , i );
155+ (* paths_out )[i - 1 ] = mii_strdup (lua_tostring (lua_state , -1 ));
156+ }
157+
158+ /* pop every rawgeti + table */
159+ lua_pop (lua_state , * num_paths_out + 1 );
160+
161+ return 0 ;
162+ }
163+ #endif
164+
68165/*
69166 * extract paths from an lmod file
70167 */
71168int _mii_analysis_lmod (const char * path , char * * * bins_out , int * num_bins_out ) {
72- char linebuf [MII_ANALYSIS_LINEBUF_SIZE ];
73- regmatch_t matches [3 ];
74-
75169 FILE * f = fopen (path , "r" );
76170
77171 if (!f ) {
78172 mii_error ("Couldn't open %s for reading : %s" , path , strerror (errno ));
79173 return -1 ;
80174 }
81175
176+ #if !MII_ENABLE_LUA
177+ char linebuf [MII_ANALYSIS_LINEBUF_SIZE ];
178+ regmatch_t matches [3 ];
179+
82180 while (fgets (linebuf , sizeof linebuf , f )) {
83181 /* strip off newline */
84182 int len = strlen (linebuf );
@@ -94,6 +192,38 @@ int _mii_analysis_lmod(const char* path, char*** bins_out, int* num_bins_out) {
94192 }
95193
96194 fclose (f );
195+ #else
196+ char * buffer ;
197+ fseek (f , 0L , SEEK_END );
198+ long s = ftell (f );
199+ rewind (f );
200+ buffer = malloc (s + 1 );
201+ if ( buffer != NULL ) {
202+ fread (buffer , s , 1 , f );
203+ fclose (f ); f = NULL ;
204+ buffer [s ] = '\0' ;
205+
206+ /* get binaries paths */
207+ char * * bin_paths ;
208+ int num_paths ;
209+ if (_mii_analysis_lua_run (lua_state , buffer , & bin_paths , & num_paths )) {
210+ mii_error ("Error occured when executing %s, skipping" , path );
211+ free (buffer );
212+ return -1 ;
213+ }
214+
215+ /* scan every path returned */
216+ for (int i = 0 ; i < num_paths ; ++ i ) {
217+ _mii_analysis_scan_path (bin_paths [i ], bins_out , num_bins_out );
218+ free (bin_paths [i ]);
219+ }
220+
221+ free (bin_paths );
222+ free (buffer );
223+ }
224+ if (f != NULL ) fclose (f );
225+ #endif
226+
97227 return 0 ;
98228}
99229
0 commit comments