Skip to content

Commit a220241

Browse files
authored
Merge pull request #6 from JLague/master
add (optional) support for more complex Lmod modulefiles
2 parents fe85e1d + af5a214 commit a220241

File tree

5 files changed

+515
-18
lines changed

5 files changed

+515
-18
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
mii
22
**/*.o
3+
*.luac

makefile

+37-14
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,49 @@
1-
PREFIX ?= /usr
2-
CC = gcc
3-
CFLAGS = -std=c99 -Wall -Werror -Wno-format-security -pedantic -O3 -DMII_RELEASE -DMII_PREFIX="\"$(PREFIX)\"" -DMII_BUILD_TIME="\"$(shell date)\""
4-
LDFLAGS =
5-
OUTPUT = mii
1+
PREFIX ?= /usr
2+
REALPREFIX = $(realpath $(PREFIX))
3+
CC = gcc
4+
CFLAGS = -std=c99 -Wall -Werror -Wno-format-security -pedantic -O3 -DMII_RELEASE -DMII_PREFIX="\"$(REALPREFIX)\"" -DMII_BUILD_TIME="\"$(shell date)\""
5+
LDFLAGS =
6+
C_OUTPUT = mii
7+
OUTPUTS = $(C_OUTPUT)
68

7-
SOURCES = $(wildcard src/*.c) src/xxhash/xxhash.c
8-
OBJECTS = $(SOURCES:.c=.o)
9+
C_SOURCES = $(wildcard src/*.c) src/xxhash/xxhash.c
10+
C_OBJECTS = $(C_SOURCES:.c=.o)
911

10-
all: $(OUTPUT)
12+
LUA_SOURCES = src/lua/utils.lua src/lua/sandbox.lua
13+
LUA_OUTPUT = sandbox.luac
14+
LUAC = luac
1115

12-
$(OUTPUT): $(OBJECTS)
13-
$(CC) $(OBJECTS) $(LDFLAGS) -o $(OUTPUT)
16+
MII_ENABLE_LUA ?= no
17+
MII_LUA_LDFLAG ?= -llua
18+
MII_LUA_INCLUDE ?=
19+
20+
ifeq ($(MII_ENABLE_LUA), yes)
21+
CFLAGS += -DMII_ENABLE_LUA $(MII_LUA_INCLUDE)
22+
LDFLAGS += $(MII_LUA_LDFLAG)
23+
OUTPUTS += $(LUA_OUTPUT)
24+
endif
25+
26+
all: $(OUTPUTS)
27+
28+
$(C_OUTPUT): $(C_OBJECTS)
29+
$(CC) $(C_OBJECTS) $(LDFLAGS) -o $(C_OUTPUT)
1430

1531
%.o: %.c
1632
$(CC) $(CFLAGS) -c $< -o $@
1733

34+
$(LUA_OUTPUT): $(LUA_SOURCES)
35+
$(LUAC) -o $@ $^
36+
1837
clean:
19-
rm -f $(OUTPUT) $(OBJECTS)
38+
rm -f $(C_OUTPUT) $(LUA_OUTPUT) $(C_OBJECTS)
2039

21-
install: $(OUTPUT)
40+
install: $(OUTPUTS)
2241
@echo "Installing mii to $(PREFIX)"
2342
mkdir -p $(PREFIX)/bin
2443
mkdir -p $(PREFIX)/share/mii
25-
cp $(OUTPUT) $(PREFIX)/bin
26-
cp -r init $(PREFIX)/share/mii
44+
cp $(C_OUTPUT) $(PREFIX)/bin
45+
cp -r init $(PREFIX)/share/mii
46+
ifeq ($(MII_ENABLE_LUA), yes)
47+
mkdir -p $(PREFIX)/share/mii/lua
48+
cp $(LUA_OUTPUT) $(PREFIX)/share/mii/lua
49+
endif

src/analysis.c

+134-4
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,41 @@
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
1935
static const char* _mii_analysis_lmod_regex_src =
2036
"\\s*(prepend_path|append_path)\\s*\\(\\s*"
2137
"\"PATH\"\\s*,\\s*\"([^\"]+)\"";
2238

2339
static 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 */
2649
char* _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 */
3356
int _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
*/
50107
void 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
*/
71168
int _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

Comments
 (0)