@@ -5,6 +5,7 @@ const resolve = require('path').resolve
55const spawn = require ( 'child_process' ) . spawn
66
77const async = require ( 'async' )
8+ const jocker = require ( 'jocker' )
89const mkdirp = require ( 'mkdirp' )
910const prompt = require ( 'prompt' )
1011const rimraf = require ( 'rimraf' ) . sync
@@ -20,15 +21,8 @@ const EXCLFS_BIN = '/bin/exclfs'
2021const HOME = '/tmp'
2122
2223
23- var ROOT_HOME = ''
2424var single
2525
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- */
3226
3327/**
3428 * This error handler traces the error and starts a node.js repl
@@ -37,12 +31,8 @@ var single
3731 */
3832function onerror ( error )
3933{
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' )
4636}
4737
4838/**
@@ -130,33 +120,33 @@ function mkdirMoveInfo(info, callback)
130120}
131121
132122/**
133- * Mounts the user filesystems
123+ * Mounts the root filesystems and exec its `/init`
124+ *
134125 * @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+ *
142131 * @example
143132 * let infos = [ mountInfo1, mountInfo2 ] // see under mkdirMountInfo
144133 * // for more Info
145134 *
146135 * // 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)
149138 */
150- function mountUserFilesystems ( arr , upperdir , callback )
139+ function mountRootFilesystems ( arr , home , callback )
151140{
152141 async . each ( arr , mkdirMountInfo , function ( error )
153142 {
154143 if ( error ) return callback ( error )
155144
145+ // System started in `single` mode, launch REPL
156146 if ( single ) return callback ( )
157147
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 )
160150 {
161151 if ( error ) console . warn ( error )
162152
@@ -166,15 +156,15 @@ function mountUserFilesystems(arr, upperdir, callback)
166156}
167157
168158/**
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+ *
171162 * @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
176166 */
177- function mountDevProcTmp_ExecInit ( upperdir , isRoot , callback )
167+ function prepareRootFilesystems ( upperdir , callback )
178168{
179169 var arr =
180170 [
@@ -190,11 +180,23 @@ function mountDevProcTmp_ExecInit(upperdir, isRoot, callback)
190180 }
191181 ]
192182
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'
194187
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 )
198200 {
199201 if ( error && error . code !== 'EEXIST' ) return callback ( error )
200202
@@ -217,33 +219,32 @@ function mountDevProcTmp_ExecInit(upperdir, isRoot, callback)
217219 rimraf ( EXCLFS_BIN )
218220 rimraf ( '/lib/node_modules/exclfs' )
219221
220- mountUserFilesystems ( arr , upperdir , callback )
222+ mountRootFilesystems ( arr , upperdir , callback )
221223 } )
222224 } )
223-
224- // Regular user
225- arr . unshift ( {
226- path : path ,
227- flags : MS_BIND ,
228- extras : { devFile : ROOT_HOME + '/dev' }
229225 } )
230-
231- mountUserFilesystems ( arr , upperdir , callback )
232226}
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+ */
233233
234234/**
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+ *
238239 * @access private
240+ *
239241 * @param {String } usersFolder The folder where all user folders are
240- * @param {String } user The name of the user
241242 * @param {Function } callback The callback function
242243 */
243- function overlay_user ( usersFolder , user , callback )
244+ function overlay_root ( usersFolder , callback )
244245{
245- var upperdir = usersFolder + '/' + user
246- var workdir = usersFolder + '/.workdirs/' + user
246+ var upperdir = usersFolder + '/root'
247+ var workdir = usersFolder + '/.workdirs/root'
247248
248249 mkdirp ( workdir , '0100' , function ( error )
249250 {
@@ -256,17 +257,14 @@ function overlay_user(usersFolder, user, callback)
256257 lowerdir : '/' ,
257258 upperdir : upperdir ,
258259 workdir : workdir
259- } ;
260+ }
260261
261- if ( user === 'root' ) upperdir = '/root'
262+ upperdir = '/root'
262263
263264 utils . mkdirMount ( upperdir , type , MS_NOSUID , extras , function ( error )
264265 {
265266 if ( error ) return callback ( error )
266267
267- if ( user !== 'root' )
268- return mountDevProcTmp_ExecInit ( upperdir , false , callback )
269-
270268 // Allow root to access to the content of the users filesystem
271269 async . eachSeries (
272270 [
@@ -284,12 +282,10 @@ function overlay_user(usersFolder, user, callback)
284282 {
285283 if ( error ) return callback ( error )
286284
287- mountDevProcTmp_ExecInit ( HOME , true , function ( error )
285+ prepareRootFilesystems ( HOME , function ( error )
288286 {
289287 if ( error ) return callback ( error )
290288
291- ROOT_HOME = HOME
292-
293289 callback ( null , HOME + '/home' )
294290 } )
295291 } )
@@ -309,39 +305,6 @@ function filterUser(user)
309305 return user [ 0 ] !== '.' && user !== 'root' && user !== 'lost+found'
310306}
311307
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-
345308/**
346309 * This helper waits with a limit of tries until the path exists
347310 * @access private
@@ -419,15 +382,38 @@ function askLocation(error)
419382 * If the `single` key is set in the cmdline it starts a admin repl
420383 * If not it just overlays the users filesystem
421384 * @access private
422- * @param {String } home The path to folder of the users
385+ * @param {String } usersFolder The path to folder of the users
423386 */
424- function adminOrUsers ( home )
387+ function adminOrUsers ( usersFolder )
425388{
426389 // Enter administrator mode
427390 if ( single ) return utils . startRepl ( 'Administrator mode' )
428391
429392 // 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+ } )
431417}
432418
433419/**
@@ -455,16 +441,17 @@ function prepareSessions()
455441 {
456442 if ( error )
457443 {
458- if ( error . code != 'ENOENT' ) return onerror ( error )
444+ if ( error . code !== 'ENOENT' ) return onerror ( error )
459445
460446 return adminOrUsers ( HOME )
461447 }
462448
463- overlay_user ( HOME , 'root' , function ( error , home )
449+ // There's an administrator account, prepare it first
450+ overlay_root ( HOME , function ( error , newHome )
464451 {
465452 if ( error ) return onerror ( error )
466453
467- adminOrUsers ( home )
454+ adminOrUsers ( newHome )
468455 } )
469456 } )
470457}
@@ -489,11 +476,10 @@ function mountUsersFS(cmdline)
489476 if ( usersDev === undefined ) usersDev = cmdline . root
490477
491478 // Running on a container (Docker, vagga), don't mount the users filesystem
492- if ( usersDev === 'container' )
493- prepareSessions ( )
479+ if ( usersDev === 'container' ) return prepareSessions ( )
494480
495481 // Running on real hardware or virtual machine, mount the users filesystem
496- else if ( usersDev )
482+ if ( usersDev )
497483 waitUntilExists ( usersDev , 5 , function ( error )
498484 {
499485 if ( error ) return askLocation . call ( cmdline , error )
@@ -514,8 +500,9 @@ function mountUsersFS(cmdline)
514500 else
515501 fs . readFile ( 'resources/readonly_warning.txt' , 'utf8' , function ( error , data )
516502 {
517- if ( ! error ) console . warn ( data )
503+ if ( error ) return onerror ( error )
518504
505+ console . warn ( data )
519506 utils . startRepl ( 'NodeOS-mount-filesystems' )
520507 } )
521508}
0 commit comments