"use strict";
/**
 * penguins-eggs
 * class: ovary.ts
 * author: Piero Proietti
 * email: piero.proietti@gmail.com
 * license: MIT
 */
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
// packages
const fs_1 = tslib_1.__importDefault(require("fs"));
const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
const node_path_1 = tslib_1.__importDefault(require("node:path"));
const node_os_1 = tslib_1.__importDefault(require("node:os"));
const shelljs_1 = tslib_1.__importDefault(require("shelljs"));
const chalk_1 = tslib_1.__importDefault(require("chalk"));
const mustache_1 = tslib_1.__importDefault(require("mustache"));
const pve_live_1 = tslib_1.__importDefault(require("./pve-live"));
// libraries
const utils_1 = require("../lib/utils");
// classes
const utils_2 = tslib_1.__importDefault(require("./utils"));
const n8_1 = tslib_1.__importDefault(require("./n8"));
const incubator_1 = tslib_1.__importDefault(require("./incubation/incubator"));
const xdg_1 = tslib_1.__importDefault(require("./xdg"));
const pacman_1 = tslib_1.__importDefault(require("./pacman"));
const settings_1 = tslib_1.__importDefault(require("./settings"));
const systemctl_1 = tslib_1.__importDefault(require("./systemctl"));
const bleach_1 = tslib_1.__importDefault(require("./bleach"));
const yolk_1 = tslib_1.__importDefault(require("./yolk"));
const displaymanager_1 = require("./incubation/fisherman-helper/displaymanager");
// backup
const promises_1 = require("fs/promises");
const fs_2 = require("fs");
const users_1 = tslib_1.__importDefault(require("./users"));
const cli_autologin_1 = tslib_1.__importDefault(require("../lib/cli-autologin"));
/**
 * Ovary:
 */
class Ovary {
    constructor() {
        this.verbose = false;
        this.echo = {};
        this.toNull = '';
        this.incubator = {};
        this.settings = {};
        this.familyId = '';
        this.snapshot_prefix = '';
        this.snapshot_basename = '';
        this.compression = '';
        this.theme = '';
        this.clone = false;
        this.cryptedclone = false;
        this.cliAutologin = new cli_autologin_1.default();
        this.ovarium = '';
        /**
         * END CLASS ovary
         */
    }
    /**
     * @returns {boolean} success
     */
    async fertilization(snapshot_prefix = '', snapshot_basename = '', theme = '', compression = '', nointeratctive = false) {
        this.settings = new settings_1.default();
        if (await this.settings.load()) {
            this.familyId = this.settings.distro.familyId;
            if (snapshot_prefix !== '') {
                this.settings.config.snapshot_prefix = snapshot_prefix;
            }
            if (snapshot_basename !== '') {
                this.settings.config.snapshot_basename = snapshot_basename;
            }
            if (theme !== '') {
                this.theme = theme;
            }
            if (compression !== '') {
                this.settings.config.compression = compression;
            }
            if (!nointeratctive) {
                return true;
            }
            this.settings.listFreeSpace();
            if (await utils_2.default.customConfirm('Select yes to continue...')) {
                return true;
            }
            this.settings.work_dir.ovarium = this.settings.config.snapshot_dir + 'ovarium/';
        }
        return false;
    }
    /**
     * produce
     * @param clone
     * @param cryptedclone
     * @param scriptOnly
     * @param yolkRenew
     * @param release
     * @param myAddons
     * @param nointeractive
     * @param noicons
     * @param unsecure
     * @param verbose
     */
    async produce(clone = false, cryptedclone = false, scriptOnly = false, yolkRenew = false, release = false, myAddons, filters, nointeractive = false, noicons = false, unsecure = false, verbose = false) {
        this.verbose = verbose;
        this.echo = utils_2.default.setEcho(verbose);
        if (this.verbose) {
            this.toNull = ' > /dev/null 2>&1';
        }
        this.clone = clone;
        this.cryptedclone = cryptedclone;
        const luksName = 'luks-eggs-data';
        const luksFile = `/tmp/${luksName}`;
        // let luksDevice = `/dev/mapper/${this.luksName}`
        // let luksMountpoint = `/mnt`
        if (this.familyId === 'debian' && utils_2.default.uefiArch() === 'amd64') {
            const yolk = new yolk_1.default();
            if (!yolk.exists()) {
                utils_2.default.warning('creating yolk');
                await yolk.create(verbose);
            }
            else if (yolkRenew) {
                utils_2.default.warning('refreshing yolk');
                await yolk.erase();
                await yolk.create(verbose);
            }
            else {
                utils_2.default.warning('using preesixent yolk');
            }
        }
        if (!fs_1.default.existsSync(this.settings.config.snapshot_dir)) {
            shelljs_1.default.mkdir('-p', this.settings.config.snapshot_dir);
        }
        await this.settings.loadRemix(this.snapshot_basename, this.theme);
        if (utils_2.default.isLive()) {
            console.log(chalk_1.default.red('>>> eggs: This is a live system! An egg cannot be produced from an egg!'));
        }
        else {
            await this.liveCreateStructure();
            // Carica calamares sono se le icone sono accettate
            if (!noicons) { // se VOGLIO le icone
                if (!nointeractive && this.settings.distro.isCalamaresAvailable && (pacman_1.default.isInstalledGui()) &&
                    this.settings.config.force_installer && !(pacman_1.default.calamaresExists())) {
                    console.log('Installing ' + chalk_1.default.bgGray('calamares') + ' due force_installer=yes.');
                    await pacman_1.default.calamaresInstall(verbose);
                    const bleach = new bleach_1.default();
                    await bleach.clean(verbose);
                }
            }
            /**
             * cryptedclone
             */
            if (cryptedclone) {
                console.log('eggs will SAVE users and users\' data ENCRYPTED on LUKS volume within the live');
                const users = await this.usersFill();
                for (const user of users) {
                    if (user.saveIt) {
                        let utype = 'user   ';
                        if (Number.parseInt(user.uid) < 1000) {
                            utype = 'service';
                        }
                        console.log(`- ${utype}: ${user.login.padEnd(16)} \thome: ${user.home}`);
                        if (user.login !== 'root') {
                            this.addRemoveExclusion(true, user.home);
                        }
                    }
                }
                /**
                 * clone
                 *
                 * users tend to set user_opt as
                 * real user when create a clone,
                 * this is WRONG here we correct
                 */
            }
            else if (this.clone) {
                this.settings.config.user_opt = 'live'; // patch for humans 
                this.settings.config.user_opt_passwd = 'evolution';
                this.settings.config.root_passwd = 'evolution';
                utils_2.default.warning('eggs will SAVE users and users\' data UNCRYPTED on the live');
                /**
                 * normal
                 */
            }
            else {
                utils_2.default.warning('eggs will REMOVE users and users\' data from live');
            }
            /**
             * exclude.list
             */
            let excludeListTemplateDir = '/etc/penguins-eggs.d/exclude.list.d/';
            let excludeListTemplate = excludeListTemplateDir + 'exclude.list.template';
            if (!fs_1.default.existsSync(excludeListTemplate)) {
                utils_2.default.warning('Cannot find: ' + excludeListTemplate);
                process.exit(1);
            }
            let excludeCustom = '';
            let excludeDev = '';
            let excludeHomes = '';
            let excludeUsr = '';
            if (filters.custom) {
                excludeCustom = fs_1.default.readFileSync(`${excludeListTemplateDir}exclude.list.custom`, 'utf8');
            }
            if (filters.dev) {
                excludeDev = `home/${await utils_2.default.getPrimaryUser()}/*`;
            }
            if (filters.homes) {
                excludeHomes = fs_1.default.readFileSync(`${excludeListTemplateDir}exclude.list.homes`, 'utf8');
            }
            if (filters.usr) {
                excludeUsr = fs_1.default.readFileSync(`${excludeListTemplateDir}exclude.list.usr`, 'utf8');
            }
            let view = {
                exclude_list_custom: excludeCustom,
                exclude_list_dev: excludeDev,
                exclude_list_homes: excludeHomes,
                exclude_list_usr: excludeUsr
            };
            const template = fs_1.default.readFileSync(excludeListTemplate, 'utf8');
            fs_1.default.writeFileSync(this.settings.config.snapshot_excludes, mustache_1.default.render(template, view));
            /**
             * NOTE: reCreate = false
             *
             * reCreate = false is just for develop
             * put reCreate = true in release
             */
            const reCreate = true;
            let mksquashfsCmd = '';
            if (reCreate) { // start pre-clone
                /**
                 * installer
                 */
                this.incubator = new incubator_1.default(this.settings.remix, this.settings.distro, this.settings.config.user_opt, this.theme, this.clone, verbose);
                await this.incubator.config(release);
                await this.syslinux();
                await this.isolinux(this.theme);
                await this.kernelCopy();
                /**
                 * we need different behaviour on
                 * initrd for different familis
                 */
                if (this.familyId === 'debian') {
                    await this.initrdDebian();
                }
                else if (this.familyId === 'archlinux') {
                    await this.initrdArch();
                }
                if (this.settings.config.make_efi) {
                    await this.makeEfi(this.theme);
                }
                await this.bindLiveFs();
                await this.copyBoot();
                if (!this.clone) {
                    /**
                     * ANCHE per cryptedclone
                     */
                    await this.cleanUsersAccounts();
                    await this.createUserLive();
                    if (pacman_1.default.isInstalledGui()) {
                        await this.createXdgAutostart(this.settings.config.theme, myAddons, noicons);
                        /**
                         * GUI installed but NOT Desktop Manager: just create motd and issue
                         */
                        if ((0, displaymanager_1.displaymanager)() === '') {
                            this.cliAutologin.addIssue(this.settings.distro.distroId, this.settings.distro.codenameId, this.settings.config.user_opt, this.settings.config.user_opt_passwd, this.settings.config.root_passwd, this.settings.work_dir.merged);
                            this.cliAutologin.addMotd(this.settings.distro.distroId, this.settings.distro.codenameId, this.settings.config.user_opt, this.settings.config.user_opt_passwd, this.settings.config.root_passwd, this.settings.work_dir.merged);
                        }
                    }
                    else {
                        this.cliAutologin.addAutologin(this.settings.distro.distroId, this.settings.distro.codenameId, this.settings.config.user_opt, this.settings.config.user_opt_passwd, this.settings.config.root_passwd, this.settings.work_dir.merged);
                    }
                    // Here we are forcing alwats cliAutologin
                    this.cliAutologin.addAutologin(this.settings.distro.distroId, this.settings.distro.codenameId, this.settings.config.user_opt, this.settings.config.user_opt_passwd, this.settings.config.root_passwd, this.settings.work_dir.merged);
                }
                await this.editLiveFs(clone, cryptedclone);
                mksquashfsCmd = await this.makeSquashfs(scriptOnly, unsecure);
                await this.uBindLiveFs(); // Lo smonto prima della fase di backup
            }
            if (cryptedclone) {
                await (0, utils_1.exec)('eggs syncto', utils_2.default.setEcho(true));
                utils_2.default.warning(`Waiting 10s, before to move ${luksFile} in ${this.ovarium}iso/live`);
                await (0, utils_1.exec)('sleep 10', utils_2.default.setEcho(false));
                utils_2.default.warning(`moving ${luksFile} in ${this.ovarium}iso/live`);
                await (0, utils_1.exec)(`mv ${luksFile} ${this.ovarium}iso/live`, this.echo);
            }
            const mkIsofsCmd = this.xorrisoCommand(clone, cryptedclone).replace(/\s\s+/g, ' ');
            const info = utils_2.default.getVolid(this.settings.remix.name);
            this.makeDotDisk(info, mksquashfsCmd, mkIsofsCmd);
            /**
             * AntiX/MX LINUX
             */
            if (fs_1.default.existsSync('/etc/antix-version')) {
                let uname = (await (0, utils_1.exec)('uname -r', { capture: true })).data;
                uname = uname.replaceAll('\n', '');
                let content = '';
                content = '#!/usr/bin/env bash';
                content += 'mkdir /live/bin -p\n';
                content += '## \n';
                content += '# cp /usr/lib/penguins-eggs/scripts/non-live-cmdline /live/bin -p\n';
                content += '# chmod +x /live/bin/non-live-cmdline\n';
                content += '## \n';
                content += 'mkdir /live/boot-dev/antiX -p\n';
                content += 'ln -s /run/live/medium/live/filesystem.squashfs /live/boot-dev/antiX/linuxfs\n';
                content += `ln -s /run/live/medium/live/initrd.img-${uname} /live/boot-dev/antiX/initrd.gz\n`;
                content += `ln -s /run/live/medium/live/vmlinuz-${uname} /live/boot-dev/antiX/vmlinuz\n`;
                content += `# md5sum /live/boot-dev/antiX/linuxfs > /live/boot-dev/antiX/linuxfs.md5\n`;
                content += `# md5sum /live/boot-dev/antiX/initrd.gz > /live/boot-dev/antiX/initrd.gz.md5\n`;
                content += `# md5sum /live/boot-dev/antiX/vmlinuz > /live/boot-dev/antiX/vmlinuz.md5\n`;
                content += `# /live/aufs -> /run/live/rootfs/filesystem.squashfs\n`;
                content += 'ln -s /run/live/rootfs/filesystem.squashfs /live/aufs\n';
                content += `# use: minstall -no-media-check\n`;
                content += 'minstall --no-media-check\n';
                let file = `${this.settings.iso_work}antix-mx-installer`;
                fs_1.default.writeFileSync(file, content);
                await (0, utils_1.exec)(`chmod +x ${file}`);
            }
            /**
             * patch to emulate miso/archiso on archilinux
             */
            if (this.familyId === 'archlinux') {
                let pathName = `arch/x86_64/airootfs`;
                let hashCmd = 'sha512sum';
                let hashExt = '.sha512';
                if (this.settings.distro.distroId === 'ManjaroLinux') {
                    pathName = `manjaro/x86_64/livefs`;
                    hashCmd = `md5sum`;
                    hashExt = '.md5';
                }
                await (0, utils_1.exec)(`mkdir ${this.settings.iso_work}${pathName}/x86_64 -p`, this.echo);
                await (0, utils_1.exec)(`mv ${this.settings.iso_work}live/filesystem.squashfs ${this.settings.iso_work}${pathName}.sfs`, this.echo);
                await (0, utils_1.exec)(`${hashCmd} ${this.settings.iso_work}${pathName}.sfs > ${this.settings.iso_work}${pathName}${hashExt}`, this.echo);
            }
            await this.makeIso(mkIsofsCmd, scriptOnly);
        }
    }
    /**
     * Crea la struttura della workdir
     */
    async liveCreateStructure() {
        if (this.verbose) {
            console.log('Ovary: liveCreateStructure');
        }
        utils_2.default.warning(`creating egg in ${this.settings.config.snapshot_dir}`);
        let cmd;
        if (!fs_1.default.existsSync(this.settings.config.snapshot_dir)) {
            cmd = `mkdir -p ${this.settings.config.snapshot_dir}`;
            this.tryCatch(cmd);
        }
        if (!fs_1.default.existsSync(this.settings.config.snapshot_dir + '/README.md')) {
            cmd = `cp ${node_path_1.default.resolve(__dirname, '../../conf/README.md')} ${this.settings.config.snapshot_dir}README.md`;
            this.tryCatch(cmd);
        }
        // Ovarium 
        if (!fs_1.default.existsSync(this.settings.work_dir.ovarium)) {
            cmd = `mkdir -p ${this.settings.work_dir.ovarium}`;
            this.tryCatch(cmd);
        }
        if (!fs_1.default.existsSync(this.settings.work_dir.lowerdir)) {
            cmd = `mkdir -p ${this.settings.work_dir.lowerdir}`;
            this.tryCatch(cmd);
        }
        if (!fs_1.default.existsSync(this.settings.work_dir.upperdir)) {
            cmd = `mkdir -p ${this.settings.work_dir.upperdir}`;
            this.tryCatch(cmd);
        }
        if (!fs_1.default.existsSync(this.settings.work_dir.workdir)) {
            cmd = `mkdir -p ${this.settings.work_dir.workdir}`;
            this.tryCatch(cmd);
        }
        if (!fs_1.default.existsSync(this.settings.work_dir.merged)) {
            cmd = `mkdir -p ${this.settings.work_dir.merged}`;
            this.tryCatch(cmd);
        }
        /**
         * Creo le directory di destinazione per boot, efi, isolinux e live
         */
        if (!fs_1.default.existsSync(this.settings.iso_work)) {
            cmd = `mkdir -p ${this.settings.iso_work}boot/grub/${utils_2.default.uefiFormat()}`;
            this.tryCatch(cmd);
            cmd = `mkdir -p ${this.settings.iso_work}efi/boot`;
            this.tryCatch(cmd);
            cmd = `mkdir -p ${this.settings.iso_work}isolinux`;
            this.tryCatch(cmd);
            cmd = `mkdir -p ${this.settings.iso_work}live`;
            this.tryCatch(cmd);
        }
        // ln iso
        cmd = `ln -s ${this.settings.iso_work} ${this.settings.config.snapshot_dir}/iso`;
        this.tryCatch(cmd);
        // ln livefs
        cmd = `ln -s ${this.settings.work_dir.merged} ${this.settings.config.snapshot_dir}/livefs`;
        this.tryCatch(cmd);
    }
    /**
     *
     * @param cmd
     */
    async tryCatch(cmd = '') {
        if (this.verbose) {
            console.log('Ovary: tryCatch');
        }
        try {
            await (0, utils_1.exec)(cmd, this.echo);
        }
        catch (error) {
            console.log(`Error: ${error}`);
            await utils_2.default.pressKeyToExit(cmd);
        }
    }
    /**
     * editLiveFs
     * - Truncate logs, remove archived log
     * - Allow all fixed drives to be mounted with pmount
     * - Enable or disable password login trhough ssh for users (not root)
     * - Create an empty /etc/fstab
     * - Blanck /etc/machine-id
     * - Add some basic files to /dev
     * - Clear configs from /etc/network/interfaces, wicd and NetworkManager and netman
     */
    async editLiveFs(clone = false, cryptedclone = false) {
        if (this.verbose) {
            console.log('Ovary: editLiveFs');
        }
        /**
         * /etc/penguins-eggs.d/is_clone file created on live
         */
        if (clone) {
            await (0, utils_1.exec)(`touch ${this.settings.work_dir.merged}/etc/penguins-eggs.d/is_clone`, this.echo);
        }
        /**
         * /etc/penguins-eggs.d/is_crypted_clone file created on live
         */
        if (cryptedclone) {
            await (0, utils_1.exec)(`touch ${this.settings.work_dir.merged}/etc/penguins-eggs.d/is_crypted_clone`, this.echo);
        }
        /**
         * /etc/default/epoptes-client created on live
         */
        if (pacman_1.default.packageIsInstalled('epoptes')) {
            const file = `${this.settings.work_dir.merged}/etc/default/epoptes-client`;
            const text = `SERVER=${node_os_1.default.hostname}.local\n`;
            fs_1.default.writeFileSync(file, text);
        }
        if (this.familyId === 'debian') {
            // Aggiungo UMASK=0077 in /etc/initramfs-tools/conf.d/calamares-safe-initramfs.conf
            const text = 'UMASK=0077\n';
            const file = '/etc/initramfs-tools/conf.d/eggs-safe-initramfs.conf';
            utils_2.default.write(file, text);
        }
        // Truncate logs, remove archived logs.
        let cmd = `find ${this.settings.work_dir.merged}/var/log -name "*gz" -print0 | xargs -0r rm -f`;
        await (0, utils_1.exec)(cmd, this.echo);
        cmd = `find ${this.settings.work_dir.merged}/var/log/ -type f -exec truncate -s 0 {} \\;`;
        await (0, utils_1.exec)(cmd, this.echo);
        // Allow all fixed drives to be mounted with pmount
        if (this.settings.config.pmount_fixed && fs_1.default.existsSync(`${this.settings.work_dir.merged}/etc/pmount.allow`)) {
            // MX aggiunto /etc
            await (0, utils_1.exec)(`sed -i 's:#/dev/sd\[a-z\]:/dev/sd\[a-z\]:' ${this.settings.work_dir.merged}/etc/pmount.allow`, this.echo);
        }
        // Remove obsolete live-config file
        if (fs_1.default.existsSync(`${this.settings.work_dir.merged}lib/live/config/1161-openssh-server`)) {
            await (0, utils_1.exec)(`rm -f ${this.settings.work_dir.merged}/lib/live/config/1161-openssh-server`, this.echo);
        }
        if (fs_1.default.existsSync(`${this.settings.work_dir.merged}/etc/ssh/sshd_config`)) {
            /**
             * enable/disable SSH root/users password login
             */
            await (0, utils_1.exec)(`sed -i '/PermitRootLogin/d' ${this.settings.work_dir.merged}/etc/ssh/sshd_config`);
            await (0, utils_1.exec)(`sed -i '/PasswordAuthentication/d' ${this.settings.work_dir.merged}/etc/ssh/sshd_config`);
            if (this.settings.config.ssh_pass) {
                await (0, utils_1.exec)(`echo 'PermitRootLogin yes' | tee -a ${this.settings.work_dir.merged}/etc/ssh/sshd_config`);
                await (0, utils_1.exec)(`echo 'PasswordAuthentication yes' | tee -a ${this.settings.work_dir.merged}/etc/ssh/sshd_config`);
            }
            else {
                await (0, utils_1.exec)(`echo 'PermitRootLogin prohibit-password' | tee -a ${this.settings.work_dir.merged}/etc/ssh/sshd_config`);
                await (0, utils_1.exec)(`echo 'PasswordAuthentication no' | tee -a ${this.settings.work_dir.merged}/etc/ssh/sshd_config`);
            }
        }
        /**
         * ufw --force reset
         */
        // if (Pacman.packageIsInstalled('ufw')) {
        //    await exec('ufw --force reset')
        // }
        /**
         * /etc/fstab should exist, even if it's empty,
         * to prevent error messages at boot
         */
        await (0, utils_1.exec)(`rm ${this.settings.work_dir.merged}/etc/fstab`, this.echo);
        await (0, utils_1.exec)(`touch ${this.settings.work_dir.merged}/etc/fstab`, this.echo);
        /**
         * Remove crypttab if exists
         * this is crucial for tpm systems.
         */
        if (fs_1.default.existsSync(`${this.settings.work_dir.merged}/etc/crypttab`)) {
            await (0, utils_1.exec)(`rm ${this.settings.work_dir.merged}/etc/crypttab`, this.echo);
        }
        /**
         * Blank out systemd machine id.
         * If it does not exist, systemd-journald will fail,
         * but if it exists and is empty, systemd will automatically
         * set up a new unique ID.
         */
        if (fs_1.default.existsSync(`${this.settings.work_dir.merged}/etc/machine-id`)) {
            await (0, utils_1.exec)(`rm ${this.settings.work_dir.merged}/etc/machine-id`, this.echo);
            await (0, utils_1.exec)(`touch ${this.settings.work_dir.merged}/etc/machine-id`, this.echo);
            utils_2.default.write(`${this.settings.work_dir.merged}/etc/machine-id`, ':');
        }
        /**
         * LMDE4: utilizza UbuntuMono16.pf2
         * aggiungo un link a /boot/grub/fonts/UbuntuMono16.pf2
         */
        shelljs_1.default.cp(`${this.settings.work_dir.merged}/boot/grub/fonts/unicode.pf2`, `${this.settings.work_dir.merged}/boot/grub/fonts/UbuntuMono16.pf2`);
        /**
        * cleaning /etc/resolv.conf
        */
        const resolvFile = `${this.settings.work_dir.merged}/etc/resolv.conf`;
        shelljs_1.default.rm(resolvFile);
        /**
         * Per tutte le distro systemd
         */
        if (utils_2.default.isSystemd()) {
            const systemdctl = new systemctl_1.default(this.verbose);
            /**
             * systemd-systemd-resolved
             */
            let resolvContent = '';
            if (await systemdctl.isActive('systemd-resolved.service')) {
                await systemdctl.stop('systemd-resolved.service');
                resolvContent = 'nameserver 127.0.0.53\noptions edns0 trust-ad\nsearch .\n';
            }
            fs_1.default.writeFileSync(resolvFile, resolvContent);
            if (await systemdctl.isEnabled('systemd-networkd.service')) {
                await systemdctl.disable('systemd-networkd.service', this.settings.work_dir.merged, true);
            }
            if (await systemdctl.isEnabled('remote-cryptsetup.target')) {
                await systemdctl.disable('remote-cryptsetup.target', this.settings.work_dir.merged, true);
            }
            if (await systemdctl.isEnabled('speech-dispatcherd.service')) {
                await systemdctl.disable('speech-dispatcherd.service', this.settings.work_dir.merged, true);
            }
            if (await systemdctl.isEnabled('wpa_supplicant-nl80211@.service')) {
                await systemdctl.disable('wpa_supplicant-nl80211@.service', this.settings.work_dir.merged, true);
            }
            if (await systemdctl.isEnabled('wpa_supplicant@.service')) {
                await systemdctl.disable('wpa_supplicant@.service', this.settings.work_dir.merged, true);
            }
            if (await systemdctl.isEnabled('wpa_supplicant-wired@.service')) {
                await systemdctl.disable('wpa_supplicant-wired@.service', this.settings.work_dir.merged, true);
            }
            /**
             * All systemd distros rm
             */
            await (0, utils_1.exec)(`rm -f ${this.settings.work_dir.merged}/var/lib/wicd/configurations/*`, this.echo);
            await (0, utils_1.exec)(`rm -f ${this.settings.work_dir.merged}/etc/wicd/wireless-settings.conf`, this.echo);
            await (0, utils_1.exec)(`rm -f ${this.settings.work_dir.merged}/etc/NetworkManager/system-connections/*`, this.echo);
            await (0, utils_1.exec)(`rm -f ${this.settings.work_dir.merged}/etc/network/wifi/*`, this.echo);
            /**
             * removing from /etc/network/:
             * if-down.d if-post-down.d if-pre-up.d if-up.d interfaces interfaces.d
             */
            const cleanDirs = ['if-down.d', 'if-post-down.d', 'if-pre-up.d', 'if-up.d', 'interfaces.d'];
            let cleanDir = '';
            for (cleanDir of cleanDirs) {
                await (0, utils_1.exec)(`rm -f ${this.settings.work_dir.merged}/etc/network/${cleanDir}/wpasupplicant`, this.echo);
            }
        }
        /**
         * Clear configs from /etc/network/interfaces, wicd and NetworkManager
         * and netman, so they aren't stealthily included in the snapshot.
         */
        if (this.familyId === 'debian') {
            if (fs_1.default.existsSync(`${this.settings.work_dir.merged}/etc/network/interfaces`)) {
                await (0, utils_1.exec)(`rm -f ${this.settings.work_dir.merged}/etc/network/interfaces`, this.echo);
                utils_2.default.write(`${this.settings.work_dir.merged}/etc/network/interfaces`, 'auto lo\niface lo inet loopback');
            }
            /**
             * add some basic files to /dev
             */
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/console`)) {
                await (0, utils_1.exec)(`mknod -m 622 ${this.settings.work_dir.merged}/dev/console c 5 1`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/null`)) {
                await (0, utils_1.exec)(`mknod -m 666 ${this.settings.work_dir.merged}/dev/null c 1 3`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/zero`)) {
                await (0, utils_1.exec)(`mknod -m 666 ${this.settings.work_dir.merged}/dev/zero c 1 5`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/ptmx`)) {
                await (0, utils_1.exec)(`mknod -m 666 ${this.settings.work_dir.merged}/dev/ptmx c 5 2`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/tty`)) {
                await (0, utils_1.exec)(`mknod -m 666 ${this.settings.work_dir.merged}/dev/tty c 5 0`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/random`)) {
                await (0, utils_1.exec)(`mknod -m 444 ${this.settings.work_dir.merged}/dev/random c 1 8`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/urandom`)) {
                await (0, utils_1.exec)(`mknod -m 444 ${this.settings.work_dir.merged}/dev/urandom c 1 9`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/{console,ptmx,tty}`)) {
                await (0, utils_1.exec)(`chown -v root:tty ${this.settings.work_dir.merged}/dev/{console,ptmx,tty}`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/fd`)) {
                await (0, utils_1.exec)(`ln -sv /proc/self/fd ${this.settings.work_dir.merged}/dev/fd`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/stdin`)) {
                await (0, utils_1.exec)(`ln -sv /proc/self/fd/0 ${this.settings.work_dir.merged}/dev/stdin`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/stdout`)) {
                await (0, utils_1.exec)(`ln -sv /proc/self/fd/1 ${this.settings.work_dir.merged}/dev/stdout`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/stderr`)) {
                await (0, utils_1.exec)(`ln -sv /proc/self/fd/2 ${this.settings.work_dir.merged}/dev/stderr`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/core`)) {
                await (0, utils_1.exec)(`ln -sv /proc/kcore ${this.settings.work_dir.merged}/dev/core`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/shm`)) {
                await (0, utils_1.exec)(`mkdir -v ${this.settings.work_dir.merged}/dev/shm`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/pts`)) {
                await (0, utils_1.exec)(`mkdir -v ${this.settings.work_dir.merged}/dev/pts`, this.echo);
            }
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/dev/shm`)) {
                await (0, utils_1.exec)(`chmod 1777 ${this.settings.work_dir.merged}/dev/shm`, this.echo);
            }
            /**
             * creo /tmp
             */
            if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/tmp`)) {
                await (0, utils_1.exec)(`mkdir ${this.settings.work_dir.merged}/tmp`, this.echo);
            }
            /**
            * Assegno 1777 a /tmp creava problemi con MXLINUX
            */
            await (0, utils_1.exec)(`chmod 1777 ${this.settings.work_dir.merged}/tmp`, this.echo);
        }
    }
    /**
     * syslinux
     */
    async syslinux() {
        if (this.verbose) {
            console.log('Ovary: syslinux');
        }
        await (0, utils_1.exec)(`cp ${this.settings.distro.syslinuxPath}/vesamenu.c32 ${this.settings.iso_work}/isolinux/`, this.echo);
        await (0, utils_1.exec)(`cp ${this.settings.distro.syslinuxPath}/chain.c32 ${this.settings.iso_work}/isolinux/`, this.echo);
        /**
         * per openSuse non sono riusciuto a determinare
         * quale pacchetto installi:
         * ldllinux.c43, libcom32 e libutil.c32
         */
        if (this.familyId !== 'suse') {
            await (0, utils_1.exec)(`cp ${this.settings.distro.syslinuxPath}/ldlinux.c32 ${this.settings.iso_work}/isolinux/`, this.echo);
            await (0, utils_1.exec)(`cp ${this.settings.distro.syslinuxPath}/libcom32.c32 ${this.settings.iso_work}/isolinux/`, this.echo);
            await (0, utils_1.exec)(`cp ${this.settings.distro.syslinuxPath}/libutil.c32 ${this.settings.iso_work}/isolinux/`, this.echo);
        }
    }
    /**
     *  async isolinux
     */
    async isolinux(theme = 'eggs') {
        if (this.verbose) {
            console.log('Ovary: isolinux');
        }
        /**
         * isolinux.bin
         */
        await (0, utils_1.exec)(`cp ${this.settings.distro.isolinuxPath}/isolinux.bin ${this.settings.iso_work}/isolinux/`, this.echo);
        /**
         * isolinux.theme.cfg
         */
        const isolinuxThemeDest = this.settings.iso_work + 'isolinux/isolinux.theme.cfg';
        let isolinuxThemeSrc = node_path_1.default.resolve(__dirname, `../../addons/${theme}/theme/livecd/isolinux.theme.cfg`);
        if (this.theme.includes('/')) {
            isolinuxThemeSrc = `${theme}/theme/livecd/isolinux.theme.cfg`;
        }
        if (!fs_1.default.existsSync(isolinuxThemeSrc)) {
            utils_2.default.warning('Cannot find: ' + isolinuxThemeSrc);
            process.exit();
        }
        fs_1.default.copyFileSync(isolinuxThemeSrc, isolinuxThemeDest);
        /**
         * isolinux.cfg from isolinux.main.cfg
         */
        const isolinuxDest = `${this.settings.iso_work}/isolinux/isolinux.cfg`;
        this.settings.iso_work + 'isolinux/isolinux.cfg';
        let isolinuxTemplate = `${theme}/theme/livecd/isolinux.main.cfg`;
        if (!fs_1.default.existsSync(isolinuxTemplate)) {
            //isolinuxTemplate = path.resolve(__dirname, '../../addons/templates/isolinux.main.cfg')
            isolinuxTemplate = node_path_1.default.resolve(__dirname, '../../addons/eggs/theme/livecd/isolinux.main.cfg');
        }
        if (!fs_1.default.existsSync(isolinuxTemplate)) {
            utils_2.default.warning('Cannot find: ' + isolinuxTemplate);
            process.exit();
        }
        const kernel_parameters = this.kernelParameters();
        const template = fs_1.default.readFileSync(isolinuxTemplate, 'utf8');
        const view = {
            fullname: this.settings.remix.fullname.toUpperCase(),
            kernel: utils_2.default.kernelVersion(),
            vmlinuz: `/live${this.settings.vmlinuz}`,
            initrdImg: `/live${this.settings.initrdImg}`,
            kernel_parameters: kernel_parameters,
        };
        fs_1.default.writeFileSync(isolinuxDest, mustache_1.default.render(template, view));
        /**
         * splash
         */
        const splashDest = `${this.settings.iso_work}/isolinux/splash.png`;
        let splashSrc = node_path_1.default.resolve(__dirname, `../../addons/${theme}/theme/livecd/splash.png`);
        if (this.theme.includes('/')) {
            splashSrc = node_path_1.default.resolve(`${theme}/theme/livecd/splash.png`);
        }
        if (!fs_1.default.existsSync(splashSrc)) {
            utils_2.default.warning('Cannot find: ' + splashSrc);
            process.exit();
        }
        fs_1.default.copyFileSync(splashSrc, splashDest);
    }
    /**
     *
     * @returns kernelParameters
     */
    kernelParameters() {
        if (this.verbose) {
            console.log('Ovary: kernelParameters');
        }
        // GRUB_CMDLINE_LINUX='ipv6.disable=1'
        const distroId = this.settings.distro.distroId;
        let kp = `boot=live components locales=${process.env.LANG}`;
        if (this.familyId === 'archlinux') {
            const volid = utils_2.default.getVolid(this.settings.remix.name);
            if (isArchiso(distroId)) {
                kp += ` archisobasedir=arch archisolabel=${volid}`;
            }
            else if (distroId === 'ManjaroLinux') {
                kp += ` misobasedir=manjaro misolabel=${volid}`;
            }
            kp += ` cow_spacesize=4G`;
        }
        return kp;
    }
    /**
     * kernelCopy
     */
    async kernelCopy() {
        utils_2.default.warning(`copying ${node_path_1.default.basename(this.settings.kernel_image)} on ISO/live`);
        let lackVmlinuzImage = false;
        if (fs_1.default.existsSync(this.settings.kernel_image)) {
            await (0, utils_1.exec)(`cp ${this.settings.kernel_image} ${this.settings.iso_work}live/`, this.echo);
        }
        else {
            utils_2.default.error(`Cannot find ${this.settings.kernel_image}`);
            lackVmlinuzImage = true;
        }
        if (lackVmlinuzImage) {
            utils_2.default.warning('Try to edit /etc/penguins-eggs.d/eggs.yaml and check for');
            utils_2.default.warning(`vmlinuz: ${this.settings.kernel_image}`);
            process.exit(1);
        }
    }
    /**
     * initrdArch()
     * necessita di echoYes
     */
    async initrdArch() {
        utils_2.default.warning(`creating ${node_path_1.default.basename(this.settings.initrdImg)} on ISO/live`);
        let initrdImg = utils_2.default.initrdImg();
        initrdImg = initrdImg.slice(Math.max(0, initrdImg.lastIndexOf('/') + 1));
        utils_2.default.warning(`Creating ${initrdImg} in ${this.settings.iso_work}live/`);
        const distroId = this.settings.distro.distroId;
        let fileConf = 'arch';
        if (!isArchiso(distroId)) {
            fileConf = distroId.toLowerCase();
        }
        let pathConf = node_path_1.default.resolve(__dirname, `../../mkinitcpio/${fileConf}/live.conf`);
        await (0, utils_1.exec)(`mkinitcpio -c ${pathConf} -g ${this.settings.iso_work}live/${initrdImg}`, utils_2.default.setEcho(true));
    }
    /**
     * We must upgrade to initrdCreate for Debian/Ubuntu
     * @returns
     */
    async initrdDebian(verbose = false) {
        utils_2.default.warning(`creating ${node_path_1.default.basename(this.settings.initrdImg)} on ISO/live`);
        let isCrypted = false;
        if (fs_1.default.existsSync('/etc/crypttab')) {
            isCrypted = true;
            await (0, utils_1.exec)('mv /etc/crypttab /etc/crypttab.saved', this.echo);
        }
        await (0, utils_1.exec)(`mkinitramfs -o ${this.settings.iso_work}/live/initrd.img-$(uname -r) ${this.toNull}`, this.echo);
        if (isCrypted) {
            await (0, utils_1.exec)('mv /etc/crypttab.saved /etc/crypttab', this.echo);
        }
    }
    /**
     * squashFs: crea in live filesystem.squashfs
     */
    async makeSquashfs(scriptOnly = false, unsecure = false) {
        if (this.verbose) {
            console.log('Ovary: makeSquashfs');
        }
        /**
         * exclude all the accurence of cryptdisks in rc0.d, etc
         */
        const fexcludes = [
            '/boot/efi/EFI',
            '/etc/fstab',
            '/etc/mtab',
            '/etc/udev/rules.d/70-persistent-cd.rules',
            '/etc/udev/rules.d/70-persistent-net.rules',
        ];
        for (const i in fexcludes) {
            this.addRemoveExclusion(true, fexcludes[i]);
        }
        /**
         * Non sò che fa, ma sicuro non serve per archlinux
         */
        if (this.familyId === 'debian') {
            const rcd = ['rc0.d', 'rc1.d', 'rc2.d', 'rc3.d', 'rc4.d', 'rc5.d', 'rc6.d', 'rcS.d'];
            let files;
            for (const i in rcd) {
                files = fs_1.default.readdirSync(`${this.settings.work_dir.merged}/etc/${rcd[i]}`);
                for (const n in files) {
                    if (files[n].includes('cryptdisks')) {
                        this.addRemoveExclusion(true, `/etc/${rcd[i]}${files[n]}`);
                    }
                }
            }
        }
        /**
         * secure
         */
        if (!unsecure) {
            this.addRemoveExclusion(true, `root/*`);
            this.addRemoveExclusion(true, `root/.*`);
        }
        if (shelljs_1.default.exec('/usr/bin/test -L /etc/localtime', { silent: true }) && shelljs_1.default.exec('cat /etc/timezone', { silent: true }) !== 'Europe/Rome') {
            // this.addRemoveExclusion(true, '/etc/localtime')
        }
        this.addRemoveExclusion(true, this.settings.config.snapshot_dir /* .absolutePath() */);
        if (fs_1.default.existsSync(`${this.settings.iso_work}/live/filesystem.squashfs`)) {
            fs_1.default.unlinkSync(`${this.settings.iso_work}/live/filesystem.squashfs`);
        }
        const compression = `-comp ${this.settings.config.compression}`;
        /**
        * limit: patch per Raspberry
        */
        let limit = '';
        if (utils_2.default.uefiArch() === 'arm64') {
            // limit = ' -processors 2 -mem 1024M'
        }
        /**
         * mksquashfs
         *
         * SYNTAX: mksquashfs source1 source2 ...
         * FILESYSTEM [OPTIONS]
         * [-ef exclude.list]
         * [-e list of exclude dirs/files]
         */
        let cmd = `mksquashfs ${this.settings.work_dir.merged} ${this.settings.iso_work}live/filesystem.squashfs ${compression} ${limit} -wildcards -ef ${this.settings.config.snapshot_excludes} ${this.settings.session_excludes}`;
        cmd = cmd.replace(/\s\s+/g, ' ');
        utils_2.default.writeX(`${this.settings.work_dir.ovarium}mksquashfs`, cmd);
        if (!scriptOnly) {
            utils_2.default.warning('creating filesystem.squashfs on ISO/live');
            // Utils.warning(`compression: ` + compression)
            const test = (await (0, utils_1.exec)(cmd, utils_2.default.setEcho(true))).code;
            if (test !== 0) {
                process.exit();
            }
        }
        return cmd;
    }
    /**
     * Restituisce true per le direcory da montare con overlay
     *
     * Ci sono tre tipologie:
     *
     * - normal solo la creazione della directory, nessun mount
     * - merged creazione della directory e mount ro
     * - mergedAndOverlay creazione directory, overlay e mount rw
     *
     * @param dir
     */
    mergedAndOverlay(dir) {
        if (this.verbose) {
            console.log('Ovary: mergedAndOverlay');
        }
        // boot viene copiato... non ricordo perchè
        const mountDirs = ['etc', 'usr', 'var'];
        let mountDir = '';
        let overlay = false;
        for (mountDir of mountDirs) {
            if (mountDir === dir) {
                overlay = true;
            }
        }
        return overlay;
    }
    /**
     * Ritorna true se c'è bisogno del mount --bind
     *
     * Ci sono tre tipologie:
     *
     * - normal solo la creazione della directory, nessun mount
     * - merged creazione della directory e mount ro
     * - mergedAndOverlay creazione directory, overlay e mount rw
     * - copied: creazione directory e copia
     */
    merged(dir) {
        if (this.verbose) {
            console.log('Ovary: merged');
        }
        let merged = true;
        if (dir === 'home') {
            merged = this.clone;
        }
        else {
            const noMergeDirs = [
                'boot', // will be copied now
                'cdrom',
                'dev',
                'media',
                'mnt',
                'proc',
                'run',
                'swapfile',
                'sys',
                'tmp',
            ];
            // deepin
            noMergeDirs.push('data', 'recovery');
            for (const noMergeDir of noMergeDirs) {
                if (dir === noMergeDir) {
                    merged = false;
                }
            }
        }
        return merged;
    }
    /**
     * Esegue il bind del fs live e
     * crea lo script bind
     *
     * @param verbose
     */
    async bindLiveFs() {
        if (this.verbose) {
            console.log('Ovary: bindLiveFs');
        }
        /**
         * Attenzione:
         * fs.readdirSync('/', { withFileTypes: true })
         * viene ignorato da Node8, ma da problemi da Node10 in poi
         */
        const dirs = fs_1.default.readdirSync('/'); // we must remove boot and 
        const startLine = '#############################################################';
        const titleLine = '# -----------------------------------------------------------';
        const endLine = '# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n';
        let lnkDest = '';
        let cmd = '';
        const cmds = [];
        cmds.push('# NOTE: cdrom, dev, live, media, mnt, proc, run, sys and tmp', `#       need just a mkdir in ${this.settings.work_dir.merged}`);
        cmds.push(`# host: ${node_os_1.default.hostname()} user: ${await utils_2.default.getPrimaryUser()}\n`);
        for (const dir of dirs) {
            cmds.push(startLine);
            if (n8_1.default.isDirectory(dir)) {
                if (dir !== 'boot') {
                    if (dir !== 'lost+found') {
                        cmd = `# /${dir} is a directory`;
                        if (this.mergedAndOverlay(dir)) {
                            /**
                             * mergedAndOverlay creazione directory, overlay e mount rw
                             */
                            cmds.push(`${cmd} need to be presente, and rw`, titleLine, '# create mountpoint lower');
                            cmds.push(await makeIfNotExist(`${this.settings.work_dir.lowerdir}/${dir}`), `# first: mount /${dir} rw in ${this.settings.work_dir.lowerdir}/${dir}`);
                            cmds.push(await rexec(`mount --bind --make-slave /${dir} ${this.settings.work_dir.lowerdir}/${dir}`, this.verbose), '# now remount it ro');
                            cmds.push(await rexec(`mount -o remount,bind,ro ${this.settings.work_dir.lowerdir}/${dir}`, this.verbose), `\n# second: create mountpoint upper, work and ${this.settings.work_dir.merged} and mount ${dir}`);
                            cmds.push(await makeIfNotExist(`${this.settings.work_dir.upperdir}/${dir}`, this.verbose));
                            cmds.push(await makeIfNotExist(`${this.settings.work_dir.workdir}/${dir}`, this.verbose));
                            cmds.push(await makeIfNotExist(`${this.settings.work_dir.merged}/${dir}`, this.verbose), `\n# thirth: mount /${dir} rw in ${this.settings.work_dir.merged}`);
                            cmds.push(await rexec(`mount -t overlay overlay -o lowerdir=${this.settings.work_dir.lowerdir}/${dir},upperdir=${this.settings.work_dir.upperdir}/${dir},workdir=${this.settings.work_dir.workdir}/${dir} ${this.settings.work_dir.merged}/${dir}`, this.verbose));
                        }
                        else if (this.merged(dir)) {
                            /*
                             * merged creazione della directory e mount ro
                             */
                            cmds.push(`${cmd} need to be present, mount ro`, titleLine);
                            cmds.push(await makeIfNotExist(`${this.settings.work_dir.merged}/${dir}`, this.verbose));
                            cmds.push(await rexec(`mount --bind --make-slave /${dir} ${this.settings.work_dir.merged}/${dir}`, this.verbose));
                            cmds.push(await rexec(`mount -o remount,bind,ro ${this.settings.work_dir.merged}/${dir}`, this.verbose));
                        }
                        else {
                            /**
                             * normal solo la creazione della directory, nessun mount
                             */
                            cmds.push(`${cmd} need to be present, no mount`, titleLine);
                            cmds.push(await makeIfNotExist(`${this.settings.work_dir.merged}/${dir}`, this.verbose), `# mount -o bind /${dir} ${this.settings.work_dir.merged}/${dir}`);
                        }
                    }
                }
            }
            else if (n8_1.default.isFile(dir)) {
                cmds.push(`# /${dir} is just a file`, titleLine);
                if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/${dir}`)) {
                    cmds.push(await rexec(`cp /${dir} ${this.settings.work_dir.merged}`, this.verbose));
                }
                else {
                    cmds.push('# file exist... skip');
                }
            }
            else if (n8_1.default.isSymbolicLink(dir)) {
                lnkDest = fs_1.default.readlinkSync(`/${dir}`);
                cmds.push(`# /${dir} is a symbolic link to /${lnkDest} in the system`, '# we need just to recreate it', `# ln -s ${this.settings.work_dir.merged}/${lnkDest} ${this.settings.work_dir.merged}/${lnkDest}`, "# but we don't know if the destination exist, and I'm too lazy today. So, for now: ", titleLine);
                if (!fs_1.default.existsSync(`${this.settings.work_dir.merged}/${dir}`)) {
                    if (fs_1.default.existsSync(lnkDest)) {
                        cmds.push(`ln -s ${this.settings.work_dir.merged}/${lnkDest} ${this.settings.work_dir.merged}/${lnkDest}`);
                    }
                    else {
                        cmds.push(await rexec(`cp -r /${dir} ${this.settings.work_dir.merged}`, this.verbose));
                    }
                }
                else {
                    cmds.push('# SymbolicLink exist... skip');
                }
            }
            cmds.push(endLine);
        }
        // Utils.writeXs(`${this.settings.config.snapshot_dir}bind`, cmds)
        utils_2.default.writeXs(`${this.settings.work_dir.ovarium}bind`, cmds);
    }
    /**
     * copyBoot
     *
     * necessario: prima era merged
     */
    async copyBoot() {
        if (this.verbose) {
            console.log('Ovary: copyBoot');
        }
        await rexec(`cp -r /boot ${this.settings.config.snapshot_mnt}filesystem.squashfs`, this.verbose);
    }
    /**
     * ubind del fs live
     * @param verbose
     */
    async uBindLiveFs() {
        if (this.verbose) {
            console.log('Ovary: uBindLiveFs');
        }
        const cmds = [];
        cmds.push('# NOTE: home, cdrom, dev, live, media, mnt, proc, run, sys and tmp', `#       need just to be removed in ${this.settings.work_dir.merged}`);
        cmds.push(`# host: ${node_os_1.default.hostname()} user: ${await utils_2.default.getPrimaryUser()}\n`);
        if (fs_1.default.existsSync(this.settings.work_dir.merged)) {
            const bindDirs = fs_1.default.readdirSync(this.settings.work_dir.merged, {
                withFileTypes: true,
            });
            for (const dir of bindDirs) {
                const dirname = n8_1.default.dirent2string(dir);
                cmds.push('#############################################################');
                if (n8_1.default.isDirectory(dirname)) {
                    cmds.push(`\n# directory: ${dirname}`);
                    if (this.mergedAndOverlay(dirname)) {
                        cmds.push(`\n# ${dirname} has overlay`, `\n# First, umount it from ${this.settings.config.snapshot_dir}`);
                        cmds.push(await rexec(`umount ${this.settings.work_dir.merged}/${dirname}`, this.verbose), `\n# Second, umount it from ${this.settings.work_dir.lowerdir}`);
                        cmds.push(await rexec(`umount ${this.settings.work_dir.lowerdir}/${dirname}`, this.verbose));
                    }
                    else if (this.merged(dirname)) {
                        cmds.push(await rexec(`umount ${this.settings.work_dir.merged}/${dirname}`, this.verbose));
                    }
                    cmds.push(`\n# remove in ${this.settings.work_dir.merged} and ${this.settings.work_dir.lowerdir}`);
                    /**
                     * We can't remove the nest!!!
                     */
                    const nest = this.settings.config.snapshot_dir.split('/');
                    if (dirname !== nest[1]) { // We can't remove first level nest
                        cmds.push(await rexec(`rm ${this.settings.work_dir.merged}/${dirname} -rf`, this.verbose));
                    }
                }
                else if (n8_1.default.isFile(dirname)) {
                    cmds.push(`\n# ${dirname} = file`);
                    cmds.push(await rexec(`rm ${this.settings.work_dir.merged}/${dirname}`, this.verbose));
                }
                else if (n8_1.default.isSymbolicLink(dirname)) {
                    cmds.push(`\n# ${dirname} = symbolicLink`);
                    cmds.push(await rexec(`rm ${this.settings.work_dir.merged}/${dirname}`, this.verbose));
                }
            }
        }
        if (this.clone) {
            cmds.push(await rexec(`umount ${this.settings.work_dir.merged}/home`, this.verbose));
        }
        // Utils.writeXs(`${this.settings.config.snapshot_dir}ubind`, cmds)
        utils_2.default.writeXs(`${this.settings.work_dir.ovarium}ubind`, cmds);
    }
    /**
     * bind dei virtual file system
     */
    async bindVfs() {
        if (this.verbose) {
            console.log('Ovary: bindVfs');
        }
        const cmds = [];
        cmds.push(`mount -o bind /dev ${this.settings.work_dir.merged}/dev`, `mount -o bind /dev/pts ${this.settings.work_dir.merged}/dev/pts`, `mount -o bind /proc ${this.settings.work_dir.merged}/proc`, `mount -o bind /sys ${this.settings.work_dir.merged}/sys`, `mount -o bind /run ${this.settings.work_dir.merged}/run`);
        // Utils.writeXs(`${this.settings.config.snapshot_dir}bindvfs`, cmds)
        utils_2.default.writeXs(`${this.settings.work_dir.ovarium}bindvfs`, cmds);
    }
    /**
     *
     * @param verbose
     */
    async ubindVfs() {
        if (this.verbose) {
            console.log('Ovary: ubindVfs');
        }
        const cmds = [];
        cmds.push(`umount ${this.settings.work_dir.merged}/dev/pts`, `umount ${this.settings.work_dir.merged}/dev`, `umount ${this.settings.work_dir.merged}/proc`, `umount ${this.settings.work_dir.merged}/run`, `umount ${this.settings.work_dir.merged}/sys`);
        // Utils.writeXs(`${this.settings.config.snapshot_dir}ubindvfs`, cmds)
        utils_2.default.writeXs(`${this.settings.work_dir.ovarium}ubindvfs`, cmds);
    }
    /**
     *
     * @param verbose
     */
    async cleanUsersAccounts() {
        if (this.verbose) {
            console.log('Ovary: cleanUsersAccounts');
        }
        /**
         * delete all user in chroot
         */
        const cmds = [];
        const cmd = `chroot ${this.settings.work_dir.merged} getent passwd {1000..60000} |awk -F: '{print $1}'`;
        const result = await (0, utils_1.exec)(cmd, {
            echo: this.verbose,
            ignore: false,
            capture: true,
        });
        const users = result.data.split('\n');
        for (let i = 0; i < users.length - 1; i++) {
            // cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} deluser ${users[i]}`, verbose))
            cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} userdel ${users[i]}`, this.verbose));
        }
    }
    /**
     * list degli utenti: grep -E 1[0-9]{3}  /etc/passwd | sed s/:/\ / | awk '{print $1}'
     * create la home per user_opt
     * @param verbose
     */
    async createUserLive() {
        if (this.verbose) {
            console.log('Ovary: createUserLive');
        }
        const cmds = [];
        cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' rm /home/' + this.settings.config.user_opt + ' -rf', this.verbose));
        cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' mkdir /home/' + this.settings.config.user_opt, this.verbose));
        cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' useradd ' + this.settings.config.user_opt + ' --home-dir /home/' + this.settings.config.user_opt + ' --shell /bin/bash ', this.verbose));
        cmds.push(await rexec('chroot  ' + this.settings.work_dir.merged + ' cp /etc/skel/. /home/' + this.settings.config.user_opt + ' -R', this.verbose));
        // da problemi con il mount sshfs
        cmds.push(await rexec('chroot  ' + this.settings.work_dir.merged + ' chown ' + this.settings.config.user_opt + ':users' + ' /home/' + this.settings.config.user_opt + ' -R', this.verbose));
        // live password
        cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' echo ' + this.settings.config.user_opt + ':' + this.settings.config.user_opt_passwd + '| chroot ' + this.settings.work_dir.merged + ' chpasswd', this.verbose));
        // root password
        cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' echo root:' + this.settings.config.root_passwd + '| chroot ' + this.settings.work_dir.merged + ' chpasswd', this.verbose));
        if (this.familyId === 'debian') {
            cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG sudo ${this.settings.config.user_opt}`, this.verbose));
        }
        else if (this.familyId === 'archlinux') {
            cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} gpasswd -a ${this.settings.config.user_opt} wheel`, this.verbose));
            // check or create group: autologin
            cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} getent group autologin || chroot ${this.settings.work_dir.merged} groupadd autologin`, this.verbose));
            cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} gpasswd -a ${this.settings.config.user_opt} autologin`, this.verbose));
        }
        /**
         * educaandos and others themes
         * users.yml
         */
        let usersConf = node_path_1.default.resolve(__dirname, `../../addons/${this.theme}/theme/calamares/users.yml`);
        if (this.theme.includes('/')) {
            usersConf = `${this.theme}/theme/calamares/modules/users.yml`;
        }
        if (fs_1.default.existsSync(usersConf)) {
            const o = js_yaml_1.default.load(fs_1.default.readFileSync(usersConf, 'utf-8'));
            for (const group of o.defaultGroups) {
                cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG ${group} ${this.settings.config.user_opt}`, this.verbose));
            }
        }
    }
    /**
     *
     */
    async createXdgAutostart(theme = 'eggs', myAddons, noicons = false) {
        if (this.verbose) {
            console.log('Ovary: createXdgAutostart');
        }
        const pathHomeLive = `/home/${this.settings.config.user_opt}`;
        if (noicons) { // NO icone
            shelljs_1.default.rm(`${this.settings.work_dir.merged}/etc/xdg/autostart/penguins-links-add.desktop`);
        }
        else { // VOGLIO le icone
            // Copia icona penguins-eggs
            shelljs_1.default.cp(node_path_1.default.resolve(__dirname, '../../assets/eggs.png'), '/usr/share/icons/');
            shelljs_1.default.cp(node_path_1.default.resolve(__dirname, '../../assets/krill.svg'), '/usr/share/icons/');
            shelljs_1.default.cp(node_path_1.default.resolve(__dirname, '../../assets/leaves.svg'), '/usr/share/icons/');
            /**
             * creazione dei link in /usr/share/applications
             */
            shelljs_1.default.cp(node_path_1.default.resolve(__dirname, '../../assets/penguins-eggs.desktop'), '/usr/share/applications/');
            /**
             * Scrivania/install-system.desktop
             */
            let installerUrl = 'install-system.desktop';
            let installerIcon = 'install-system.sh';
            if (pacman_1.default.calamaresExists()) {
                shelljs_1.default.cp(node_path_1.default.resolve(__dirname, `../../addons/${theme}/theme/applications/install-system.desktop`), `${this.settings.work_dir.merged}/usr/share/applications/`);
            }
            else if (pacman_1.default.packageIsInstalled('live-installer')) {
                // carico la policy per live-installer
                const policySource = node_path_1.default.resolve(__dirname, '../../assets/live-installer/com.github.pieroproietti.penguins-eggs.policy');
                const policyDest = '/usr/share/polkit-1/actions/com.github.pieroproietti.penguins-eggs.policy';
                shelljs_1.default.cp(policySource, policyDest);
                await (0, utils_1.exec)(`sed -i 's/auth_admin/yes/' ${policyDest}`);
                // carico in filesystem.live packages-remove
                shelljs_1.default.cp(node_path_1.default.resolve(__dirname, '../../assets/live-installer/filesystem.packages-remove'), `${this.settings.iso_work}/live/`);
                shelljs_1.default.touch(`${this.settings.iso_work}/live/filesystem.packages`);
                installerUrl = 'penguins-live-installer.desktop';
                installerIcon = 'utilities-terminal';
                shelljs_1.default.cp(node_path_1.default.resolve(__dirname, '../../assets/penguins-live-installer.desktop'), `${this.settings.work_dir.merged}/usr/share/applications/`);
            }
            else {
                installerUrl = 'penguins-krill.desktop';
                installerIcon = 'utilities-terminal';
                shelljs_1.default.cp(node_path_1.default.resolve(__dirname, '../../assets/penguins-krill.desktop'), `${this.settings.work_dir.merged}/usr/share/applications/`);
            }
            /**
             * flags
             */
            // adapt
            if (myAddons.adapt) {
                const dirAddon = node_path_1.default.resolve(__dirname, '../../addons/eggs/adapt/');
                shelljs_1.default.cp(`${dirAddon}/applications/eggs-adapt.desktop`, `${this.settings.work_dir.merged}/usr/share/applications/`);
                shelljs_1.default.cp(`${dirAddon}/bin/adapt`, `${this.settings.work_dir.merged}/usr/bin/`);
                shelljs_1.default.chmod('+x', `${this.settings.work_dir.merged}/usr/bin/adapt`);
            }
            // ichoice
            if (myAddons.ichoice) {
                installerUrl = 'eggs-ichoice.desktop';
                installerIcon = 'system-software-install';
                const dirAddon = node_path_1.default.resolve(__dirname, '../../addons/eggs/ichoice/');
                shelljs_1.default.cp(`${dirAddon}/applications/eggs-ichoice.desktop`, `${this.settings.work_dir.merged}/usr/share/applications/`);
                shelljs_1.default.cp(`${dirAddon}/bin/eggs-ichoice.sh`, `${this.settings.work_dir.merged}/usr/bin/`);
                shelljs_1.default.chmod('+x', `${this.settings.work_dir.merged}/usr/bin/eggs-ichoice.sh`);
            }
            // pve
            if (myAddons.pve) {
                /**
                 * create service pve-live
                 */
                const pve = new pve_live_1.default();
                pve.create(this.settings.work_dir.merged);
                /**
                 * adding a desktop link for pve
                 */
                const dirAddon = node_path_1.default.resolve(__dirname, '../../addons/eggs/pve');
                shelljs_1.default.cp(`${dirAddon}/artwork/eggs-pve.png`, `${this.settings.work_dir.merged}/usr/share/icons/`);
                shelljs_1.default.cp(`${dirAddon}/applications/eggs-pve.desktop`, `${this.settings.work_dir.merged}/usr/share/applications/`);
            }
            // rsupport
            if (myAddons.rsupport) {
                const dirAddon = node_path_1.default.resolve(__dirname, '../../addons/eggs/rsupport');
                shelljs_1.default.cp(`${dirAddon}/applications/eggs-rsupport.desktop`, `${this.settings.work_dir.merged}/usr/share/applications/`);
                shelljs_1.default.cp(`${dirAddon}/artwork/eggs-rsupport.png`, `${this.settings.work_dir.merged}/usr/share/icons/`);
            }
            /**
             * configuro add-penguins-desktop-icons in /etc/xdg/autostart
             */
            const dirAutostart = `${this.settings.work_dir.merged}/etc/xdg/autostart`;
            if (fs_1.default.existsSync(dirAutostart)) {
                // Creo l'avviatore xdg: DEVE essere add-penguins-links.desktop
                shelljs_1.default.cp(node_path_1.default.resolve(__dirname, '../../assets/penguins-links-add.desktop'), dirAutostart);
                // create /usr/bin/penguins-links-add.sh
                const script = '/usr/bin/penguins-links-add.sh';
                let text = '';
                text += '#!/bin/sh\n';
                text += 'DESKTOP=$(xdg-user-dir DESKTOP)\n';
                text += 'test -d "$DESKTOP" && mkdir -p "$DESKTOP"\n';
                text += `cp /usr/share/applications/${installerUrl} "$DESKTOP"\n`;
                if (pacman_1.default.packageIsInstalled('lxde-core')) {
                    text += this.lxdeLink('penguins-eggs.desktop', "Penguins' eggs", 'eggs');
                    if (myAddons.adapt)
                        text += this.lxdeLink('eggs-adapt.desktop', 'Adapt', 'video-display');
                    if (myAddons.pve)
                        text += this.lxdeLink('eggs-pve.desktop', 'Proxmox VE', 'proxmox-ve');
                    if (myAddons.rsupport)
                        text += this.lxdeLink('eggs-rsupport.desktop', 'Remote assistance', 'remote-assistance');
                }
                else {
                    text += 'cp /usr/share/applications/penguins-eggs.desktop "$DESKTOP"\n';
                    if (myAddons.adapt)
                        text += 'cp /usr/share/applications/eggs-adapt.desktop "$DESKTOP"\n';
                    if (myAddons.pve)
                        text += 'cp /usr/share/applications/eggs-pve.desktop "$DESKTOP"\n';
                    if (myAddons.rsupport)
                        text += 'cp /usr/share/applications/eggs-rsupport.desktop "$DESKTOP"\n';
                }
                /**
                 * enable desktop links
                 */
                if (pacman_1.default.packageIsInstalled('gdm3') || pacman_1.default.packageIsInstalled('gdm')) {
                    // GNOME
                    text += 'test -f /usr/share/applications/penguins-eggs.desktop && cp /usr/share/applications/penguins-eggs.desktop "$DESKTOP"\n';
                    text += 'test -f "$DESKTOP"/op && chmod a+x "$DESKTOP"/penguins-eggs.desktop\n';
                    text += 'test -f "$DESKTOP"/penguins-eggs.desktop && gio set "$DESKTOP"/penguins-eggs.desktop metadata::trusted true\n';
                    text += `test -f /usr/share/applications/${installerUrl} && cp /usr/share/applications/${installerUrl} "$DESKTOP"\n`;
                    text += `test -f "$DESKTOP"/${installerUrl} && chmod a+x "$DESKTOP"/${installerUrl}\n`;
                    text += `test -f "$DESKTOP"/${installerUrl} && gio set "$DESKTOP"/${installerUrl} metadata::trusted true\n`;
                }
                else if (pacman_1.default.packageIsInstalled('xfce4-session')) {
                    // f=FILE; gio set -t string $f metadata::xfce-exe-checksum "$(sha256sum $f | awk '{print $1}')"
                    text += 'chmod +x "$DESKTOP"/*.desktop';
                    // await exec(`f="$DESKTOP"/*.desktop; gio set -t string $f metadata::xfce-exe-checksum "$(sha256sum $f | awk '{print $1}')"`)
                }
                else {
                    // OTHERS: CINNAMON/KDE/ETC
                    text += 'chmod +x "$DESKTOP"/*.desktop';
                }
                fs_1.default.writeFileSync(script, text, 'utf8');
                await (0, utils_1.exec)(`chmod a+x ${script}`, this.echo);
            }
        } // END se VOGLIO le icone
        await xdg_1.default.autologin(await utils_2.default.getPrimaryUser(), this.settings.config.user_opt, this.settings.work_dir.merged);
    }
    /**
     * Creazione link desktop per lxde
     * @param name
     * @param icon
     */
    lxdeLink(file, name, icon) {
        if (this.verbose) {
            console.log('Ovary: lxdeLink');
        }
        const lnk = `lnk-${file}`;
        let text = '';
        text += `echo "[Desktop Entry]" >$DESKTOP/${lnk}\n`;
        text += `echo "Type=Link" >> $DESKTOP/${lnk}\n`;
        text += `echo "Name=${name}" >> $DESKTOP/${lnk}\n`;
        text += `echo "Icon=${icon}" >> $DESKTOP/${lnk}\n`;
        text += `echo "URL=/usr/share/applications/${file}" >> $DESKTOP/${lnk}\n\n`;
        return text;
    }
    /**
     * Add or remove exclusion
     * @param add {boolean} true = add, false remove
     * @param exclusion {atring} path to add/remove
     */
    addRemoveExclusion(add, exclusion) {
        if (this.verbose) {
            console.log('Ovary: addRemoveExclusion');
        }
        if (exclusion.startsWith('/')) {
            exclusion = exclusion.slice(1); // remove / initial Non compatible with rsync
        }
        if (add) {
            this.settings.session_excludes += this.settings.session_excludes === '' ? `-e '${exclusion}' ` : ` '${exclusion}' `;
        }
        else {
            this.settings.session_excludes.replace(` '${exclusion}'`, '');
            if (this.settings.session_excludes === '-e') {
                this.settings.session_excludes = '';
            }
        }
    }
    // #######################################################################################
    /**
     * makeEfi
    */
    // #######################################################################################
    async makeEfi(theme = 'eggs') {
        if (this.verbose) {
            console.log('Ovary: makeEfi');
        }
        const memdiskDir = this.settings.config.snapshot_mnt + 'memdiskDir';
        const efiWorkDir = this.settings.efi_work;
        const isoDir = this.settings.iso_work;
        /**
         * il pachetto grub/grub2 DEVE essere presente
         */
        const grubName = pacman_1.default.whichGrubIsInstalled();
        if (grubName === '') {
            utils_2.default.error('Something went wrong! Cannot find grub! Run lsb_release -a and check the result');
            process.exit(1);
        }
        /**
         * Creo o cancello e creo: memdiskDir
         */
        if (fs_1.default.existsSync(memdiskDir)) {
            await (0, utils_1.exec)(`rm ${memdiskDir} -rf`, this.echo);
        }
        utils_2.default.warning('creating temporary memdiskDir on ' + memdiskDir);
        await (0, utils_1.exec)(`mkdir ${memdiskDir}`);
        await (0, utils_1.exec)(`mkdir ${memdiskDir}/boot`, this.echo);
        await (0, utils_1.exec)(`mkdir ${memdiskDir}/boot/grub`, this.echo);
        /**
         * for initial grub.cfg in memdisk
         */
        const grubCfg = `${memdiskDir}/boot/grub/grub.cfg`;
        let text = '';
        text += 'search --file --set=root /.disk/info\n';
        text += 'set prefix=($root)/boot/grub\n';
        text += `source $prefix/${utils_2.default.uefiFormat()}/grub.cfg\n`;
        utils_2.default.write(grubCfg, text);
        // #################################
        /**
         * start with empty efiWorkDir
         */
        if (fs_1.default.existsSync(efiWorkDir)) {
            await (0, utils_1.exec)(`rm ${efiWorkDir} -rf`, this.echo);
        }
        utils_2.default.warning('creating temporary efiWordDir on ' + efiWorkDir);
        await (0, utils_1.exec)(`mkdir ${efiWorkDir}`, this.echo);
        await (0, utils_1.exec)(`mkdir ${efiWorkDir}boot`, this.echo);
        await (0, utils_1.exec)(`mkdir ${efiWorkDir}boot/grub`, this.echo);
        await (0, utils_1.exec)(`mkdir ${efiWorkDir}boot/grub/${utils_2.default.uefiFormat()}`, this.echo);
        await (0, utils_1.exec)(`mkdir ${efiWorkDir}efi`, this.echo);
        await (0, utils_1.exec)(`mkdir ${efiWorkDir}efi/boot`, this.echo);
        /**
        * copy splash to efiWorkDir
        */
        const splashDest = `${efiWorkDir}boot/grub/splash.png`;
        let splashSrc = node_path_1.default.resolve(__dirname, `../../addons/${theme}/theme/livecd/splash.png`);
        if (this.theme.includes('/')) {
            splashSrc = `${theme}/theme/livecd/splash.png`;
        }
        if (!fs_1.default.existsSync(splashSrc)) {
            utils_2.default.warning('Cannot find: ' + splashSrc);
            process.exit();
        }
        await (0, utils_1.exec)(`cp ${splashSrc} ${splashDest}`, this.echo);
        /**
         * copy theme
         */
        const themeDest = `${efiWorkDir}boot/grub/theme.cfg`;
        let themeSrc = node_path_1.default.resolve(__dirname, `../../addons/${theme}/theme/livecd/grub.theme.cfg`);
        if (this.theme.includes('/')) {
            themeSrc = `${theme}/theme/livecd/grub.theme.cfg`;
        }
        if (!fs_1.default.existsSync(themeSrc)) {
            utils_2.default.warning('Cannot find: ' + themeSrc);
            process.exit();
        }
        await (0, utils_1.exec)(`cp ${themeSrc} ${themeDest}`, this.echo);
        /**
         * second grub.cfg file in efiWork
         */
        //         for i in $(ls /usr/lib/grub/x86_64-efi            |grep part_|grep \.mod|sed 's/.mod//'); do echo "insmod $i" >>              boot/grub/x86_64-efi/grub.cfg; done
        let cmd = `for i in $(ls /usr/lib/grub/${utils_2.default.uefiFormat()}|grep part_|grep \.mod|sed 's/.mod//'); do echo "insmod $i" >> ${efiWorkDir}boot/grub/${utils_2.default.uefiFormat()}/grub.cfg; done`;
        await (0, utils_1.exec)(cmd, this.echo);
        //cmd = `for i in efi_gop efi_uga ieee1275_fb vbe vga video_bochs video_cirrus jpeg png gfxterm ; do echo "insmod $i" >> ${efiWorkDir}boot/grub/${Utils.uefiFormat()}/grub.cfg ; done`
        cmd = `for i in efi_gop efi_uga ieee1275_fb vbe vga video_bochs video_cirrus jpeg png gfxterm ; do echo "insmod $i" >> ${efiWorkDir}boot/grub/${utils_2.default.uefiFormat()}/grub.cfg ; done`;
        await (0, utils_1.exec)(cmd, this.echo);
        await (0, utils_1.exec)(`echo "source /boot/grub/grub.cfg" >> ${efiWorkDir}boot/grub/${utils_2.default.uefiFormat()}/grub.cfg`, this.echo);
        /**
         * andiamo in memdiskDir
         */
        /**
         * make a tarred "memdisk" to embed in the grub image
         *
         * NOTE: it's CRUCIAL to chdir before tar!!!
         */
        const currentDir = process.cwd();
        process.chdir(memdiskDir);
        await (0, utils_1.exec)('tar -cvf memdisk boot', this.echo);
        process.chdir(currentDir);
        // -O, --format=FORMAT
        // -m --memdisk=FILE embed FILE as a memdisk image
        // -o, --output=FILE embed FILE as a memdisk image
        // -p, --prefix=DIR set prefix directory
        //                               --format=x86_64-efi         --memdisk=memdisk          --output=bootx64.efi           --prefix?DIR set prefix directory
        //          grub-mkimage         -O "x86_64-efi"             -m "memdisk"               -o "bootx64.efi"               -p '(memdisk)/boot/grub' search iso9660 configfile normal memdisk tar cat part_msdos part_gpt fat ext2 ntfs ntfscomp hfsplus chain boot linux
        //                                   arm64-efi 
        await (0, utils_1.exec)(`${grubName}-mkimage  -O "${utils_2.default.uefiFormat()}" \
                -m "${memdiskDir}/memdisk" \
                -o "${memdiskDir}/${utils_2.default.uefiBN()}" \
                -p '(memdisk)/boot/grub' \
                search iso9660 configfile normal memdisk tar cat part_msdos part_gpt fat ext2 ntfs ntfscomp hfsplus chain boot linux`, this.echo);
        // popd torna in efiWorkDir
        // copy the grub image to efi/boot (to go later in the device's root)
        await (0, utils_1.exec)(`cp ${memdiskDir}/${utils_2.default.uefiBN()} ${efiWorkDir}efi/boot`, this.echo);
        // #######################
        // Do the boot image "boot/grub/efiboot.img"
        await (0, utils_1.exec)(`dd if=/dev/zero of=${efiWorkDir}boot/grub/efiboot.img bs=1K count=1440`, this.echo);
        await (0, utils_1.exec)(`/sbin/mkdosfs -F 12 ${efiWorkDir}boot/grub/efiboot.img`, this.echo);
        await (0, utils_1.exec)(`mkdir ${efiWorkDir}img-mnt`, this.echo);
        await (0, utils_1.exec)(`mount -o loop ${efiWorkDir}boot/grub/efiboot.img ${efiWorkDir}img-mnt`, this.echo);
        await (0, utils_1.exec)(`mkdir ${efiWorkDir}img-mnt/efi`, this.echo);
        await (0, utils_1.exec)(`mkdir ${efiWorkDir}img-mnt/efi/boot`, this.echo);
        // era cp -r
        await (0, utils_1.exec)(`cp ${memdiskDir}/${utils_2.default.uefiBN()} ${efiWorkDir}img-mnt/efi/boot`, this.echo);
        // #######################
        // copy modules and font
        await (0, utils_1.exec)(`cp -r /usr/lib/grub/${utils_2.default.uefiFormat()}/* ${efiWorkDir}boot/grub/${utils_2.default.uefiFormat()}/`, this.echo);
        // if this doesn't work try another font from the same place (grub's default, unicode.pf2, is much larger)
        // Either of these will work, and they look the same to me. Unicode seems to work with qemu. -fsr
        if (fs_1.default.existsSync('/usr/share/grub/font.pf2')) {
            await (0, utils_1.exec)(`cp /usr/share/grub/font.pf2 ${efiWorkDir}boot/grub/font.pf2`, this.echo);
        }
        else if (fs_1.default.existsSync('/usr/share/grub/unicode.pf2')) {
            await (0, utils_1.exec)(`cp /usr/share/grub/unicode.pf2 ${efiWorkDir}boot/grub/font.pf2`, this.echo);
        }
        else if (fs_1.default.existsSync('/usr/share/grub/ascii.pf2')) {
            await (0, utils_1.exec)(`cp /usr/share/grub/ascii.pf2 ${efiWorkDir}boot/grub/font.pf2`, this.echo);
        }
        // doesn't need to be root-owned
        // chown -R 1000:1000 $(pwd) 2>/dev/null
        // Cleanup efi temps
        await (0, utils_1.exec)(`umount ${efiWorkDir}img-mnt`, this.echo);
        await (0, utils_1.exec)(`rmdir ${efiWorkDir}img-mnt`, this.echo);
        await (0, utils_1.exec)(`rm ${memdiskDir}/img-mnt -rf`, this.echo);
        //  popd
        // Copy efi files to iso
        await (0, utils_1.exec)(`rsync -avx  ${efiWorkDir}boot ${isoDir}/`, this.echo);
        await (0, utils_1.exec)(`rsync -avx ${efiWorkDir}efi  ${isoDir}/`, this.echo);
        // Do the main grub.cfg (which gets loaded last):
        // grub.theme.cfg
        let grubThemeSrc = node_path_1.default.resolve(__dirname, `../../addons/${theme}/theme/livecd/grub.theme.cfg`);
        if (this.theme.includes('/')) {
            grubThemeSrc = `${theme}/theme/livecd/grub.theme.cfg`;
        }
        const grubThemeDest = `${isoDir}/boot/grub/theme.cfg`;
        if (!fs_1.default.existsSync(grubThemeSrc)) {
            utils_2.default.warning('Cannot find: ' + grubThemeSrc);
            process.exit();
        }
        fs_1.default.copyFileSync(grubThemeSrc, grubThemeDest);
        /**
        * prepare grub.cfg from grub.main.cfg
        */
        let grubTemplate = `${theme}/theme/livecd/grub.main.cfg`;
        if (!fs_1.default.existsSync(grubTemplate)) {
            // grubTemplate = path.resolve(__dirname, '../../addons/templates/grub.main.cfg')
            grubTemplate = node_path_1.default.resolve(__dirname, '../../addons/eggs/theme/livecd/grub.main.cfg');
        }
        if (!fs_1.default.existsSync(grubTemplate)) {
            utils_2.default.warning('Cannot find: ' + grubTemplate);
            process.exit();
        }
        const kernel_parameters = this.kernelParameters();
        const grubDest = `${isoDir}/boot/grub/grub.cfg`;
        const template = fs_1.default.readFileSync(grubTemplate, 'utf8');
        const view = {
            fullname: this.settings.remix.fullname.toUpperCase(),
            kernel: utils_2.default.kernelVersion(),
            vmlinuz: `/live${this.settings.vmlinuz}`,
            initrdImg: `/live${this.settings.initrdImg}`,
            kernel_parameters: kernel_parameters,
        };
        fs_1.default.writeFileSync(grubDest, mustache_1.default.render(template, view));
        /**
        * loopback.cfg
        */
        fs_1.default.writeFileSync(`${isoDir}/boot/grub/loopback.cfg`, 'source /boot/grub/grub.cfg\n');
        // console.log('end makeEfi')
        // process.exit()
    }
    // #######################################################################################
    /**
     * makeDotDisk
     */
    makeDotDisk(info = '', mksquashfs = '', mkisofs = '') {
        if (this.verbose) {
            console.log('Ovary: makeDotDisk');
        }
        const dotDisk = this.settings.iso_work + '.disk';
        if (fs_1.default.existsSync(dotDisk)) {
            shelljs_1.default.rm('-rf', dotDisk);
        }
        shelljs_1.default.mkdir('-p', dotDisk);
        let text = `# Created at: ${utils_2.default.formatDate(new Date())}\n`;
        text += `# penguins_eggs v. ${utils_2.default.getPackageVersion()}\n`;
        // .disk/info
        fs_1.default.writeFileSync(dotDisk + '/info', text, 'utf-8');
        // .disk/mksquashfs
        fs_1.default.writeFileSync(dotDisk + '/mksquashfs', text + mksquashfs, 'utf-8');
        // .disk/mkisofs
        fs_1.default.writeFileSync(dotDisk + '/mkisofs', text + mkisofs, 'utf-8');
    }
    /**
     *
     * @param cryptedclone
     * @returns cmd 4 mkiso
     */
    xorrisoCommand(clone = false, cryptedclone = false) {
        if (this.verbose) {
            console.log('Ovary: xorrisoCommand');
        }
        const volid = utils_2.default.getVolid(this.settings.remix.name);
        let prefix = this.settings.config.snapshot_prefix;
        let typology = '';
        // typology is applied only with standard egg-of
        if (prefix.slice(0, 7) === 'egg-of_') {
            if (clone) {
                typology = '_clone';
            }
            else if (cryptedclone) {
                typology = '_crypted';
            }
            if (fs_1.default.existsSync('/usr/bin/eui-start.sh')) {
                typology += "_EUI";
            }
        }
        const postfix = utils_2.default.getPostfix();
        this.settings.isoFilename = prefix + volid + '_' + utils_2.default.uefiArch() + typology + postfix;
        // 
        const output = this.settings.config.snapshot_mnt + this.settings.isoFilename;
        let command = '';
        // const appid = `-appid "${this.settings.distro.distroId}" `
        // const publisher = `-publisher "${this.settings.distro.distroId}/${this.settings.distro.codenameId}" `
        // const preparer = '-preparer "prepared by eggs <https://penguins-eggs.net>" '
        let isoHybridMbr = '';
        if (this.settings.config.make_isohybrid) {
            const isolinuxFile = this.settings.distro.isolinuxPath + 'isohdpfx.bin';
            if (fs_1.default.existsSync(isolinuxFile)) {
                isoHybridMbr = `-isohybrid-mbr ${isolinuxFile}`;
            }
            else {
                utils_2.default.warning(`Can't create isohybrid image. File: ${isolinuxFile} not found. \nThe resulting image will be a standard iso file`);
            }
        }
        // uefi_opt="-uefi_elToritoAltBoot-alt-boot -e boot/grub/efiboot.img -isohybrid-gpt-basdat -no-emul-boot"
        let uefi_elToritoAltBoot = '';
        let uefi_e = '';
        let uefi_isohybridGptBasdat = '';
        let uefi_noEmulBoot = '';
        if (this.settings.config.make_efi) {
            uefi_elToritoAltBoot = '-eltorito-alt-boot';
            uefi_e = '-e boot/grub/efiboot.img';
            uefi_isohybridGptBasdat = '-isohybrid-gpt-basdat';
            uefi_noEmulBoot = '-no-emul-boot';
        }
        /**
          * info Debian GNU/Linux 10.8.0 "Buster" - Official i386 NETINST 20210206-10:54
          * mkisofs xorriso -as mkisofs
          * -r
          * -checksum_algorithm_iso md5,sha1,sha256,sha512
          * -V 'Debian 10.8.0 i386 n'
          * -o /srv/cdbuilder.debian.org/dst/deb-cd/out/2busteri386/debian-10.8.0-i386-NETINST-1.iso
          *       -jigdo-jigdo /srv/cdbuilder.debian.org/dst/deb-cd/out/2busteri386/debian-10.8.0-i386-NETINST-1.jigdo
          *       -jigdo-template /srv/cdbuilder.debian.org/dst/deb-cd/out/2busteri386/debian-10.8.0-i386-NETINST-1.template
          *       -jigdo-map Debian=/srv/cdbuilder.debian.org/src/ftp/debian/
          *       -jigdo-exclude boot1
          *       -md5-list /srv/cdbuilder.debian.org/src/deb-cd/tmp/2busteri386/buster/md5-check
          *       -jigdo-min-file-size 1024
          *       -jigdo-exclude 'README*'
          *       -jigdo-exclude /doc/
          *       -jigdo-exclude /md5sum.txt
          *       -jigdo-exclude /.disk/
          *       -jigdo-exclude /pics/
          *       -jigdo-exclude 'Release*'
          *       -jigdo-exclude 'Packages*'
          *       -jigdo-exclude 'Sources*'
          * -J
          * -joliet-long
          * -cache-inodes
          * -isohybrid-mbr syslinux/usr/lib/ISOLINUX/isohdpfx.bin
          * -b isolinux/isolinux.bin
          * -c isolinux/boot.cat
          * -boot-load-size 4
          * -boot-info-table
          * -no-emul-boot
          * -uefi_elToritoAltBoot-alt-boot
          * -e boot/grub/efi.img
          * -no-emul-boot
          * -isohybrid-gpt-basdat
          *         isohybrid-apm-hfsplus
          * boot1 CD1
       
        command = `xorriso -as mkisofs \
         -r \
         -checksum_algorithm_iso md5,sha1,sha256,sha512 \
         -V ${volid} \
         -o ${output} \
         -J \
         -joliet-long \
         -cache-inodes  \
         ${isoHybridMbr} \
         -b isolinux/isolinux.bin \
         -c isolinux/boot.cat \
         -boot-load-size 4 \
         -boot-info-table \
         -no-emul-boot \
         ${uefi_eltoritoAltBoot} \
         ${uefi_e} \
         ${uefi_noEmulBoot} \
         ${uefi_isohybridGptBasdat}
         ${this.settings.iso_work}`
        */
        /**
         * how is made in refracta
         *
         * -isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin
         * uefi_opt="-eltorito-alt-boot -e boot/grub/efiboot.img -isohybrid-gpt-basdat -no-emul-boot"
         *
         * xorriso -as mkisofs -r \
         * -J \
         * -joliet-long \
         * -l \
         * -iso-level 3 \
         * ${isohybrid_opt} \
         * -partition_offset 16 \
         * -V "$volid" \
         * -b isolinux/isolinux.bin \
         * -c isolinux/boot.cat \
         * -no-emul-boot \
         * -boot-load-size 4 \
         * -boot-info-table \
         * ${uefi_opt} \
         * -o "$snapshot_dir"/"$filename" iso/
         */
        command = `xorriso -as mkisofs \
     -J \
     -joliet-long \
     -l \
     -iso-level 3 \
     ${isoHybridMbr} \
     -partition_offset 16 \
     -V ${volid} \
     -b isolinux/isolinux.bin \
     -c isolinux/boot.cat \
     -no-emul-boot \
     -boot-load-size 4 \
     -boot-info-table \
     ${uefi_elToritoAltBoot} \
     ${uefi_e} \
     ${uefi_isohybridGptBasdat} \
     ${uefi_noEmulBoot} \
     -o ${output} ${this.settings.iso_work}`;
        return command;
    }
    /**
     * makeIso
     * cmd: cmd 4 xorirriso
     */
    async makeIso(cmd, scriptOnly = false) {
        // echo = { echo: true, ignore: false }
        if (this.verbose) {
            console.log('Ovary: makeIso');
        }
        utils_2.default.writeX(`${this.settings.work_dir.ovarium}mkisofs`, cmd);
        if (!scriptOnly) {
            const test = (await (0, utils_1.exec)(cmd, utils_2.default.setEcho(true))).code;
            if (test !== 0) {
                process.exit();
            }
            // Create link to iso
            const src = this.settings.config.snapshot_mnt + this.settings.isoFilename;
            const dest = this.settings.config.snapshot_dir + this.settings.isoFilename;
            await (0, utils_1.exec)(`ln -s ${src} ${dest}`);
            // Create md5sum, sha256sum
            if (this.settings.config.make_md5sum) {
                utils_2.default.warning('creating md5, sha256');
                await (0, utils_1.exec)(`md5sum ${src} > ${dest.replace('.iso', '.md5')}`);
                await (0, utils_1.exec)(`sha256sum ${src} > ${dest.replace('.iso', '.sha256')}`);
            }
        }
    }
    /**
     * finished = show the results
     * @param scriptOnly
     */
    finished(scriptOnly = false) {
        utils_2.default.titles('produce');
        if (!scriptOnly) {
            console.log('eggs is finished!\n\nYou can find the file iso: ' + chalk_1.default.cyanBright(this.settings.isoFilename) + '\nin the nest: ' + chalk_1.default.cyanBright(this.settings.config.snapshot_dir) + '.');
        }
        else {
            console.log('eggs is finished!\n\nYou can find the scripts to build iso: ' + chalk_1.default.cyanBright(this.settings.isoFilename) + '\nin the ovarium: ' + chalk_1.default.cyanBright(this.settings.config.snapshot_dir) + '.');
            console.log('usage');
            console.log(chalk_1.default.cyanBright(`cd ${this.settings.config.snapshot_dir}`));
            console.log(chalk_1.default.cyanBright('sudo ./bind'));
            console.log('Make all yours modifications in the directories filesystem.squashfs and iso.');
            console.log('After when you are ready:');
            console.log(chalk_1.default.cyanBright('sudo ./mksquashfs'));
            console.log(chalk_1.default.cyanBright('sudo ./mkisofs'));
            console.log(chalk_1.default.cyanBright('sudo ./ubind'));
            console.log('happy hacking!');
        }
        console.log();
        console.log('Remember, on liveCD user = ' + chalk_1.default.cyanBright(this.settings.config.user_opt) + '/' + chalk_1.default.cyanBright(this.settings.config.user_opt_passwd));
        console.log('                    root = ' + chalk_1.default.cyanBright('root') + '/' + chalk_1.default.cyanBright(this.settings.config.root_passwd));
    }
    /**
    * fill
    */
    async usersFill() {
        if (this.verbose) {
            console.log('Ovary: usersFill');
        }
        const usersArray = [];
        await (0, promises_1.access)('/etc/passwd', fs_2.constants.R_OK | fs_2.constants.W_OK);
        const passwd = fs_1.default.readFileSync('/etc/passwd', 'utf-8').split('\n');
        for (const element of passwd) {
            const line = element.split(':');
            const users = new users_1.default(line[0], line[1], line[2], line[3], line[4], line[5], line[6]);
            await users.getValues();
            if (users.password !== undefined) {
                usersArray.push(users);
            }
        }
        return usersArray;
    }
}
exports.default = Ovary;
/**
 * FUNCTIONS
 */
/**
 * Crea il path se non esiste
 * @param path
 */
async function makeIfNotExist(path, verbose = false) {
    if (verbose) {
        console.log(`Ovary: makeIfNotExist(${path})`);
    }
    const echo = utils_2.default.setEcho(verbose);
    let cmd = `# ${path} alreasy exist`;
    if (!fs_1.default.existsSync(path)) {
        cmd = `mkdir ${path} -p`;
        await (0, utils_1.exec)(cmd, echo);
    }
    return cmd;
}
/**
 *
 * @param cmd
 * @param echo
 */
async function rexec(cmd, verbose = false) {
    if (verbose) {
        console.log(`Ovary: rexec(${cmd})`);
    }
    const echo = utils_2.default.setEcho(verbose);
    const check = await (0, utils_1.exec)(cmd, echo);
    if (!cmd.startsWith('umount')) { // skip umount errors
        if (check.code !== 0) {
            console.log(`eggs >>> error on command: ` + chalk_1.default.cyan(cmd) + ', code: ' + chalk_1.default.cyan(check.code));
        }
    }
    return cmd;
}
/**
 * ManjaroLinux Not isArchiso
 */
function isArchiso(distro) {
    let found = false;
    if (distro !== 'ManjaroLinux') {
        found = true;
    }
    return found;
}
