const fs = require("fs"); const YAML = require('yaml'); const child_process = require('child_process'); global.servicesProcesses = {}; global.servicesTimers = {}; const chalk = require("chalk"); let me = { list: () => { let services = {}; for (let name of fs.readdirSync(systemRoot + "/LaunchDaemons")) { services[name.substring(0, name.length - 4)] = YAML.parse(fs.readFileSync(systemRoot + "/LaunchDaemons/" + name).toString()); } log("MistyCore-LaunchDaemons", "Gathered list of launch daemons"); return services; }, reachTarget: (target) => { process.stdout.clearLine(null); process.stdout.cursorTo(0); process.stdout.write(" Loading launch daemons for target " + target + "..."); log("MistyCore-LaunchDaemons", "Reached target: " + target); let matchingServices = []; for (let name of fs.readdirSync(systemRoot + "/LaunchDaemons")) { let service = YAML.parse(fs.readFileSync(systemRoot + "/LaunchDaemons/" + name).toString()); if (service.metadata.target === target || parseInt(service.metadata.target) === target) { service.name = name; matchingServices.push(service); } } log("MistyCore-LaunchDaemons", "Starting " + matchingServices.length + " launch daemons"); process.stdout.write(chalk.green(" Success") + "\n"); for (let service of matchingServices) { me.start(service.name); } }, stop: (name, force) => { let displayName = name.substring(0, name.length - 4); log("MistyCore-LaunchDaemons", "Stopping " + displayName); log("MistyCore-LaunchDaemons", "Reading configuration from " + systemRoot + "/LaunchDaemons/" + name); let service = YAML.parse(fs.readFileSync(systemRoot + "/LaunchDaemons/" + name).toString()); let pid = parseInt(fs.readFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName).toString()); if (pid === -1) { log("MistyCore-LaunchDaemons", "Cannot stop " + displayName + ": launch daemon is not running"); } else { if (service.commands.stop) { log("MistyCore-LaunchDaemons", "Launch daemon is using start/stop commands, not stopping as a daemon"); try { child_process.execSync(service.commands.stop, { shell: "/System/Binaries/sh" }); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "-1"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); } catch (e) { log("MistyCore-LaunchDaemons", "Launch daemon has failed to stop"); log("MistyCore-LaunchDaemons", e.stack); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "-2"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); } } else { if (force) { log("MistyCore-LaunchDaemons", "Launch daemon is using start/stop commands, killing process"); process.kill(pid, "SIGKILL"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "-1"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); } else { log("MistyCore-LaunchDaemons", "Launch daemon is using start/stop commands, terminating process"); process.kill(pid); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "-1"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); } } } }, restart: (name, force) => { let displayName = name.substring(0, name.length - 4); log("MistyCore-LaunchDaemons", "Restarting " + displayName); log("MistyCore-LaunchDaemons", "Reading configuration from " + systemRoot + "/LaunchDaemons/" + name); let service = YAML.parse(fs.readFileSync(systemRoot + "/LaunchDaemons/" + name).toString()); if (service.commands.restart) { log("MistyCore-LaunchDaemons", "Launch daemon is using restart commands, not restarting as a daemon"); try { child_process.execSync(service.commands.restart, { shell: "/System/Binaries/sh" }); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "0"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); } catch (e) { log("MistyCore-LaunchDaemons", "Launch daemon has failed to restart"); log("MistyCore-LaunchDaemons", e.stack); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "-2"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); } } else { log("MistyCore-LaunchDaemons", "Launch daemon is not using restart commands, restarting as a daemon"); me.stop(name, force); me.start(name, true); } }, start: (name, hidden) => { let displayName = name.substring(0, name.length - 4); fs.writeFileSync(systemRoot + "/Logs/LaunchDaemons/" + displayName + ".log", ""); log("MistyCore-LaunchDaemons", "Starting " + displayName); log("MistyCore-LaunchDaemons", "Reading configuration from " + systemRoot + "/LaunchDaemons/" + name); let service = YAML.parse(fs.readFileSync(systemRoot + "/LaunchDaemons/" + name).toString()); if (!hidden) { process.stdout.clearLine(null); process.stdout.cursorTo(0); process.stdout.write(" Starting launch daemon: " + displayName + "..."); } if (service.commands.stop) { log("MistyCore-LaunchDaemons", "Launch daemon is using start/stop commands, not starting as a daemon"); try { let proc = child_process.exec(service.commands.start, { shell: "/System/Binaries/sh" }); global.servicesProcesses[proc.pid] = proc; global.servicesTimers[proc.pid] = setTimeout(() => { proc.kill("SIGKILL"); log("MistyCore-LaunchDaemons", "Launch daemon has failed to start"); log("MistyCore-LaunchDaemons", "Startup timed out"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "-2"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); }, 10000); proc.on('exit', (code) => { if (code === 0) { log("MistyCore-LaunchDaemons", "Launch daemon has completed startup"); delete global.servicesProcesses[proc.pid]; clearTimeout(global.servicesTimers[proc.pid]); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "0"); } else { log("MistyCore-LaunchDaemons", "Launch daemon has failed to start"); log("MistyCore-LaunchDaemons", "Process exited with code " + code); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "-2"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); } }) proc.stdout.on('data', (data) => { fs.appendFileSync(systemRoot + "/Logs/LaunchDaemons/" + displayName + ".log", data); log(displayName, data.toString()); }); proc.stderr.on('data', (data) => { fs.appendFileSync(systemRoot + "/Logs/LaunchDaemons/" + displayName + ".log", data); log(displayName, data.toString()); }); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "-3"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); if (!hidden) { process.stdout.write(chalk.green(" Success") + "\n"); } } catch (e) { log("MistyCore-LaunchDaemons", "Launch daemon has failed to start"); log("MistyCore-LaunchDaemons", e.stack); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "-2"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); if (!hidden) { process.stdout.write(chalk.yellow(" Failure") + "\n"); console.log(""); console.log(chalk.red.inverse("MistyOS is unable to start up.")); console.log(""); console.log(chalk.red("A failing launch daemon is preventing MistyOS from starting up correctly.")); console.log(" " + chalk.red("Launch daemon: " + displayName)); console.log(" " + chalk.red("Error message: " + e.message)); console.log(""); console.log(chalk.red("Try starting your device in safe mode by holding Shift during start up.")); global.halt(); } } } else { log("MistyCore-LaunchDaemons", "Launch daemon is not using start/stop commands, starting as a daemon"); try { let proc = child_process.exec(service.commands.start, {shell: "/System/Binaries/sh"}); global.servicesProcesses[proc.pid] = proc; proc.on('exit', (code) => { if (code === 0 || code === null) { log("MistyCore-LaunchDaemons", "Launch daemon has stopped"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "-1"); } else { log("MistyCore-LaunchDaemons", "Launch daemon has failed with code " + code); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "-2"); } fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); }) proc.stdout.on('data', (data) => { fs.appendFileSync(systemRoot + "/Logs/LaunchDaemons/" + displayName + ".log", data); log(displayName, data.toString()); }); proc.stderr.on('data', (data) => { fs.appendFileSync(systemRoot + "/Logs/LaunchDaemons/" + displayName + ".log", data); log(displayName, data.toString()); }); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, proc.pid.toString()); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); } catch (e) { log("MistyCore-LaunchDaemons", "Launch daemon has failed to start"); log("MistyCore-LaunchDaemons", e.stack); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemons/" + displayName, "-2"); fs.writeFileSync(systemRoot + "/../Volumes/VM/LaunchDaemonsTimes/" + displayName, new Date().getTime().toString()); } } } } module.exports = me;