penguins-eggs
Version:
A remaster system tool, compatible with Almalinux, Alpine, Arch, Debian, Devuan, Fedora, Manjaro, Opensuse, Ubuntu and derivatives
209 lines (208 loc) • 10.4 kB
JavaScript
/**
* ./src/classes/ovary.d/bind-live-fs.ts
* penguins-eggs v.25.7.x / ecmascript 2020
* author: Piero Proietti
* email: piero.proietti@gmail.com
* license: MIT
*/
// packages
import fs from 'fs';
import path from 'node:path';
import os from 'os';
// classes
import { exec } from '../../lib/utils.js';
import Utils from '../utils.js';
// functions
import rexec from './rexec.js';
// _dirname
const __dirname = path.dirname(new URL(import.meta.url).pathname);
/**
* Esegue il bind del filesystem live e
* crea lo script bind
*/
export async function bindLiveFs() {
if (this.verbose) {
console.log('Ovary: bindLiveFs');
}
/**
* dirs = readdirsync /
*/
const dirs = fs.readdirSync('/');
const startLine = '#############################################################';
const endLine = '#\n';
let lnkDest = '';
const 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: ${os.hostname()} user: ${await Utils.getPrimaryUser()}\n`);
for (const dir of dirs) {
cmds.push(startLine);
const statDir = fs.lstatSync(`/${dir}`);
if (statDir.isSymbolicLink()) {
/**
* Link
*/
cmds.push(`# /${dir} is a symbolic link to /${lnkDest}`);
lnkDest = fs.readlinkSync(`/${dir}`);
if (fs.existsSync(`${this.settings.work_dir.merged}/${dir}`)) {
cmds.push('# SymbolicLink exist... skip');
}
else if (fs.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 if (statDir.isDirectory()) {
/**
* Directory
*/
cmds.push(`# /${dir} is a directory`);
if (dir !== 'ci' && dir !== 'lost+found') {
if (this.copied(dir)) {
cmds.push(`# /${dir} is copied if not exists on filesystem.squashfs`);
const chkDir = path.join(this.settings.work_dir.merged, dir);
cmds.push(`if ! [ -d "${chkDir}" ]; then`);
cmds.push(await rexec(` cp -a /${dir} ${this.settings.work_dir.merged}/`, this.verbose), `fi`);
continue;
}
else if (this.mergedAndOverlay(dir)) {
cmds.push(`# /${dir} mergedAndOverlay (rw)\n`, '# 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)) {
cmds.push(`# /${dir} merged (ro)`);
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 {
cmds.push(`# /${dir} just created`);
cmds.push(await makeIfNotExist(`${this.settings.work_dir.merged}/${dir}`, this.verbose));
}
}
/**
* File
*/
}
else if (statDir.isFile()) {
cmds.push(`# /${dir} is just a file`);
if (fs.existsSync(`${this.settings.work_dir.merged}/${dir}`)) {
cmds.push('# file exist... skip');
}
else {
cmds.push(await rexec(`cp -p /${dir} ${this.settings.work_dir.merged}`, this.verbose));
}
}
cmds.push(endLine);
}
// ==============================================================================
// FIX CRUCIALE USR MERGE (Eseguito LIVE via rexec)
// ==============================================================================
cmds.push(startLine, '# FORCE USR MERGE LAYOUT (Fix for Debian 12+ / RISC-V)', '# Ensures bin, sbin, lib, lib64 point to usr/... inside the merged dir');
const linkNames = ['bin', 'sbin', 'lib', 'lib64'];
const mergedDir = this.settings.work_dir.merged;
for (const link of linkNames) {
const linkPath = `${mergedDir}/${link}`;
// 1. Se esiste una directory fisica (errore rsync), la rimuoviamo subito
if (fs.existsSync(linkPath) && !fs.lstatSync(linkPath).isSymbolicLink() && fs.lstatSync(linkPath).isDirectory()) {
// Usiamo exec normale per la pulizia, o rexec se vuoi loggarlo
cmds.push(await rexec(`rm -rf ${linkPath}`, this.verbose));
}
// 2. Creiamo il link se non esiste (o se l'abbiamo appena rimosso)
if (!fs.existsSync(linkPath)) {
// Eseguiamo SUBITO il comando e lo salviamo nella lista cmds
cmds.push(await rexec(`ln -sf usr/${link} ${linkPath}`, this.verbose));
}
}
cmds.push(endLine);
// Utils.writeXs(`${this.settings.config.snapshot_dir}bind`, cmds)
Utils.writeXs(`${this.settings.work_dir.bin}bind`, cmds);
}
/**
* ubind del fs live
* @param verbose
*/
export async function uBindLiveFs() {
if (this.verbose) {
console.log('Ovary: uBindLiveFs');
}
const startLine = '#############################################################';
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: ${os.hostname()} user: ${await Utils.getPrimaryUser()}\n`);
if (fs.existsSync(this.settings.work_dir.merged)) {
const bindDirs = fs.readdirSync(this.settings.work_dir.merged, {
withFileTypes: true
});
for (const dir of bindDirs) {
const dirname = dir.name;
const hostPath = `/${dirname}`;
cmds.push(startLine);
// FIX: Se il file/dir non esiste sull'HOST (es. lib64 che abbiamo creato noi),
// lo rimuoviamo semplicemente dalla destinazione e passiamo al prossimo.
if (!fs.existsSync(hostPath)) {
cmds.push(`\n# ${dirname} does not exist on host (custom created) -> remove`);
cmds.push(await rexec(`rm -rf ${this.settings.work_dir.merged}/${dirname}`, this.verbose));
continue;
}
// Da qui in poi siamo sicuri che hostPath esiste, quindi fs.statSync non crasherÃ
if (fs.statSync(hostPath).isDirectory()) {
cmds.push(`\n# directory: ${dirname}`);
if (this.copied(dirname)) {
cmds.push(`\n# ${dirname} was copied, do nothings`);
continue;
}
else 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}`);
const nest = this.settings.config.snapshot_dir.split('/');
// We can't remove first level nest
if (dirname !== nest[1]) {
cmds.push(await rexec(`rm -rf ${this.settings.work_dir.merged}/${dirname}`, this.verbose));
}
}
else if (fs.statSync(hostPath).isFile()) {
cmds.push(`\n# ${dirname} = file`);
cmds.push(await rexec(`rm -f ${this.settings.work_dir.merged}/${dirname}`, this.verbose));
}
else if (fs.statSync(hostPath).isSymbolicLink()) {
cmds.push(`\n# ${dirname} = symbolicLink`);
cmds.push(await rexec(`rm -f ${this.settings.work_dir.merged}/${dirname}`, this.verbose));
}
}
}
if (this.clone || this.fullcrypt) {
cmds.push(await rexec(`umount ${this.settings.work_dir.merged}/home`, this.verbose));
}
Utils.writeXs(`${this.settings.work_dir.bin}ubind`, cmds);
}
/**
* Crea il path se non esiste
* @param path
*/
async function makeIfNotExist(path, verbose = false) {
if (verbose) {
console.log(`Ovary: makeIfNotExist(${path})`);
}
const echo = Utils.setEcho(verbose);
let cmd = `# ${path} alreasy exist`;
if (!fs.existsSync(path)) {
cmd = `mkdir ${path} -p`;
await exec(cmd, echo);
}
return cmd;
}