penguins-eggs
Version:
A remaster system tool, compatible with Almalinux, Alpine, Arch, Debian, Devuan, Fedora, Manjaro, Opensuse, Ubuntu and derivatives
143 lines (142 loc) • 6.78 kB
JavaScript
/**
* ./src/classes/ovary.d/luks-root.ts
* penguins-eggs v.25.10.x / ecmascript 2020
* author: Piero Proietti
* email: piero.proietti@gmail.com
* license: MIT
*/
// packages
import fs from 'fs';
import { exec } from '../../lib/utils.js';
import Utils from '../utils.js';
const noop = () => { };
/**
* luksRoot()
* create a container LUKS with the entire
* filesystem.squashfs
*/
export async function luksRoot() {
const loggers = {
info: this.hidden ? noop : Utils.info,
log: this.hidden ? noop : console.log,
success: this.hidden ? noop : Utils.success,
warning: this.hidden ? noop : Utils.warning
};
const { info, log, success, warning } = loggers;
// filesystem.squashfs
const live_fs = `${this.settings.iso_work}live/filesystem.squashfs`;
try {
/**
* this.luksMappedName = 'root.img';
* this.luksFile = `/var/tmp/${luksMappedName}`
* this.luksDevice = `/dev/mapper/${luksMappedName}`
* this.luksMountpoint = `/tmp/mnt/${luksMappedName}`
* this.luksPassword = '0'
*/
if (this.hidden) {
Utils.warning('intentionally blank. System is working, please wait');
}
log();
log('====================================');
log(` Creating ${this.luksMappedName}`);
log('====================================');
if (!fs.existsSync(live_fs)) {
throw new Error(`filesystem.squashfs not found at: ${live_fs}`);
}
const stats = fs.statSync(live_fs);
const { size } = stats; // Dimensione REALE del file in Byte
// -------------------------------------------------------------
// CALCOLO DIMENSIONE OTTIMIZZATA (No shrink, safe allocation)
// -------------------------------------------------------------
// 1. Overhead Ext4: Inode, bitmap, superblocchi. ~3-4% è standard senza journal.
const fsOverhead = Math.ceil(size * 0.04);
// 2. Header LUKS: Solitamente 16MB per LUKS2, usiamo 32MB per sicurezza.
const luksHeader = 32 * 1024 * 1024;
// 3. Margine di sicurezza (Buffer): 120MB fissi.
// Questo spazio evita errori di "Disk full" durante la copia dei metadati.
// Viene compensato dall'uso di "-m 0" nella formattazione.
const safetyBuffer = 120 * 1024 * 1024;
// 4. Somma totale
const calculatedSize = size + fsOverhead + luksHeader + safetyBuffer;
// 5. Allineamento a 4MB (Performance storage)
const alignment = 4 * 1024 * 1024;
const luksSize = Math.ceil(calculatedSize / alignment) * alignment;
warning(`------------------------------------------`);
warning(`SAFE SIZE CALCULATION (No Shrink):`);
warning(` Payload (SquashFS): ${bytesToGB(size)}`);
warning(` Calc. Overhead: ${bytesToGB(luksSize - size)}`);
warning(` TOTAL CONTAINER: ${bytesToGB(luksSize)}`);
warning(`------------------------------------------`);
warning(`creating partition LUKS: ${this.luksFile}`);
await this.luksExecuteCommand('truncate', ['--size', `${luksSize}`, this.luksFile]);
warning(`formatting ${this.luksFile} as a LUKS volume...`);
const luksFormatArgs = this.buildLuksFormatArgs(this.luksConfig, this.luksFile);
await this.luksExecuteCommand('cryptsetup', luksFormatArgs, `${this.luksPassword}\n`);
warning(`opening the LUKS volume. It will be mapped to ${this.luksDevice}`);
await this.luksExecuteCommand('cryptsetup', ['luksOpen', this.luksFile, this.luksMappedName], `${this.luksPassword}\n`);
// -------------------------------------------------------------
// FORMATTAZIONE EXT4
// -m 0 : Imposta i blocchi riservati a 0% (recupera spazio)
// -O ^has_journal : Disabilita il journal (risparmia spazio e scritture)
// -------------------------------------------------------------
warning(`formatting ext4 (without journal, 0% reserved)...`);
await exec(`mkfs.ext4 -m 0 -O ^has_journal -L live-root ${this.luksDevice}`, this.echo);
warning(`mounting ${this.luksDevice} on ${this.luksMountpoint}`);
if (fs.existsSync(this.luksMountpoint)) {
if (Utils.isMountpoint(this.luksMountpoint)) {
throw new Error(`${this.luksMountpoint} is already mounted, process will abort!`);
}
else {
await exec(`rm -rf ${this.luksMountpoint}`, this.echo);
}
}
await exec(`mkdir -p ${this.luksMountpoint}`, this.echo);
await exec(`mount /dev/mapper/${this.luksMappedName} ${this.luksMountpoint}`, this.echo);
warning(`moving ${live_fs} ${this.luksMountpoint}/filesystem.squashfs`);
await exec(`mv ${live_fs} ${this.luksMountpoint}/filesystem.squashfs`, this.echo);
warning(`Syncing filesystem on ${this.luksMountpoint}...`);
await exec('sync', this.echo); // Forza scrittura dati su disco
/**
* SHRINK DISABILITATO
* Non eseguiamo this.luksShrink() per evitare corruzione dati.
* Abbiamo calcolato la dimensione corretta all'inizio.
*/
// Procedura di chiusura manuale (sostituisce quella dentro shrink)
warning(`Unmounting ${this.luksMountpoint}...`);
await exec(`umount ${this.luksMountpoint}`, this.echo);
warning(`Closing LUKS volume ${this.luksMappedName}...`);
await this.luksExecuteCommand('cryptsetup', ['close', this.luksMappedName]);
warning(`moving ${this.luksMappedName} on (ISO)/live.`);
await exec(`mv ${this.luksFile} ${this.settings.iso_work}/live/root.img`, this.echo);
}
catch (error) {
if (error instanceof Error) {
Utils.error(`ERROR: ${error.message}`);
}
else {
Utils.error(`An unknown error has occurred.`);
}
Utils.warning('Cleaning performed following the error...');
if (fs.existsSync(this.luksMountpoint)) {
await exec(`umount -lf ${this.luksMountpoint}`).catch(() => { });
}
if (fs.existsSync(this.luksDevice)) {
await this.luksExecuteCommand('cryptsetup', ['close', this.luksMappedName]).catch(() => { });
}
if (fs.existsSync(this.luksFile)) {
Utils.warning(`Removing temporary container: ${this.luksFile}`);
fs.unlinkSync(this.luksFile);
}
await Utils.pressKeyToExit();
process.exit(1);
}
}
/**
* Converte bytes in gigabytes per la visualizzazione.
*/
function bytesToGB(bytes) {
if (bytes === 0)
return '0.00 GB';
const gigabytes = bytes / (1024 * 1024 * 1024);
return gigabytes.toFixed(2) + ' GB';
}