-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheib.lua
More file actions
executable file
·304 lines (257 loc) · 7.1 KB
/
Copy patheib.lua
File metadata and controls
executable file
·304 lines (257 loc) · 7.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#!/usr/bin/env lua
v = {
major = 0,
minor = 0,
}
-- load config.lua into the config table
config = {}
confun = loadfile("./config.lua")
setfenv(confun, config)
confun()
-- append an empty snapshot at the end for chroot/down changes to use; prevents
-- polluting the last snapshot with unrelated changes and allows chroot into the
-- final rootfs without having to find the last snapshot in use
config.snapshots[#config.snapshots+1] = {name = "root", modules = {}}
TARGET = config.path.target
QEMU = config.path.qemu
fs = {}
function fs.rmtree(dir)
local rc = os.execute("rm -rf " .. dir)
if rc ~= 0 then
error("cannot remove " .. dir)
end
end
function fs.mkdir(dir)
local rc = os.execute("mkdir -p " .. dir)
if rc ~= 0 then
error("cannot create " .. dir)
end
end
ckp = {}
function ckp.path(name)
return "./snapshots/" .. name
end
function ckp.empty()
return ckp.path(".empty")
end
function ckp.work()
return ckp.path(".work")
end
function ckp.clear()
local rc = os.execute("umount -R " .. TARGET)
if rc ~= 0 then
-- TODO we get an error here if the target is not mounted; figure out a
-- way to ignore these errors
-- error("cannot unmount " .. TARGET)
end
fs.rmtree(ckp.work())
end
function ckp.reset(name)
ckp.clear()
local clear = name == nil
for i, snapshot in ipairs(config.snapshots) do
if snapshot.name == name then
clear = true
end
if clear then
fs.rmtree(ckp.path(snapshot.name))
end
end
end
function ckp.lowerdirs(name)
local result = ckp.empty()
for i, snapshot in ipairs(config.snapshots) do
if snapshot.name == name then
return result
end
result = ckp.path(snapshot.name) .. ":" .. result
end
end
function ckp.load(name)
ckp.clear()
fs.mkdir(ckp.empty())
fs.mkdir(ckp.work())
fs.mkdir(ckp.path(name))
fs.mkdir(TARGET)
local o = string.format(
"-olowerdir=%s,upperdir=%s,workdir=%s",
ckp.lowerdirs(name),
ckp.path(name),
ckp.path(".work")
)
local cmd = string.format("mount -t overlay overlay %s %s", o, TARGET)
print(cmd)
local rc = os.execute(cmd)
if rc ~= 0 then
error("cannot mount " .. name)
end
end
function genenv(mod)
local env = "env -i"
for k, v in pairs(config[mod]) do
env = env .. " " .. k .. "='" .. v .. "'"
end
return env
end
function shcontext(ctx)
local reset = 0
for i, commands in ipairs(ctx) do
reset = i
rc = os.execute(commands[1])
if rc ~= 0 then
break
end
end
while reset > 0 do
if ctx[reset][2] ~= nil then
os.execute(ctx[reset][2])
end
reset = reset - 1
end
return rc
end
function chroot(command)
ctx = {
{"cp " .. QEMU .. " " .. TARGET .. "/usr/bin/",
"rm " .. TARGET .. "/usr/bin/qemu-*"},
{"mount -t proc /proc " .. TARGET .. "/proc",
"umount " .. TARGET .. "/proc"},
{"mount --rbind /sys " .. TARGET .. "/sys",
"umount -l " .. TARGET .. "/sys"},
{"mount --rbind /dev " .. TARGET .. "/dev",
"umount -l " .. TARGET .. "/dev"},
{"mkdir -p " .. TARGET .. "/proc/sys/fs/binfmt_misc", nil},
{"mount --rbind /proc/sys/fs/binfmt_misc " .. TARGET .. "/proc/sys/fs/binfmt_misc",
"umount " .. TARGET .. "/proc/sys/fs/binfmt_misc"},
{"chroot " .. TARGET .. " " .. command, nil},
}
local rc = shcontext(ctx)
return rc
end
function find_module(mod)
-- TODO allow a list of paths and search through them
return config.path.mod .. "/" .. mod .. ".sh"
end
function eib_run(stage, mod)
local env = genenv(mod) .. " TARGET=" .. TARGET
local modpath = find_module(mod)
return env .. " " .. config.path.run .. " " .. stage .. " " .. modpath
end
function do_up(mod)
rc = os.execute(eib_run("up", mod))
if rc ~= 0 then
error("failed bringing up " .. mod)
end
end
function do_fix(mod)
local env = genenv(mod)
local modpath = "/opt/eib/" .. mod .. ".sh"
-- busybox symlinks aren't installed yet (namely, /usr/bin/env doesn't
-- exist), so we call the busybox binary directly
rc = chroot("/bin/busybox " .. env .. " /opt/eib/eib-run.sh fix " .. modpath)
if rc ~= 0 then
error("failed fixing " .. mod)
end
end
function do_down(mod)
rc = os.execute(eib_run("down", mod))
if rc ~= 0 then
error("failed bringing up " .. mod)
end
end
function do_setup_fix()
local eib_path = TARGET .. "/opt/eib/"
rc = os.execute("mkdir -p " .. eib_path)
if rc ~= 0 then
error("failed creating " .. eib_path)
end
for i, snapshot in ipairs(config.snapshots) do
for j, mod in ipairs(snapshot.modules) do
rc = os.execute("cp " .. find_module(mod) .. " " .. eib_path)
if rc ~= 0 then
error("failed copying " .. mod .. " to " .. eib_path)
end
end
end
rc = os.execute("cp " .. config.path.run .. " " .. eib_path)
if rc ~= 0 then
error("failed copying eib-run.sh to " .. eib_path)
end
end
function do_teardown_fix()
local eib_path = TARGET .. "/opt/eib/"
rc = os.execute("rm -rf " .. eib_path)
if rc ~= 0 then
error("failed cleaning up " .. eib_path)
end
end
function do_build(snapshot)
if snapshot ~= nil then
ckp.reset(snapshot)
else
ckp.reset()
end
local start = snapshot == nil
for i, ss in ipairs(config.snapshots) do
if ss.name == snapshot then
start = true
end
if start then
ckp.load(ss.name)
for j, mod in ipairs(ss.modules) do
do_up(mod)
end
end
end
do_setup_fix()
for i, snapshot in ipairs(config.snapshots) do
for j, mod in ipairs(snapshot.modules) do
do_fix(mod)
end
end
do_teardown_fix()
for i = #config.snapshots, 1, -1 do
snapshot = config.snapshots[i]
for j, mod in ipairs(snapshot.modules) do
do_down(mod)
end
end
end
function do_chroot(snapshot)
-- if no snapshot is provided, load the final root snapshot
if snapshot == nil then
snapshot = "root"
end
-- load (but do not reset) the given snapshot
ckp.load(snapshot)
-- open a chroot shell
chroot("/bin/sh")
end
commands = {
build = function(i)
if arg[i+1] ~= nil then
error("unrecognized argument: " .. arg[i+1])
end
do_build(arg[i])
end,
chroot = function(i)
if arg[i+1] ~= nil then
error("unrecognized argument: " .. arg[i+1])
end
do_chroot(arg[i])
end,
version = function(i)
if arg[i] ~= nil then
error("unrecognized argument: " .. arg[i])
end
print("v" .. tostring(v.major) .. "." .. tostring(v.minor))
end,
}
if arg[1] then
if commands[arg[1]] == nil then
error("unrecognized command: " .. arg[1])
end
commands[arg[1]](2)
else
commands["build"](2)
end