penguins-eggs 10.0.53 → 10.0.54

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 (344) hide show
  1. package/.oclif.manifest.json +1548 -2
  2. package/README.md +788 -0
  3. package/addons/eggs/theme/livecd/grub.main.simple.cfg +49 -0
  4. package/addons/eggs/theme/livecd/isolinux.theme.cfg +6 -5
  5. package/conf/distros/fedora/calamares/settings.yml +0 -6
  6. package/dist/classes/bleach.d.ts +32 -0
  7. package/dist/classes/bleach.js +135 -0
  8. package/dist/classes/cfs.d.ts +17 -0
  9. package/dist/classes/cfs.js +39 -0
  10. package/dist/classes/cli-autologin.d.ts +52 -0
  11. package/dist/classes/cli-autologin.js +247 -0
  12. package/dist/classes/compressors.d.ts +54 -0
  13. package/dist/classes/compressors.js +109 -0
  14. package/dist/classes/daddy.d.ts +26 -0
  15. package/dist/classes/daddy.js +167 -0
  16. package/dist/classes/distro.d.ts +32 -0
  17. package/dist/classes/distro.js +341 -0
  18. package/dist/classes/diversions.d.ts +48 -0
  19. package/dist/classes/diversions.js +116 -0
  20. package/dist/classes/incubation/branding.d.ts +17 -0
  21. package/dist/classes/incubation/branding.js +85 -0
  22. package/dist/classes/incubation/fisherman-helper/displaymanager.d.ts +11 -0
  23. package/dist/classes/incubation/fisherman-helper/displaymanager.js +40 -0
  24. package/dist/classes/incubation/fisherman-helper/packages.d.ts +20 -0
  25. package/dist/classes/incubation/fisherman-helper/packages.js +72 -0
  26. package/dist/classes/incubation/fisherman-helper/settings.d.ts +15 -0
  27. package/dist/classes/incubation/fisherman-helper/settings.js +83 -0
  28. package/dist/classes/incubation/fisherman.d.ts +70 -0
  29. package/dist/classes/incubation/fisherman.js +263 -0
  30. package/dist/classes/incubation/incubator.d/alpine.d.ts +32 -0
  31. package/dist/classes/incubation/incubator.d/alpine.js +78 -0
  32. package/dist/classes/incubation/incubator.d/bionic.d.ts +32 -0
  33. package/dist/classes/incubation/incubator.d/bionic.js +83 -0
  34. package/dist/classes/incubation/incubator.d/buster.d.ts +32 -0
  35. package/dist/classes/incubation/incubator.d/buster.js +85 -0
  36. package/dist/classes/incubation/incubator.d/jessie.d.ts +31 -0
  37. package/dist/classes/incubation/incubator.d/jessie.js +44 -0
  38. package/dist/classes/incubation/incubator.d/noble.d.ts +32 -0
  39. package/dist/classes/incubation/incubator.d/noble.js +85 -0
  40. package/dist/classes/incubation/incubator.d/openmamba.d.ts +32 -0
  41. package/dist/classes/incubation/incubator.d/openmamba.js +81 -0
  42. package/dist/classes/incubation/incubator.d/opensuse.d.ts +32 -0
  43. package/dist/classes/incubation/incubator.d/opensuse.js +81 -0
  44. package/dist/classes/incubation/incubator.d/rolling.d.ts +32 -0
  45. package/dist/classes/incubation/incubator.d/rolling.js +80 -0
  46. package/dist/classes/incubation/incubator.d.ts +44 -0
  47. package/dist/classes/incubation/incubator.js +382 -0
  48. package/dist/classes/incubation/installer.d.ts +13 -0
  49. package/dist/classes/incubation/installer.js +52 -0
  50. package/dist/classes/keyboards.d.ts +50 -0
  51. package/dist/classes/keyboards.js +287 -0
  52. package/dist/classes/locales.d.ts +21 -0
  53. package/dist/classes/locales.js +77 -0
  54. package/dist/classes/network.d.ts +37 -0
  55. package/dist/classes/network.js +98 -0
  56. package/dist/classes/ovary.d.ts +198 -0
  57. package/dist/classes/ovary.js +1849 -0
  58. package/dist/classes/pacman.d/aldos.d.ts +52 -0
  59. package/dist/classes/pacman.d/aldos.js +100 -0
  60. package/dist/classes/pacman.d/alpine.d.ts +56 -0
  61. package/dist/classes/pacman.d/alpine.js +162 -0
  62. package/dist/classes/pacman.d/archlinux.d.ts +62 -0
  63. package/dist/classes/pacman.d/archlinux.js +137 -0
  64. package/dist/classes/pacman.d/debian.d.ts +65 -0
  65. package/dist/classes/pacman.d/debian.js +143 -0
  66. package/dist/classes/pacman.d/fedora.d.ts +53 -0
  67. package/dist/classes/pacman.d/fedora.js +101 -0
  68. package/dist/classes/pacman.d/openmamba.d.ts +52 -0
  69. package/dist/classes/pacman.d/openmamba.js +100 -0
  70. package/dist/classes/pacman.d/opensuse.d.ts +53 -0
  71. package/dist/classes/pacman.d/opensuse.js +102 -0
  72. package/dist/classes/pacman.d/voidlinux.d.ts +52 -0
  73. package/dist/classes/pacman.d/voidlinux.js +90 -0
  74. package/dist/classes/pacman.d.ts +139 -0
  75. package/dist/classes/pacman.js +775 -0
  76. package/dist/classes/pve-live.d.ts +17 -0
  77. package/dist/classes/pve-live.js +52 -0
  78. package/dist/classes/pxe.d.ts +74 -0
  79. package/dist/classes/pxe.js +410 -0
  80. package/dist/classes/settings.d.ts +53 -0
  81. package/dist/classes/settings.js +185 -0
  82. package/dist/classes/sources_list.d.ts +28 -0
  83. package/dist/classes/sources_list.js +89 -0
  84. package/dist/classes/systemctl.d.ts +47 -0
  85. package/dist/classes/systemctl.js +86 -0
  86. package/dist/classes/tailor.d.ts +50 -0
  87. package/dist/classes/tailor.js +526 -0
  88. package/dist/classes/tools.d.ts +26 -0
  89. package/dist/classes/tools.js +50 -0
  90. package/dist/classes/users.d.ts +28 -0
  91. package/dist/classes/users.js +143 -0
  92. package/dist/classes/utils.d.ts +324 -0
  93. package/dist/classes/utils.js +984 -0
  94. package/dist/classes/xdg.d.ts +45 -0
  95. package/dist/classes/xdg.js +337 -0
  96. package/dist/classes/yolk.d.ts +33 -0
  97. package/dist/classes/yolk.js +114 -0
  98. package/dist/commands/adapt.d.ts +17 -0
  99. package/dist/commands/adapt.js +33 -0
  100. package/dist/commands/analyze.d.ts +26 -0
  101. package/dist/commands/analyze.js +95 -0
  102. package/dist/commands/calamares.d.ts +29 -0
  103. package/dist/commands/calamares.js +112 -0
  104. package/dist/commands/config.d.ts +35 -0
  105. package/dist/commands/config.js +120 -0
  106. package/dist/commands/cuckoo.d.ts +16 -0
  107. package/dist/commands/cuckoo.js +62 -0
  108. package/dist/commands/dad.d.ts +20 -0
  109. package/dist/commands/dad.js +46 -0
  110. package/dist/commands/export/iso.d.ts +19 -0
  111. package/dist/commands/export/iso.js +55 -0
  112. package/dist/commands/export/pkg.d.ts +29 -0
  113. package/dist/commands/export/pkg.js +163 -0
  114. package/dist/commands/export/tarballs.d.ts +27 -0
  115. package/dist/commands/export/tarballs.js +84 -0
  116. package/dist/commands/install.d.ts +37 -0
  117. package/dist/commands/install.js +88 -0
  118. package/dist/commands/kill.d.ts +24 -0
  119. package/dist/commands/kill.js +50 -0
  120. package/dist/commands/love.d.ts +20 -0
  121. package/dist/commands/love.js +59 -0
  122. package/dist/commands/mom.d.ts +16 -0
  123. package/dist/commands/mom.js +30 -0
  124. package/dist/commands/produce.d.ts +34 -0
  125. package/dist/commands/produce.js +201 -0
  126. package/dist/commands/status.d.ts +23 -0
  127. package/dist/commands/status.js +31 -0
  128. package/dist/commands/syncfrom.d.ts +45 -0
  129. package/dist/commands/syncfrom.js +152 -0
  130. package/dist/commands/syncto.d.ts +40 -0
  131. package/dist/commands/syncto.js +175 -0
  132. package/dist/commands/tools/clean.d.ts +18 -0
  133. package/dist/commands/tools/clean.js +37 -0
  134. package/dist/commands/tools/ppa.d.ts +26 -0
  135. package/dist/commands/tools/ppa.js +138 -0
  136. package/dist/commands/tools/skel.d.ts +18 -0
  137. package/dist/commands/tools/skel.js +44 -0
  138. package/dist/commands/tools/stat.d.ts +31 -0
  139. package/dist/commands/tools/stat.js +70 -0
  140. package/dist/commands/tools/yolk.d.ts +24 -0
  141. package/dist/commands/tools/yolk.js +45 -0
  142. package/dist/commands/update.d.ts +51 -0
  143. package/dist/commands/update.js +219 -0
  144. package/dist/commands/wardrobe/get.d.ts +23 -0
  145. package/dist/commands/wardrobe/get.js +52 -0
  146. package/dist/commands/wardrobe/list.d.ts +24 -0
  147. package/dist/commands/wardrobe/list.js +125 -0
  148. package/dist/commands/wardrobe/show.d.ts +25 -0
  149. package/dist/commands/wardrobe/show.js +97 -0
  150. package/dist/commands/wardrobe/wear.d.ts +26 -0
  151. package/dist/commands/wardrobe/wear.js +84 -0
  152. package/dist/components/finished.d.ts +16 -0
  153. package/dist/components/finished.js +56 -0
  154. package/dist/components/information.d.ts +8 -0
  155. package/dist/components/information.js +154 -0
  156. package/dist/components/install.d.ts +15 -0
  157. package/dist/components/install.js +60 -0
  158. package/dist/components/keyboard.d.ts +16 -0
  159. package/dist/components/keyboard.js +54 -0
  160. package/dist/components/location.d.ts +16 -0
  161. package/dist/components/location.js +59 -0
  162. package/dist/components/network.d.ts +19 -0
  163. package/dist/components/network.js +65 -0
  164. package/dist/components/partitions.d.ts +16 -0
  165. package/dist/components/partitions.js +73 -0
  166. package/dist/components/steps.d.ts +13 -0
  167. package/dist/components/steps.js +148 -0
  168. package/dist/components/summary.d.ts +24 -0
  169. package/dist/components/summary.js +81 -0
  170. package/dist/components/title.d.ts +11 -0
  171. package/dist/components/title.js +35 -0
  172. package/dist/components/users.d.ts +24 -0
  173. package/dist/components/users.js +80 -0
  174. package/dist/components/welcome.d.ts +13 -0
  175. package/dist/components/welcome.js +63 -0
  176. package/dist/index-old.d.ts +8 -0
  177. package/dist/index-old.js +8 -0
  178. package/dist/index.d.ts +54 -0
  179. package/dist/index.js +147 -0
  180. package/dist/interfaces/i-addons.d.ts +12 -0
  181. package/dist/interfaces/i-addons.js +8 -0
  182. package/dist/interfaces/i-analyze.d.ts +17 -0
  183. package/dist/interfaces/i-analyze.js +17 -0
  184. package/dist/interfaces/i-app.d.ts +14 -0
  185. package/dist/interfaces/i-app.js +8 -0
  186. package/dist/interfaces/i-branding.d.ts +36 -0
  187. package/dist/interfaces/i-branding.js +8 -0
  188. package/dist/interfaces/i-calamares-displaymanager.d.ts +17 -0
  189. package/dist/interfaces/i-calamares-displaymanager.js +1 -0
  190. package/dist/interfaces/i-calamares-finished.d.ts +12 -0
  191. package/dist/interfaces/i-calamares-finished.js +1 -0
  192. package/dist/interfaces/i-calamares-packages.d.ts +28 -0
  193. package/dist/interfaces/i-calamares-packages.js +1 -0
  194. package/dist/interfaces/i-calamares-partition.d.ts +40 -0
  195. package/dist/interfaces/i-calamares-partition.js +1 -0
  196. package/dist/interfaces/i-config-tools.d.ts +15 -0
  197. package/dist/interfaces/i-config-tools.js +8 -0
  198. package/dist/interfaces/i-devices.d.ts +20 -0
  199. package/dist/interfaces/i-devices.js +8 -0
  200. package/dist/interfaces/i-distro.d.ts +23 -0
  201. package/dist/interfaces/i-distro.js +8 -0
  202. package/dist/interfaces/i-drive-list.d.ts +33 -0
  203. package/dist/interfaces/i-drive-list.js +8 -0
  204. package/dist/interfaces/i-eggs-config.d.ts +32 -0
  205. package/dist/interfaces/i-eggs-config.js +8 -0
  206. package/dist/interfaces/i-excludes.d.ts +14 -0
  207. package/dist/interfaces/i-excludes.js +8 -0
  208. package/dist/interfaces/i-exec.d.ts +11 -0
  209. package/dist/interfaces/i-exec.js +8 -0
  210. package/dist/interfaces/i-initrd.d.ts +13 -0
  211. package/dist/interfaces/i-initrd.js +8 -0
  212. package/dist/interfaces/i-install.d.ts +16 -0
  213. package/dist/interfaces/i-install.js +8 -0
  214. package/dist/interfaces/i-installer.d.ts +17 -0
  215. package/dist/interfaces/i-installer.js +8 -0
  216. package/dist/interfaces/i-krill-config.d.ts +33 -0
  217. package/dist/interfaces/i-krill-config.js +8 -0
  218. package/dist/interfaces/i-krill.d.ts +42 -0
  219. package/dist/interfaces/i-krill.js +8 -0
  220. package/dist/interfaces/i-materia.d.ts +36 -0
  221. package/dist/interfaces/i-materia.js +8 -0
  222. package/dist/interfaces/i-net.d.ts +16 -0
  223. package/dist/interfaces/i-net.js +8 -0
  224. package/dist/interfaces/i-packages.d.ts +16 -0
  225. package/dist/interfaces/i-packages.js +8 -0
  226. package/dist/interfaces/i-partitions.d.ts +16 -0
  227. package/dist/interfaces/i-partitions.js +8 -0
  228. package/dist/interfaces/i-pxe.d.ts +45 -0
  229. package/dist/interfaces/i-pxe.js +1 -0
  230. package/dist/interfaces/i-remix.d.ts +21 -0
  231. package/dist/interfaces/i-remix.js +8 -0
  232. package/dist/interfaces/i-settings.d.ts +33 -0
  233. package/dist/interfaces/i-settings.js +8 -0
  234. package/dist/interfaces/i-user.d.ts +14 -0
  235. package/dist/interfaces/i-user.js +8 -0
  236. package/dist/interfaces/i-workdir.d.ts +14 -0
  237. package/dist/interfaces/i-workdir.js +8 -0
  238. package/dist/interfaces/i-xkb-model.d.ts +24 -0
  239. package/dist/interfaces/i-xkb-model.js +8 -0
  240. package/dist/interfaces/index.d.ts +25 -0
  241. package/dist/interfaces/index.js +8 -0
  242. package/dist/krill/modules/add-user.d.ts +20 -0
  243. package/dist/krill/modules/add-user.js +48 -0
  244. package/dist/krill/modules/bootloader-config.d.ts +14 -0
  245. package/dist/krill/modules/bootloader-config.js +165 -0
  246. package/dist/krill/modules/bootloader.d.ts +14 -0
  247. package/dist/krill/modules/bootloader.js +157 -0
  248. package/dist/krill/modules/change-password.d.ts +15 -0
  249. package/dist/krill/modules/change-password.js +18 -0
  250. package/dist/krill/modules/del-live-user.d.ts +14 -0
  251. package/dist/krill/modules/del-live-user.js +39 -0
  252. package/dist/krill/modules/fstab.d.ts +14 -0
  253. package/dist/krill/modules/fstab.js +123 -0
  254. package/dist/krill/modules/grubcfg.d.ts +17 -0
  255. package/dist/krill/modules/grubcfg.js +29 -0
  256. package/dist/krill/modules/hostname.d.ts +13 -0
  257. package/dist/krill/modules/hostname.js +50 -0
  258. package/dist/krill/modules/initramfs-cfg.d.ts +14 -0
  259. package/dist/krill/modules/initramfs-cfg.js +22 -0
  260. package/dist/krill/modules/initramfs.d.ts +13 -0
  261. package/dist/krill/modules/initramfs.js +54 -0
  262. package/dist/krill/modules/locale-cfg.d.ts +10 -0
  263. package/dist/krill/modules/locale-cfg.js +58 -0
  264. package/dist/krill/modules/locale.d.ts +13 -0
  265. package/dist/krill/modules/locale.js +91 -0
  266. package/dist/krill/modules/m-keyboard.d.ts +14 -0
  267. package/dist/krill/modules/m-keyboard.js +58 -0
  268. package/dist/krill/modules/machine-id.d.ts +15 -0
  269. package/dist/krill/modules/machine-id.js +33 -0
  270. package/dist/krill/modules/mkfs.d.ts +15 -0
  271. package/dist/krill/modules/mkfs.js +50 -0
  272. package/dist/krill/modules/mount-fs.d.ts +17 -0
  273. package/dist/krill/modules/mount-fs.js +62 -0
  274. package/dist/krill/modules/mount-vfs.d.ts +17 -0
  275. package/dist/krill/modules/mount-vfs.js +40 -0
  276. package/dist/krill/modules/network-cfg.d.ts +19 -0
  277. package/dist/krill/modules/network-cfg.js +64 -0
  278. package/dist/krill/modules/packages.d.ts +14 -0
  279. package/dist/krill/modules/packages.js +111 -0
  280. package/dist/krill/modules/partition.d.ts +20 -0
  281. package/dist/krill/modules/partition.js +324 -0
  282. package/dist/krill/modules/remove-installer-link.d.ts +13 -0
  283. package/dist/krill/modules/remove-installer-link.js +35 -0
  284. package/dist/krill/modules/umount.d.ts +14 -0
  285. package/dist/krill/modules/umount.js +28 -0
  286. package/dist/krill/modules/unpackfs.d.ts +13 -0
  287. package/dist/krill/modules/unpackfs.js +20 -0
  288. package/dist/krill/prepare.d.ts +78 -0
  289. package/dist/krill/prepare.js +624 -0
  290. package/dist/krill/sequence.d.ts +154 -0
  291. package/dist/krill/sequence.js +652 -0
  292. package/dist/lib/get_address.d.ts +8 -0
  293. package/dist/lib/get_address.js +23 -0
  294. package/dist/lib/get_dns.d.ts +8 -0
  295. package/dist/lib/get_dns.js +23 -0
  296. package/dist/lib/get_domain.d.ts +8 -0
  297. package/dist/lib/get_domain.js +23 -0
  298. package/dist/lib/get_gateway.d.ts +8 -0
  299. package/dist/lib/get_gateway.js +23 -0
  300. package/dist/lib/get_hostname.d.ts +8 -0
  301. package/dist/lib/get_hostname.js +23 -0
  302. package/dist/lib/get_netmask.d.ts +8 -0
  303. package/dist/lib/get_netmask.js +23 -0
  304. package/dist/lib/get_password.d.ts +8 -0
  305. package/dist/lib/get_password.js +36 -0
  306. package/dist/lib/get_userfullname.d.ts +8 -0
  307. package/dist/lib/get_userfullname.js +23 -0
  308. package/dist/lib/get_username.d.ts +8 -0
  309. package/dist/lib/get_username.js +23 -0
  310. package/dist/lib/kill_me_softly.d.ts +11 -0
  311. package/dist/lib/kill_me_softly.js +61 -0
  312. package/dist/lib/select_address_type.d.ts +8 -0
  313. package/dist/lib/select_address_type.js +24 -0
  314. package/dist/lib/select_filesystem_type.d.ts +8 -0
  315. package/dist/lib/select_filesystem_type.js +46 -0
  316. package/dist/lib/select_installation_device.d.ts +8 -0
  317. package/dist/lib/select_installation_device.js +30 -0
  318. package/dist/lib/select_installation_mode.d.ts +8 -0
  319. package/dist/lib/select_installation_mode.js +24 -0
  320. package/dist/lib/select_interface.d.ts +8 -0
  321. package/dist/lib/select_interface.js +24 -0
  322. package/dist/lib/select_keyboard_layout.d.ts +11 -0
  323. package/dist/lib/select_keyboard_layout.js +36 -0
  324. package/dist/lib/select_keyboard_model.d.ts +11 -0
  325. package/dist/lib/select_keyboard_model.js +34 -0
  326. package/dist/lib/select_keyboard_option.d.ts +11 -0
  327. package/dist/lib/select_keyboard_option.js +34 -0
  328. package/dist/lib/select_keyboard_variant.d.ts +11 -0
  329. package/dist/lib/select_keyboard_variant.js +35 -0
  330. package/dist/lib/select_languages.d.ts +8 -0
  331. package/dist/lib/select_languages.js +28 -0
  332. package/dist/lib/select_regions.d.ts +8 -0
  333. package/dist/lib/select_regions.js +24 -0
  334. package/dist/lib/select_user_swap_choice.d.ts +8 -0
  335. package/dist/lib/select_user_swap_choice.js +34 -0
  336. package/dist/lib/select_zones.d.ts +8 -0
  337. package/dist/lib/select_zones.js +518 -0
  338. package/dist/lib/utils.d.ts +34 -0
  339. package/dist/lib/utils.js +79 -0
  340. package/dist/penguins-eggs-tarball-10.0.54-1-linux-x64.tar.gz +0 -0
  341. package/package.json +11 -7
  342. package/scripts/_eggs +10 -1
  343. package/scripts/eggs.bash +1 -0
  344. /package/addons/eggs/theme/livecd/{grub.main.cfg → grub.main.full.cfg} +0 -0
@@ -0,0 +1,1849 @@
1
+ /**
2
+ * ./src/classes/ovary.ts
3
+ * penguins-eggs v.10.0.0 / ecmascript 2020
4
+ * author: Piero Proietti
5
+ * email: piero.proietti@gmail.com
6
+ * license: MIT
7
+ */
8
+ import chalk from 'chalk';
9
+ import yaml from 'js-yaml';
10
+ import mustache from 'mustache';
11
+ // packages
12
+ import fs from 'node:fs';
13
+ import { constants } from 'node:fs';
14
+ // backup
15
+ import { access } from 'node:fs/promises';
16
+ import os from 'node:os';
17
+ import path from 'node:path';
18
+ import shx from 'shelljs';
19
+ // libraries
20
+ import { exec } from '../lib/utils.js';
21
+ import Bleach from './bleach.js';
22
+ import CliAutologin from './cli-autologin.js';
23
+ import { displaymanager } from './incubation/fisherman-helper/displaymanager.js';
24
+ import Incubator from './incubation/incubator.js';
25
+ import Pacman from './pacman.js';
26
+ import PveLive from './pve-live.js';
27
+ import Settings from './settings.js';
28
+ import Systemctl from './systemctl.js';
29
+ import Users from './users.js';
30
+ import Diversions from './diversions.js';
31
+ // classes
32
+ import Utils from './utils.js';
33
+ import Xdg from './xdg.js';
34
+ import Repo from './yolk.js';
35
+ // _dirname
36
+ const __dirname = path.dirname(new URL(import.meta.url).pathname);
37
+ /**
38
+ * Ovary:
39
+ */
40
+ export default class Ovary {
41
+ cliAutologin = new CliAutologin();
42
+ clone = false;
43
+ compression = '';
44
+ cryptedclone = false;
45
+ echo = {};
46
+ familyId = '';
47
+ genisoimage = false;
48
+ incubator = {};
49
+ nest = '';
50
+ settings = {};
51
+ snapshot_basename = '';
52
+ snapshot_prefix = '';
53
+ theme = '';
54
+ toNull = '';
55
+ verbose = false;
56
+ volid = '';
57
+ /**
58
+ * Add or remove exclusion
59
+ * @param add {boolean} true = add, false remove
60
+ * @param exclusion {string} path to add/remove
61
+ */
62
+ addRemoveExclusion(add, exclusion) {
63
+ if (this.verbose) {
64
+ console.log('Ovary: addRemoveExclusion');
65
+ }
66
+ if (exclusion.startsWith('/')) {
67
+ exclusion = exclusion.slice(1); // remove / initial Non compatible with rsync
68
+ }
69
+ if (add) {
70
+ this.settings.session_excludes += this.settings.session_excludes === '' ? `-e '${exclusion}' ` : ` '${exclusion}' `;
71
+ }
72
+ else {
73
+ this.settings.session_excludes.replace(` '${exclusion}'`, '');
74
+ if (this.settings.session_excludes === '-e') {
75
+ this.settings.session_excludes = '';
76
+ }
77
+ }
78
+ }
79
+ /**
80
+ * Esegue il bind del fs live e
81
+ * crea lo script bind
82
+ *
83
+ * @param verbose
84
+ */
85
+ async bindLiveFs() {
86
+ if (this.verbose) {
87
+ console.log('Ovary: bindLiveFs');
88
+ }
89
+ /**
90
+ * dirs = readdirsync /
91
+ */
92
+ const dirs = fs.readdirSync('/');
93
+ const startLine = '#############################################################';
94
+ const titleLine = '# ---------------------------------------------------------';
95
+ const endLine = '# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n';
96
+ let lnkDest = '';
97
+ let cmd = '';
98
+ const cmds = [];
99
+ cmds.push('# NOTE: cdrom, dev, live, media, mnt, proc, run, sys and tmp', `# need just a mkdir in ${this.settings.work_dir.merged}`);
100
+ cmds.push(`# host: ${os.hostname()} user: ${await Utils.getPrimaryUser()}\n`);
101
+ for (const dir of dirs) {
102
+ cmds.push(startLine);
103
+ let statDir = fs.lstatSync(`/${dir}`);
104
+ /**
105
+ * Link
106
+ */
107
+ if (statDir.isSymbolicLink()) {
108
+ lnkDest = fs.readlinkSync(`/${dir}`);
109
+ 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);
110
+ if (fs.existsSync(`${this.settings.work_dir.merged}/${dir}`)) {
111
+ cmds.push('# SymbolicLink exist... skip');
112
+ }
113
+ else if (fs.existsSync(lnkDest)) {
114
+ cmds.push(`ln -s ${this.settings.work_dir.merged}/${lnkDest} ${this.settings.work_dir.merged}/${lnkDest}`);
115
+ }
116
+ else {
117
+ cmds.push(await rexec(`cp -r /${dir} ${this.settings.work_dir.merged}`, this.verbose));
118
+ }
119
+ /**
120
+ * Directory
121
+ */
122
+ }
123
+ else if (statDir.isDirectory()) {
124
+ if (dir === 'boot') {
125
+ cmds.push(`# /boot is copied actually`);
126
+ cmds.push(await rexec(`cp -r /boot ${this.settings.config.snapshot_mnt}filesystem.squashfs`, this.verbose));
127
+ }
128
+ if (dir !== 'boot' && dir !== 'lost+found') {
129
+ cmd = `# /${dir} is a directory`;
130
+ if (this.mergedAndOverlay(dir)) {
131
+ /**
132
+ * mergedAndOverlay creazione directory, overlay e mount rw
133
+ */
134
+ cmds.push(`${cmd} need to be present, and rw`, titleLine, '# create mountpoint lower');
135
+ cmds.push(await makeIfNotExist(`${this.settings.work_dir.lowerdir}/${dir}`), `# first: mount /${dir} rw in ${this.settings.work_dir.lowerdir}/${dir}`);
136
+ cmds.push(await rexec(`mount --bind --make-slave /${dir} ${this.settings.work_dir.lowerdir}/${dir}`, this.verbose), '# now remount it ro');
137
+ 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}`);
138
+ cmds.push(await makeIfNotExist(`${this.settings.work_dir.upperdir}/${dir}`, this.verbose));
139
+ cmds.push(await makeIfNotExist(`${this.settings.work_dir.workdir}/${dir}`, this.verbose));
140
+ cmds.push(await makeIfNotExist(`${this.settings.work_dir.merged}/${dir}`, this.verbose), `\n# thirth: mount /${dir} rw in ${this.settings.work_dir.merged}`);
141
+ 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));
142
+ }
143
+ else if (this.merged(dir)) {
144
+ /*
145
+ * merged creazione della directory e mount ro
146
+ */
147
+ cmds.push(`${cmd} need to be present, mount ro`, titleLine);
148
+ cmds.push(await makeIfNotExist(`${this.settings.work_dir.merged}/${dir}`, this.verbose));
149
+ cmds.push(await rexec(`mount --bind --make-slave /${dir} ${this.settings.work_dir.merged}/${dir}`, this.verbose));
150
+ cmds.push(await rexec(`mount -o remount,bind,ro ${this.settings.work_dir.merged}/${dir}`, this.verbose));
151
+ }
152
+ else {
153
+ /**
154
+ * normal solo la creazione della directory, nessun mount
155
+ */
156
+ cmds.push(`${cmd} need to be present, no mount`, titleLine);
157
+ cmds.push(await makeIfNotExist(`${this.settings.work_dir.merged}/${dir}`, this.verbose), `# mount -o bind /${dir} ${this.settings.work_dir.merged}/${dir}`);
158
+ }
159
+ }
160
+ /**
161
+ * File
162
+ */
163
+ }
164
+ else if (statDir.isFile()) {
165
+ cmds.push(`# /${dir} is just a file`, titleLine);
166
+ if (fs.existsSync(`${this.settings.work_dir.merged}/${dir}`)) {
167
+ cmds.push('# file exist... skip');
168
+ }
169
+ else {
170
+ cmds.push(await rexec(`cp /${dir} ${this.settings.work_dir.merged}`, this.verbose));
171
+ }
172
+ }
173
+ cmds.push(endLine);
174
+ }
175
+ // Utils.writeXs(`${this.settings.config.snapshot_dir}bind`, cmds)
176
+ Utils.writeXs(`${this.settings.work_dir.ovarium}bind`, cmds);
177
+ }
178
+ /**
179
+ * bind dei virtual file system
180
+ */
181
+ async bindVfs() {
182
+ if (this.verbose) {
183
+ console.log('Ovary: bindVfs');
184
+ }
185
+ const cmds = [];
186
+ 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`);
187
+ // Utils.writeXs(`${this.settings.config.snapshot_dir}bindvfs`, cmds)
188
+ Utils.writeXs(`${this.settings.work_dir.ovarium}bindvfs`, cmds);
189
+ }
190
+ /**
191
+ *
192
+ * @param verbose
193
+ */
194
+ async cleanUsersAccounts() {
195
+ if (this.verbose) {
196
+ console.log('Ovary: cleanUsersAccounts');
197
+ }
198
+ /**
199
+ * delete all user in chroot
200
+ */
201
+ const cmds = [];
202
+ const cmd = `chroot ${this.settings.work_dir.merged} getent passwd {1000..60000} |awk -F: '{print $1}'`;
203
+ const result = await exec(cmd, {
204
+ capture: true,
205
+ echo: this.verbose,
206
+ ignore: false
207
+ });
208
+ const users = result.data.split('\n');
209
+ let deluser = Diversions.deluser(this.familyId);
210
+ for (let i = 0; i < users.length - 1; i++) {
211
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} ${deluser} ${users[i]}`, this.verbose));
212
+ }
213
+ }
214
+ /**
215
+ * list degli utenti: grep -E 1[0-9]{3} /etc/passwd | sed s/:/\ / | awk '{print $1}'
216
+ * create la home per user_opt
217
+ * @param verbose
218
+ */
219
+ async createUserLive() {
220
+ if (this.verbose) {
221
+ console.log('Ovary: createUserLive');
222
+ }
223
+ const cmds = [];
224
+ cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' rm /home/' + this.settings.config.user_opt + ' -rf', this.verbose));
225
+ cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' mkdir /home/' + this.settings.config.user_opt, this.verbose));
226
+ // Create user using useradd
227
+ 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));
228
+ // live password don't work with SELINUX
229
+ 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));
230
+ // root password Don't work with SELINUX
231
+ 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));
232
+ // Alpine naked don't have /etc/skel
233
+ if (fs.existsSync('/etc/skel')) {
234
+ cmds.push(await rexec('chroot ' + this.settings.work_dir.merged + ' cp /etc/skel/. /home/' + this.settings.config.user_opt + ' -R', this.verbose));
235
+ }
236
+ // da problemi con il mount sshfs
237
+ 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));
238
+ switch (this.familyId) {
239
+ case 'debian': {
240
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG sudo ${this.settings.config.user_opt}`, this.verbose));
241
+ break;
242
+ }
243
+ case 'alpine': {
244
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG cdrom ${this.settings.config.user_opt}`, this.verbose));
245
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG games ${this.settings.config.user_opt}`, this.verbose));
246
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG input ${this.settings.config.user_opt}`, this.verbose));
247
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG users ${this.settings.config.user_opt}`, this.verbose));
248
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG video ${this.settings.config.user_opt}`, this.verbose));
249
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG wheel ${this.settings.config.user_opt}`, this.verbose));
250
+ break;
251
+ }
252
+ case 'archlinux': {
253
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} gpasswd -a ${this.settings.config.user_opt} wheel`, this.verbose));
254
+ // check or create group: autologin
255
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} getent group autologin || chroot ${this.settings.work_dir.merged} groupadd autologin`, this.verbose));
256
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} gpasswd -a ${this.settings.config.user_opt} autologin`, this.verbose));
257
+ break;
258
+ }
259
+ case 'fedora': {
260
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG wheel ${this.settings.config.user_opt}`, this.verbose));
261
+ break;
262
+ }
263
+ case 'openmamba': {
264
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG sysadmin ${this.settings.config.user_opt}`, this.verbose));
265
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG autologin ${this.settings.config.user_opt}`, this.verbose));
266
+ break;
267
+ }
268
+ // No default
269
+ }
270
+ /**
271
+ * educaandos and others themes
272
+ * users.yml
273
+ */
274
+ let usersConf = path.resolve(__dirname, `../../addons/${this.theme}/theme/calamares/users.yml`);
275
+ if (this.theme.includes('/')) {
276
+ usersConf = `${this.theme}/theme/calamares/modules/users.yml`;
277
+ }
278
+ if (fs.existsSync(usersConf)) {
279
+ const o = yaml.load(fs.readFileSync(usersConf, 'utf8'));
280
+ for (const group of o.defaultGroups) {
281
+ cmds.push(await rexec(`chroot ${this.settings.work_dir.merged} usermod -aG ${group} ${this.settings.config.user_opt}`, this.verbose));
282
+ }
283
+ }
284
+ }
285
+ /**
286
+ *
287
+ */
288
+ async createXdgAutostart(theme = 'eggs', myAddons, myLinks = [], noicons = false) {
289
+ if (this.verbose) {
290
+ console.log('Ovary: createXdgAutostart');
291
+ }
292
+ const pathHomeLive = `/home/${this.settings.config.user_opt}`;
293
+ // VOGLIO le icone
294
+ // Copia icona penguins-eggs
295
+ shx.cp(path.resolve(__dirname, '../../assets/eggs.png'), '/usr/share/icons/');
296
+ shx.cp(path.resolve(__dirname, '../../assets/krill.svg'), '/usr/share/icons/');
297
+ shx.cp(path.resolve(__dirname, '../../assets/leaves.svg'), '/usr/share/icons/');
298
+ /**
299
+ * creazione dei link in /usr/share/applications
300
+ */
301
+ shx.cp(path.resolve(__dirname, '../../assets/penguins-eggs.desktop'), '/usr/share/applications/');
302
+ /**
303
+ * Scrivania/install-system.desktop
304
+ */
305
+ let installerLink = 'install-system.desktop';
306
+ if (Pacman.calamaresExists()) {
307
+ /**
308
+ * Replace Exec in install-system.desktop per biglinux e bigcommunity
309
+ */
310
+ if (this.settings.distro.distroId === 'BigLinux' || this.settings.distro.distroId === 'BigCommunity') {
311
+ let installSystemDesktop = path.resolve(__dirname, `../../addons/${theme}/theme/applications/install-system.desktop`);
312
+ await exec(`sed -i 's|^Exec=.*|Exec=/usr/bin/calamares_polkit %f|' ${installSystemDesktop}`);
313
+ }
314
+ shx.cp(path.resolve(__dirname, `../../addons/${theme}/theme/applications/install-system.desktop`), `${this.settings.work_dir.merged}/usr/share/applications/`);
315
+ }
316
+ else if (Pacman.packageIsInstalled('live-installer')) {
317
+ /**
318
+ * LMD£ live-installer
319
+ */
320
+ const policySource = path.resolve(__dirname, '../../assets/live-installer/com.github.pieroproietti.penguins-eggs.policy');
321
+ const policyDest = '/usr/share/polkit-1/actions/com.github.pieroproietti.penguins-eggs.policy';
322
+ shx.cp(policySource, policyDest);
323
+ await exec(`sed -i 's/auth_admin/yes/' ${policyDest}`);
324
+ // carico in filesystem.live packages-remove
325
+ shx.cp(path.resolve(__dirname, '../../assets/live-installer/filesystem.packages-remove'), `${this.settings.iso_work}/live/`);
326
+ shx.touch(`${this.settings.iso_work}/live/filesystem.packages`);
327
+ installerLink = 'penguins-live-installer.desktop';
328
+ shx.cp(path.resolve(__dirname, '../../assets/penguins-live-installer.desktop'), `${this.settings.work_dir.merged}/usr/share/applications/`);
329
+ }
330
+ else if (Pacman.packageIsInstalled('ubiquity')) {
331
+ /**
332
+ * UBUNTU ubiquity
333
+ */
334
+ const policySource = path.resolve(__dirname, '../../assets/ubiquity-installer/com.github.pieroproietti.penguins-eggs.policy');
335
+ const policyDest = '/usr/share/polkit-1/actions/com.github.pieroproietti.penguins-eggs.policy';
336
+ shx.cp(policySource, policyDest);
337
+ await exec(`sed -i 's/auth_admin/yes/' ${policyDest}`);
338
+ // carico in filesystem.live packages-remove
339
+ shx.cp(path.resolve(__dirname, '../../assets/ubiquity-installer/filesystem.packages-remove'), `${this.settings.iso_work}/live/`);
340
+ shx.touch(`${this.settings.iso_work}/live/filesystem.packages`);
341
+ installerLink = 'penguins-ubiquity-installer.desktop';
342
+ shx.cp(path.resolve(__dirname, '../../assets/penguins-ubiquity-installer.desktop'), `${this.settings.work_dir.merged}/usr/share/applications/`);
343
+ }
344
+ else {
345
+ installerLink = 'penguins-krill.desktop';
346
+ shx.cp(path.resolve(__dirname, '../../assets/penguins-krill.desktop'), `${this.settings.work_dir.merged}/usr/share/applications/`);
347
+ }
348
+ /**
349
+ * flags
350
+ */
351
+ // adapt
352
+ if (myAddons.adapt) {
353
+ const dirAddon = path.resolve(__dirname, '../../addons/eggs/adapt/');
354
+ shx.cp(`${dirAddon}/applications/eggs-adapt.desktop`, `${this.settings.work_dir.merged}/usr/share/applications/`);
355
+ }
356
+ // pve
357
+ if (myAddons.pve) {
358
+ /**
359
+ * create service pve-live
360
+ */
361
+ const pve = new PveLive();
362
+ pve.create(this.settings.work_dir.merged);
363
+ /**
364
+ * adding a desktop link for pve
365
+ */
366
+ const dirAddon = path.resolve(__dirname, '../../addons/eggs/pve');
367
+ shx.cp(`${dirAddon}/artwork/eggs-pve.png`, `${this.settings.work_dir.merged}/usr/share/icons/`);
368
+ shx.cp(`${dirAddon}/applications/eggs-pve.desktop`, `${this.settings.work_dir.merged}/usr/share/applications/`);
369
+ }
370
+ // rsupport
371
+ if (myAddons.rsupport) {
372
+ const dirAddon = path.resolve(__dirname, '../../addons/eggs/rsupport');
373
+ shx.cp(`${dirAddon}/applications/eggs-rsupport.desktop`, `${this.settings.work_dir.merged}/usr/share/applications/`);
374
+ shx.cp(`${dirAddon}/artwork/eggs-rsupport.png`, `${this.settings.work_dir.merged}/usr/share/icons/`);
375
+ }
376
+ /**
377
+ * configuro add-penguins-desktop-icons in /etc/xdg/autostart
378
+ */
379
+ const dirAutostart = `${this.settings.work_dir.merged}/etc/xdg/autostart`;
380
+ if (fs.existsSync(dirAutostart)) {
381
+ // Creo l'avviatore xdg: DEVE essere add-penguins-links.desktop
382
+ shx.cp(path.resolve(__dirname, '../../assets/penguins-links-add.desktop'), dirAutostart);
383
+ // create /usr/bin/penguins-links-add.sh
384
+ const script = '/usr/bin/penguins-links-add.sh';
385
+ let text = '';
386
+ text += '#!/bin/sh\n';
387
+ text += 'DESKTOP=$(xdg-user-dir DESKTOP)\n';
388
+ text += 'while [ ! -d "$DESKTOP" ]; do\n';
389
+ text += ' DESKTOP=$(xdg-user-dir DESKTOP)\n';
390
+ text += ' sleep 1\n';
391
+ text += 'done\n';
392
+ text += `cp /usr/share/applications/${installerLink} "$DESKTOP"\n`;
393
+ if (Pacman.packageIsInstalled('lxde-core')) {
394
+ if (!noicons) {
395
+ text += this.lxdeLink('penguins-eggs.desktop', "Penguins' eggs", 'eggs');
396
+ }
397
+ if (myAddons.adapt)
398
+ text += this.lxdeLink('eggs-adapt.desktop', 'Adapt', 'video-display');
399
+ if (myAddons.pve)
400
+ text += this.lxdeLink('eggs-pve.desktop', 'Proxmox VE', 'proxmox-ve');
401
+ if (myAddons.rsupport)
402
+ text += this.lxdeLink('eggs-rsupport.desktop', 'Remote assistance', 'remote-assistance');
403
+ }
404
+ else {
405
+ if (!noicons) {
406
+ text += 'cp /usr/share/applications/penguins-eggs.desktop "$DESKTOP"\n';
407
+ }
408
+ if (myLinks.length > 0) {
409
+ for (const link of myLinks) {
410
+ text += `cp /usr/share/applications/${link}.desktop "$DESKTOP"\n`;
411
+ }
412
+ }
413
+ if (myAddons.adapt)
414
+ text += 'cp /usr/share/applications/eggs-adapt.desktop "$DESKTOP"\n';
415
+ if (myAddons.pve)
416
+ text += 'cp /usr/share/applications/eggs-pve.desktop "$DESKTOP"\n';
417
+ if (myAddons.rsupport)
418
+ text += 'cp /usr/share/applications/eggs-rsupport.desktop "$DESKTOP"\n';
419
+ }
420
+ /**
421
+ * enable desktop links
422
+ */
423
+ if (Pacman.packageIsInstalled('gdm3') || Pacman.packageIsInstalled('gdm')) {
424
+ // GNOME
425
+ text += 'test -f /usr/share/applications/penguins-eggs.desktop && cp /usr/share/applications/penguins-eggs.desktop "$DESKTOP"\n';
426
+ text += 'test -f "$DESKTOP"/op && chmod a+x "$DESKTOP"/penguins-eggs.desktop\n';
427
+ text += 'test -f "$DESKTOP"/penguins-eggs.desktop && gio set "$DESKTOP"/penguins-eggs.desktop metadata::trusted true\n';
428
+ text += `test -f /usr/share/applications/${installerLink} && cp /usr/share/applications/${installerLink} "$DESKTOP"\n`;
429
+ text += `test -f "$DESKTOP"/${installerLink} && chmod a+x "$DESKTOP"/${installerLink}\n`;
430
+ text += `test -f "$DESKTOP"/${installerLink} && gio set "$DESKTOP"/${installerLink} metadata::trusted true\n`;
431
+ }
432
+ else if (Pacman.packageIsInstalled('xfce4-session')) {
433
+ text += `# xfce: enable-desktop-links\n`;
434
+ text += `for f in "$DESKTOP"/*.desktop; do chmod +x "$f"; gio set -t string "$f" metadata::xfce-exe-checksum "$(sha256sum "$f" | awk '{print $1}')"; done\n`;
435
+ }
436
+ else {
437
+ text += `# others: enable-desktop-links\n`;
438
+ text += 'chmod +x "$DESKTOP"/*.desktop\n';
439
+ }
440
+ fs.writeFileSync(script, text, 'utf8');
441
+ await exec(`chmod a+x ${script}`, this.echo);
442
+ }
443
+ await Xdg.autologin(await Utils.getPrimaryUser(), this.settings.config.user_opt, this.settings.work_dir.merged);
444
+ }
445
+ /**
446
+ * editLiveFs
447
+ * - Truncate logs, remove archived log
448
+ * - Allow all fixed drives to be mounted with pmount
449
+ * - Enable or disable password login trhough ssh for users (not root)
450
+ * - Create an empty /etc/fstab
451
+ * - Blanck /etc/machine-id
452
+ * - Add some basic files to /dev
453
+ * - Clear configs from /etc/network/interfaces, wicd and NetworkManager and netman
454
+ */
455
+ async editLiveFs(clone = false, cryptedclone = false) {
456
+ if (this.verbose) {
457
+ console.log('Ovary: editLiveFs');
458
+ }
459
+ /**
460
+ * /etc/penguins-eggs.d/is_clone file created on live
461
+ */
462
+ if (clone) {
463
+ await exec(`touch ${this.settings.work_dir.merged}/etc/penguins-eggs.d/is_clone`, this.echo);
464
+ }
465
+ /**
466
+ * /etc/penguins-eggs.d/is_crypted_clone file created on live
467
+ */
468
+ if (cryptedclone) {
469
+ await exec(`touch ${this.settings.work_dir.merged}/etc/penguins-eggs.d/is_crypted_clone`, this.echo);
470
+ }
471
+ /**
472
+ * /etc/default/epoptes-client created on live
473
+ */
474
+ if (Pacman.packageIsInstalled('epoptes')) {
475
+ const file = `${this.settings.work_dir.merged}/etc/default/epoptes-client`;
476
+ const text = `SERVER=${os.hostname}.local\n`;
477
+ fs.writeFileSync(file, text);
478
+ }
479
+ if (this.familyId === 'debian') {
480
+ // Aggiungo UMASK=0077 in /etc/initramfs-tools/conf.d/calamares-safe-initramfs.conf
481
+ const text = 'UMASK=0077\n';
482
+ const file = '/etc/initramfs-tools/conf.d/eggs-safe-initramfs.conf';
483
+ Utils.write(file, text);
484
+ }
485
+ // Truncate logs, remove archived logs.
486
+ let cmd = `find ${this.settings.work_dir.merged}/var/log -name "*gz" -print0 | xargs -0r rm -f`;
487
+ await exec(cmd, this.echo);
488
+ cmd = `find ${this.settings.work_dir.merged}/var/log/ -type f -exec truncate -s 0 {} \\;`;
489
+ await exec(cmd, this.echo);
490
+ // Allow all fixed drives to be mounted with pmount
491
+ if (this.settings.config.pmount_fixed && fs.existsSync(`${this.settings.work_dir.merged}/etc/pmount.allow`)) {
492
+ // MX aggiunto /etc
493
+ await exec(`sed -i 's:#/dev/sd\[a-z\]:/dev/sd\[a-z\]:' ${this.settings.work_dir.merged}/etc/pmount.allow`, this.echo);
494
+ }
495
+ // Remove obsolete live-config file
496
+ if (fs.existsSync(`${this.settings.work_dir.merged}lib/live/config/1161-openssh-server`)) {
497
+ await exec(`rm -f ${this.settings.work_dir.merged}/lib/live/config/1161-openssh-server`, this.echo);
498
+ }
499
+ if (fs.existsSync(`${this.settings.work_dir.merged}/etc/ssh/sshd_config`)) {
500
+ /**
501
+ * enable/disable SSH root/users password login
502
+ */
503
+ await exec(`sed -i '/PermitRootLogin/d' ${this.settings.work_dir.merged}/etc/ssh/sshd_config`);
504
+ await exec(`sed -i '/PasswordAuthentication/d' ${this.settings.work_dir.merged}/etc/ssh/sshd_config`);
505
+ if (this.settings.config.ssh_pass) {
506
+ await exec(`echo 'PasswordAuthentication yes' | tee -a ${this.settings.work_dir.merged}/etc/ssh/sshd_config`, this.echo);
507
+ }
508
+ else {
509
+ await exec(`echo 'PermitRootLogin prohibit-password' | tee -a ${this.settings.work_dir.merged}/etc/ssh/sshd_config`, this.echo);
510
+ await exec(`echo 'PasswordAuthentication no' | tee -a ${this.settings.work_dir.merged}/etc/ssh/sshd_config`, this.echo);
511
+ }
512
+ }
513
+ /**
514
+ * ufw --force reset
515
+ */
516
+ // if (Pacman.packageIsInstalled('ufw')) {
517
+ // await exec('ufw --force reset')
518
+ // }
519
+ /**
520
+ * /etc/fstab should exist, even if it's empty,
521
+ * to prevent error messages at boot
522
+ */
523
+ await exec(`rm ${this.settings.work_dir.merged}/etc/fstab`, this.echo);
524
+ await exec(`touch ${this.settings.work_dir.merged}/etc/fstab`, this.echo);
525
+ /**
526
+ * Remove crypttab if exists
527
+ * this is crucial for tpm systems.
528
+ */
529
+ if (fs.existsSync(`${this.settings.work_dir.merged}/etc/crypttab`)) {
530
+ await exec(`rm ${this.settings.work_dir.merged}/etc/crypttab`, this.echo);
531
+ }
532
+ /**
533
+ * Blank out systemd machine id.
534
+ * If it does not exist, systemd-journald will fail,
535
+ * but if it exists and is empty, systemd will automatically
536
+ * set up a new unique ID.
537
+ */
538
+ if (fs.existsSync(`${this.settings.work_dir.merged}/etc/machine-id`)) {
539
+ await exec(`rm ${this.settings.work_dir.merged}/etc/machine-id`, this.echo);
540
+ await exec(`touch ${this.settings.work_dir.merged}/etc/machine-id`, this.echo);
541
+ Utils.write(`${this.settings.work_dir.merged}/etc/machine-id`, ':');
542
+ }
543
+ /**
544
+ * LMDE4: utilizza UbuntuMono16.pf2
545
+ * aggiungo un link a /boot/grub/fonts/UbuntuMono16.pf2
546
+ */
547
+ if (fs.existsSync(`${this.settings.work_dir.merged}/boot/grub/fonts/unicode.pf2`)) {
548
+ shx.cp(`${this.settings.work_dir.merged}/boot/grub/fonts/unicode.pf2`, `${this.settings.work_dir.merged}/boot/grub/fonts/UbuntuMono16.pf2`);
549
+ }
550
+ /**
551
+ * cleaning /etc/resolv.conf
552
+ */
553
+ const resolvFile = `${this.settings.work_dir.merged}/etc/resolv.conf`;
554
+ shx.rm(resolvFile);
555
+ /**
556
+ * Per tutte le distro systemd
557
+ */
558
+ if (Utils.isSystemd()) {
559
+ const systemdctl = new Systemctl(this.verbose);
560
+ /**
561
+ * systemd-systemd-resolved
562
+ */
563
+ let resolvContent = '';
564
+ if (await systemdctl.isActive('systemd-resolved.service')) {
565
+ await systemdctl.stop('systemd-resolved.service');
566
+ resolvContent = 'nameserver 127.0.0.53\noptions edns0 trust-ad\nsearch .\n';
567
+ }
568
+ fs.writeFileSync(resolvFile, resolvContent);
569
+ if (await systemdctl.isEnabled('systemd-networkd.service')) {
570
+ await systemdctl.disable('systemd-networkd.service', this.settings.work_dir.merged, true);
571
+ }
572
+ if (await systemdctl.isEnabled('remote-cryptsetup.target')) {
573
+ await systemdctl.disable('remote-cryptsetup.target', this.settings.work_dir.merged, true);
574
+ }
575
+ if (await systemdctl.isEnabled('speech-dispatcherd.service')) {
576
+ await systemdctl.disable('speech-dispatcherd.service', this.settings.work_dir.merged, true);
577
+ }
578
+ if (await systemdctl.isEnabled('wpa_supplicant-nl80211@.service')) {
579
+ await systemdctl.disable('wpa_supplicant-nl80211@.service', this.settings.work_dir.merged, true);
580
+ }
581
+ if (await systemdctl.isEnabled('wpa_supplicant@.service')) {
582
+ await systemdctl.disable('wpa_supplicant@.service', this.settings.work_dir.merged, true);
583
+ }
584
+ if (await systemdctl.isEnabled('wpa_supplicant-wired@.service')) {
585
+ await systemdctl.disable('wpa_supplicant-wired@.service', this.settings.work_dir.merged, true);
586
+ }
587
+ /**
588
+ * All systemd distros rm
589
+ */
590
+ await exec(`rm -f ${this.settings.work_dir.merged}/var/lib/wicd/configurations/*`, this.echo);
591
+ await exec(`rm -f ${this.settings.work_dir.merged}/etc/wicd/wireless-settings.conf`, this.echo);
592
+ await exec(`rm -f ${this.settings.work_dir.merged}/etc/NetworkManager/system-connections/*`, this.echo);
593
+ await exec(`rm -f ${this.settings.work_dir.merged}/etc/network/wifi/*`, this.echo);
594
+ /**
595
+ * removing from /etc/network/:
596
+ * if-down.d if-post-down.d if-pre-up.d if-up.d interfaces interfaces.d
597
+ */
598
+ const cleanDirs = ['if-down.d', 'if-post-down.d', 'if-pre-up.d', 'if-up.d', 'interfaces.d'];
599
+ let cleanDir = '';
600
+ for (cleanDir of cleanDirs) {
601
+ await exec(`rm -f ${this.settings.work_dir.merged}/etc/network/${cleanDir}/wpasupplicant`, this.echo);
602
+ }
603
+ }
604
+ /**
605
+ * Clear configs from /etc/network/interfaces, wicd and NetworkManager
606
+ * and netman, so they aren't stealthily included in the snapshot.
607
+ */
608
+ if (this.familyId === 'debian') {
609
+ if (fs.existsSync(`${this.settings.work_dir.merged}/etc/network/interfaces`)) {
610
+ await exec(`rm -f ${this.settings.work_dir.merged}/etc/network/interfaces`, this.echo);
611
+ Utils.write(`${this.settings.work_dir.merged}/etc/network/interfaces`, 'auto lo\niface lo inet loopback');
612
+ }
613
+ /**
614
+ * add some basic files to /dev
615
+ */
616
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/console`)) {
617
+ await exec(`mknod -m 622 ${this.settings.work_dir.merged}/dev/console c 5 1`, this.echo);
618
+ }
619
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/null`)) {
620
+ await exec(`mknod -m 666 ${this.settings.work_dir.merged}/dev/null c 1 3`, this.echo);
621
+ }
622
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/zero`)) {
623
+ await exec(`mknod -m 666 ${this.settings.work_dir.merged}/dev/zero c 1 5`, this.echo);
624
+ }
625
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/ptmx`)) {
626
+ await exec(`mknod -m 666 ${this.settings.work_dir.merged}/dev/ptmx c 5 2`, this.echo);
627
+ }
628
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/tty`)) {
629
+ await exec(`mknod -m 666 ${this.settings.work_dir.merged}/dev/tty c 5 0`, this.echo);
630
+ }
631
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/random`)) {
632
+ await exec(`mknod -m 444 ${this.settings.work_dir.merged}/dev/random c 1 8`, this.echo);
633
+ }
634
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/urandom`)) {
635
+ await exec(`mknod -m 444 ${this.settings.work_dir.merged}/dev/urandom c 1 9`, this.echo);
636
+ }
637
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/{console,ptmx,tty}`)) {
638
+ await exec(`chown -v root:tty ${this.settings.work_dir.merged}/dev/{console,ptmx,tty}`, this.echo);
639
+ }
640
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/fd`)) {
641
+ await exec(`ln -sv /proc/self/fd ${this.settings.work_dir.merged}/dev/fd`, this.echo);
642
+ }
643
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/stdin`)) {
644
+ await exec(`ln -sv /proc/self/fd/0 ${this.settings.work_dir.merged}/dev/stdin`, this.echo);
645
+ }
646
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/stdout`)) {
647
+ await exec(`ln -sv /proc/self/fd/1 ${this.settings.work_dir.merged}/dev/stdout`, this.echo);
648
+ }
649
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/stderr`)) {
650
+ await exec(`ln -sv /proc/self/fd/2 ${this.settings.work_dir.merged}/dev/stderr`, this.echo);
651
+ }
652
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/core`)) {
653
+ await exec(`ln -sv /proc/kcore ${this.settings.work_dir.merged}/dev/core`, this.echo);
654
+ }
655
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/shm`)) {
656
+ await exec(`mkdir -v ${this.settings.work_dir.merged}/dev/shm`, this.echo);
657
+ }
658
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/pts`)) {
659
+ await exec(`mkdir -v ${this.settings.work_dir.merged}/dev/pts`, this.echo);
660
+ }
661
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/dev/shm`)) {
662
+ await exec(`chmod 1777 ${this.settings.work_dir.merged}/dev/shm`, this.echo);
663
+ }
664
+ /**
665
+ * creo /tmp
666
+ */
667
+ if (!fs.existsSync(`${this.settings.work_dir.merged}/tmp`)) {
668
+ await exec(`mkdir ${this.settings.work_dir.merged}/tmp`, this.echo);
669
+ }
670
+ /**
671
+ * Assegno 1777 a /tmp creava problemi con MXLINUX
672
+ */
673
+ await exec(`chmod 1777 ${this.settings.work_dir.merged}/tmp`, this.echo);
674
+ }
675
+ }
676
+ /**
677
+ * @returns {boolean} success
678
+ */
679
+ async fertilization(snapshot_prefix = '', snapshot_basename = '', theme = '', compression = '', nointeratctive = false) {
680
+ this.settings = new Settings();
681
+ if (await this.settings.load()) {
682
+ await this.settings.loadRemix(this.theme);
683
+ this.volid = Utils.getVolid(this.settings.remix.name);
684
+ this.familyId = this.settings.distro.familyId;
685
+ this.nest = this.settings.config.snapshot_mnt;
686
+ if (snapshot_prefix !== '') {
687
+ this.settings.config.snapshot_prefix = snapshot_prefix;
688
+ }
689
+ if (snapshot_basename !== '') {
690
+ this.settings.config.snapshot_basename = snapshot_basename;
691
+ }
692
+ if (theme !== '') {
693
+ this.theme = theme;
694
+ }
695
+ if (compression !== '') {
696
+ this.settings.config.compression = compression;
697
+ }
698
+ if (!nointeratctive) {
699
+ return true;
700
+ }
701
+ this.settings.listFreeSpace();
702
+ if (await Utils.customConfirm('Select yes to continue...')) {
703
+ return true;
704
+ }
705
+ }
706
+ return false;
707
+ }
708
+ /**
709
+ * finished = show the results
710
+ * @param scriptOnly
711
+ */
712
+ finished(scriptOnly = false) {
713
+ Utils.titles('produce');
714
+ if (scriptOnly) {
715
+ console.log('eggs is finished!\n\nYou can find the scripts to build iso: ' + chalk.cyanBright(this.settings.isoFilename) + '\nin the ovarium: ' + chalk.cyanBright(this.settings.config.snapshot_dir) + '.');
716
+ console.log('usage');
717
+ console.log(chalk.cyanBright(`cd ${this.settings.config.snapshot_dir}`));
718
+ console.log(chalk.cyanBright('sudo ./bind'));
719
+ console.log('Make all yours modifications in the directories filesystem.squashfs and iso.');
720
+ console.log('After when you are ready:');
721
+ console.log(chalk.cyanBright('sudo ./mksquashfs'));
722
+ console.log(chalk.cyanBright('sudo ./mkisofs'));
723
+ console.log(chalk.cyanBright('sudo ./ubind'));
724
+ console.log('happy hacking!');
725
+ }
726
+ else {
727
+ console.log('eggs is finished!\n\nYou can find the file iso: ' + chalk.cyanBright(this.settings.isoFilename) + '\nin the nest: ' + chalk.cyanBright(this.settings.config.snapshot_dir) + '.');
728
+ }
729
+ console.log();
730
+ console.log('Remember, on liveCD user = ' + chalk.cyanBright(this.settings.config.user_opt) + '/' + chalk.cyanBright(this.settings.config.user_opt_passwd));
731
+ console.log(' root = ' + chalk.cyanBright('root') + '/' + chalk.cyanBright(this.settings.config.root_passwd));
732
+ if (this.genisoimage) {
733
+ console.log(`Note: format UDF, generated by ${chalk.cyanBright('genisoimage')}`);
734
+ }
735
+ }
736
+ /**
737
+ * mkinitfs()
738
+ */
739
+ async initrdAlpine() {
740
+ Utils.warning(`creating ${path.basename(this.settings.initrdImg)} Alpine on ISO/live`);
741
+ const sidecar = path.resolve(__dirname, `../../mkinitfs/initramfs-init.in`);
742
+ Utils.warning(`Adding ${sidecar} to /usr/share/mkinitfs/initramfs-init`);
743
+ await exec(`cp ${sidecar} /usr/share/mkinitfs/initramfs-init`);
744
+ let initrdImg = Utils.initrdImg();
745
+ initrdImg = initrdImg.slice(Math.max(0, initrdImg.lastIndexOf('/') + 1));
746
+ const pathConf = path.resolve(__dirname, `../../mkinitfs/live.conf`);
747
+ await exec(`mkinitfs -c ${pathConf} -o ${this.settings.iso_work}live/${initrdImg}`, Utils.setEcho(true));
748
+ }
749
+ /**
750
+ * mkinitcpio()
751
+ */
752
+ async initrdArch() {
753
+ let initrdImg = Utils.initrdImg();
754
+ initrdImg = initrdImg.slice(Math.max(0, initrdImg.lastIndexOf('/') + 1));
755
+ Utils.warning(`creating ${path.basename(this.settings.initrdImg)} using mkinitcpio on ISO/live`);
756
+ const { distroId } = this.settings.distro;
757
+ let fileConf = 'arch';
758
+ if (Diversions.isManjaroBased(distroId)) {
759
+ fileConf = 'manjarolinux';
760
+ if (distroId === "BigLinux" || distroId === "BigCommunity") {
761
+ fileConf = 'biglinux';
762
+ }
763
+ }
764
+ const pathConf = path.resolve(__dirname, `../../mkinitcpio/${fileConf}/live.conf`);
765
+ await exec(`mkinitcpio -c ${pathConf} -g ${this.settings.iso_work}live/${initrdImg}`, this.echo);
766
+ }
767
+ /**
768
+ * mkinitramfs() Debian
769
+ */
770
+ async initrdDebian(verbose = false) {
771
+ Utils.warning(`creating ${path.basename(this.settings.initrdImg)} using mkinitramfs on ISO/live`);
772
+ let isCrypted = false;
773
+ if (fs.existsSync('/etc/crypttab')) {
774
+ isCrypted = true;
775
+ await exec('mv /etc/crypttab /etc/crypttab.saved', this.echo);
776
+ }
777
+ await exec(`mkinitramfs -o ${this.settings.iso_work}/live/initrd.img-$(uname -r) ${this.toNull}`, this.echo);
778
+ if (isCrypted) {
779
+ await exec('mv /etc/crypttab.saved /etc/crypttab', this.echo);
780
+ }
781
+ }
782
+ /**
783
+ * dracut() Fedora/Openmamba/Opensuse/Voidlinux
784
+ */
785
+ async initrdDracut() {
786
+ Utils.warning(`creating ${path.basename(this.settings.initrdImg)} using dracut on ISO/live`);
787
+ const kernelVersion = shx.exec('uname -r', { silent: true }).stdout.trim();
788
+ const conf = path.resolve(__dirname, `../../dracut/dracut.conf`);
789
+ const confdir = path.resolve(__dirname, `../../dracut/dracut.conf.d`);
790
+ if (this.familyId === 'aldos') {
791
+ await exec(`dracut --force --confdir ${confdir} ${this.settings.iso_work}live/${this.settings.initrdImg}`, Utils.setEcho(true));
792
+ }
793
+ else {
794
+ await exec(`dracut --confdir ${confdir} ${this.settings.iso_work}live/${this.settings.initrdImg}`, this.echo);
795
+ }
796
+ }
797
+ /**
798
+ * syslinux: da syspath
799
+ */
800
+ async syslinux(theme = 'eggs') {
801
+ let syspath = path.resolve(__dirname, `../../syslinux`);
802
+ await exec(`cp ${syspath}/chain.c32 ${this.settings.iso_work}/isolinux/`, this.echo);
803
+ await exec(`cp ${syspath}/isohdpfx.bin ${this.settings.iso_work}/isolinux/`, this.echo);
804
+ // just fo x64 arch
805
+ await exec(`cp ${syspath}/isolinux.bin ${this.settings.iso_work}/isolinux/`, this.echo);
806
+ await exec(`cp ${syspath}/ldlinux.c32 ${this.settings.iso_work}/isolinux/`, this.echo);
807
+ await exec(`cp ${syspath}/libcom32.c32 ${this.settings.iso_work}/isolinux/`, this.echo);
808
+ await exec(`cp ${syspath}/libutil.c32 ${this.settings.iso_work}/isolinux/`, this.echo);
809
+ await exec(`cp ${syspath}/vesamenu.c32 ${this.settings.iso_work}/isolinux/`, this.echo);
810
+ const isolinuxThemeDest = this.settings.iso_work + 'isolinux/isolinux.theme.cfg';
811
+ let isolinuxThemeSrc = path.resolve(__dirname, `../../addons/${theme}/theme/livecd/isolinux.theme.cfg`);
812
+ if (this.theme.includes('/')) {
813
+ isolinuxThemeSrc = `${theme}/theme/livecd/isolinux.theme.cfg`;
814
+ }
815
+ if (!fs.existsSync(isolinuxThemeSrc)) {
816
+ Utils.warning('Cannot find: ' + isolinuxThemeSrc);
817
+ process.exit();
818
+ }
819
+ fs.copyFileSync(isolinuxThemeSrc, isolinuxThemeDest);
820
+ /**
821
+ * isolinux.cfg from isolinux.main.cfg
822
+ */
823
+ const isolinuxDest = `${this.settings.iso_work}/isolinux/isolinux.cfg`;
824
+ this.settings.iso_work + 'isolinux/isolinux.cfg';
825
+ let isolinuxTemplate = `${theme}/theme/livecd/isolinux.main.cfg`;
826
+ if (!fs.existsSync(isolinuxTemplate)) {
827
+ isolinuxTemplate = path.resolve(__dirname, '../../addons/eggs/theme/livecd/isolinux.main.cfg');
828
+ }
829
+ if (!fs.existsSync(isolinuxTemplate)) {
830
+ Utils.warning('Cannot find: ' + isolinuxTemplate);
831
+ process.exit();
832
+ }
833
+ const kernel_parameters = Diversions.kernelParameters(this.familyId, this.volid); // this.kernelParameters()
834
+ const template = fs.readFileSync(isolinuxTemplate, 'utf8');
835
+ const view = {
836
+ fullname: this.settings.remix.fullname.toUpperCase(),
837
+ initrdImg: `/live${this.settings.initrdImg}`,
838
+ kernel: Utils.kernelVersion(),
839
+ kernel_parameters,
840
+ vmlinuz: `/live${this.settings.vmlinuz}`
841
+ };
842
+ fs.writeFileSync(isolinuxDest, mustache.render(template, view));
843
+ /**
844
+ * splash
845
+ */
846
+ const splashDest = `${this.settings.iso_work}/isolinux/splash.png`;
847
+ let splashSrc = path.resolve(__dirname, `../../addons/${theme}/theme/livecd/splash.png`);
848
+ if (this.theme.includes('/')) {
849
+ splashSrc = path.resolve(`${theme}/theme/livecd/splash.png`);
850
+ }
851
+ if (!fs.existsSync(splashSrc)) {
852
+ Utils.warning('Cannot find: ' + splashSrc);
853
+ process.exit();
854
+ }
855
+ fs.copyFileSync(splashSrc, splashDest);
856
+ }
857
+ /**
858
+ * kernelCopy
859
+ */
860
+ async kernelCopy() {
861
+ Utils.warning(`copying ${path.basename(this.settings.kernel_image)} on ISO/live`);
862
+ let lackVmlinuzImage = false;
863
+ if (fs.existsSync(this.settings.kernel_image)) {
864
+ await exec(`cp ${this.settings.kernel_image} ${this.settings.iso_work}live/`, this.echo);
865
+ }
866
+ else {
867
+ Utils.error(`Cannot find ${this.settings.kernel_image}`);
868
+ lackVmlinuzImage = true;
869
+ }
870
+ if (lackVmlinuzImage) {
871
+ Utils.warning('Try to edit /etc/penguins-eggs.d/eggs.yaml and check for');
872
+ Utils.warning(`vmlinuz: ${this.settings.kernel_image}`);
873
+ process.exit(1);
874
+ }
875
+ }
876
+ /**
877
+ * Crea la struttura della workdir
878
+ */
879
+ async liveCreateStructure() {
880
+ if (this.verbose) {
881
+ console.log('Ovary: liveCreateStructure');
882
+ }
883
+ Utils.warning(`creating egg in ${this.settings.config.snapshot_dir}`);
884
+ let cmd;
885
+ if (!fs.existsSync(this.settings.config.snapshot_dir)) {
886
+ cmd = `mkdir -p ${this.settings.config.snapshot_dir}`;
887
+ this.tryCatch(cmd);
888
+ }
889
+ if (!fs.existsSync(this.settings.config.snapshot_dir + '/README.md')) {
890
+ cmd = `cp ${path.resolve(__dirname, '../../conf/README.md')} ${this.settings.config.snapshot_dir}README.md`;
891
+ this.tryCatch(cmd);
892
+ }
893
+ // Ovarium
894
+ if (!fs.existsSync(this.settings.work_dir.ovarium)) {
895
+ cmd = `mkdir -p ${this.settings.work_dir.ovarium}`;
896
+ this.tryCatch(cmd);
897
+ }
898
+ if (!fs.existsSync(this.settings.work_dir.lowerdir)) {
899
+ cmd = `mkdir -p ${this.settings.work_dir.lowerdir}`;
900
+ this.tryCatch(cmd);
901
+ }
902
+ if (!fs.existsSync(this.settings.work_dir.upperdir)) {
903
+ cmd = `mkdir -p ${this.settings.work_dir.upperdir}`;
904
+ this.tryCatch(cmd);
905
+ }
906
+ if (!fs.existsSync(this.settings.work_dir.workdir)) {
907
+ cmd = `mkdir -p ${this.settings.work_dir.workdir}`;
908
+ this.tryCatch(cmd);
909
+ }
910
+ if (!fs.existsSync(this.settings.work_dir.merged)) {
911
+ cmd = `mkdir -p ${this.settings.work_dir.merged}`;
912
+ this.tryCatch(cmd);
913
+ }
914
+ /**
915
+ * Creo le directory di destinazione per boot, efi, isolinux e live
916
+ */
917
+ if (!fs.existsSync(this.settings.iso_work)) {
918
+ cmd = `mkdir -p ${this.settings.iso_work}boot/grub/${Utils.uefiFormat()}`;
919
+ this.tryCatch(cmd);
920
+ cmd = `mkdir -p ${this.settings.iso_work}isolinux`;
921
+ this.tryCatch(cmd);
922
+ cmd = `mkdir -p ${this.settings.iso_work}live`;
923
+ this.tryCatch(cmd);
924
+ }
925
+ // ln iso
926
+ cmd = `ln -s ${this.settings.iso_work} ${this.settings.config.snapshot_dir}/iso`;
927
+ this.tryCatch(cmd);
928
+ // ln livefs
929
+ cmd = `ln -s ${this.settings.work_dir.merged} ${this.settings.config.snapshot_dir}/livefs`;
930
+ this.tryCatch(cmd);
931
+ }
932
+ /**
933
+ * makeDotDisk
934
+ */
935
+ makeDotDisk(info = '', mksquashfs = '', mkisofs = '') {
936
+ if (this.verbose) {
937
+ console.log('Ovary: makeDotDisk');
938
+ }
939
+ const dotDisk = this.settings.iso_work + '.disk';
940
+ if (fs.existsSync(dotDisk)) {
941
+ shx.rm('-rf', dotDisk);
942
+ }
943
+ shx.mkdir('-p', dotDisk);
944
+ let text = `# Created at: ${Utils.formatDate(new Date())}\n`;
945
+ text += `# penguins_eggs v. ${Utils.getPackageVersion()}\n`;
946
+ // .disk/info
947
+ fs.writeFileSync(dotDisk + '/info', text, 'utf-8');
948
+ // .disk/mksquashfs
949
+ fs.writeFileSync(dotDisk + '/mksquashfs', text + mksquashfs, 'utf-8');
950
+ // .disk/mkisofs
951
+ fs.writeFileSync(dotDisk + '/mkisofs', text + mkisofs, 'utf-8');
952
+ }
953
+ /**
954
+ * makeEFI
955
+ */
956
+ async makeEfi(theme = 'eggs') {
957
+ if (this.verbose) {
958
+ console.log('Ovary: makeEfi');
959
+ }
960
+ const memdiskDir = this.settings.config.snapshot_mnt + 'memdiskDir';
961
+ const efiWorkDir = this.settings.efi_work;
962
+ const isoDir = this.settings.iso_work;
963
+ /**
964
+ * il pachetto grub/grub2 DEVE essere presente
965
+ */
966
+ const grubName = Diversions.grubName(this.familyId);
967
+ if (grubName === '') {
968
+ Utils.error('Something went wrong! Cannot find grub! Run lsb_release -a and check the result');
969
+ process.exit(1);
970
+ }
971
+ /**
972
+ * Creo o cancello e creo: memdiskDir
973
+ */
974
+ if (fs.existsSync(memdiskDir)) {
975
+ await exec(`rm ${memdiskDir} -rf`, this.echo);
976
+ }
977
+ Utils.warning('creating temporary memdiskDir on ' + memdiskDir);
978
+ await exec(`mkdir ${memdiskDir}`);
979
+ await exec(`mkdir ${memdiskDir}/boot`, this.echo);
980
+ await exec(`mkdir ${memdiskDir}/boot/grub`, this.echo);
981
+ /**
982
+ * for initial grub.cfg in memdisk
983
+ */
984
+ const grubCfg = `${memdiskDir}/boot/grub/grub.cfg`;
985
+ let text = '';
986
+ text += 'search --file --set=root /.disk/info\n';
987
+ text += 'set prefix=($root)/boot/grub\n';
988
+ text += `source $prefix/${Utils.uefiFormat()}/grub.cfg\n`;
989
+ Utils.write(grubCfg, text);
990
+ // #################################
991
+ /**
992
+ * start with empty efiWorkDir
993
+ */
994
+ if (fs.existsSync(efiWorkDir)) {
995
+ await exec(`rm ${efiWorkDir} -rf`, this.echo);
996
+ }
997
+ Utils.warning('creating temporary efiWordDir on ' + efiWorkDir);
998
+ await exec(`mkdir ${efiWorkDir}`, this.echo);
999
+ await exec(`mkdir ${efiWorkDir}boot`, this.echo);
1000
+ await exec(`mkdir ${efiWorkDir}boot/grub`, this.echo);
1001
+ await exec(`mkdir ${efiWorkDir}boot/grub/${Utils.uefiFormat()}`, this.echo);
1002
+ await exec(`mkdir ${efiWorkDir}EFI`, this.echo);
1003
+ await exec(`mkdir ${efiWorkDir}EFI/BOOT`, this.echo);
1004
+ /**
1005
+ * copy splash to efiWorkDir
1006
+ */
1007
+ const splashDest = `${efiWorkDir}boot/grub/splash.png`;
1008
+ let splashSrc = path.resolve(__dirname, `../../addons/${theme}/theme/livecd/splash.png`);
1009
+ if (this.theme.includes('/')) {
1010
+ splashSrc = `${theme}/theme/livecd/splash.png`;
1011
+ }
1012
+ if (!fs.existsSync(splashSrc)) {
1013
+ Utils.warning('Cannot find: ' + splashSrc);
1014
+ process.exit();
1015
+ }
1016
+ await exec(`cp ${splashSrc} ${splashDest}`, this.echo);
1017
+ /**
1018
+ * copy theme
1019
+ */
1020
+ const themeDest = `${efiWorkDir}boot/grub/theme.cfg`;
1021
+ let themeSrc = path.resolve(__dirname, `../../addons/${theme}/theme/livecd/grub.theme.cfg`);
1022
+ if (this.theme.includes('/')) {
1023
+ themeSrc = `${theme}/theme/livecd/grub.theme.cfg`;
1024
+ }
1025
+ if (!fs.existsSync(themeSrc)) {
1026
+ Utils.warning('Cannot find: ' + themeSrc);
1027
+ process.exit();
1028
+ }
1029
+ await exec(`cp ${themeSrc} ${themeDest}`, this.echo);
1030
+ /**
1031
+ * second grub.cfg file in efiWork
1032
+ */
1033
+ // 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
1034
+ //let cmd = `for i in $(ls /usr/lib/grub/${Utils.uefiFormat()}|grep part_|grep \.mod|sed 's/.mod//'); do echo "insmod $i" >> ${efiWorkDir}boot/grub/${Utils.uefiFormat()}/grub.cfg; done`
1035
+ let cmd = `for i in $(ls /usr/lib/grub/${Utils.uefiFormat()}|grep part_|grep \.mod|sed 's/.mod//'); do echo "insmod $i" >> ${efiWorkDir}boot/grub/${Utils.uefiFormat()}/grub.cfg; done`;
1036
+ await exec(cmd, this.echo);
1037
+ // 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`
1038
+ // not find: ieee1275_fb.mod vbe.mod vga.mod
1039
+ cmd = `for i in efi_gop efi_uga vga video_bochs video_cirrus jpeg png gfxterm ; do echo "insmod $i" >> ${efiWorkDir}boot/grub/${Utils.uefiFormat()}/grub.cfg ; done`;
1040
+ await exec(cmd, this.echo);
1041
+ await exec(`echo "source /boot/grub/grub.cfg" >> ${efiWorkDir}boot/grub/${Utils.uefiFormat()}/grub.cfg`, this.echo);
1042
+ /**
1043
+ * andiamo in memdiskDir
1044
+ */
1045
+ /**
1046
+ * make a tarred "memdisk" to embed in the grub image
1047
+ *
1048
+ * NOTE: it's CRUCIAL to chdir before tar!!!
1049
+ */
1050
+ const currentDir = process.cwd();
1051
+ process.chdir(memdiskDir);
1052
+ await exec('tar -cvf memdisk boot', this.echo);
1053
+ process.chdir(currentDir);
1054
+ // -O, --format=FORMAT
1055
+ // -m --memdisk=FILE embed FILE as a memdisk image
1056
+ // -o, --output=FILE embed FILE as a memdisk image
1057
+ // -p, --prefix=DIR set prefix directory
1058
+ // --format=x86_64-efi --memdisk=memdisk --output=bootx64.efi --prefix?DIR set prefix directory
1059
+ // 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
1060
+ // arm64-efi
1061
+ await exec(`${grubName}-mkimage -O "${Utils.uefiFormat()}" \
1062
+ -m "${memdiskDir}/memdisk" \
1063
+ -o "${memdiskDir}/${Utils.uefiBN()}" \
1064
+ -p '(memdisk)/boot/grub' \
1065
+ search iso9660 configfile normal memdisk tar cat part_msdos part_gpt fat ext2 ntfs ntfscomp hfsplus chain boot linux`, this.echo);
1066
+ // popd torna in efiWorkDir
1067
+ // copy the grub image to efi/boot (to go later in the device's root)
1068
+ await exec(`cp ${memdiskDir}/${Utils.uefiBN()} ${efiWorkDir}EFI/BOOT`, this.echo);
1069
+ // #######################
1070
+ // Create boot image "boot/grub/efiboot.img"
1071
+ await exec(`dd if=/dev/zero of=${efiWorkDir}boot/grub/efiboot.img bs=1K count=1440`, this.echo);
1072
+ await exec(`/sbin/mkdosfs -F 12 ${efiWorkDir}boot/grub/efiboot.img`, this.echo);
1073
+ await exec(`mkdir ${efiWorkDir}img-mnt`, this.echo);
1074
+ await exec(`mount -o loop ${efiWorkDir}boot/grub/efiboot.img ${efiWorkDir}img-mnt`, this.echo);
1075
+ await exec(`mkdir ${efiWorkDir}img-mnt/EFI`, this.echo);
1076
+ await exec(`mkdir ${efiWorkDir}img-mnt/EFI/BOOT`, this.echo);
1077
+ await exec(`cp ${memdiskDir}/${Utils.uefiBN()} ${efiWorkDir}img-mnt/EFI/BOOT`, this.echo);
1078
+ // #######################
1079
+ // copy modules and font
1080
+ await exec(`cp -r /usr/lib/grub/${Utils.uefiFormat()}/* ${efiWorkDir}boot/grub/${Utils.uefiFormat()}/`, this.echo);
1081
+ // if this doesn't work try another font from the same place (grub's default, unicode.pf2, is much larger)
1082
+ // Either of these will work, and they look the same to me. Unicode seems to work with qemu. -fsr
1083
+ if (fs.existsSync('/usr/share/grub/font.pf2')) {
1084
+ await exec(`cp /usr/share/grub/font.pf2 ${efiWorkDir}boot/grub/font.pf2`, this.echo);
1085
+ }
1086
+ else if (fs.existsSync('/usr/share/grub/unicode.pf2')) {
1087
+ await exec(`cp /usr/share/grub/unicode.pf2 ${efiWorkDir}boot/grub/font.pf2`, this.echo);
1088
+ }
1089
+ else if (fs.existsSync('/usr/share/grub/ascii.pf2')) {
1090
+ await exec(`cp /usr/share/grub/ascii.pf2 ${efiWorkDir}boot/grub/font.pf2`, this.echo);
1091
+ }
1092
+ // Doesn't need to be root-owned
1093
+ // chown -R 1000:1000 $(pwd) 2>/dev/null
1094
+ // Cleanup efi temps
1095
+ await exec(`umount ${efiWorkDir}img-mnt`, this.echo);
1096
+ await exec(`rmdir ${efiWorkDir}img-mnt`, this.echo);
1097
+ await exec(`rm ${memdiskDir}/img-mnt -rf`, this.echo);
1098
+ // popd
1099
+ // Copy efi files to ISO
1100
+ await exec(`rsync -avx ${efiWorkDir}boot ${isoDir}/`, this.echo);
1101
+ await exec(`rsync -avx ${efiWorkDir}EFI ${isoDir}/`, this.echo);
1102
+ // Do the main grub.cfg (which gets loaded last):
1103
+ // grub.theme.cfg
1104
+ let grubThemeSrc = path.resolve(__dirname, `../../addons/${theme}/theme/livecd/grub.theme.cfg`);
1105
+ if (this.theme.includes('/')) {
1106
+ grubThemeSrc = `${theme}/theme/livecd/grub.theme.cfg`;
1107
+ }
1108
+ const grubThemeDest = `${isoDir}/boot/grub/theme.cfg`;
1109
+ if (!fs.existsSync(grubThemeSrc)) {
1110
+ Utils.warning('Cannot find: ' + grubThemeSrc);
1111
+ process.exit();
1112
+ }
1113
+ fs.copyFileSync(grubThemeSrc, grubThemeDest);
1114
+ /**
1115
+ * prepare grub.cfg from grub.main.cfg
1116
+ */
1117
+ let grubTemplate = `${theme}/theme/livecd/grub.main.cfg`;
1118
+ if (!fs.existsSync(grubTemplate)) {
1119
+ grubTemplate = path.resolve(__dirname, '../../addons/eggs/theme/livecd/grub.main.cfg');
1120
+ }
1121
+ if (!fs.existsSync(grubTemplate)) {
1122
+ Utils.warning('Cannot find: ' + grubTemplate);
1123
+ process.exit();
1124
+ }
1125
+ const kernel_parameters = Diversions.kernelParameters(this.familyId, this.volid); // this.kernelParameters()
1126
+ const grubDest = `${isoDir}/boot/grub/grub.cfg`;
1127
+ const template = fs.readFileSync(grubTemplate, 'utf8');
1128
+ const view = {
1129
+ fullname: this.settings.remix.fullname.toUpperCase(),
1130
+ initrdImg: `/live${this.settings.initrdImg}`,
1131
+ kernel: Utils.kernelVersion(),
1132
+ kernel_parameters,
1133
+ vmlinuz: `/live${this.settings.vmlinuz}`
1134
+ };
1135
+ fs.writeFileSync(grubDest, mustache.render(template, view));
1136
+ /**
1137
+ * loopback.cfg
1138
+ */
1139
+ fs.writeFileSync(`${isoDir}/boot/grub/loopback.cfg`, 'source /boot/grub/grub.cfg\n');
1140
+ }
1141
+ /**
1142
+ * makeIso
1143
+ * cmd: cmd 4 xorriso
1144
+ */
1145
+ async makeIso(cmd, scriptOnly = false) {
1146
+ // echo = { echo: true, ignore: false }
1147
+ if (this.verbose) {
1148
+ console.log('Ovary: makeIso');
1149
+ }
1150
+ Utils.writeX(`${this.settings.work_dir.ovarium}mkisofs`, cmd);
1151
+ // Create link to iso ALLWAYES
1152
+ const src = this.settings.config.snapshot_mnt + this.settings.isoFilename;
1153
+ const dest = this.settings.config.snapshot_dir + this.settings.isoFilename;
1154
+ await exec(`ln -s ${src} ${dest}`);
1155
+ if (!scriptOnly) {
1156
+ const test = (await exec(cmd, Utils.setEcho(true))).code;
1157
+ if (test !== 0) {
1158
+ process.exit();
1159
+ }
1160
+ // Create link to iso
1161
+ const src = this.settings.config.snapshot_mnt + this.settings.isoFilename;
1162
+ const dest = this.settings.config.snapshot_dir + this.settings.isoFilename;
1163
+ await exec(`ln -s ${src} ${dest}`);
1164
+ // Create md5sum, sha256sum
1165
+ if (this.settings.config.make_md5sum) {
1166
+ Utils.warning('creating md5, sha256');
1167
+ await exec(`md5sum ${src} > ${dest.replace('.iso', '.md5')}`);
1168
+ await exec(`sha256sum ${src} > ${dest.replace('.iso', '.sha256')}`);
1169
+ }
1170
+ }
1171
+ }
1172
+ /**
1173
+ * squashFs: crea in live filesystem.squashfs
1174
+ */
1175
+ async makeSquashfs(scriptOnly = false, unsecure = false) {
1176
+ if (this.verbose) {
1177
+ console.log('Ovary: makeSquashfs');
1178
+ }
1179
+ /**
1180
+ * exclude all the accurence of cryptdisks in rc0.d, etc
1181
+ */
1182
+ 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'];
1183
+ for (const i in fexcludes) {
1184
+ this.addRemoveExclusion(true, fexcludes[i]);
1185
+ }
1186
+ /**
1187
+ * Non sò che fa, ma sicuro non serve per archlinux
1188
+ */
1189
+ if (this.familyId === 'debian') {
1190
+ const rcd = ['rc0.d', 'rc1.d', 'rc2.d', 'rc3.d', 'rc4.d', 'rc5.d', 'rc6.d', 'rcS.d'];
1191
+ let files;
1192
+ for (const i in rcd) {
1193
+ files = fs.readdirSync(`${this.settings.work_dir.merged}/etc/${rcd[i]}`);
1194
+ for (const n in files) {
1195
+ if (files[n].includes('cryptdisks')) {
1196
+ this.addRemoveExclusion(true, `/etc/${rcd[i]}${files[n]}`);
1197
+ }
1198
+ }
1199
+ }
1200
+ }
1201
+ /**
1202
+ * secure
1203
+ */
1204
+ if (!unsecure) {
1205
+ this.addRemoveExclusion(true, `root/*`);
1206
+ this.addRemoveExclusion(true, `root/.*`);
1207
+ }
1208
+ if (shx.exec('/usr/bin/test -L /etc/localtime', { silent: true }) && shx.exec('cat /etc/timezone', { silent: true }) !== 'Europe/Rome') {
1209
+ // this.addRemoveExclusion(true, '/etc/localtime')
1210
+ }
1211
+ this.addRemoveExclusion(true, this.settings.config.snapshot_dir /* .absolutePath() */);
1212
+ if (fs.existsSync(`${this.settings.iso_work}/live/filesystem.squashfs`)) {
1213
+ fs.unlinkSync(`${this.settings.iso_work}/live/filesystem.squashfs`);
1214
+ }
1215
+ const compression = `-comp ${this.settings.config.compression}`;
1216
+ /**
1217
+ * limit: patch per Raspberry
1218
+ */
1219
+ const limit = '';
1220
+ if (Utils.uefiArch() === 'arm64') {
1221
+ // limit = ' -processors 2 -mem 1024M'
1222
+ }
1223
+ /**
1224
+ * mksquashfs
1225
+ *
1226
+ * SYNTAX: mksquashfs source1 source2 ...
1227
+ * FILESYSTEM [OPTIONS]
1228
+ * [-ef exclude.list]
1229
+ * [-e list of exclude dirs/files]
1230
+ */
1231
+ 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}`;
1232
+ cmd = cmd.replaceAll(/\s\s+/g, ' ');
1233
+ Utils.writeX(`${this.settings.work_dir.ovarium}mksquashfs`, cmd);
1234
+ if (!scriptOnly) {
1235
+ Utils.warning('creating filesystem.squashfs on ISO/live');
1236
+ // Utils.warning(`compression: ` + compression)
1237
+ const test = (await exec(cmd, Utils.setEcho(true))).code;
1238
+ if (test !== 0) {
1239
+ process.exit();
1240
+ }
1241
+ }
1242
+ return cmd;
1243
+ }
1244
+ /**
1245
+ * Ritorna true se c'è bisogno del mount --bind
1246
+ *
1247
+ * Ci sono tre tipologie:
1248
+ *
1249
+ * - normal solo la creazione della directory, nessun mount
1250
+ * - merged creazione della directory e mount ro
1251
+ * - mergedAndOverlay creazione directory, overlay e mount rw
1252
+ * - copied: creazione directory e copia
1253
+ */
1254
+ merged(dir) {
1255
+ if (this.verbose) {
1256
+ console.log('Ovary: merged');
1257
+ }
1258
+ let merged = true;
1259
+ if (dir === 'home') {
1260
+ merged = this.clone;
1261
+ }
1262
+ else {
1263
+ const noMergeDirs = [
1264
+ 'boot', // will be copied now
1265
+ 'cdrom',
1266
+ 'dev',
1267
+ 'media',
1268
+ 'mnt',
1269
+ 'proc',
1270
+ 'run',
1271
+ 'swapfile',
1272
+ 'sys',
1273
+ 'tmp'
1274
+ ];
1275
+ // deepin
1276
+ noMergeDirs.push('data', 'recovery');
1277
+ for (const noMergeDir of noMergeDirs) {
1278
+ if (dir === noMergeDir) {
1279
+ merged = false;
1280
+ }
1281
+ }
1282
+ }
1283
+ return merged;
1284
+ }
1285
+ /**
1286
+ * Restituisce true per le direcory da montare con overlay
1287
+ *
1288
+ * Ci sono tre tipologie:
1289
+ *
1290
+ * - normal solo la creazione della directory, nessun mount
1291
+ * - merged creazione della directory e mount ro
1292
+ * - mergedAndOverlay creazione directory, overlay e mount rw
1293
+ *
1294
+ * @param dir
1295
+ */
1296
+ mergedAndOverlay(dir) {
1297
+ if (this.verbose) {
1298
+ console.log('Ovary: mergedAndOverlay');
1299
+ }
1300
+ /**
1301
+ * Debian: usrmerged
1302
+ * bin -> usr/bin
1303
+ * lib -> usr/lib
1304
+ * lib64 -> usr/lib64
1305
+ * sbin -> usr/sbin
1306
+ *
1307
+ * 'bin' rimossa da overlay
1308
+ */
1309
+ // aggiunto bin per autologin su Alpine
1310
+ const mountDirs = ['etc', 'usr', 'var'];
1311
+ let mountDir = '';
1312
+ let overlay = false;
1313
+ for (mountDir of mountDirs) {
1314
+ if (mountDir === dir) {
1315
+ overlay = true;
1316
+ }
1317
+ }
1318
+ return overlay;
1319
+ }
1320
+ /**
1321
+ * produce
1322
+ * @param clone
1323
+ * @param cryptedclone
1324
+ * @param scriptOnly
1325
+ * @param yolkRenew
1326
+ * @param release
1327
+ * @param myAddons
1328
+ * @param nointeractive
1329
+ * @param noicons
1330
+ * @param unsecure
1331
+ * @param verbose
1332
+ */
1333
+ async produce(clone = false, cryptedclone = false, scriptOnly = false, yolkRenew = false, release = false, myAddons, myLinks, excludes, nointeractive = false, noicons = false, unsecure = false, verbose = false) {
1334
+ this.verbose = verbose;
1335
+ this.echo = Utils.setEcho(verbose);
1336
+ if (this.verbose) {
1337
+ this.toNull = ' > /dev/null 2>&1';
1338
+ }
1339
+ this.clone = clone;
1340
+ this.cryptedclone = cryptedclone;
1341
+ const luksName = 'luks-volume';
1342
+ const luksFile = `/tmp/${luksName}`;
1343
+ if (this.familyId === 'debian' && Utils.uefiArch() === 'amd64') {
1344
+ const yolk = new Repo();
1345
+ if (!yolk.exists()) {
1346
+ Utils.warning('creating yolk');
1347
+ await yolk.create(verbose);
1348
+ }
1349
+ else if (yolkRenew) {
1350
+ Utils.warning('refreshing yolk');
1351
+ await yolk.erase();
1352
+ await yolk.create(verbose);
1353
+ }
1354
+ else {
1355
+ Utils.warning('using preesixent yolk');
1356
+ }
1357
+ }
1358
+ if (!fs.existsSync(this.settings.config.snapshot_dir)) {
1359
+ shx.mkdir('-p', this.settings.config.snapshot_dir);
1360
+ }
1361
+ if (Utils.isLive()) {
1362
+ console.log(chalk.red('>>> eggs: This is a live system! An egg cannot be produced from an egg!'));
1363
+ }
1364
+ else {
1365
+ await this.liveCreateStructure();
1366
+ // Carica calamares sono se le icone sono accettate
1367
+ if (!noicons && // se VOGLIO le icone
1368
+ !nointeractive &&
1369
+ this.settings.distro.isCalamaresAvailable &&
1370
+ Pacman.isInstalledGui() &&
1371
+ this.settings.config.force_installer &&
1372
+ !Pacman.calamaresExists()) {
1373
+ console.log('Installing ' + chalk.bgGray('calamares') + ' due force_installer=yes.');
1374
+ await Pacman.calamaresInstall(verbose);
1375
+ const bleach = new Bleach();
1376
+ await bleach.clean(verbose);
1377
+ }
1378
+ if (cryptedclone) {
1379
+ /**
1380
+ * cryptedclone
1381
+ */
1382
+ console.log("eggs will SAVE users and users' data ENCRYPTED");
1383
+ /*
1384
+ const users = await this.usersFill()
1385
+ for (const user of users) {
1386
+ if (user.saveIt) {
1387
+ let utype = 'user '
1388
+ if (Number.parseInt(user.uid) < 1000) {
1389
+ utype = 'service'
1390
+ }
1391
+ //console.log(`- ${utype}: ${user.login.padEnd(16)} \thome: ${user.home}`)
1392
+ if (user.login !== 'root') {
1393
+ this.addRemoveExclusion(true, user.home)
1394
+ }
1395
+ }
1396
+ }
1397
+ */
1398
+ }
1399
+ else if (this.clone) {
1400
+ /**
1401
+ * clone
1402
+ *
1403
+ * users tend to set user_opt as
1404
+ * real user when create a clone,
1405
+ * this is WRONG here we correct
1406
+ */
1407
+ this.settings.config.user_opt = 'live'; // patch for humans
1408
+ this.settings.config.user_opt_passwd = 'evolution';
1409
+ this.settings.config.root_passwd = 'evolution';
1410
+ Utils.warning("eggs will SAVE users and users' data UNCRYPTED on the live");
1411
+ }
1412
+ else {
1413
+ /**
1414
+ * normal
1415
+ */
1416
+ Utils.warning("eggs will REMOVE users and users' data from live");
1417
+ }
1418
+ /**
1419
+ * exclude.list
1420
+ */
1421
+ if (!excludes.static /**
1422
+ * create exclude.list if not exists
1423
+ */
1424
+ &&
1425
+ !fs.existsSync('/etc/penguins-eggs/exclude.list')) {
1426
+ const excludeListTemplateDir = '/etc/penguins-eggs.d/exclude.list.d/';
1427
+ const excludeListTemplate = excludeListTemplateDir + 'master.list';
1428
+ if (!fs.existsSync(excludeListTemplate)) {
1429
+ Utils.warning('Cannot find: ' + excludeListTemplate);
1430
+ process.exit(1);
1431
+ }
1432
+ let excludeUsr = '';
1433
+ let excludeVar = '';
1434
+ let excludeHomes = '';
1435
+ let excludeHome = '';
1436
+ if (excludes.usr) {
1437
+ excludeUsr = fs.readFileSync(`${excludeListTemplateDir}usr.list`, 'utf8');
1438
+ }
1439
+ if (excludes.var) {
1440
+ excludeVar = fs.readFileSync(`${excludeListTemplateDir}var.list`, 'utf8');
1441
+ }
1442
+ if (excludes.homes) {
1443
+ excludeHomes = fs.readFileSync(`${excludeListTemplateDir}homes.list`, 'utf8');
1444
+ }
1445
+ if (excludes.home) {
1446
+ excludeHome = `home/${await Utils.getPrimaryUser()}/*`;
1447
+ }
1448
+ const view = {
1449
+ home_list: excludeHome,
1450
+ homes_list: excludeHomes,
1451
+ usr_list: excludeUsr,
1452
+ var_list: excludeVar
1453
+ };
1454
+ const template = fs.readFileSync(excludeListTemplate, 'utf8');
1455
+ fs.writeFileSync(this.settings.config.snapshot_excludes, mustache.render(template, view));
1456
+ }
1457
+ /**
1458
+ * NOTE: reCreate = false
1459
+ *
1460
+ * reCreate = false is just for develop
1461
+ * put reCreate = true in release
1462
+ */
1463
+ const reCreate = true;
1464
+ let mksquashfsCmd = '';
1465
+ if (reCreate) {
1466
+ // start pre-clone
1467
+ /**
1468
+ * installer
1469
+ */
1470
+ this.incubator = new Incubator(this.settings.remix, this.settings.distro, this.settings.config.user_opt, this.theme, this.clone, verbose);
1471
+ await this.incubator.config(release);
1472
+ await this.syslinux(this.theme);
1473
+ //await this.isolinux(this.theme)
1474
+ await this.kernelCopy();
1475
+ /**
1476
+ * differents initfs for different families
1477
+ */
1478
+ if (this.familyId === 'alpine') {
1479
+ await this.initrdAlpine();
1480
+ }
1481
+ else if (this.familyId === 'archlinux') {
1482
+ await this.initrdArch();
1483
+ }
1484
+ else if (this.familyId === 'debian') {
1485
+ await this.initrdDebian();
1486
+ }
1487
+ else if (this.familyId === 'aldos' ||
1488
+ this.familyId === 'fedora' ||
1489
+ this.familyId === 'openmamba' ||
1490
+ this.familyId === 'opensuse' ||
1491
+ this.familyId === 'voidlinux') {
1492
+ await this.initrdDracut();
1493
+ }
1494
+ if (this.settings.config.make_efi) {
1495
+ await this.makeEfi(this.theme);
1496
+ }
1497
+ await this.bindLiveFs();
1498
+ if (!this.clone) {
1499
+ /**
1500
+ * ANCHE per cryptedclone
1501
+ */
1502
+ await this.cleanUsersAccounts();
1503
+ await this.createUserLive();
1504
+ if (Pacman.isInstalledGui()) {
1505
+ await this.createXdgAutostart(this.settings.config.theme, myAddons, myLinks, noicons);
1506
+ /**
1507
+ * GUI installed but NOT Desktop Manager: just create motd and issue
1508
+ */
1509
+ if (displaymanager().length > 0) {
1510
+ 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);
1511
+ 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);
1512
+ }
1513
+ }
1514
+ else {
1515
+ this.cliAutologin.add(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);
1516
+ }
1517
+ }
1518
+ await this.editLiveFs(clone, cryptedclone);
1519
+ mksquashfsCmd = await this.makeSquashfs(scriptOnly, unsecure);
1520
+ await this.uBindLiveFs(); // Lo smonto prima della fase di backup
1521
+ }
1522
+ if (cryptedclone) {
1523
+ let synctoCmd = `eggs syncto -f ${luksFile}`;
1524
+ if (excludes.home) {
1525
+ synctoCmd += ' --excludes'; // from Marco, usa home.list
1526
+ }
1527
+ await exec(synctoCmd, Utils.setEcho(true));
1528
+ Utils.warning(`moving ${luksFile} in ${this.nest}iso/live`);
1529
+ await exec(`mv ${luksFile} ${this.nest}iso/live`, this.echo);
1530
+ }
1531
+ const mkIsofsCmd = (await this.xorrisoCommand(clone, cryptedclone)).replaceAll(/\s\s+/g, ' ');
1532
+ this.makeDotDisk(this.volid, mksquashfsCmd, mkIsofsCmd);
1533
+ /**
1534
+ * AntiX/MX LINUX
1535
+ */
1536
+ if (fs.existsSync('/etc/antix-version')) {
1537
+ let uname = (await exec('uname -r', { capture: true })).data;
1538
+ uname = uname.replaceAll('\n', '');
1539
+ let content = '';
1540
+ content = '#!/usr/bin/env bash';
1541
+ content += 'mkdir /live/bin -p\n';
1542
+ content += '## \n';
1543
+ content += '# cp /usr/lib/penguins-eggs/scripts/non-live-cmdline /live/bin -p\n';
1544
+ content += '# chmod +x /live/bin/non-live-cmdline\n';
1545
+ content += '## \n';
1546
+ content += 'mkdir /live/boot-dev/antiX -p\n';
1547
+ content += 'ln -s /run/live/medium/live/filesystem.squashfs /live/boot-dev/antiX/linuxfs\n';
1548
+ content += `ln -s /run/live/medium/live/initrd.img-${uname} /live/boot-dev/antiX/initrd.gz\n`;
1549
+ content += `ln -s /run/live/medium/live/vmlinuz-${uname} /live/boot-dev/antiX/vmlinuz\n`;
1550
+ content += `# md5sum /live/boot-dev/antiX/linuxfs > /live/boot-dev/antiX/linuxfs.md5\n`;
1551
+ content += `# md5sum /live/boot-dev/antiX/initrd.gz > /live/boot-dev/antiX/initrd.gz.md5\n`;
1552
+ content += `# md5sum /live/boot-dev/antiX/vmlinuz > /live/boot-dev/antiX/vmlinuz.md5\n`;
1553
+ content += `# /live/aufs -> /run/live/rootfs/filesystem.squashfs\n`;
1554
+ content += 'ln -s /run/live/rootfs/filesystem.squashfs /live/aufs\n';
1555
+ content += `# use: minstall -no-media-check\n`;
1556
+ content += 'minstall --no-media-check\n';
1557
+ const file = `${this.settings.iso_work}antix-mx-installer`;
1558
+ fs.writeFileSync(file, content);
1559
+ await exec(`chmod +x ${file}`);
1560
+ }
1561
+ /**
1562
+ * patch to emulate miso/archiso on archilinux family
1563
+ */
1564
+ if (this.familyId === 'archlinux') {
1565
+ let pathName = `arch/x86_64/airootfs`;
1566
+ let hashCmd = 'sha512sum';
1567
+ let hashExt = '.sha512';
1568
+ if (Diversions.isManjaroBased(this.settings.distro.distroId)) {
1569
+ pathName = `manjaro/x86_64/livefs`;
1570
+ hashCmd = `md5sum`;
1571
+ hashExt = '.md5';
1572
+ }
1573
+ await exec(`mkdir ${this.settings.iso_work}${pathName}/x86_64 -p`, this.echo);
1574
+ fs.linkSync(`${this.settings.iso_work}live/filesystem.squashfs`, `${this.settings.iso_work}${pathName}.sfs`);
1575
+ }
1576
+ /**
1577
+ * patch per aldos
1578
+ if (this.familyId === 'aldos') {
1579
+ await exec(`mkdir ${this.settings.iso_work}LiveOS -p`, this.echo)
1580
+ fs.linkSync(`${this.settings.iso_work}live/filesystem.squashfs`, `${this.settings.iso_work}LiveOS/squashfs.img`)
1581
+ }
1582
+ */
1583
+ await this.makeIso(mkIsofsCmd, scriptOnly);
1584
+ }
1585
+ }
1586
+ /**
1587
+ *
1588
+ * @param cmd
1589
+ */
1590
+ async tryCatch(cmd = '') {
1591
+ if (this.verbose) {
1592
+ console.log('Ovary: tryCatch');
1593
+ }
1594
+ try {
1595
+ await exec(cmd, this.echo);
1596
+ }
1597
+ catch (error) {
1598
+ console.log(`Error: ${error}`);
1599
+ await Utils.pressKeyToExit(cmd);
1600
+ }
1601
+ }
1602
+ /**
1603
+ * ubind del fs live
1604
+ * @param verbose
1605
+ */
1606
+ async uBindLiveFs() {
1607
+ if (this.verbose) {
1608
+ console.log('Ovary: uBindLiveFs');
1609
+ }
1610
+ const cmds = [];
1611
+ 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}`);
1612
+ cmds.push(`# host: ${os.hostname()} user: ${await Utils.getPrimaryUser()}\n`);
1613
+ if (fs.existsSync(this.settings.work_dir.merged)) {
1614
+ const bindDirs = fs.readdirSync(this.settings.work_dir.merged, {
1615
+ withFileTypes: true
1616
+ });
1617
+ for (const dir of bindDirs) {
1618
+ const dirname = dir.name;
1619
+ cmds.push('#############################################################');
1620
+ if (fs.statSync(`/${dirname}`).isDirectory()) {
1621
+ cmds.push(`\n# directory: ${dirname}`);
1622
+ if (this.mergedAndOverlay(dirname)) {
1623
+ cmds.push(`\n# ${dirname} has overlay`, `\n# First, umount it from ${this.settings.config.snapshot_dir}`);
1624
+ cmds.push(await rexec(`umount ${this.settings.work_dir.merged}/${dirname}`, this.verbose), `\n# Second, umount it from ${this.settings.work_dir.lowerdir}`);
1625
+ cmds.push(await rexec(`umount ${this.settings.work_dir.lowerdir}/${dirname}`, this.verbose));
1626
+ }
1627
+ else if (this.merged(dirname)) {
1628
+ cmds.push(await rexec(`umount ${this.settings.work_dir.merged}/${dirname}`, this.verbose));
1629
+ }
1630
+ cmds.push(`\n# remove in ${this.settings.work_dir.merged} and ${this.settings.work_dir.lowerdir}`);
1631
+ /**
1632
+ * We can't remove the nest!!!
1633
+ */
1634
+ const nest = this.settings.config.snapshot_dir.split('/');
1635
+ if (dirname !== nest[1]) {
1636
+ // We can't remove first level nest
1637
+ cmds.push(await rexec(`rm -rf ${this.settings.work_dir.merged}/${dirname}`, this.verbose));
1638
+ }
1639
+ }
1640
+ else if (fs.statSync(`/${dirname}`).isFile()) {
1641
+ cmds.push(`\n# ${dirname} = file`);
1642
+ cmds.push(await rexec(`rm -f ${this.settings.work_dir.merged}/${dirname}`, this.verbose));
1643
+ }
1644
+ else if (fs.statSync(`/${dirname}`).isSymbolicLink()) {
1645
+ cmds.push(`\n# ${dirname} = symbolicLink`);
1646
+ cmds.push(await rexec(`rm -f ${this.settings.work_dir.merged}/${dirname}`, this.verbose));
1647
+ }
1648
+ }
1649
+ }
1650
+ if (this.clone) {
1651
+ cmds.push(await rexec(`umount ${this.settings.work_dir.merged}/home`, this.verbose));
1652
+ }
1653
+ // Utils.writeXs(`${this.settings.config.snapshot_dir}ubind`, cmds)
1654
+ Utils.writeXs(`${this.settings.work_dir.ovarium}ubind`, cmds);
1655
+ }
1656
+ /**
1657
+ *
1658
+ * @param verbose
1659
+ */
1660
+ async ubindVfs() {
1661
+ if (this.verbose) {
1662
+ console.log('Ovary: ubindVfs');
1663
+ }
1664
+ const cmds = [];
1665
+ 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`);
1666
+ // Utils.writeXs(`${this.settings.config.snapshot_dir}ubindvfs`, cmds)
1667
+ Utils.writeXs(`${this.settings.work_dir.ovarium}ubindvfs`, cmds);
1668
+ }
1669
+ /**
1670
+ * fill
1671
+ */
1672
+ async usersFill() {
1673
+ if (this.verbose) {
1674
+ console.log('Ovary: usersFill');
1675
+ }
1676
+ const usersArray = [];
1677
+ await access('/etc/passwd', constants.R_OK | constants.W_OK);
1678
+ const passwd = fs.readFileSync('/etc/passwd', 'utf8').split('\n');
1679
+ for (const element of passwd) {
1680
+ const line = element.split(':');
1681
+ const users = new Users(line[0], line[1], line[2], line[3], line[4], line[5], line[6]);
1682
+ await users.getValues();
1683
+ if (users.password !== undefined) {
1684
+ usersArray.push(users);
1685
+ }
1686
+ }
1687
+ return usersArray;
1688
+ }
1689
+ /**
1690
+ *
1691
+ * @param cryptedclone
1692
+ * @returns cmd 4 mkiso
1693
+ */
1694
+ async xorrisoCommand(clone = false, cryptedclone = false) {
1695
+ if (this.verbose) {
1696
+ console.log('Ovary: xorrisoCommand');
1697
+ }
1698
+ const prefix = this.settings.config.snapshot_prefix;
1699
+ let typology = '';
1700
+ // typology is applied only with standard egg-of
1701
+ if (prefix.slice(0, 7) === 'egg-of_') {
1702
+ if (clone) {
1703
+ typology = '_clone';
1704
+ }
1705
+ else if (cryptedclone) {
1706
+ typology = '_crypted';
1707
+ }
1708
+ if (fs.existsSync('/usr/bin/eui-start.sh')) {
1709
+ typology += '_EUI';
1710
+ }
1711
+ }
1712
+ const postfix = Utils.getPostfix();
1713
+ this.settings.isoFilename = prefix + this.volid + '_' + Utils.uefiArch() + typology + postfix;
1714
+ //
1715
+ const output = this.settings.config.snapshot_mnt + this.settings.isoFilename;
1716
+ let command = '';
1717
+ // const appid = `-appid "${this.settings.distro.distroId}" `
1718
+ // const publisher = `-publisher "${this.settings.distro.distroId}/${this.settings.distro.codenameId}" `
1719
+ // const preparer = '-preparer "prepared by eggs <https://penguins-eggs.net>" '
1720
+ let isoHybridMbr = '';
1721
+ if (this.settings.config.make_isohybrid) {
1722
+ const isolinuxFile = this.settings.distro.syslinuxPath + '/isohdpfx.bin';
1723
+ if (fs.existsSync(isolinuxFile)) {
1724
+ isoHybridMbr = `-isohybrid-mbr ${isolinuxFile}`;
1725
+ }
1726
+ else {
1727
+ Utils.warning(`Can't create isohybrid image. File: ${isolinuxFile} not found. \nThe resulting image will be a standard iso file`);
1728
+ }
1729
+ }
1730
+ if (Pacman.packageIsInstalled('genisoimage')) {
1731
+ this.genisoimage = true;
1732
+ command = `genisoimage \
1733
+ -iso-level 3 \
1734
+ -allow-limited-size \
1735
+ -joliet-long \
1736
+ -r \
1737
+ -V ${this.volid} \
1738
+ -cache-inodes \
1739
+ -J \
1740
+ -l \
1741
+ -b isolinux/isolinux.bin \
1742
+ -c isolinux/boot.cat \
1743
+ -no-emul-boot \
1744
+ -boot-load-size 4 \
1745
+ -boot-info-table \
1746
+ -eltorito-alt-boot \
1747
+ -e boot/grub/efiboot.img \
1748
+ -o ${output} ${this.settings.iso_work}`;
1749
+ return command;
1750
+ }
1751
+ /**
1752
+ * xorriso
1753
+ */
1754
+ // uefi_opt="-uefi_elToritoAltBoot-alt-boot -e boot/grub/efiboot.img -isohybrid-gpt-basdat -no-emul-boot"
1755
+ let uefi_elToritoAltBoot = '';
1756
+ let uefi_e = '';
1757
+ let uefi_isohybridGptBasdat = '';
1758
+ let uefi_noEmulBoot = '';
1759
+ if (this.settings.config.make_efi) {
1760
+ uefi_elToritoAltBoot = '-eltorito-alt-boot';
1761
+ uefi_e = '-e boot/grub/efiboot.img';
1762
+ uefi_isohybridGptBasdat = '-isohybrid-gpt-basdat';
1763
+ uefi_noEmulBoot = '-no-emul-boot';
1764
+ }
1765
+ /**
1766
+ * L'immagine efi è efiboot.img ed è
1767
+ * presente in boot/grub/efiboot.img
1768
+ * per cui:
1769
+ * -append_partition 2 0xef efiboot.img
1770
+ * --efi-boot efiboot.img
1771
+ * non sono necessari
1772
+ */
1773
+ command = `xorriso -as mkisofs \
1774
+ -J \
1775
+ -joliet-long \
1776
+ -l \
1777
+ -iso-level 3 \
1778
+ ${isoHybridMbr} \
1779
+ -partition_offset 16 \
1780
+ -V ${this.volid} \
1781
+ -b isolinux/isolinux.bin \
1782
+ -c isolinux/boot.cat \
1783
+ -no-emul-boot \
1784
+ -boot-load-size 4 \
1785
+ -boot-info-table \
1786
+ ${uefi_elToritoAltBoot} \
1787
+ ${uefi_e} \
1788
+ ${uefi_isohybridGptBasdat} \
1789
+ ${uefi_noEmulBoot} \
1790
+ -o ${output} ${this.settings.iso_work}`;
1791
+ return command;
1792
+ }
1793
+ /**
1794
+ * Creazione link desktop per lxde
1795
+ * @param name
1796
+ * @param icon
1797
+ */
1798
+ lxdeLink(file, name, icon) {
1799
+ if (this.verbose) {
1800
+ console.log('Ovary: lxdeLink');
1801
+ }
1802
+ const lnk = `lnk-${file}`;
1803
+ let text = '';
1804
+ text += `echo "[Desktop Entry]" >$DESKTOP/${lnk}\n`;
1805
+ text += `echo "Type=Link" >> $DESKTOP/${lnk}\n`;
1806
+ text += `echo "Name=${name}" >> $DESKTOP/${lnk}\n`;
1807
+ text += `echo "Icon=${icon}" >> $DESKTOP/${lnk}\n`;
1808
+ text += `echo "URL=/usr/share/applications/${file}" >> $DESKTOP/${lnk}\n\n`;
1809
+ return text;
1810
+ }
1811
+ }
1812
+ /**
1813
+ * FUNCTIONS
1814
+ */
1815
+ /**
1816
+ * Crea il path se non esiste
1817
+ * @param path
1818
+ */
1819
+ async function makeIfNotExist(path, verbose = false) {
1820
+ if (verbose) {
1821
+ console.log(`Ovary: makeIfNotExist(${path})`);
1822
+ }
1823
+ const echo = Utils.setEcho(verbose);
1824
+ let cmd = `# ${path} alreasy exist`;
1825
+ if (!fs.existsSync(path)) {
1826
+ cmd = `mkdir ${path} -p`;
1827
+ await exec(cmd, echo);
1828
+ }
1829
+ return cmd;
1830
+ }
1831
+ /**
1832
+ *
1833
+ * @param cmd
1834
+ * @param echo
1835
+ */
1836
+ async function rexec(cmd, verbose = false) {
1837
+ if (verbose) {
1838
+ console.log(`Ovary: rexec(${cmd})`);
1839
+ }
1840
+ const echo = Utils.setEcho(verbose);
1841
+ /**
1842
+ * skip umount errors
1843
+ */
1844
+ const check = await exec(cmd, echo);
1845
+ if (!cmd.startsWith('umount') && check.code !== 0) {
1846
+ console.log(`eggs >>> error on command: ` + chalk.cyan(cmd) + ', code: ' + chalk.cyan(check.code));
1847
+ }
1848
+ return cmd;
1849
+ }