diff --git a/.vscode/settings.json b/.vscode/settings.json index 26df38b..8797bb7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,6 @@ { - "python.linting.enabled": false + "python.linting.enabled": false, + "files.associations": { + "*.inc": "cpp" + } } \ No newline at end of file diff --git a/binding.gyp b/binding.gyp index fba7035..7439fbd 100644 --- a/binding.gyp +++ b/binding.gyp @@ -6,6 +6,20 @@ "sources": [ "clibs/chibrax/syscall.cc" ] + }, + { + "target_name": "ioctl", + 'cflags': [ '-Wall' ], + "sources": [ + "clibs/chibrax/ioctl.cc" + ] + }, + { + "target_name": "mount", + 'cflags': [ '-Wall' ], + "sources": [ + "clibs/chibrax/mount.cc" + ] } ] } \ No newline at end of file diff --git a/clibs.sh b/clibs.sh index 662c0ab..abc75ed 100755 --- a/clibs.sh +++ b/clibs.sh @@ -2,4 +2,9 @@ node node_modules/node-gyp/bin/node-gyp.js configure sudo node node_modules/node-gyp/bin/node-gyp.js build -cp build/Release/syscall.node rootfs\ overrides/chibrax/syscall.node \ No newline at end of file +echo "syscall" +cp build/Release/syscall.node rootfs\ overrides/chibrax/syscall.node +echo "ioctl" +cp build/Release/ioctl.node rootfs\ overrides/chibrax/ioctl.node +echo "mount" +cp build/Release/mount.node rootfs\ overrides/chibrax/mount.node diff --git a/clibs/chibrax/ioctl.cc b/clibs/chibrax/ioctl.cc new file mode 100644 index 0000000..4993ceb --- /dev/null +++ b/clibs/chibrax/ioctl.cc @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include + +#define nodeparam v8::FunctionCallbackInfo + +namespace ioctlNode { + void nodeIoctl(const nodeparam& args) { + v8::Isolate* isolate = args.GetIsolate(); + + + + if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsUint32()) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "Argument 1& 2 must be a number").ToLocalChecked())); + return; + } + + v8::String::Utf8Value str(isolate, args[0]); + std::string cppStr(*str); + + int fd = open(cppStr.c_str(), 'r'); + unsigned long request = args[1].As()->Value(); + int params[args.Length() - 2]; + for(int i = 1 ; i < args.Length(); i++ ) { + if (!args[i]->IsNumber()) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "Argument must be a number").ToLocalChecked())); + return; + } + params[i - 1] = args[i].As()->Value(); + } + + args.GetReturnValue().Set(ioctl(fd, request, ¶ms)); + close(fd); + } + + + void Initialize(v8::Local exports) { + NODE_SET_METHOD(exports, "ioctl", nodeIoctl); + } + + NODE_MODULE(ioctl_api, Initialize) +} diff --git a/clibs/chibrax/mount.cc b/clibs/chibrax/mount.cc new file mode 100644 index 0000000..74810be --- /dev/null +++ b/clibs/chibrax/mount.cc @@ -0,0 +1,64 @@ +#include +#include +#include + +namespace mountNode { + void nodemount(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = args.GetIsolate(); + + if (!args[0]->IsString()) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "First argument must be a string pointing to a device").ToLocalChecked())); + return; + } + + if (!args[1]->IsString()) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "Argument must be a string pointing to a folder").ToLocalChecked())); + return; + } + + if (!args[2]->IsString()) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "Argument must be a filesystem name").ToLocalChecked())); + return; + } + + if (!args[3]->IsNumber()) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "Argument must be a number made from the mount flags").ToLocalChecked())); + return; + } + + if (!args[4]->IsString()) { + isolate->ThrowException(v8::Exception::TypeError( + v8::String::NewFromUtf8(isolate, "Argument must be a string").ToLocalChecked())); + return; + } + + v8::String::Utf8Value devpathV8(isolate, args[0]); + std::string devpath(*devpathV8); + + v8::String::Utf8Value mountPointV8(isolate, args[1]); + std::string mountPoint(*mountPointV8); + + v8::String::Utf8Value fsTypeV8(isolate, args[2]); + std::string fsType(*fsTypeV8); + + unsigned long rwFlags = args[3].As()->Value(); + + //comma separated parameters passed directly into the fs driver + v8::String::Utf8Value fsFlagsV8(isolate, args[4]); + std::string fsFlags(*fsFlagsV8); + + const int returnValue = mount(devpath.c_str(), mountPoint.c_str(), fsType.c_str(), rwFlags, fsFlags.c_str()); + args.GetReturnValue().Set(returnValue); + } + + + void Initialize(v8::Local exports) { + NODE_SET_METHOD(exports, "mount", nodemount); + } + + NODE_MODULE(mount_api, Initialize) +} diff --git a/rootfs overrides/chibrax/.gitignore b/rootfs overrides/chibrax/.gitignore index 8114c0e..dbf4f60 100644 --- a/rootfs overrides/chibrax/.gitignore +++ b/rootfs overrides/chibrax/.gitignore @@ -1 +1,3 @@ -syscall.node \ No newline at end of file +syscall.node +ioctl.node +mount.node \ No newline at end of file diff --git a/rootfs overrides/chibrax/audio.js b/rootfs overrides/chibrax/audio.js index 4dca7ec..8377257 100644 --- a/rootfs overrides/chibrax/audio.js +++ b/rootfs overrides/chibrax/audio.js @@ -6,4 +6,4 @@ module.exports = (path) => { const data = fs.readFileSync(path) fs.writeFileSync(audiopath, data) } -} \ No newline at end of file +} diff --git a/rootfs overrides/chibrax/index.js b/rootfs overrides/chibrax/index.js index 1e9c935..26ff3fb 100644 --- a/rootfs overrides/chibrax/index.js +++ b/rootfs overrides/chibrax/index.js @@ -1,3 +1,4 @@ + //@ts-check function panic() { console.log("/!\\ INIT PANIK /!\\ LOSE CHIBRE") @@ -6,15 +7,12 @@ function panic() { async function main() { try { - const audio = require('./audio.js') + const initd = require('./initd.js') const reboot = require('./reboot.js') - const input = require('./input.js') const { fHook } = require("./hook.js") - console.log("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n") + console.clear() console.log(` - - _______ _________ ______ _______ _______ ( ____ \\|\\ /|\\__ __/( ___ \\ ( ____ )( ___ )|\\ /| | ( \\/| ) ( | ) ( | ( ) )| ( )|| ( ) |( \\ / ) @@ -35,7 +33,7 @@ async function main() { `) - audio('/chibrax/sheeebr.wav') + await initd() //chainload into sheebr await fHook("/usr/bin/sheebr.js") diff --git a/rootfs overrides/chibrax/initd.js b/rootfs overrides/chibrax/initd.js new file mode 100644 index 0000000..aa2f525 --- /dev/null +++ b/rootfs overrides/chibrax/initd.js @@ -0,0 +1,84 @@ +//@ts-check +const fs = require('fs') +const path = require('path') + +/** + * @typedef {{ name: string, before: string[], after: string[], init(): undefined | Promise }} InitScript + */ +async function init() { + + const initdFiles = fs.readdirSync('/etc/init.d/') + const initdScripts = initdFiles.filter( (v) => v.endsWith('.js')) + + /** + * @type { Array } + */ + const finishedScripts = [] + + /** + * @type { Array } + */ + const scripts = [] + + for(const script of initdScripts) { + const scriptCandidate = require(path.join('/etc/init.d/', script)) + if(scriptCandidate?.before && scriptCandidate?.after && scriptCandidate?.init) + scripts.push({ ...scriptCandidate, name: script}) + else + console.error(`Invalid(missing exports) script error :${script}`) + } + + const befores = processBefores(scripts) + + let i = 0 + while(scripts.length) { + const s = scripts[i % scripts.length] + i += 1 + if(isSubSet(s.after, finishedScripts) && ( !befores[s.name] || isSubSet(befores[s.name], finishedScripts) )) { + //on supprime ce service + scripts.splice(scripts.indexOf(s)) + + const result = s.init() + if(typeof result?.then === 'function') { + await result + } + finishedScripts.push(s.name) + } + } +} + +/** + * @template T + * @param {Array} arraya + * @param {Array} arrayb + */ +function isSubSet(arraya, arrayb) { + for(const a of arraya) { + if(!arrayb.includes(a)) { + return false + } + } + return true +} + +/** + * + * @param {Array} scripts + * @returns {{ [key: string]: string[] }} + */ +function processBefores(scripts) { + /** + * @type {{ [key: string]: string[] }} + */ + const result = {} + for(const script of scripts) { + for(const before of script.before){ + if(! result[before]) result[before] = [script.name] + else result[before].push(script.name) + } + } + return result +} + + +module.exports = init \ No newline at end of file diff --git a/rootfs overrides/chibrax/keyboard.js b/rootfs overrides/chibrax/keyboard.js deleted file mode 100644 index 0e9c1db..0000000 --- a/rootfs overrides/chibrax/keyboard.js +++ /dev/null @@ -1,7 +0,0 @@ -const fs = require('fs') - -function setLayOut(layout) { - -} - -fs.readFileSync('/etc/vconsole.conf') \ No newline at end of file diff --git a/rootfs overrides/chibrax/mount.js b/rootfs overrides/chibrax/mount.js new file mode 100644 index 0000000..68963fa --- /dev/null +++ b/rootfs overrides/chibrax/mount.js @@ -0,0 +1,68 @@ +//@ts-check +const fs =require('fs') +/** + * @type {{ mount: (device_path: string, mount_point: string, fs: string, flags: number, fsparams: string ) => number }} + *///@ts-expect-error +const nodemount = require("./mount.node") +/** + * @deprecated + */ +const cmount = nodemount.mount + + +/* These are the fs-independent mount-flags: up to 16 flags are + supported */ +const flags = { + MS_RDONLY: 1, /* Mount read-only. */ + MS_NOSUID: 2, /* Ignore suid and sgid bits. */ + MS_NODEV: 4, /* Disallow access to device special files. */ + MS_NOEXEC: 8, /* Disallow program execution. */ + MS_SYNCHRONOUS: 16, /* Writes are synced at once. */ + MS_REMOUNT: 32, /* Alter flags of a mounted FS. */ + MS_MANDLOCK: 64, /* Allow mandatory locks on an FS. */ + MS_DIRSYNC: 128, /* Directory modifications are synchronous. */ + MS_NOATIME: 1024, /* Do not update access times. */ + MS_NODIRATIME: 2048, /* Do not update directory access times. */ + MS_BIND: 4096, /* Bind directory at different place. */ + MS_MOVE: 8192, + MS_REC: 16384, + MS_SILENT: 32768, + MS_POSIXACL: 1 << 16, /* VFS does not apply the umask. */ + MS_UNBINDABLE: 1 << 17, /* Change to unbindable. */ + MS_PRIVATE: 1 << 18, /* Change to private. */ + MS_SLAVE: 1 << 19, /* Change to slave. */ + MS_SHARED: 1 << 20, /* Change to shared. */ + MS_RELATIME: 1 << 21, /* Update atime relative to mtime/ctime. */ + MS_KERNMOUNT: 1 << 22, /* This is a kern_mount call. */ + MS_I_VERSION: 1 << 23, /* Update inode I_version field. */ + MS_STRICTATIME: 1 << 24, /* Always perform atime updates. */ + MS_LAZYTIME: 1 << 25, /* Update the on-disk [acm]times lazily. */ + MS_ACTIVE: 1 << 30, + MS_NOUSER: 1 << 31 +}; + +/** + * @param {string} devicePath + * @param {string} mountPoint + * @param {string} fstype + * @param {number} flags + * @param {string} fsparams + * @returns {number} + */ +function mount(devicePath, mountPoint, fstype, flags, fsparams) { + const supportedFilesystems = require('./suportedFilesystems') + + const filesystem = supportedFilesystems.find( v => v.name === fstype) + if(! filesystem) { + throw "Invalid filesystem" + } + + if(! fs.existsSync(devicePath) && filesystem.hasdev) + throw "Device don't exist" + return cmount(devicePath, mountPoint, fstype, flags, fsparams) +} + + + + +module.exports = { mount, cmount, flags } \ No newline at end of file diff --git a/rootfs overrides/chibrax/suportedFilesystems.js b/rootfs overrides/chibrax/suportedFilesystems.js new file mode 100644 index 0000000..2917ef9 --- /dev/null +++ b/rootfs overrides/chibrax/suportedFilesystems.js @@ -0,0 +1,9 @@ +//@ts-check +const fs = require('fs') + +const systems = fs.readFileSync('/proc/filesystems', { encoding: 'utf-8' }).split('\n') + +const filesystems = systems.map(s => ({ hasdev: !s.includes('nodev'), name: s.includes('nodev') ? s.split('nodev')[1].trim() : s.trim() })) + +module.exports = filesystems +Object.freeze(module.exports) \ No newline at end of file diff --git a/rootfs overrides/etc/init.d/filesystem.js b/rootfs overrides/etc/init.d/filesystem.js new file mode 100644 index 0000000..e819ae0 --- /dev/null +++ b/rootfs overrides/etc/init.d/filesystem.js @@ -0,0 +1,20 @@ +//@ts-check +const { cmount, mount, flags } = require('../../chibrax/mount.js') + +async function init() { + cmount("dummy", "/proc", "proc", + flags.MS_NODEV | flags.MS_RDONLY | flags.MS_NOSUID | flags.MS_RELATIME + , "") + + mount("dummy", "/sys", "sysfs", flags.MS_NODEV | flags.MS_NOSUID | flags.MS_RELATIME, "") + mount("dummy", "/tmp", "tmpfs", flags.MS_NODEV, "") +} + +const after = [] // list of init script to load before +const before = [] + +module.exports = { + init, + after, + before +} \ No newline at end of file diff --git a/rootfs overrides/etc/init.d/sample.js.example b/rootfs overrides/etc/init.d/sample.js.example new file mode 100644 index 0000000..a4bb524 --- /dev/null +++ b/rootfs overrides/etc/init.d/sample.js.example @@ -0,0 +1,13 @@ +//async is optional but recomended for optimisation (optimisations are yet to be implemented) +async function init() { + //code to execute +} + +const after = [] // list of init script to load before +const before = [] + +module.exports = { + init, + after, + before +} \ No newline at end of file diff --git a/rootfs overrides/etc/init.d/startupSound.js b/rootfs overrides/etc/init.d/startupSound.js new file mode 100644 index 0000000..bdb5892 --- /dev/null +++ b/rootfs overrides/etc/init.d/startupSound.js @@ -0,0 +1,14 @@ +const audio = require('/chibrax/audio.js') + +async function init() { + audio('/chibrax/sheeebr.wav') +} + +const after = [ "filesystem.js" ] // list of init script to load before +const before = [] + +module.exports = { + init, + after, + before +} \ No newline at end of file diff --git a/rootfs overrides/usr/bin/ip.js b/rootfs overrides/usr/bin/ip.js index 681b7dd..f375b79 100644 --- a/rootfs overrides/usr/bin/ip.js +++ b/rootfs overrides/usr/bin/ip.js @@ -1,2 +1,3 @@ +//@ts-check const os = require('os'); console.log(os.networkInterfaces()); \ No newline at end of file