penguins-eggs 25.11.29 → 25.12.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/.oclif.manifest.json +1 -1
  2. package/README.md +72 -110
  3. package/README.pdf +11041 -10623
  4. package/conf/derivatives.yaml +2 -1
  5. package/conf/exclude.list.d/var.list +11 -6
  6. package/dist/appimage/dependency-manager.js +1 -1
  7. package/dist/classes/cli-autologin.js +77 -52
  8. package/dist/classes/compressors.d.ts +7 -10
  9. package/dist/classes/compressors.js +44 -31
  10. package/dist/classes/distro.js +2 -2
  11. package/dist/classes/diversions.js +2 -3
  12. package/dist/classes/incubation/fisherman-helper/initcpio.d.ts +2 -5
  13. package/dist/classes/incubation/fisherman-helper/initcpio.js +7 -4
  14. package/dist/classes/incubation/fisherman-helper/settings.js +1 -1
  15. package/dist/classes/incubation/fisherman.js +1 -1
  16. package/dist/classes/incubation/incubator.js +1 -1
  17. package/dist/classes/ovary.d/create-xdg-autostart.js +1 -1
  18. package/dist/classes/ovary.d/edit-live-fs.d.ts +1 -12
  19. package/dist/classes/ovary.d/edit-live-fs.js +129 -135
  20. package/dist/classes/ovary.d/make-dot-disk.js +1 -1
  21. package/dist/classes/ovary.d/produce.js +1 -1
  22. package/dist/classes/ovary.d/user-create-live.d.ts +4 -10
  23. package/dist/classes/ovary.d/user-create-live.js +82 -84
  24. package/dist/classes/ovary.d/users-remove.d.ts +5 -6
  25. package/dist/classes/ovary.d/users-remove.js +61 -31
  26. package/dist/classes/ovary.d.ts +2 -2
  27. package/dist/classes/ovary.js +2 -2
  28. package/dist/classes/pacman.d/alpine.js +2 -2
  29. package/dist/classes/pacman.d/archlinux.js +2 -2
  30. package/dist/classes/pacman.d/debian.js +2 -3
  31. package/dist/classes/pacman.d/fedora.js +2 -3
  32. package/dist/classes/pacman.d/openmamba.js +2 -3
  33. package/dist/classes/pacman.d/opensuse.js +2 -3
  34. package/dist/classes/pacman.d.ts +0 -5
  35. package/dist/classes/pacman.js +3 -16
  36. package/dist/classes/pve-live.js +1 -1
  37. package/dist/classes/settings.js +1 -1
  38. package/dist/classes/sys-users.d.ts +76 -0
  39. package/dist/classes/sys-users.js +206 -0
  40. package/dist/classes/utils.d/kernel.js +3 -3
  41. package/dist/classes/utils.d.ts +15 -6
  42. package/dist/classes/utils.js +79 -46
  43. package/dist/classes/xdg.js +1 -1
  44. package/dist/classes/yolk.js +2 -4
  45. package/dist/commands/export/appimage.js +3 -3
  46. package/dist/commands/export/pkg.js +3 -3
  47. package/dist/commands/export/tarballs.js +3 -3
  48. package/dist/commands/krill.js +1 -1
  49. package/dist/commands/produce.js +9 -4
  50. package/dist/commands/setup/install.js +1 -1
  51. package/dist/commands/setup/purge.js +1 -1
  52. package/dist/commands/tools/yolk.js +1 -1
  53. package/dist/commands/update.js +1 -2
  54. package/dist/interfaces/i-exec.d.ts +1 -0
  55. package/dist/krill/classes/prepare.d/location.js +1 -1
  56. package/dist/krill/classes/prepare.d/partitions.js +1 -1
  57. package/dist/krill/classes/prepare.d/users.js +2 -2
  58. package/dist/krill/classes/prepare.js +5 -5
  59. package/dist/krill/classes/sequence.d/add_user.d.ts +3 -15
  60. package/dist/krill/classes/sequence.d/add_user.js +87 -57
  61. package/dist/krill/classes/sequence.d/change_password.d.ts +5 -7
  62. package/dist/krill/classes/sequence.d/change_password.js +25 -10
  63. package/dist/krill/classes/sequence.d/del_live_user.d.ts +5 -7
  64. package/dist/krill/classes/sequence.d/del_live_user.js +39 -25
  65. package/dist/krill/classes/sequence.d/fstab.js +1 -1
  66. package/dist/krill/classes/sequence.d/grubcfg.d.ts +3 -7
  67. package/dist/krill/classes/sequence.d/grubcfg.js +33 -13
  68. package/dist/krill/classes/sequence.d/mkfs.js +1 -2
  69. package/dist/krill/classes/sequence.d/unpackfs.d.ts +2 -4
  70. package/dist/krill/classes/sequence.d/unpackfs.js +8 -5
  71. package/dist/krill/classes/sequence.js +2 -3
  72. package/dist/krill/components/title.js +2 -2
  73. package/dist/krill/lib/select_installation_device.js +1 -1
  74. package/dist/krill/lib/select_replaced_partition.js +1 -1
  75. package/dist/lib/utils.d.ts +51 -19
  76. package/dist/lib/utils.js +225 -20
  77. package/manpages/doc/man/eggs.1.gz +0 -0
  78. package/manpages/doc/man/eggs.html +8 -8
  79. package/package.json +9 -9
  80. package/perrisbrewery/template/dependencies.yaml +1 -0
  81. package/scripts/boot-encrypted-root.sh +220 -0
  82. package/scripts/mount-encrypted-home.sh +324 -0
  83. package/dracut/create-symlink +0 -71
  84. package/dracut/dracut-log.txt +0 -3
  85. package/dracut/export +0 -4
  86. package/dracut/export-dracut-analysis +0 -51
  87. package/dracut/export-dracut-log +0 -2
  88. package/dracut/mkisofs +0 -10
  89. package/dracut/renew-initramfs +0 -17
  90. package/dracut/sbin2bin +0 -10
  91. package/dracut/update-dracut-conf-d +0 -2
  92. package/dracut/update-dracut-modules +0 -62
package/dist/lib/utils.js CHANGED
@@ -5,34 +5,239 @@
5
5
  * email: piero.proietti@gmail.com
6
6
  * license: MIT
7
7
  */
8
- import { spawn } from 'child_process';
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ // Importiamo con alias per poter wrappare
11
+ import { spawn as nodeSpawn, spawnSync as nodeSpawnSync } from 'child_process';
9
12
  /**
10
- *
11
- * @param command
12
- * @param param1
13
- * @returns
13
+ * Pulizia AppImage
14
+ * Variabili d'ambiente da rimuovere per evitare conflitti quando si eseguono
15
+ * comandi di sistema dall'interno di una AppImage.
16
+ */
17
+ const APPIMAGE_ENV_BLACKLIST = [
18
+ 'LD_LIBRARY_PATH', 'LD_PRELOAD', 'PYTHONPATH', 'PERLLIB',
19
+ 'GSETTINGS_SCHEMA_DIR', 'QT_PLUGIN_PATH', 'XDG_DATA_DIRS',
20
+ 'LIBRARY_PATH', 'PKG_CONFIG_PATH', 'GIO_MODULE_DIR', 'APPIMAGE', 'APPDIR'
21
+ ];
22
+ /**
23
+ * Ottiene un ambiente pulito dalle variabili AppImage
24
+ * @returns Oggetto process.env sanificato
25
+ */
26
+ function getCleanEnv() {
27
+ const env = { ...process.env };
28
+ if (process.env.APPIMAGE) {
29
+ APPIMAGE_ENV_BLACKLIST.forEach((key) => delete env[key]);
30
+ }
31
+ return env;
32
+ }
33
+ /**
34
+ * spawnSync (WRAPPER INTELLIGENTE)
35
+ * Supporta:
36
+ * 1. (command, args, options)
37
+ * 2. (command, options) -> args diventa []
38
+ * Pulisce automaticamente l'ambiente.
39
+ */
40
+ export function spawnSync(command, arg2, arg3) {
41
+ let args = [];
42
+ let options = {};
43
+ // Rilevamento argomenti (Polimorfismo)
44
+ if (Array.isArray(arg2)) {
45
+ args = arg2;
46
+ options = arg3 || {};
47
+ }
48
+ else if (arg2 && typeof arg2 === 'object') {
49
+ // TypeScript fix: cast esplicito per evitare errori di tipo union
50
+ options = arg2;
51
+ }
52
+ const env = getCleanEnv();
53
+ const finalEnv = { ...env, ...(options.env || {}) };
54
+ return nodeSpawnSync(command, args, {
55
+ ...options,
56
+ env: finalEnv
57
+ });
58
+ }
59
+ /**
60
+ * spawn (WRAPPER INTELLIGENTE)
61
+ * Supporta:
62
+ * 1. (command, args, options)
63
+ * 2. (command, options) -> args diventa []
64
+ * Pulisce automaticamente l'ambiente.
65
+ */
66
+ export function spawn(command, arg2, arg3) {
67
+ let args = [];
68
+ let options = {};
69
+ // Rilevamento argomenti (Polimorfismo)
70
+ if (Array.isArray(arg2)) {
71
+ args = arg2;
72
+ options = arg3 || {};
73
+ }
74
+ else if (arg2 && typeof arg2 === 'object') {
75
+ // TypeScript fix: cast esplicito
76
+ options = arg2;
77
+ }
78
+ const env = getCleanEnv();
79
+ const finalEnv = { ...env, ...(options.env || {}) };
80
+ return nodeSpawn(command, args, {
81
+ ...options,
82
+ env: finalEnv
83
+ });
84
+ }
85
+ /**
86
+ * shx
87
+ * Sostituto drop-in per shelljs che usa API native e ambiente pulito.
88
+ */
89
+ export const shx = {
90
+ sed: (flag, regex, replacement, file) => {
91
+ if (!fs.existsSync(file))
92
+ return;
93
+ const content = fs.readFileSync(file, 'utf8');
94
+ const searchRegex = typeof regex === 'string' ? new RegExp(regex, 'g') : regex;
95
+ const newContent = content.replace(searchRegex, replacement);
96
+ fs.writeFileSync(file, newContent, 'utf8');
97
+ },
98
+ touch: (file) => {
99
+ const time = new Date();
100
+ try {
101
+ fs.utimesSync(file, time, time);
102
+ }
103
+ catch (err) {
104
+ fs.closeSync(fs.openSync(file, 'w'));
105
+ }
106
+ },
107
+ cp: (arg1, arg2, arg3) => {
108
+ const src = arg3 ? arg2 : arg1;
109
+ const dest = arg3 ? arg3 : arg2;
110
+ // --- GESTIONE WILDCARD (*) ---
111
+ if (src.endsWith('*')) {
112
+ const srcDir = path.dirname(src);
113
+ if (!fs.existsSync(srcDir))
114
+ return;
115
+ if (!fs.existsSync(dest))
116
+ fs.mkdirSync(dest, { recursive: true });
117
+ const items = fs.readdirSync(srcDir);
118
+ items.forEach(item => {
119
+ const s = path.join(srcDir, item);
120
+ const d = path.join(dest, item);
121
+ fs.cpSync(s, d, { recursive: true, force: true });
122
+ });
123
+ return;
124
+ }
125
+ // ----------------------------
126
+ let finalDest = dest;
127
+ if (fs.existsSync(dest) && fs.statSync(dest).isDirectory()) {
128
+ finalDest = path.join(dest, path.basename(src));
129
+ }
130
+ if (fs.existsSync(src)) {
131
+ fs.cpSync(src, finalDest, { recursive: true, force: true });
132
+ }
133
+ },
134
+ rm: (arg1, arg2) => {
135
+ const target = arg2 ? arg2 : arg1;
136
+ fs.rmSync(target, { recursive: true, force: true });
137
+ },
138
+ mkdir: (arg1, arg2) => {
139
+ const dir = arg2 ? arg2 : arg1;
140
+ fs.mkdirSync(dir, { recursive: true });
141
+ },
142
+ mv: (src, dest) => {
143
+ if (!fs.existsSync(src))
144
+ return;
145
+ fs.renameSync(src, dest);
146
+ },
147
+ chmod: (mode, file) => {
148
+ if (!fs.existsSync(file))
149
+ return;
150
+ let finalMode = mode;
151
+ if (mode === '+x')
152
+ finalMode = 0o755;
153
+ if (typeof mode === 'string' && !isNaN(parseInt(mode, 8))) {
154
+ finalMode = parseInt(mode, 8);
155
+ }
156
+ fs.chmodSync(file, finalMode);
157
+ },
158
+ test: (flag, pathToCheck) => {
159
+ try {
160
+ const stats = fs.statSync(pathToCheck);
161
+ if (flag === '-f')
162
+ return stats.isFile();
163
+ if (flag === '-d')
164
+ return stats.isDirectory();
165
+ return true; // -e
166
+ }
167
+ catch (e) {
168
+ return false;
169
+ }
170
+ },
171
+ which: (cmd) => {
172
+ const result = shx.exec(`command -v ${cmd}`, { silent: true });
173
+ return result.code === 0 ? result.stdout.trim() : null;
174
+ },
175
+ ln: (flag, target, link) => {
176
+ if (fs.existsSync(link) || fs.lstatSync(link, { throwIfNoEntry: false })) {
177
+ fs.rmSync(link, { force: true });
178
+ }
179
+ fs.symlinkSync(target, link);
180
+ },
181
+ exec: (command, options = {}) => {
182
+ const env = getCleanEnv();
183
+ const spawnOpts = {
184
+ stdio: options.silent ? 'pipe' : 'inherit',
185
+ env: env,
186
+ shell: '/bin/bash',
187
+ encoding: 'utf-8'
188
+ };
189
+ // Usiamo nodeSpawnSync perché calcoliamo l'env qui sopra
190
+ const result = nodeSpawnSync(command, [], spawnOpts);
191
+ return {
192
+ code: result.status ?? 1,
193
+ stdout: result.stdout ? result.stdout.toString() : '',
194
+ stderr: result.stderr ? result.stderr.toString() : ''
195
+ };
196
+ }
197
+ };
198
+ /**
199
+ * execSync
200
+ */
201
+ export function execSync(command, options = {}) {
202
+ const { echo = false, ignore = false, stdio } = options;
203
+ if (echo)
204
+ console.log(command);
205
+ const isSilent = ignore || stdio === 'ignore';
206
+ const result = shx.exec(command, { silent: isSilent });
207
+ if (result.code !== 0) {
208
+ throw new Error(`Command failed: ${command}\nExit Code: ${result.code}\nStderr: ${result.stderr}`);
209
+ }
210
+ return result.stdout.trim();
211
+ }
212
+ /**
213
+ * exec (Async)
14
214
  */
15
215
  export async function exec(command, { echo = false, ignore = false, capture = false } = {}) {
16
216
  return new Promise((resolve, reject) => {
17
- if (echo) {
217
+ if (echo)
18
218
  console.log(command);
19
- }
20
- // Opzioni di base per spawn
21
- const spawnOptions = {
22
- stdio: ignore ? 'ignore' : capture ? 'pipe' : 'inherit'
23
- };
24
- const child = spawn('bash', ['-c', command], spawnOptions);
219
+ const env = getCleanEnv();
220
+ // Usiamo nodeSpawn direttamente qui per coerenza
221
+ const child = nodeSpawn(command, [], {
222
+ stdio: ignore ? 'ignore' : (capture ? 'pipe' : 'inherit'),
223
+ env: env,
224
+ shell: '/bin/bash'
225
+ });
25
226
  let stdout = '';
26
- if (capture) {
27
- child.stdout?.on('data', (data) => {
28
- stdout += data;
29
- });
30
- }
227
+ let stderr = '';
228
+ if (capture && child.stdout)
229
+ child.stdout.on('data', d => stdout += d.toString());
230
+ if (capture && child.stderr)
231
+ child.stderr.on('data', d => stderr += d.toString());
31
232
  child.on('error', (error) => {
32
- reject({ code: 1, error });
233
+ reject({ code: 1, error, stderr });
33
234
  });
34
- child.on('exit', (code) => {
35
- resolve({ code, data: stdout });
235
+ child.on('close', (code) => {
236
+ resolve({
237
+ code: code || 0,
238
+ data: stdout.trim(),
239
+ error: code !== 0 ? stderr.trim() : undefined
240
+ });
36
241
  });
37
242
  });
38
243
  }
Binary file
@@ -6,12 +6,12 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
7
  </head>
8
8
  <body>
9
- <h1>eggs(1) -- the reproductive system of penguins: eggs v25.11.29</h1>
9
+ <h1>eggs(1) -- the reproductive system of penguins: eggs v25.12.7</h1>
10
10
  <h1>SYNOPSIS</h1>
11
11
  <p>eggs is a console utility, in active development, who let you to remaster your system and redistribuite it as live ISO image.</p>
12
12
  <h1>INSTALL</h1>
13
13
  <p>penguins-eggs as an AppImage, it can be installed on all supported distributions. Download it from https://github.com/pieroproietti/penguins-eggs/releases, then run the following commands:</p>
14
- <pre><code>$ chmod +x penguins-eggs_25.11.29-1_amd64-x86_64.AppImage
14
+ <pre><code>$ chmod +x penguins-eggs_25.12.7-1_amd64-x86_64.AppImage
15
15
  $ sudo mv /usr/local/bin
16
16
  $ sudo eggs setup
17
17
  </code></pre>
@@ -19,30 +19,30 @@ $ sudo eggs setup
19
19
  <pre><code>$ doas apk add penguins-eggs@testing
20
20
  </code></pre>
21
21
  <p>AlmaLinux/RockyLinux</p>
22
- <pre><code>$ sudo dnf install ./penguins-eggs_25.11.29-1_amd64-1rocky9.5..x86_64.rpm
22
+ <pre><code>$ sudo dnf install ./penguins-eggs_25.12.7-1_amd64-1rocky9.5..x86_64.rpm
23
23
 
24
24
  </code></pre>
25
25
  <p>Arch</p>
26
26
  <pre><code>$ sudo pacman -S penguins-eggs
27
- $ sudo pacman -U penguins-eggs_25.11.29-1_amd64-1-x86_64.pkg.tar.zst
27
+ $ sudo pacman -U penguins-eggs_25.12.7-1_amd64-1-x86_64.pkg.tar.zst
28
28
  </code></pre>
29
29
  <p>Debian/Devuan/Ubuntu</p>
30
30
  <pre><code>$ sudo apt install penguins-eggs
31
- $ sudo dpkg -i penguins-eggs_25.11.29-1_amd64.deb
31
+ $ sudo dpkg -i penguins-eggs_25.12.7-1_amd64.deb
32
32
  </code></pre>
33
33
  <p>Fedora</p>
34
- <pre><code>$ sudo dnf install ./penguins-eggs_25.11.29-1_amd64-1fedora.x86_64.rpm
34
+ <pre><code>$ sudo dnf install ./penguins-eggs_25.12.7-1_amd64-1fedora.x86_64.rpm
35
35
  </code></pre>
36
36
  <p>Manjaro</p>
37
37
  <pre><code>$ sudo pamac install penguins-eggs
38
38
  </code></pre>
39
39
  <p>OpenMamba</p>
40
- <pre><code>$ sudo dnf install ./penguins-eggs_25.11.29-1_amd64-1mamba.x86_64.rpm
40
+ <pre><code>$ sudo dnf install ./penguins-eggs_25.12.7-1_amd64-1mamba.x86_64.rpm
41
41
  </code></pre>
42
42
  <h1>USAGE</h1>
43
43
  <pre><code>$ eggs (-v|--version|version)
44
44
 
45
- penguins-eggs/25.11.29
45
+ penguins-eggs/25.12.7
46
46
  $ eggs --help [COMMAND]
47
47
 
48
48
  USAGE
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "penguins-eggs",
3
3
  "shortName": "eggs",
4
4
  "description": "A remaster system tool, compatible with Almalinux, Alpine, Arch, Debian, Devuan, Fedora, Manjaro, Opensuse, Ubuntu and derivatives",
5
- "version": "25.11.29",
5
+ "version": "25.12.7",
6
6
  "author": "Piero Proietti",
7
7
  "bin": {
8
8
  "eggs": "./bin/run.js"
@@ -13,13 +13,14 @@
13
13
  "@oclif/plugin-autocomplete": "^3.2.39",
14
14
  "@oclif/plugin-help": "^6.2.36",
15
15
  "@oclif/plugin-version": "^2.2.36",
16
- "@types/express": "^5.0.5",
16
+ "@types/express": "^5.0.6",
17
17
  "ansis": "^4.2.0",
18
18
  "axios": "^1.13.2",
19
+ "bcryptjs": "^3.0.3",
19
20
  "chalk": "^5.6.2",
20
21
  "cli-cursor": "^5.0.0",
21
22
  "debug": "^4.4.3",
22
- "express": "^5.1.0",
23
+ "express": "^5.2.1",
23
24
  "ink": "^5",
24
25
  "ink-progress-bar": "^3.0.0",
25
26
  "ink-spinner": "^5.0.0",
@@ -29,7 +30,6 @@
29
30
  "netmask": "^2.0.2",
30
31
  "react": "^18.3.1",
31
32
  "read": "^4.1.0",
32
- "shelljs": "^0.10.0",
33
33
  "systeminformation": "^5.27.11",
34
34
  "tftp": "^0.1.2",
35
35
  "ws": "^8.18.3"
@@ -37,6 +37,7 @@
37
37
  "devDependencies": {
38
38
  "@oclif/prettier-config": "^0.2.1",
39
39
  "@oclif/test": "^4.1.15",
40
+ "@types/bcryptjs": "^3.0.0",
40
41
  "@types/chai": "^5.2.3",
41
42
  "@types/debug": "^4.1.12",
42
43
  "@types/glob": "^9.0.0",
@@ -48,24 +49,23 @@
48
49
  "@types/node": "^22.15.30",
49
50
  "@types/react": "^18.3.18",
50
51
  "@types/read": "^0.0.32",
51
- "@types/shelljs": "^0.8.17",
52
52
  "@types/ws": "^8.18.1",
53
53
  "chai": "^6.2.1",
54
54
  "eslint": "^9.39.1",
55
- "eslint-config-oclif": "^6.0.119",
55
+ "eslint-config-oclif": "^6.0.124",
56
56
  "eslint-config-prettier": "^10.1.8",
57
57
  "glob": "^13.0.0",
58
58
  "mocha": "^11.7.5",
59
- "oclif": "^4.22.50",
59
+ "oclif": "^4.22.54",
60
60
  "perrisbrewery": "^25.9.16",
61
- "prettier": "^3.7.2",
61
+ "prettier": "^3.7.4",
62
62
  "shx": "^0.4.0",
63
63
  "ts-node": "10.9.2",
64
64
  "ts-prune": "^0.10.3",
65
65
  "typescript": "^5.9.3"
66
66
  },
67
67
  "engines": {
68
- "node": ">=16.0.0"
68
+ "node": ">=22.0.0"
69
69
  },
70
70
  "files": [
71
71
  ".oclif.manifest.json",
@@ -22,6 +22,7 @@ common:
22
22
  - lvm2 # pvdisplay in krill
23
23
  - nodejs (>= 18)
24
24
  - parted
25
+ - pxelinux
25
26
  - policykit-1 | pkexec # calamares
26
27
  - rsync
27
28
  - squashfs-tools
@@ -0,0 +1,220 @@
1
+ #!/bin/sh
2
+ # /scripts/live-premount/boot-encrypted-root.sh
3
+ #
4
+ # This script is designed to Boot Encrypted Linux Live (BELL).
5
+ #
6
+ # Its main purpose is to find an encrypted root image file (root.img) 
7
+ # on a live USB/DVD, ask the user for a passphrase to unlock it, 
8
+ # and then copy the main system filesystem (filesystem.squashfs) 
9
+ # from inside the encrypted image into RAM.
10
+
11
+ # the process continue with standard live-boot 
12
+
13
+ # enable echo
14
+ # set -e
15
+
16
+ echo "BELL: Boot Encrypted Linux Live"
17
+
18
+ #################################################
19
+ # 1. Setup and Find Media
20
+
21
+ # 1.1 load modules
22
+ echo "BELL: loading modules..."
23
+ modprobe loop 2>/dev/null || true
24
+ modprobe dm_mod 2>/dev/null || true
25
+ modprobe dm_crypt 2>/dev/null || true
26
+ modprobe overlay 2>/dev/null || true
27
+ modprobe ext4 2>/dev/null || true
28
+ modprobe squashfs 2>/dev/null || true
29
+ sleep 2
30
+
31
+
32
+ # 1.2 find BELL media drive
33
+ echo "BELL: find BELL media drive..."
34
+ mkdir -p /mnt/live-media /mnt/ext4
35
+ BELL_MEDIA_MNT="/mnt/live-media"
36
+ LIVE_DEV=""
37
+
38
+ # find to max 20 devices
39
+ MAX_WAIT_DEV=20; COUNT_DEV=0
40
+ while [ -z "$LIVE_DEV" ] && [ $COUNT_DEV -lt $MAX_WAIT_DEV ]; do
41
+ ls /dev > /dev/null
42
+ for dev in /dev/sr* /dev/sd* /dev/vd* /dev/nvme*n*; do
43
+ if [ ! -b "$dev" ]; then continue; fi
44
+ if mount -o ro "$dev" "$BELL_MEDIA_MNT" 2>/dev/null; then
45
+ if [ -f "${BELL_MEDIA_MNT}/live/root.img" ]; then
46
+ echo "BELL: Found BELL media on $dev"
47
+ LIVE_DEV=$dev
48
+ break 2
49
+ else
50
+ umount "$BELL_MEDIA_MNT" 2>/dev/null || true
51
+ fi
52
+ fi
53
+ done
54
+ sleep 1
55
+ COUNT_DEV=$((COUNT_DEV+1))
56
+ done
57
+
58
+ if [ -z "$LIVE_DEV" ]; then
59
+ echo "BELL: Error: no live BELL drive found!"
60
+ ls /dev
61
+ exit 1
62
+ fi
63
+
64
+ ROOT_IMG_RO="${BELL_MEDIA_MNT}/live/root.img"
65
+ RAM_MEDIA_MNT="/run/live/medium" # final destination in RAM
66
+
67
+
68
+ #################################################
69
+ # 2. Prepare Encrypted Image
70
+
71
+ # 2.1 loop device
72
+ echo "BELL: loop device association for $ROOT_IMG_RO..."
73
+ LOOP_DEV_OUTPUT=$(/sbin/losetup -f --show "$ROOT_IMG_RO" 2>/dev/null); LOSETUP_EXIT_STATUS=$?
74
+ if [ $LOSETUP_EXIT_STATUS -ne 0 ] || [ -z "$LOOP_DEV_OUTPUT" ] || ! [ -b "$LOOP_DEV_OUTPUT" ]; then
75
+ echo "BELL: Error: loop association failed!"
76
+ exit 1
77
+ fi
78
+ LOOP_DEV="$LOOP_DEV_OUTPUT"
79
+ echo "BELL: loop device $ROOT_IMG_RO associated to: $LOOP_DEV"
80
+
81
+
82
+
83
+ #################################################
84
+ # 3. Unlock LUKS (User Interaction)
85
+
86
+ # disable 'set -e' to let 3 tempts 
87
+ #set +e
88
+ MAX_ATTEMPTS=3
89
+ ATTEMPT=1
90
+ UNLOCKED=0
91
+
92
+ while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do
93
+
94
+ # check if plymouth is active
95
+ if plymouth --ping 2>/dev/null; then
96
+
97
+ # request the password in plymouth and pass it to cryptsetup via stdin (--key-file -)
98
+ if plymouth ask-for-password --prompt="Enter passphrase ($ATTEMPT/$MAX_ATTEMPTS)" | cryptsetup open --readonly --key-file - "$LOOP_DEV" live-root; then
99
+ UNLOCKED=1
100
+ break
101
+ else
102
+ if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then
103
+ plymouth display-message --text="Incorrect passphrase. Try again..."
104
+ sleep 2 # wait 2 seconds to read message
105
+ fi
106
+ fi
107
+ else
108
+ # Fallback: Plymouth not active
109
+ echo "Please enter passphrase for $LOOP_DEV ($ATTEMPT/$MAX_ATTEMPTS):"
110
+
111
+ if cryptsetup open --readonly "$LOOP_DEV" live-root; then
112
+ UNLOCKED=1
113
+ break
114
+ else
115
+ if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then
116
+ echo "Incorrect passphrase. Please try again."
117
+ fi
118
+ fi
119
+ fi
120
+
121
+ ATTEMPT=$((ATTEMPT + 1))
122
+ sleep 1
123
+ done
124
+
125
+ # Enable echo
126
+ # set -e
127
+
128
+ # check if all attempts have failed
129
+ if [ $UNLOCKED -eq 0 ]; then
130
+ if plymouth --ping 2>/dev/null; then
131
+ plymouth display-message --text="LUKS Unlock Failed: Max attempts reached"
132
+ sleep 5
133
+ fi
134
+ /sbin/losetup -d "$LOOP_DEV" || true
135
+ exit 1
136
+ fi
137
+
138
+ echo "BELL: LUKS unlocked ($LOOP_DEV -> live-root) [readonly]. Waiting for mapper..."
139
+
140
+
141
+ #################################################
142
+ # 4. copy System to RAM
143
+
144
+ # 4.1 waiting mapper
145
+ MAX_WAIT_MAP=10; COUNT_MAP=0
146
+ while [ ! -b /dev/mapper/live-root ] && [ $COUNT_MAP -lt $MAX_WAIT_MAP ]; do
147
+ sleep 1
148
+ COUNT_MAP=$((COUNT_MAP+1))
149
+ done
150
+
151
+ if [ ! -b /dev/mapper/live-root ]; then
152
+ echo "BELL: Error: mapper did not appear."
153
+ cryptsetup close live-root || true
154
+ /sbin/losetup -d "$LOOP_DEV" || true
155
+ exit 1
156
+ fi
157
+
158
+ # 4.2 mount ext4 filesystem
159
+ echo "BELL: mounting ext4 filesystem..."
160
+ mount -t ext4 -o ro /dev/mapper/live-root /mnt/ext4
161
+
162
+ SQFS_SRC="/mnt/ext4/filesystem.squashfs"
163
+ if [ ! -f "$SQFS_SRC" ]; then
164
+ echo "BELL: error: $SQFS_SRC not found!"
165
+ exit 1
166
+ fi
167
+
168
+
169
+ # 4.3. Prepare RAM destination /run
170
+ echo "BELL: preparing RAM disk ${RAM_MEDIA_MNT}..."
171
+ SQFS_SIZE_BYTES=$(stat -c%s "$SQFS_SRC")
172
+ NEEDED_SIZE_MB=$(( $SQFS_SIZE_BYTES / 1024 / 1024 + 500 )) # add 500MB buffer
173
+ echo "BELL: Estimated space required in /run: ${NEEDED_SIZE_MB} MB"
174
+ echo "BELL: increase size /run (tmpfs)..."
175
+ if ! mount -o remount,size=${NEEDED_SIZE_MB}M /run; then
176
+ echo "BELL: WARN: Remount /run failed, space may be insufficient."
177
+ df -h /run
178
+ fi
179
+ mkdir -p "${RAM_MEDIA_MNT}/live"
180
+
181
+ # 4.4 copy ONLY filesystem.squashfs to RAM
182
+ SQFS_DEST="${RAM_MEDIA_MNT}/live/filesystem.squashfs"
183
+ echo "BELL: copying $SQFS_SRC -> $SQFS_DEST..."
184
+ if command -v rsync >/dev/null; then
185
+ rsync -a --info=progress2 "$SQFS_SRC" "$SQFS_DEST"
186
+ else
187
+ cp "$SQFS_SRC" "$SQFS_DEST"
188
+ fi
189
+ SQFS_SIZE=$(du -h "$SQFS_DEST" | cut -f1)
190
+ echo "BELL: filesystem.squashfs ($SQFS_SIZE) copied to RAM."
191
+
192
+ # 4.5 copy .disk
193
+ if [ -d "${BELL_MEDIA_MNT}/.disk" ]; then
194
+ cp -a "${BELL_MEDIA_MNT}/.disk" "${RAM_MEDIA_MNT}/"
195
+ echo "BELL: .disk copied."
196
+ else
197
+ echo "BELL: Warning: .disk not found."
198
+ fi
199
+
200
+ # 4.6 Copy vmlinuz and initrd (we need to install the system)
201
+ cp -a "${BELL_MEDIA_MNT}/live/vmlinuz"* "${RAM_MEDIA_MNT}/live/" 2>/dev/null || true
202
+ cp -a "${BELL_MEDIA_MNT}/live/initrd"* "${RAM_MEDIA_MNT}/live/" 2>/dev/null || true
203
+ echo "BELL: Attempted kernel/initrd copy (any errors ignored)."
204
+
205
+
206
+ #################################################
207
+ # 6. Cleanup and Hand-off
208
+ echo "BELL: cleaning used mounts and devices..."
209
+ umount /mnt/ext4 || echo "BELL: WARN: umount /mnt/ext4 failed ($?)"
210
+ cryptsetup close live-root || echo "BELL: WARN: cryptsetup close live-root failed ($?)"
211
+ /sbin/losetup -d "$LOOP_DEV" || echo "BELL: WARN: losetup -d $LOOP_DEV failed ($?)"
212
+ umount "$BELL_MEDIA_MNT" || echo "BELL: WARN: umount ${BELL_MEDIA_MNT} failed ($?)"
213
+ echo "BELL: cleaning complete."
214
+
215
+
216
+ # 6.1 switching to live boot
217
+ echo "BELL: live ISO image built in RAM on ${RAM_MEDIA_MNT}"
218
+ # ls -l "$RAM_MEDIA_MNT"
219
+ # ls -l "${RAM_MEDIA_MNT}/live"
220
+ exit 0