UNPKG

nodeos-mount-utils

Version:
297 lines (257 loc) 8.38 kB
'use strict' var fs = require('fs') var proc = require('child_process') var repl = require('repl') var mkdirp = require('mkdirp') var mount = require('nodeos-mount') /** * @module nodeos-mount-utils */ /** * Create a directory without permissions to read, write nor execute * * @param {String} path Path where directory will be created * @param {Function} callback Callback */ function mkdir(path, callback) { mkdirp.mkdirp(path, '0000', function(error) { // catch everything, but not Entry Exists if(error && error.code !== 'EEXIST') return callback(error) return callback() }) } /** * Execute the init file * * @param {String} HOME Path of the home folder where the init file is located * @param {Array} [argv] Array of arguments */ function execInit(HOME, argv, callback) { if(argv instanceof Function) { callback = argv argv = [] } // get a stat of the home folder fs.stat(HOME, function(error, homeStat) { if(error) { // Return every error but no ENOENT if(error.code !== 'ENOENT') return callback(error) return callback(`${HOME} not found`) } // path to the init file const initPath = `${HOME}/init` fs.stat(initPath, function(error, initStat) { if(error) { // Return every error but no ENOENT if(error.code !== 'ENOENT') return callback(error) return callback(`${initPath} not found`) } // check if the init file is an actual file if(!initStat.isFile()) return callback(`${initPath} is not a file`) if(homeStat.uid !== initStat.uid || homeStat.gid !== initStat.gid) return callback(`${HOME} uid & gid don't match with its init`) // Start user's init argv = [homeStat.uid, homeStat.gid].concat(argv) const env = { cwd: HOME, stdio: 'inherit' } proc.spawn(`${__dirname}/bin/chrootInit`, argv, env).on('exit', callback) }) }) } /** * Asynchronous function for creating a * directory and then mount the `dev` file to it * * @example * mkdirMount('path/to/my/dir', 'type', {devFile: 'path/to/my/dev'}, function(err){}) * @see For more Information please visit * {@link https://github.com/NodeOS/nodeos-mount#mountmountsource-target-fstype-options-datastr-callback|this} * site * * @param {String} path Directory to mount the device to. * @param {String} type Filesystem identificator (one of /proc/filesystems). * @param {Array|Number} [flags] See below. * @param {String|Object} [extras] The data argument is interpreted by the * different file systems. * Typically it is a string of comma-separated * options understood by this file system. * @param {String} [extras.dev] Device-File being mounted (located in /dev) a.k.a. devFile. * @param {Function} callback Function called after the mount operation finishes. * Receives only one argument err. */ function mkdirMount(path, type, flags, extras, callback) { if(flags && (flags.constructor.name === 'Object' || flags instanceof Function)) { callback = extras extras = flags flags = null } if(extras instanceof Function) { callback = extras extras = null } mkdir(path, function(error) { if(error) return callback(error) mount.mount(path, type, flags, extras, callback) }) } /** * Mounts a filesystem through a path * * @example * mountfs('path/to/mount/to', 'type', {devFile: 'path/to/dev'}, * function(err){}) * @see For more Information please visit * {@link https://github.com/NodeOS/nodeos-mount#mountmountsource-target-fstype-options-datastr-callback|this} * site * * @param {String} path Directory to mount the device to. * @param {String} type Filesystem identificator (one of /proc/filesystems). * @param {Array|Number} [flags] See below. * @param {Object|String} [extras] The data argument is interpreted by the * different file systems. * Typically it is a string of comma-separated * options understood by this file system. * @param {Function} callback Function called after the mount operation finishes. * Receives only one argument err. */ function mountfs(path, type, flags, extras, callback) { if(flags && (flags.constructor.name === 'Object' || flags instanceof Function)) { callback = extras extras = flags flags = null } if(extras instanceof Function) { callback = extras extras = null } fs.stat('/.dockerinit', function(error) { // Running on Docker? if(!error) return callback() // catch everything, but not "Error no Entry" if(error.code !== 'ENOENT') return callback(error) // mount the filesystem mkdirMount(path, type, flags, extras, callback) }) } /** * Asynchronously move a subtree. * * The source specifies an existing mount point and target specifies the new * location. The move is atomic: at no point is the subtree unmounted. The * filesystemtype, mountflags, and data arguments are ignored. * * @example * move('source/path', 'target/path', function(err) {}) * @see For more Information please visit * {@link https://github.com/NodeOS/nodeos-mount#mountmountsource-target-fstype-options-datastr-callback|this} * site * * @param {String} source The source subtree to move * @param {String} target The path to move the subtree into * @param {Function} callback Function called after the mount operation finishes. * Receives only one argument err. */ function move(source, target, callback) { mount.mount(target, mount.MS_MOVE, {devFile: source}, function(error) { if(error) return callback(error) fs.readdir(source, function(err, files) { if(err) return callback(err) if(files.length) return callback() fs.rmdir(source, callback) }) }) } /** * Synchronously move a subtree * * The source specifies an existing mount point and target specifies the new * location. The move is atomic: at no point is the subtree unmounted. The * filesystemtype, mountflags, and data arguments are ignored. * * @example * moveSync('source/path', 'target/path') * @see For more Information please visit * {@link https://github.com/NodeOS/nodeos-mount#mountmountsource-target-fstype-options-datastr-callback|this} * site * * @param {String} source The source subtree to move * @param {String} target The path to move the subtree into */ function moveSync(source, target) { mount.mountSync(target, mount.MS_MOVE, {devFile: source}) // if no more file is in the source path if(!fs.readdirSync(source).length) fs.rmdirSync(source) // then delete the source } /** * Asynchronously create a target directory mount the source with MS_MOVE to it * and move all files to the newly created directory * * @example * mkdirMove('source/path', 'target/path', function(err) {}) * * @param {String} source The source subtree to move * @param {String} target The path to move the subtree into * @param {Function} callback Function called after the mount operation finishes. * Receives only one argument err. */ function mkdirMove(source, target, callback) { // create target directory mkdir(target, function(error) { if(error) return callback(error) // move all the files to the target move(source, target, callback) }) } /** * Starts a repl in case if somethings not working * * @param {String} promp The name of the prompt * * @event repl#exit */ function startRepl(prompt) { console.log('Starting REPL session') repl.start(`${prompt}> `).on('exit', function() { console.log('Got "exit" event from repl!') process.exit(2) }) } exports.flags = mount exports.mkdir = mkdir exports.execInit = execInit exports.mkdirMount = mkdirMount exports.mountfs = mountfs exports.move = move exports.moveSync = moveSync exports.mkdirMove = mkdirMove exports.startRepl = startRepl