@@ -5,6 +5,7 @@ const resolve = require('path').resolve
5
5
const spawn = require ( 'child_process' ) . spawn
6
6
7
7
const async = require ( 'async' )
8
+ const jocker = require ( 'jocker' )
8
9
const mkdirp = require ( 'mkdirp' )
9
10
const prompt = require ( 'prompt' )
10
11
const rimraf = require ( 'rimraf' ) . sync
@@ -20,15 +21,8 @@ const EXCLFS_BIN = '/bin/exclfs'
20
21
const HOME = '/tmp'
21
22
22
23
23
- var ROOT_HOME = ''
24
24
var single
25
25
26
- /**
27
- * This callback is part of the `mountDevProcTmp_ExecInit` function
28
- * @callback mountDevProcCallback
29
- * @param {Error } error The callback is called with a error if the devices
30
- * couldnt be mounted
31
- */
32
26
33
27
/**
34
28
* This error handler traces the error and starts a node.js repl
@@ -37,12 +31,8 @@ var single
37
31
*/
38
32
function onerror ( error )
39
33
{
40
- if ( error )
41
- {
42
- // Error mounting the root filesystem or executing init, enable REPL
43
- console . trace ( error )
44
- utils . startRepl ( 'NodeOS-mount-filesystems' )
45
- }
34
+ console . trace ( error )
35
+ utils . startRepl ( 'NodeOS-mount-filesystems' )
46
36
}
47
37
48
38
/**
@@ -130,33 +120,33 @@ function mkdirMoveInfo(info, callback)
130
120
}
131
121
132
122
/**
133
- * Mounts the user filesystems
123
+ * Mounts the root filesystems and exec its `/init`
124
+ *
134
125
* @access private
135
- * @param {Array } arr A array containing objects with
136
- * the mounting information **For more Information
137
- * see mkdirMountInfo**
138
- * @param {String } upperdir Path to the Init file
139
- * The path must contain a init file
140
- * Because execInit checks the gid & uid of the file
141
- * and of the "upperdir"
126
+ *
127
+ * @param {Array } arr An array containing objects with the mounting information
128
+ * **For more Information see mkdirMountInfo**
129
+ * @param {String } home Path to the `root` home. It must contain an `/init` file
130
+ *
142
131
* @example
143
132
* let infos = [ mountInfo1, mountInfo2 ] // see under mkdirMountInfo
144
133
* // for more Info
145
134
*
146
135
* // Its necessary to exclude the init file from the path because
147
- * // mountUserFilesystems does that for you
148
- * mountUserFilesystems (infos, 'path/to/initfile', callback)
136
+ * // `mountRootFilesystems()` does that for you
137
+ * mountRootFilesystems (infos, 'path/to/initfile', callback)
149
138
*/
150
- function mountUserFilesystems ( arr , upperdir , callback )
139
+ function mountRootFilesystems ( arr , home , callback )
151
140
{
152
141
async . each ( arr , mkdirMountInfo , function ( error )
153
142
{
154
143
if ( error ) return callback ( error )
155
144
145
+ // System started in `single` mode, launch REPL
156
146
if ( single ) return callback ( )
157
147
158
- // Execute init
159
- utils . execInit ( upperdir , function ( error )
148
+ // Execute `root` user init in un-priviledged environment
149
+ jocker . exec ( home , '/init' , { PATH : '/bin' } , function ( error )
160
150
{
161
151
if ( error ) console . warn ( error )
162
152
@@ -166,15 +156,15 @@ function mountUserFilesystems(arr, upperdir, callback)
166
156
}
167
157
168
158
/**
169
- * Waits until dev is mounted and then executes `mountUserFilesystems` to
170
- * mount `${upperdir}/proc` and `${upperdir}/tmp`
159
+ * Waits until `/dev` is mounted and then executes `mountRootFilesystems()` to
160
+ * mount `root`'s `${upperdir}/proc` and `${upperdir}/tmp`
161
+ *
171
162
* @access private
172
- * @param {String } upperdir The upperdir
173
- * @param {Boolean } isRoot True if user is root, false if not
174
- * @param {Function } callback The callback function
175
- * @return {mountDevProcCallback } Returns the callback function
163
+ *
164
+ * @param {String } upperdir The upperdir
165
+ * @param {mountDevProcCallback } callback The callback function
176
166
*/
177
- function mountDevProcTmp_ExecInit ( upperdir , isRoot , callback )
167
+ function prepareRootFilesystems ( upperdir , callback )
178
168
{
179
169
var arr =
180
170
[
@@ -190,11 +180,23 @@ function mountDevProcTmp_ExecInit(upperdir, isRoot, callback)
190
180
}
191
181
]
192
182
193
- var path = upperdir + '/dev'
183
+ // Using ExclFS filesystem
184
+ fs . access ( EXCLFS_BIN , fs . constants . X_OK , function ( error )
185
+ {
186
+ var path = upperdir + '/dev'
194
187
195
- // Root user
196
- if ( isRoot && fs . existsSync ( EXCLFS_BIN ) )
197
- return mkdirp ( path , '0000' , function ( error )
188
+ if ( error )
189
+ {
190
+ arr . unshift ( {
191
+ path : path ,
192
+ flags : MS_BIND ,
193
+ extras : { devFile : '/dev' }
194
+ } )
195
+
196
+ return mountRootFilesystems ( arr , upperdir , callback )
197
+ }
198
+
199
+ mkdirp ( path , '0000' , function ( error )
198
200
{
199
201
if ( error && error . code !== 'EEXIST' ) return callback ( error )
200
202
@@ -217,33 +219,32 @@ function mountDevProcTmp_ExecInit(upperdir, isRoot, callback)
217
219
rimraf ( EXCLFS_BIN )
218
220
rimraf ( '/lib/node_modules/exclfs' )
219
221
220
- mountUserFilesystems ( arr , upperdir , callback )
222
+ mountRootFilesystems ( arr , upperdir , callback )
221
223
} )
222
224
} )
223
-
224
- // Regular user
225
- arr . unshift ( {
226
- path : path ,
227
- flags : MS_BIND ,
228
- extras : { devFile : ROOT_HOME + '/dev' }
229
225
} )
230
-
231
- mountUserFilesystems ( arr , upperdir , callback )
232
226
}
227
+ /**
228
+ * @callback mountDevProcCallback
229
+ *
230
+ * @param {Error } error The callback is called with an error if the devices
231
+ * couldn't be mounted
232
+ */
233
233
234
234
/**
235
- * `overlay_user` first creates the workdir (with `0100` permission)
236
- * which is a string out of the folder where all users are located, a
237
- * constant `.workdirs` and the username e.g. `${usersFolder}/.workdirs/${user}`
235
+ * Creates the workdir (with `0100` permission) which is a string out of the
236
+ * folder where all users are located, a constant `.workdirs` and the username
237
+ * e.g. `${usersFolder}/.workdirs/${user}`
238
+ *
238
239
* @access private
240
+ *
239
241
* @param {String } usersFolder The folder where all user folders are
240
- * @param {String } user The name of the user
241
242
* @param {Function } callback The callback function
242
243
*/
243
- function overlay_user ( usersFolder , user , callback )
244
+ function overlay_root ( usersFolder , callback )
244
245
{
245
- var upperdir = usersFolder + '/' + user
246
- var workdir = usersFolder + '/.workdirs/' + user
246
+ var upperdir = usersFolder + '/root'
247
+ var workdir = usersFolder + '/.workdirs/root'
247
248
248
249
mkdirp ( workdir , '0100' , function ( error )
249
250
{
@@ -256,17 +257,14 @@ function overlay_user(usersFolder, user, callback)
256
257
lowerdir : '/' ,
257
258
upperdir : upperdir ,
258
259
workdir : workdir
259
- } ;
260
+ }
260
261
261
- if ( user === 'root' ) upperdir = '/root'
262
+ upperdir = '/root'
262
263
263
264
utils . mkdirMount ( upperdir , type , MS_NOSUID , extras , function ( error )
264
265
{
265
266
if ( error ) return callback ( error )
266
267
267
- if ( user !== 'root' )
268
- return mountDevProcTmp_ExecInit ( upperdir , false , callback )
269
-
270
268
// Allow root to access to the content of the users filesystem
271
269
async . eachSeries (
272
270
[
@@ -284,12 +282,10 @@ function overlay_user(usersFolder, user, callback)
284
282
{
285
283
if ( error ) return callback ( error )
286
284
287
- mountDevProcTmp_ExecInit ( HOME , true , function ( error )
285
+ prepareRootFilesystems ( HOME , function ( error )
288
286
{
289
287
if ( error ) return callback ( error )
290
288
291
- ROOT_HOME = HOME
292
-
293
289
callback ( null , HOME + '/home' )
294
290
} )
295
291
} )
@@ -309,39 +305,6 @@ function filterUser(user)
309
305
return user [ 0 ] !== '.' && user !== 'root' && user !== 'lost+found'
310
306
}
311
307
312
- /**
313
- * Mount users directories and exec their `init` files
314
- * @access private
315
- * @param {String } usersFolder The path to all user directories
316
- * @param {Function } callback The callback function
317
- * @return {Function } Returns the callback either with a error
318
- * or with null if everything was fine
319
- */
320
- function overlay_users ( usersFolder , callback )
321
- {
322
- function done ( error )
323
- {
324
- // Remove the modules from initramfs to free memory
325
- // rimraf('/lib/node_modules')
326
- rimraf ( '/lib/node_modules/nodeos-mount-utils' )
327
-
328
- // Make '/usr' a opaque folder (OverlayFS feature)
329
- rimraf ( '/usr' )
330
-
331
- callback ( error )
332
- }
333
-
334
- // Mount users directories and exec their init files
335
- fs . readdir ( usersFolder , function ( error , users )
336
- {
337
- if ( error ) return done ( error )
338
-
339
- async . each ( users . filter ( filterUser ) ,
340
- overlay_user . bind ( undefined , usersFolder ) ,
341
- done )
342
- } )
343
- }
344
-
345
308
/**
346
309
* This helper waits with a limit of tries until the path exists
347
310
* @access private
@@ -419,15 +382,38 @@ function askLocation(error)
419
382
* If the `single` key is set in the cmdline it starts a admin repl
420
383
* If not it just overlays the users filesystem
421
384
* @access private
422
- * @param {String } home The path to folder of the users
385
+ * @param {String } usersFolder The path to folder of the users
423
386
*/
424
- function adminOrUsers ( home )
387
+ function adminOrUsers ( usersFolder )
425
388
{
426
389
// Enter administrator mode
427
390
if ( single ) return utils . startRepl ( 'Administrator mode' )
428
391
429
392
// Users filesystem don't have a root user, just overlay users folders
430
- overlay_users ( home , onerror )
393
+
394
+ function done ( error )
395
+ {
396
+ // Remove the modules from initramfs to free memory
397
+ // rimraf('/lib/node_modules')
398
+ rimraf ( '/lib/node_modules/jocker' )
399
+
400
+ // Make '/usr' a opaque folder (OverlayFS feature)
401
+ rimraf ( '/usr' )
402
+
403
+ if ( error ) onerror ( error )
404
+ }
405
+
406
+ // Mount users directories and exec their init files
407
+ fs . readdir ( usersFolder , function ( error , users )
408
+ {
409
+ if ( error ) return done ( error )
410
+
411
+ async . each ( users . filter ( filterUser ) , function ( username , callback )
412
+ {
413
+ jocker . run ( usersFolder + '/' + username , '/init' , { PATH : '/bin' } , callback )
414
+ } ,
415
+ done )
416
+ } )
431
417
}
432
418
433
419
/**
@@ -455,16 +441,17 @@ function prepareSessions()
455
441
{
456
442
if ( error )
457
443
{
458
- if ( error . code != 'ENOENT' ) return onerror ( error )
444
+ if ( error . code !== 'ENOENT' ) return onerror ( error )
459
445
460
446
return adminOrUsers ( HOME )
461
447
}
462
448
463
- overlay_user ( HOME , 'root' , function ( error , home )
449
+ // There's an administrator account, prepare it first
450
+ overlay_root ( HOME , function ( error , newHome )
464
451
{
465
452
if ( error ) return onerror ( error )
466
453
467
- adminOrUsers ( home )
454
+ adminOrUsers ( newHome )
468
455
} )
469
456
} )
470
457
}
@@ -489,11 +476,10 @@ function mountUsersFS(cmdline)
489
476
if ( usersDev === undefined ) usersDev = cmdline . root
490
477
491
478
// Running on a container (Docker, vagga), don't mount the users filesystem
492
- if ( usersDev === 'container' )
493
- prepareSessions ( )
479
+ if ( usersDev === 'container' ) return prepareSessions ( )
494
480
495
481
// Running on real hardware or virtual machine, mount the users filesystem
496
- else if ( usersDev )
482
+ if ( usersDev )
497
483
waitUntilExists ( usersDev , 5 , function ( error )
498
484
{
499
485
if ( error ) return askLocation . call ( cmdline , error )
@@ -514,8 +500,9 @@ function mountUsersFS(cmdline)
514
500
else
515
501
fs . readFile ( 'resources/readonly_warning.txt' , 'utf8' , function ( error , data )
516
502
{
517
- if ( ! error ) console . warn ( data )
503
+ if ( error ) return onerror ( error )
518
504
505
+ console . warn ( data )
519
506
utils . startRepl ( 'NodeOS-mount-filesystems' )
520
507
} )
521
508
}
0 commit comments