typescript-virtual-container 1.5.2 → 1.5.4

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 (364) hide show
  1. package/README.md +43 -23
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/SSHMimic/executor.js +23 -5
  4. package/dist/commands/basename.d.ts +13 -0
  5. package/dist/commands/basename.js +45 -0
  6. package/dist/commands/file.d.ts +8 -0
  7. package/dist/commands/file.js +57 -0
  8. package/dist/commands/fun.d.ts +32 -0
  9. package/dist/commands/fun.js +172 -0
  10. package/dist/commands/ifconfig.d.ts +7 -0
  11. package/dist/commands/ifconfig.js +52 -0
  12. package/dist/commands/last.d.ts +13 -0
  13. package/dist/commands/last.js +68 -0
  14. package/dist/commands/manuals-bundle.js +598 -6
  15. package/dist/commands/registry.js +24 -2
  16. package/dist/commands/runtime.js +159 -106
  17. package/dist/commands/sh.js +5 -0
  18. package/dist/commands/tput.d.ts +13 -0
  19. package/dist/commands/tput.js +76 -0
  20. package/dist/commands/w.d.ts +7 -0
  21. package/dist/commands/w.js +38 -0
  22. package/dist/utils/expand.d.ts +12 -0
  23. package/dist/utils/expand.js +84 -0
  24. package/package.json +9 -3
  25. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -50
  26. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -31
  27. package/.github/dependabot.yml +0 -27
  28. package/.github/pull_request_template.md +0 -21
  29. package/.github/workflows/create-pull-request.yml +0 -85
  30. package/.github/workflows/publish.yml +0 -25
  31. package/.github/workflows/test-battery.yml +0 -102
  32. package/.vscode/settings.json +0 -20
  33. package/CODE_OF_CONDUCT.md +0 -39
  34. package/CONTRIBUTING.md +0 -59
  35. package/HONEYPOT.md +0 -358
  36. package/SECURITY.md +0 -33
  37. package/benchmark-results.txt +0 -40
  38. package/benchmark-virtualshell.ts +0 -88
  39. package/biome.json +0 -37
  40. package/build.js +0 -22
  41. package/builds/fortune-nyx-v1.5.1-directbash-k6.1.0.mjs +0 -1768
  42. package/builds/fortune-nyx-v1.5.1-ssh-nosftp.js +0 -1768
  43. package/builds/fortune-nyx-v1.5.1-ssh.cjs +0 -1769
  44. package/builds/fortune-nyx-v1.5.1-web.min.js +0 -17022
  45. package/bun.lock +0 -244
  46. package/docs/.nojekyll +0 -1
  47. package/docs/app.js +0 -1755
  48. package/docs/assets/hierarchy.js +0 -1
  49. package/docs/assets/highlight.css +0 -162
  50. package/docs/assets/icons.js +0 -18
  51. package/docs/assets/icons.svg +0 -1
  52. package/docs/assets/main.js +0 -60
  53. package/docs/assets/navigation.js +0 -1
  54. package/docs/assets/search.js +0 -1
  55. package/docs/assets/style.css +0 -1633
  56. package/docs/classes/HoneyPot.html +0 -31
  57. package/docs/classes/IdleManager.html +0 -162
  58. package/docs/classes/SshClient.html +0 -66
  59. package/docs/classes/VirtualFileSystem.html +0 -279
  60. package/docs/classes/VirtualPackageManager.html +0 -63
  61. package/docs/classes/VirtualSftpServer.html +0 -169
  62. package/docs/classes/VirtualShell.html +0 -285
  63. package/docs/classes/VirtualSshServer.html +0 -182
  64. package/docs/classes/VirtualUserManager.html +0 -276
  65. package/docs/demo.html +0 -82
  66. package/docs/functions/assertDiff.html +0 -6
  67. package/docs/functions/diffSnapshots.html +0 -7
  68. package/docs/functions/formatDiff.html +0 -6
  69. package/docs/functions/getArg.html +0 -13
  70. package/docs/functions/getFlag.html +0 -15
  71. package/docs/functions/ifFlag.html +0 -11
  72. package/docs/hierarchy.html +0 -1
  73. package/docs/index.html +0 -1869
  74. package/docs/interfaces/AuditLogEntry.html +0 -6
  75. package/docs/interfaces/CommandContext.html +0 -22
  76. package/docs/interfaces/CommandResult.html +0 -26
  77. package/docs/interfaces/ExecStream.html +0 -11
  78. package/docs/interfaces/HoneyPotStats.html +0 -16
  79. package/docs/interfaces/IdleManagerOptions.html +0 -7
  80. package/docs/interfaces/InstalledPackage.html +0 -20
  81. package/docs/interfaces/NanoEditorSession.html +0 -8
  82. package/docs/interfaces/PackageDefinition.html +0 -30
  83. package/docs/interfaces/PackageFile.html +0 -8
  84. package/docs/interfaces/PasswordChallenge.html +0 -16
  85. package/docs/interfaces/RemoveOptions.html +0 -4
  86. package/docs/interfaces/ShellEnv.html +0 -6
  87. package/docs/interfaces/ShellModule.html +0 -14
  88. package/docs/interfaces/ShellProperties.html +0 -14
  89. package/docs/interfaces/ShellStream.html +0 -11
  90. package/docs/interfaces/SudoChallenge.html +0 -24
  91. package/docs/interfaces/VfsBaseNode.html +0 -12
  92. package/docs/interfaces/VfsDiff.html +0 -10
  93. package/docs/interfaces/VfsDiffEntry.html +0 -6
  94. package/docs/interfaces/VfsDiffModified.html +0 -10
  95. package/docs/interfaces/VfsDirectoryNode.html +0 -15
  96. package/docs/interfaces/VfsFileNode.html +0 -17
  97. package/docs/interfaces/VfsOptions.html +0 -26
  98. package/docs/interfaces/VfsSnapshot.html +0 -3
  99. package/docs/interfaces/VfsSnapshotBaseNode.html +0 -8
  100. package/docs/interfaces/VfsSnapshotDirectoryNode.html +0 -10
  101. package/docs/interfaces/VfsSnapshotFileNode.html +0 -12
  102. package/docs/interfaces/VirtualActiveSession.html +0 -12
  103. package/docs/interfaces/VirtualSftpServerOptions.html +0 -7
  104. package/docs/interfaces/VirtualShellVfsLike.html +0 -15
  105. package/docs/interfaces/VirtualShellVfsOptions.html +0 -3
  106. package/docs/interfaces/WriteFileOptions.html +0 -6
  107. package/docs/media/LICENSE +0 -21
  108. package/docs/modules.html +0 -1
  109. package/docs/types/ArgParseOptions.html +0 -4
  110. package/docs/types/CommandMode.html +0 -2
  111. package/docs/types/CommandOutcome.html +0 -2
  112. package/docs/types/IdleState.html +0 -1
  113. package/docs/types/VfsNodeStats.html +0 -2
  114. package/docs/types/VfsNodeType.html +0 -2
  115. package/docs/types/VfsPersistenceMode.html +0 -5
  116. package/docs/types/VfsSnapshotNode.html +0 -2
  117. package/examples/README.md +0 -288
  118. package/examples/app.js +0 -1755
  119. package/examples/app.ts +0 -299
  120. package/examples/build.js +0 -27
  121. package/examples/demo.html +0 -33
  122. package/examples/honeypot-audit.ts +0 -180
  123. package/examples/honeypot-export.ts +0 -253
  124. package/examples/honeypot-quickstart.ts +0 -110
  125. package/examples/index.html +0 -82
  126. package/examples/server.js +0 -55
  127. package/polyfills/buffer.js +0 -117
  128. package/polyfills/node_child_process/index.js +0 -2
  129. package/polyfills/node_crypto/index.js +0 -167
  130. package/polyfills/node_events/index.js +0 -9
  131. package/polyfills/node_fs/index.js +0 -202
  132. package/polyfills/node_fs/promises.js +0 -4
  133. package/polyfills/node_os/index.js +0 -9
  134. package/polyfills/node_path/index.js +0 -28
  135. package/polyfills/node_vm/index.js +0 -7
  136. package/polyfills/node_zlib/index.js +0 -3
  137. package/polyfills/process.js +0 -14
  138. package/polyfills/ssh2/index.js +0 -75
  139. package/scripts/build-all.mjs +0 -226
  140. package/scripts/build-names.mjs +0 -43
  141. package/scripts/generate-manuals-bundle.mjs +0 -49
  142. package/scripts/postinstall.js +0 -42
  143. package/scripts/publish-package.sh +0 -70
  144. package/src/Honeypot/index.ts +0 -457
  145. package/src/SSHClient/index.ts +0 -270
  146. package/src/SSHMimic/exec.ts +0 -49
  147. package/src/SSHMimic/executor.ts +0 -251
  148. package/src/SSHMimic/hostKey.ts +0 -21
  149. package/src/SSHMimic/index.ts +0 -337
  150. package/src/SSHMimic/loginBanner.ts +0 -36
  151. package/src/SSHMimic/loginFormat.ts +0 -10
  152. package/src/SSHMimic/prompt.ts +0 -14
  153. package/src/SSHMimic/sftp.ts +0 -883
  154. package/src/VirtualFileSystem/binaryPack.ts +0 -258
  155. package/src/VirtualFileSystem/index.ts +0 -1193
  156. package/src/VirtualFileSystem/internalTypes.ts +0 -43
  157. package/src/VirtualFileSystem/journal.ts +0 -171
  158. package/src/VirtualFileSystem/path.ts +0 -74
  159. package/src/VirtualPackageManager/index.ts +0 -1006
  160. package/src/VirtualShell/idleManager.ts +0 -137
  161. package/src/VirtualShell/index.ts +0 -475
  162. package/src/VirtualShell/shell.ts +0 -700
  163. package/src/VirtualShell/shellParser.ts +0 -285
  164. package/src/VirtualUserManager/index.ts +0 -758
  165. package/src/bun.d.ts +0 -1
  166. package/src/commands/adduser.ts +0 -103
  167. package/src/commands/alias.ts +0 -69
  168. package/src/commands/apt.ts +0 -233
  169. package/src/commands/awk.ts +0 -168
  170. package/src/commands/base64.ts +0 -29
  171. package/src/commands/cat.ts +0 -52
  172. package/src/commands/cd.ts +0 -25
  173. package/src/commands/chmod.ts +0 -85
  174. package/src/commands/clear.ts +0 -15
  175. package/src/commands/command-helpers.ts +0 -286
  176. package/src/commands/cp.ts +0 -83
  177. package/src/commands/curl.ts +0 -147
  178. package/src/commands/cut.ts +0 -36
  179. package/src/commands/date.ts +0 -30
  180. package/src/commands/declare.ts +0 -49
  181. package/src/commands/deluser.ts +0 -98
  182. package/src/commands/df.ts +0 -23
  183. package/src/commands/diff.ts +0 -43
  184. package/src/commands/dpkg.ts +0 -180
  185. package/src/commands/du.ts +0 -56
  186. package/src/commands/echo.ts +0 -58
  187. package/src/commands/env.ts +0 -23
  188. package/src/commands/exit.ts +0 -18
  189. package/src/commands/export.ts +0 -34
  190. package/src/commands/find.ts +0 -68
  191. package/src/commands/free.ts +0 -47
  192. package/src/commands/grep.ts +0 -116
  193. package/src/commands/groups.ts +0 -19
  194. package/src/commands/gzip.ts +0 -88
  195. package/src/commands/head.ts +0 -52
  196. package/src/commands/help.ts +0 -152
  197. package/src/commands/helpers.ts +0 -234
  198. package/src/commands/history.ts +0 -34
  199. package/src/commands/hostname.ts +0 -14
  200. package/src/commands/htop.ts +0 -20
  201. package/src/commands/id.ts +0 -19
  202. package/src/commands/index.ts +0 -9
  203. package/src/commands/kill.ts +0 -19
  204. package/src/commands/ln.ts +0 -71
  205. package/src/commands/ls.ts +0 -243
  206. package/src/commands/lsb-release.ts +0 -63
  207. package/src/commands/man.ts +0 -31
  208. package/src/commands/manuals/adduser.txt +0 -11
  209. package/src/commands/manuals/apt-cache.txt +0 -12
  210. package/src/commands/manuals/apt.txt +0 -20
  211. package/src/commands/manuals/awk.txt +0 -13
  212. package/src/commands/manuals/cat.txt +0 -14
  213. package/src/commands/manuals/cd.txt +0 -16
  214. package/src/commands/manuals/chmod.txt +0 -16
  215. package/src/commands/manuals/clear.txt +0 -10
  216. package/src/commands/manuals/cp.txt +0 -10
  217. package/src/commands/manuals/curl.txt +0 -20
  218. package/src/commands/manuals/date.txt +0 -14
  219. package/src/commands/manuals/declare.txt +0 -12
  220. package/src/commands/manuals/deluser.txt +0 -10
  221. package/src/commands/manuals/df.txt +0 -10
  222. package/src/commands/manuals/dpkg-query.txt +0 -11
  223. package/src/commands/manuals/dpkg.txt +0 -14
  224. package/src/commands/manuals/du.txt +0 -11
  225. package/src/commands/manuals/echo.txt +0 -11
  226. package/src/commands/manuals/false.txt +0 -10
  227. package/src/commands/manuals/find.txt +0 -11
  228. package/src/commands/manuals/free.txt +0 -12
  229. package/src/commands/manuals/grep.txt +0 -13
  230. package/src/commands/manuals/groups.txt +0 -10
  231. package/src/commands/manuals/gzip.txt +0 -11
  232. package/src/commands/manuals/head.txt +0 -10
  233. package/src/commands/manuals/help.txt +0 -11
  234. package/src/commands/manuals/history.txt +0 -11
  235. package/src/commands/manuals/hostname.txt +0 -10
  236. package/src/commands/manuals/id.txt +0 -10
  237. package/src/commands/manuals/kill.txt +0 -13
  238. package/src/commands/manuals/ls.txt +0 -20
  239. package/src/commands/manuals/lsb_release.txt +0 -14
  240. package/src/commands/manuals/mkdir.txt +0 -10
  241. package/src/commands/manuals/mv.txt +0 -10
  242. package/src/commands/manuals/nano.txt +0 -11
  243. package/src/commands/manuals/neofetch.txt +0 -10
  244. package/src/commands/manuals/node.txt +0 -13
  245. package/src/commands/manuals/npm.txt +0 -13
  246. package/src/commands/manuals/npx.txt +0 -13
  247. package/src/commands/manuals/passwd.txt +0 -11
  248. package/src/commands/manuals/ping.txt +0 -10
  249. package/src/commands/manuals/printf.txt +0 -11
  250. package/src/commands/manuals/ps.txt +0 -10
  251. package/src/commands/manuals/pwd.txt +0 -10
  252. package/src/commands/manuals/python3.txt +0 -13
  253. package/src/commands/manuals/readlink.txt +0 -10
  254. package/src/commands/manuals/return.txt +0 -10
  255. package/src/commands/manuals/rm.txt +0 -10
  256. package/src/commands/manuals/sed.txt +0 -11
  257. package/src/commands/manuals/set.txt +0 -11
  258. package/src/commands/manuals/shift.txt +0 -10
  259. package/src/commands/manuals/sleep.txt +0 -10
  260. package/src/commands/manuals/sort.txt +0 -12
  261. package/src/commands/manuals/source.txt +0 -11
  262. package/src/commands/manuals/ssh.txt +0 -11
  263. package/src/commands/manuals/stat.txt +0 -10
  264. package/src/commands/manuals/su.txt +0 -13
  265. package/src/commands/manuals/sudo.txt +0 -11
  266. package/src/commands/manuals/tail.txt +0 -10
  267. package/src/commands/manuals/tar.txt +0 -19
  268. package/src/commands/manuals/tee.txt +0 -10
  269. package/src/commands/manuals/test.txt +0 -11
  270. package/src/commands/manuals/touch.txt +0 -11
  271. package/src/commands/manuals/tr.txt +0 -10
  272. package/src/commands/manuals/trap.txt +0 -10
  273. package/src/commands/manuals/true.txt +0 -10
  274. package/src/commands/manuals/type.txt +0 -10
  275. package/src/commands/manuals/uname.txt +0 -12
  276. package/src/commands/manuals/uniq.txt +0 -12
  277. package/src/commands/manuals/unset.txt +0 -10
  278. package/src/commands/manuals/uptime.txt +0 -11
  279. package/src/commands/manuals/wc.txt +0 -12
  280. package/src/commands/manuals/wget.txt +0 -12
  281. package/src/commands/manuals/which.txt +0 -10
  282. package/src/commands/manuals/whoami.txt +0 -10
  283. package/src/commands/manuals/xargs.txt +0 -10
  284. package/src/commands/manuals-bundle.ts +0 -898
  285. package/src/commands/mkdir.ts +0 -31
  286. package/src/commands/mv.ts +0 -50
  287. package/src/commands/nano.ts +0 -38
  288. package/src/commands/neofetch.ts +0 -53
  289. package/src/commands/node.ts +0 -341
  290. package/src/commands/npm.ts +0 -132
  291. package/src/commands/passwd.ts +0 -50
  292. package/src/commands/ping.ts +0 -32
  293. package/src/commands/printf.ts +0 -129
  294. package/src/commands/ps.ts +0 -58
  295. package/src/commands/pwd.ts +0 -9
  296. package/src/commands/python.ts +0 -2229
  297. package/src/commands/read.ts +0 -46
  298. package/src/commands/registry.ts +0 -249
  299. package/src/commands/rm.ts +0 -42
  300. package/src/commands/runtime.ts +0 -378
  301. package/src/commands/sed.ts +0 -68
  302. package/src/commands/seq.ts +0 -43
  303. package/src/commands/set.ts +0 -29
  304. package/src/commands/sh.ts +0 -467
  305. package/src/commands/shift.ts +0 -63
  306. package/src/commands/sleep.ts +0 -20
  307. package/src/commands/sort.ts +0 -46
  308. package/src/commands/source.ts +0 -52
  309. package/src/commands/stat.ts +0 -61
  310. package/src/commands/su.ts +0 -72
  311. package/src/commands/sudo.ts +0 -76
  312. package/src/commands/tail.ts +0 -53
  313. package/src/commands/tar.ts +0 -102
  314. package/src/commands/tee.ts +0 -36
  315. package/src/commands/test.ts +0 -137
  316. package/src/commands/touch.ts +0 -28
  317. package/src/commands/tr.ts +0 -70
  318. package/src/commands/tree.ts +0 -20
  319. package/src/commands/true.ts +0 -27
  320. package/src/commands/type.ts +0 -48
  321. package/src/commands/uname.ts +0 -29
  322. package/src/commands/uniq.ts +0 -39
  323. package/src/commands/unset.ts +0 -17
  324. package/src/commands/uptime.ts +0 -54
  325. package/src/commands/wc.ts +0 -55
  326. package/src/commands/wget.ts +0 -148
  327. package/src/commands/which.ts +0 -37
  328. package/src/commands/who.ts +0 -25
  329. package/src/commands/whoami.ts +0 -14
  330. package/src/commands/xargs.ts +0 -31
  331. package/src/index.ts +0 -67
  332. package/src/modules/linuxRootfs.ts +0 -1961
  333. package/src/modules/neofetch.ts +0 -358
  334. package/src/modules/shellInteractive.ts +0 -57
  335. package/src/modules/shellRuntime.ts +0 -76
  336. package/src/self-standalone.ts +0 -542
  337. package/src/standalone-wo-sftp.ts +0 -38
  338. package/src/standalone.ts +0 -72
  339. package/src/types/commands.ts +0 -146
  340. package/src/types/pipeline.ts +0 -52
  341. package/src/types/streams.ts +0 -32
  342. package/src/types/tar-stream.d.ts +0 -38
  343. package/src/types/vfs.ts +0 -98
  344. package/src/utils/expand.ts +0 -491
  345. package/src/utils/perfLogger.ts +0 -72
  346. package/src/utils/tokenize.ts +0 -98
  347. package/src/utils/vfsDiff.ts +0 -275
  348. package/tests/command-helpers.test.ts +0 -116
  349. package/tests/commands-admin-net.test.ts +0 -441
  350. package/tests/commands-advanced.test.ts +0 -456
  351. package/tests/commands-core.test.ts +0 -562
  352. package/tests/commands-missing.test.ts +0 -570
  353. package/tests/commands-specific-units.test.ts +0 -327
  354. package/tests/commands-text-sys.test.ts +0 -445
  355. package/tests/expand.test.ts +0 -170
  356. package/tests/helpers.test.ts +0 -97
  357. package/tests/new-features.test.ts +0 -1036
  358. package/tests/parser-executor.test.ts +0 -37
  359. package/tests/sftp.test.ts +0 -323
  360. package/tests/ssh-exec.test.ts +0 -45
  361. package/tests/test-helper.ts +0 -79
  362. package/tests/users.test.ts +0 -86
  363. package/tsconfig.json +0 -49
  364. package/typedoc.json +0 -47
@@ -1,1961 +0,0 @@
1
- /** biome-ignore-all lint/style/useNamingConvention: ENV VAR KEYS + system names */
2
- /**
3
- * linuxRootfs.ts
4
- *
5
- * Bootstraps a realistic Linux directory hierarchy in the VFS.
6
- * Called once during VirtualShell initialization. Idempotent — skips
7
- * paths that already exist so FS-mode snapshots survive restarts.
8
- *
9
- * Emulation fidelity: modelled after a Fortune GNU/Linux 1.0 (Nyx)
10
- * container with Firecracker MicroVM kernel 6.x, virtio block devices
11
- * (vda/vdb/vdc/vdd), cgroups v1 hierarchy, Node.js 22, Python 3.12,
12
- * GCC 13, OpenJDK 21, and a Fortune-style package database.
13
- *
14
- * Public API:
15
- * - bootstrapLinuxRootfs() one-shot boot (VirtualShell calls this)
16
- * - refreshProc() refresh /proc/* (call on session changes)
17
- * - syncEtcPasswd() sync /etc/passwd|group|shadow from UserManager
18
- * - createLinuxRootfsEngine() engine with .boot() + .tick() for live loops
19
- */
20
-
21
- import * as os from "node:os";
22
- import VirtualFileSystem from "../VirtualFileSystem";
23
- import { decodeVfs } from "../VirtualFileSystem/binaryPack";
24
- import type { ShellProperties } from "../VirtualShell";
25
- import type { VirtualActiveSession, VirtualUserManager } from "../VirtualUserManager";
26
-
27
-
28
- // ─── helpers ────────────────────────────────────────────────────────────────
29
-
30
- function ensureDir(vfs: VirtualFileSystem, path: string, mode = 0o755): void {
31
- if (!vfs.exists(path)) vfs.mkdir(path, mode);
32
- }
33
-
34
- function ensureFile(
35
- vfs: VirtualFileSystem,
36
- path: string,
37
- content: string,
38
- mode = 0o644,
39
- ): void {
40
- vfs.writeStub(path, content, mode);
41
- }
42
-
43
- function write(vfs: VirtualFileSystem, path: string, content: string): void {
44
- vfs.writeFile(path, content);
45
- }
46
-
47
- /** FNV-1a 32-bit — deterministic seed from any string */
48
- function fnv1a(str: string): number {
49
- let h = 2166136261;
50
- for (let i = 0; i < str.length; i++) {
51
- h ^= str.charCodeAt(i);
52
- h = Math.imul(h, 16777619);
53
- }
54
- return h >>> 0;
55
- }
56
-
57
- // ─── /etc ────────────────────────────────────────────────────────────────────
58
-
59
- function bootstrapEtc(
60
- vfs: VirtualFileSystem,
61
- hostname: string,
62
- props: ShellProperties,
63
- ): void {
64
- ensureDir(vfs, "/etc");
65
-
66
- // os-release — Fortune Nyx identity
67
- ensureFile(
68
- vfs,
69
- "/etc/os-release",
70
- `${[
71
- `NAME="Fortune GNU/Linux"`,
72
- `PRETTY_NAME="${props.os}"`,
73
- `ID=fortune`,
74
- `ID_LIKE=debian`,
75
- `HOME_URL="https://github.com/itsrealfortune/typescript-virtual-container"`,
76
- `VERSION_CODENAME=nyx`,
77
- `VERSION_ID="24.04"`,
78
- `FORTUNE_CODENAME=nyx`,
79
- ].join("\n")}\n`,
80
- );
81
-
82
- ensureFile(vfs, "/etc/debian_version", "nyx/stable\n");
83
- ensureFile(vfs, "/etc/hostname", `${hostname}\n`);
84
- ensureFile(
85
- vfs,
86
- "/etc/shells",
87
- "/bin/sh\n/bin/bash\n/usr/bin/bash\n/bin/dash\n/usr/bin/dash\n",
88
- );
89
- ensureFile(
90
- vfs,
91
- "/etc/profile",
92
- `${[
93
- "export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
94
- "export PS1='\\u@\\h:\\w\\$ '",
95
- ].join("\n")}\n`,
96
- );
97
-
98
- ensureFile(vfs, "/etc/issue", "Fortune GNU/Linux 24.04 LTS \\n \\l\n");
99
- ensureFile(vfs, "/etc/issue.net", "Fortune GNU/Linux 24.04 LTS\n");
100
- ensureFile(
101
- vfs,
102
- "/etc/motd",
103
- ["", `Welcome to ${props.os}`, `Kernel: ${props.kernel}`, ""].join("\n"),
104
- );
105
- ensureFile(vfs, "/etc/lsb-release",
106
- `${[
107
- "DISTRIB_ID=Fortune",
108
- "DISTRIB_RELEASE=24.04",
109
- "DISTRIB_CODENAME=nyx",
110
- `DISTRIB_DESCRIPTION="${props.os}"`,
111
- ].join("\n")}\n`,
112
- );
113
-
114
- // APT — Fortune Nyx sources
115
- ensureDir(vfs, "/etc/apt");
116
- ensureDir(vfs, "/etc/apt/sources.list.d");
117
- ensureDir(vfs, "/etc/apt/trusted.gpg.d");
118
- ensureDir(vfs, "/etc/apt/keyrings");
119
- ensureFile(
120
- vfs,
121
- "/etc/apt/sources.list",
122
- `${[
123
- "# Fortune GNU/Linux package sources (Fortune 1.0 Nyx)",
124
- "deb [virtual] fortune://packages.fortune.local nyx main contrib non-free",
125
- "deb [virtual] fortune://packages.fortune.local nyx-updates main contrib non-free",
126
- "deb [virtual] fortune://security.fortune.local nyx-security main",
127
- ].join("\n")}\n`,
128
- );
129
- ensureFile(vfs, "/etc/apt/apt.conf.d/70debconf", `// debconf config\n`);
130
-
131
- // network
132
- ensureDir(vfs, "/etc/network");
133
- ensureFile(
134
- vfs,
135
- "/etc/network/interfaces",
136
- `${[
137
- "auto lo",
138
- "iface lo inet loopback",
139
- "",
140
- "auto eth0",
141
- "iface eth0 inet dhcp",
142
- ].join("\n")}\n`,
143
- );
144
- ensureDir(vfs, "/etc/netplan");
145
- ensureFile(
146
- vfs,
147
- "/etc/netplan/01-eth0.yaml",
148
- `${[
149
- "network:",
150
- " version: 2",
151
- " ethernets:",
152
- " eth0:",
153
- " dhcp4: true",
154
- ].join("\n")}\n`,
155
- );
156
-
157
- ensureFile(vfs, "/etc/resolv.conf", "nameserver 1.1.1.1\nnameserver 8.8.8.8\n");
158
-
159
- ensureFile(
160
- vfs,
161
- "/etc/hosts",
162
- `${[
163
- "127.0.0.1 localhost",
164
- `127.0.1.1 ${hostname}`,
165
- "::1 localhost ip6-localhost ip6-loopback",
166
- "fe00::0 ip6-localnet",
167
- "ff00::0 ip6-mcastprefix",
168
- "ff02::1 ip6-allnodes",
169
- "ff02::2 ip6-allrouters",
170
- ].join("\n")}\n`,
171
- );
172
-
173
- ensureFile(vfs, "/etc/nsswitch.conf",
174
- `${[
175
- "passwd: files systemd",
176
- "group: files systemd",
177
- "shadow: files",
178
- "hosts: files dns",
179
- "networks: files",
180
- "protocols: db files",
181
- "services: db files",
182
- "ethers: db files",
183
- "rpc: db files",
184
- ].join("\n")}\n`,
185
- );
186
-
187
- ensureDir(vfs, "/etc/cron.d");
188
- ensureDir(vfs, "/etc/cron.daily");
189
- ensureDir(vfs, "/etc/cron.hourly");
190
- ensureDir(vfs, "/etc/cron.weekly");
191
- ensureDir(vfs, "/etc/cron.monthly");
192
- ensureDir(vfs, "/etc/init.d");
193
- ensureDir(vfs, "/etc/systemd");
194
- ensureDir(vfs, "/etc/systemd/system");
195
- ensureDir(vfs, "/etc/systemd/system/multi-user.target.wants");
196
- ensureDir(vfs, "/etc/systemd/network");
197
- ensureFile(vfs, "/etc/systemd/system.conf",
198
- "[Manager]\nDefaultTimeoutStartSec=90s\nDefaultTimeoutStopSec=90s\n",
199
- );
200
-
201
- // fstab — virtio block devices matching Firecracker layout
202
- ensureFile(
203
- vfs,
204
- "/etc/fstab",
205
- `${[
206
- "# <file system> <mount point> <type> <options> <dump> <pass>",
207
- "/dev/vda / ext4 rw,relatime,resuid=65534,resgid=65534 0 1",
208
- "/dev/vdb /opt/rclone squashfs ro,relatime,errors=continue 0 0",
209
- "tmpfs /tmp tmpfs defaults,noatime 0 0",
210
- "tmpfs /run tmpfs defaults,noatime 0 0",
211
- "tmpfs /dev/shm tmpfs rw,relatime 0 0",
212
- ].join("\n")}\n`,
213
- );
214
-
215
- // login.defs
216
- ensureFile(
217
- vfs,
218
- "/etc/login.defs",
219
- `${[
220
- "MAIL_DIR /var/mail",
221
- "PASS_MAX_DAYS 99999",
222
- "PASS_MIN_DAYS 0",
223
- "PASS_WARN_AGE 7",
224
- "UID_MIN 1000",
225
- "UID_MAX 60000",
226
- "GID_MIN 1000",
227
- "GID_MAX 60000",
228
- "CREATE_HOME yes",
229
- "UMASK 022",
230
- "USERGROUPS_ENAB yes",
231
- "ENCRYPT_METHOD SHA512",
232
- ].join("\n")}\n`,
233
- );
234
-
235
- // security + pam
236
- ensureDir(vfs, "/etc/security");
237
- ensureFile(vfs, "/etc/security/limits.conf",
238
- "# /etc/security/limits.conf\n* soft nofile 1024\n* hard nofile 65536\n",
239
- );
240
- ensureFile(vfs, "/etc/security/access.conf", "# /etc/security/access.conf\n");
241
-
242
- ensureDir(vfs, "/etc/pam.d");
243
- ensureFile(vfs, "/etc/pam.d/common-auth",
244
- "auth [success=1 default=ignore] pam_unix.so nullok\nauth requisite pam_deny.so\nauth required pam_permit.so\n",
245
- );
246
- ensureFile(vfs, "/etc/pam.d/common-account",
247
- "account [success=1 new_authtok_reqd=done default=ignore] pam_unix.so\naccount requisite pam_deny.so\naccount required pam_permit.so\n",
248
- );
249
- ensureFile(vfs, "/etc/pam.d/common-password",
250
- "password [success=1 default=ignore] pam_unix.so obscure sha512\npassword requisite pam_deny.so\npassword required pam_permit.so\n",
251
- );
252
- ensureFile(vfs, "/etc/pam.d/common-session",
253
- "session [default=1] pam_permit.so\nsession requisite pam_deny.so\nsession required pam_permit.so\nsession optional pam_umask.so\nsession required pam_unix.so\n",
254
- );
255
- ensureFile(vfs, "/etc/pam.d/sshd",
256
- "@include common-auth\n@include common-account\n@include common-session\n",
257
- );
258
- ensureFile(vfs, "/etc/pam.d/login",
259
- "@include common-auth\n@include common-account\n@include common-session\n",
260
- );
261
- ensureFile(vfs, "/etc/pam.d/sudo",
262
- "@include common-auth\n@include common-account\n@include common-session\n",
263
- );
264
-
265
- // sudo
266
- ensureDir(vfs, "/etc/sudoers.d");
267
- ensureFile(vfs, "/etc/sudoers",
268
- "Defaults\tenv_reset\nDefaults\tmail_badpass\nDefaults\tsecure_path=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\nroot ALL=(ALL:ALL) ALL\n%sudo ALL=(ALL:ALL) ALL\n",
269
- 0o440,
270
- );
271
- ensureFile(vfs, "/etc/sudoers.d/README",
272
- "# Files in this directory are parsed by sudo, if the file is not a backup.\n",
273
- 0o440,
274
- );
275
-
276
- // ld
277
- ensureFile(vfs, "/etc/ld.so.conf", "include /etc/ld.so.conf.d/*.conf\n");
278
- ensureDir(vfs, "/etc/ld.so.conf.d");
279
- ensureFile(vfs, "/etc/ld.so.conf.d/x86_64-linux-gnu.conf",
280
- "/lib/x86_64-linux-gnu\n/usr/lib/x86_64-linux-gnu\n",
281
- );
282
- ensureFile(vfs, "/etc/ld.so.conf.d/fakeroot.conf",
283
- "/usr/lib/x86_64-linux-gnu/libfakeroot\n",
284
- );
285
-
286
- // locale + timezone
287
- ensureFile(vfs, "/etc/locale.conf", "LANG=en_US.UTF-8\n");
288
- ensureFile(vfs, "/etc/locale.gen", "en_US.UTF-8 UTF-8\n");
289
- ensureFile(vfs, "/etc/default/locale", "LANG=en_US.UTF-8\n");
290
- ensureFile(vfs, "/etc/timezone", "UTC\n");
291
- ensureFile(vfs, "/etc/localtime", "UTC\n");
292
-
293
- // environment
294
- ensureFile(vfs, "/etc/environment",
295
- "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\n",
296
- );
297
-
298
- // adduser.conf
299
- ensureFile(vfs, "/etc/adduser.conf",
300
- `${[
301
- "DSHELL=/bin/bash",
302
- "DHOME=/home",
303
- "GROUPHOMES=no",
304
- "LETTERHOMES=no",
305
- "SKEL=/etc/skel",
306
- "FIRST_SYSTEM_UID=100",
307
- "LAST_SYSTEM_UID=999",
308
- "FIRST_SYSTEM_GID=100",
309
- "LAST_SYSTEM_GID=999",
310
- "FIRST_UID=1000",
311
- "LAST_UID=59999",
312
- "FIRST_GID=1000",
313
- "LAST_GID=59999",
314
- "USERGROUPS=yes",
315
- "NAME_REGEX=\"^[a-z][-a-z0-9_]*$\"",
316
- "SYS_NAME_REGEX=\"^[a-z_][-a-z0-9_]*$\"",
317
- ].join("\n")}\n`,
318
- );
319
-
320
- // /etc/skel
321
- ensureDir(vfs, "/etc/skel");
322
- ensureFile(vfs, "/etc/skel/.bashrc",
323
- `${[
324
- "# ~/.bashrc: executed by bash(1) for non-login shells.",
325
- "case $- in",
326
- " *i*) ;;",
327
- " *) return;;",
328
- "esac",
329
- "HISTCONTROL=ignoreboth",
330
- "HISTSIZE=1000",
331
- "HISTFILESIZE=2000",
332
- "shopt -s histappend",
333
- "shopt -s checkwinsize",
334
- "alias ll='ls -alF'",
335
- "alias la='ls -A'",
336
- "alias l='ls -CF'",
337
- ].join("\n")}\n`,
338
- );
339
- ensureFile(vfs, "/etc/skel/.bash_logout", "# ~/.bash_logout\n");
340
- ensureFile(vfs, "/etc/skel/.profile",
341
- "# ~/.profile\n[ -n \"$BASH_VERSION\" ] && [ -f \"$HOME/.bashrc\" ] && . \"$HOME/.bashrc\"\n",
342
- );
343
-
344
- // alternatives
345
- ensureDir(vfs, "/etc/alternatives");
346
- const alternatives: [string, string][] = [
347
- ["python3", "/usr/bin/python3.12"],
348
- ["python", "/usr/bin/python3.12"],
349
- ["editor", "/usr/bin/nano"],
350
- ["vi", "/usr/bin/nano"],
351
- ["cc", "/usr/bin/gcc"],
352
- ["gcc", "/usr/bin/gcc-13"],
353
- ["g++", "/usr/bin/g++-13"],
354
- ["java", "/usr/lib/jvm/java-21-openjdk-amd64/bin/java"],
355
- ["node", "/usr/bin/node"],
356
- ["npm", "/usr/bin/npm"],
357
- ["awk", "/usr/bin/mawk"],
358
- ["pager", "/usr/bin/less"],
359
- ];
360
- for (const [name, target] of alternatives) {
361
- ensureFile(vfs, `/etc/alternatives/${name}`, target);
362
- }
363
-
364
- // java
365
- ensureDir(vfs, "/etc/java-21-openjdk");
366
- ensureDir(vfs, "/etc/java-21-openjdk/security");
367
- ensureFile(vfs, "/etc/java-21-openjdk/security/java.security", "# java.security\n");
368
- ensureFile(vfs, "/etc/java-21-openjdk/logging.properties", "# logging.properties\n");
369
-
370
- // misc
371
- ensureFile(vfs, "/etc/bash.bashrc",
372
- "# System-wide .bashrc\n[ -z \"$PS1\" ] && return\n",
373
- );
374
- ensureFile(vfs, "/etc/inputrc",
375
- "# /etc/inputrc\n$include /etc/inputrc.d\nset bell-style none\n",
376
- );
377
- ensureFile(vfs, "/etc/magic", "# magic\n");
378
- ensureFile(vfs, "/etc/magic.mime", "# magic.mime\n");
379
- ensureFile(vfs, "/etc/papersize", "a4\n");
380
- ensureFile(vfs, "/etc/ucf.conf", "# ucf.conf\n");
381
- ensureFile(vfs, "/etc/gai.conf",
382
- "# getaddrinfo() configuration\nlabel ::1/128 0\nprecedence ::1/128 50\n",
383
- );
384
- ensureFile(vfs, "/etc/services",
385
- "# Network services\nftp 21/tcp\nssh 22/tcp\nsmtp 25/tcp\nhttp 80/tcp\nhttps 443/tcp\n",
386
- );
387
- ensureFile(vfs, "/etc/protocols",
388
- "# protocols\nip 0 IP\nicmp 1 ICMP\ntcp 6 TCP\nudp 17 UDP\n",
389
- );
390
-
391
- ensureDir(vfs, "/etc/profile.d");
392
- ensureFile(vfs, "/etc/profile.d/01-locale-fix.sh",
393
- "[ -z \"$LANG\" ] && export LANG=en_US.UTF-8\n",
394
- );
395
- ensureFile(vfs, "/etc/profile.d/apps-bin-path.sh",
396
- "export PATH=\"$PATH:/snap/bin\"\n",
397
- );
398
- }
399
-
400
- // ─── /etc/passwd + /etc/group + /etc/shadow ─────────────────────────────────
401
-
402
- /**
403
- * Sync `/etc/passwd`, `/etc/group`, and `/etc/shadow` from the
404
- * VirtualUserManager's current user list into the VFS.
405
- */
406
- export function syncEtcPasswd(
407
- vfs: VirtualFileSystem,
408
- users: VirtualUserManager,
409
- ): void {
410
- const userList = users.listUsers();
411
-
412
- const passwdLines = [
413
- "root:x:0:0:root:/root:/bin/bash",
414
- "daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin",
415
- "bin:x:2:2:bin:/bin:/usr/sbin/nologin",
416
- "sys:x:3:3:sys:/dev:/usr/sbin/nologin",
417
- "sync:x:4:65534:sync:/bin:/bin/sync",
418
- "games:x:5:60:games:/usr/games:/usr/sbin/nologin",
419
- "man:x:6:12:man:/var/cache/man:/usr/sbin/nologin",
420
- "lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin",
421
- "mail:x:8:8:mail:/var/mail:/usr/sbin/nologin",
422
- "news:x:9:9:news:/var/spool/news:/usr/sbin/nologin",
423
- "uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin",
424
- "proxy:x:13:13:proxy:/bin:/usr/sbin/nologin",
425
- "www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin",
426
- "backup:x:34:34:backup:/var/backups:/usr/sbin/nologin",
427
- "list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin",
428
- "irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin",
429
- "_apt:x:42:65534::/nonexistent:/usr/sbin/nologin",
430
- "nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin",
431
- "messagebus:x:100:106::/nonexistent:/usr/sbin/nologin",
432
- "systemd-network:x:998:998:systemd Network Management:/:/usr/sbin/nologin",
433
- "systemd-resolve:x:999:999:systemd Resolver:/:/usr/sbin/nologin",
434
- "polkitd:x:997:997:polkit:/nonexistent:/usr/sbin/nologin",
435
- ];
436
-
437
- let uid = 1000;
438
- for (const u of userList) {
439
- if (u === "root") continue;
440
- passwdLines.push(`${u}:x:${uid}:${uid}::/home/${u}:/bin/bash`);
441
- uid++;
442
- }
443
-
444
- vfs.writeFile("/etc/passwd", `${passwdLines.join("\n")}\n`);
445
-
446
- const sudoers = userList.filter((u) => users.isSudoer(u)).join(",");
447
- const nonRootUsers = userList.filter((u) => u !== "root").join(",");
448
-
449
- const groupLines = [
450
- "root:x:0:",
451
- "daemon:x:1:",
452
- "bin:x:2:",
453
- "sys:x:3:",
454
- "adm:x:4:syslog",
455
- "tty:x:5:",
456
- "disk:x:6:",
457
- "lp:x:7:",
458
- "mail:x:8:",
459
- "news:x:9:",
460
- "uucp:x:10:",
461
- "man:x:12:",
462
- "proxy:x:13:",
463
- "kmem:x:15:",
464
- "dialout:x:20:",
465
- "fax:x:21:",
466
- "voice:x:22:",
467
- "cdrom:x:24:",
468
- "floppy:x:25:",
469
- "tape:x:26:",
470
- `sudo:x:27:${sudoers}`,
471
- "audio:x:29:",
472
- "dip:x:30:",
473
- "www-data:x:33:",
474
- "backup:x:34:",
475
- "operator:x:37:",
476
- "list:x:38:",
477
- "irc:x:39:",
478
- "src:x:40:",
479
- "_apt:x:42:",
480
- "shadow:x:42:",
481
- "utmp:x:43:",
482
- "video:x:44:",
483
- "sasl:x:45:",
484
- "plugdev:x:46:",
485
- "staff:x:50:",
486
- "games:x:60:",
487
- `users:x:100:${nonRootUsers}`,
488
- "nogroup:x:65534:",
489
- "messagebus:x:106:",
490
- "systemd-network:x:998:",
491
- "systemd-resolve:x:999:",
492
- "polkitd:x:997:",
493
- ];
494
- vfs.writeFile("/etc/group", `${groupLines.join("\n")}\n`);
495
-
496
- const shadowLines = [
497
- "root:*:19000:0:99999:7:::",
498
- "daemon:*:19000:0:99999:7:::",
499
- "nobody:*:19000:0:99999:7:::",
500
- "messagebus:*:19000:0:99999:7:::",
501
- "_apt:*:19000:0:99999:7:::",
502
- "systemd-network:!:19000:::::::",
503
- "systemd-resolve:!:19000:::::::",
504
- "polkitd:!:19000:::::::",
505
- ];
506
- for (const u of userList) {
507
- if (u === "root") continue;
508
- shadowLines.push(`${u}:!:19000:0:99999:7:::`);
509
- }
510
- vfs.writeFile("/etc/shadow", `${shadowLines.join("\n")}\n`, { mode: 0o640 });
511
- }
512
-
513
- // ─── /proc helpers ───────────────────────────────────────────────────────────
514
-
515
- function ttyToPid(tty: string): number {
516
- const match = tty.match(/(\d+)$/);
517
- return 1000 + (match?.[1] ? parseInt(match[1], 10) : 0);
518
- }
519
-
520
- function writeProcPid(
521
- vfs: VirtualFileSystem,
522
- pid: number,
523
- username: string,
524
- _tty: string,
525
- cmdline: string,
526
- startedAt: string,
527
- env: Record<string, string>,
528
- ): void {
529
- const dir = `/proc/${pid}`;
530
- ensureDir(vfs, dir);
531
- ensureDir(vfs, `${dir}/fd`);
532
- ensureDir(vfs, `${dir}/fdinfo`);
533
- ensureDir(vfs, `${dir}/net`);
534
-
535
- const uptimeSec = Math.floor((Date.now() - new Date(startedAt).getTime()) / 1000);
536
- const comm = cmdline.split(/\s+/)[0] ?? "bash";
537
-
538
- write(vfs, `${dir}/cmdline`, `${cmdline.replace(/\s+/g, "\0")}\0`);
539
- write(vfs, `${dir}/comm`, comm);
540
- write(
541
- vfs,
542
- `${dir}/status`,
543
- `${[
544
- `Name: ${comm}`,
545
- `Umask: 0022`,
546
- `State: S (sleeping)`,
547
- `Tgid: ${pid}`,
548
- `Pid: ${pid}`,
549
- `PPid: 1`,
550
- `TracerPid: 0`,
551
- `Uid: 0\t0\t0\t0`,
552
- `Gid: 0\t0\t0\t0`,
553
- `FDSize: 64`,
554
- `Groups:`,
555
- `VmPeak: 20480 kB`,
556
- `VmSize: 16384 kB`,
557
- `VmLck: 0 kB`,
558
- `VmPin: 0 kB`,
559
- `VmHWM: 4096 kB`,
560
- `VmRSS: 4096 kB`,
561
- `RssAnon: 512 kB`,
562
- `RssFile: 3584 kB`,
563
- `RssShmem: 0 kB`,
564
- `VmData: 2048 kB`,
565
- `VmStk: 132 kB`,
566
- `VmExe: 924 kB`,
567
- `VmLib: 2744 kB`,
568
- `VmPTE: 52 kB`,
569
- `VmSwap: 0 kB`,
570
- `Threads: 1`,
571
- `SigQ: 0/31968`,
572
- `SigPnd: 0000000000000000`,
573
- `SigBlk: 0000000000010000`,
574
- `SigIgn: 0000000000380004`,
575
- `SigCgt: 000000004b817efb`,
576
- `CapInh: 0000000000000000`,
577
- `CapPrm: 000001ffffffffff`,
578
- `CapEff: 000001ffffffffff`,
579
- `CapBnd: 000001ffffffffff`,
580
- `CapAmb: 0000000000000000`,
581
- `NoNewPrivs: 0`,
582
- `Seccomp: 0`,
583
- `voluntary_ctxt_switches: 100`,
584
- `nonvoluntary_ctxt_switches: 10`,
585
- ].join("\n")}\n`,
586
- );
587
- write(
588
- vfs,
589
- `${dir}/stat`,
590
- `${pid} (${comm}) S 1 ${pid} ${pid} 0 -1 4194304 0 0 0 0 ${uptimeSec} 0 0 0 20 0 1 0 0 16777216 4096 18446744073709551615 93824992235520 93824992290000 140737488347024 0 0 0 65536 3686404 1266761467 1 0 0 17 0 0 0 0 0 0\n`,
591
- );
592
- write(
593
- vfs,
594
- `${dir}/statm`,
595
- `4096 1024 768 231 0 512 0\n`,
596
- );
597
- write(
598
- vfs,
599
- `${dir}/environ`,
600
- `${Object.entries(env).map(([k, v]) => `${k}=${v}`).join("\0")}\0`,
601
- );
602
- write(vfs, `${dir}/cwd`, `/home/${username}\0`);
603
- write(vfs, `${dir}/exe`, "/bin/bash\0");
604
- write(vfs, `${dir}/maps`,
605
- "00400000-004e7000 r-xp 00000000 fd:00 131073 /bin/bash\n" +
606
- "006e7000-006e8000 r--p 000e7000 fd:00 131073 /bin/bash\n" +
607
- "006e8000-006f1000 rw-p 000e8000 fd:00 131073 /bin/bash\n" +
608
- "7fff00000000-7fff00001000 rw-p 00000000 00:00 0 [stack]\n" +
609
- "7fff00000000-7fff00001000 r-xp 00000000 00:00 0 [vdso]\n",
610
- );
611
- write(vfs, `${dir}/limits`,
612
- `${[
613
- "Limit Soft Limit Hard Limit Units",
614
- "Max cpu time unlimited unlimited seconds",
615
- "Max file size unlimited unlimited bytes",
616
- "Max data size unlimited unlimited bytes",
617
- "Max stack size 8388608 unlimited bytes",
618
- "Max core file size 0 unlimited bytes",
619
- "Max resident set unlimited unlimited bytes",
620
- "Max processes 31968 31968 processes",
621
- "Max open files 1048576 1048576 files",
622
- "Max locked memory 8388608 8388608 bytes",
623
- "Max address space unlimited unlimited bytes",
624
- "Max file locks unlimited unlimited locks",
625
- "Max pending signals 31968 31968 signals",
626
- "Max msgqueue size 819200 819200 bytes",
627
- "Max nice priority 0 0",
628
- "Max realtime priority 0 0",
629
- "Max realtime timeout unlimited unlimited us",
630
- ].join("\n")}\n`,
631
- );
632
- write(vfs, `${dir}/io`,
633
- "rchar: 1048576\nwchar: 65536\nsyscr: 512\nsyscw: 64\nread_bytes: 0\nwrite_bytes: 0\ncancelled_write_bytes: 0\n",
634
- );
635
- write(vfs, `${dir}/oom_score`, "0\n");
636
- write(vfs, `${dir}/oom_score_adj`, "0\n");
637
- write(vfs, `${dir}/loginuid`, "0\n");
638
- write(vfs, `${dir}/wchan`, "poll_schedule_timeout\n");
639
- write(vfs, `${dir}/schedstat`, "1000000 0 1\n");
640
-
641
- for (const fd of ["0", "1", "2"]) {
642
- ensureFile(vfs, `${dir}/fd/${fd}`, "");
643
- ensureFile(vfs, `${dir}/fdinfo/${fd}`,
644
- `pos:\t0\nflags:\t0${fd === "0" ? "2" : fd === "1" ? "1" : "1"}02\nmnt_id:\t13\n`,
645
- );
646
- }
647
- }
648
-
649
- // ─── /proc boot log ──────────────────────────────────────────────────────────
650
-
651
- function bootProcLog(vfs: VirtualFileSystem, props: ShellProperties): void {
652
- ensureDir(vfs, "/proc/boot");
653
- ensureFile(
654
- vfs,
655
- "/proc/boot/log",
656
- `${[
657
- `[ 0.000000] Linux version ${props.kernel} (fortune@build) #1 SMP PREEMPT_DYNAMIC`,
658
- "[ 0.000000] Command line: console=ttyS0 reboot=k panic=1 nomodule random.trust_cpu=1 ipv6.disable=1",
659
- "[ 0.000060] BIOS-provided physical RAM map:",
660
- "[ 0.000070] ACPI: RSDP 0x00000000000F05B0 000014 (v00 BOCHS )",
661
- "[ 0.000120] PCI: Using configuration type 1 for base access",
662
- "[ 0.000240] clocksource: tsc-early: mask: 0xffffffffffffffff",
663
- "[ 0.000320] ACPI: IRQ0 used by override",
664
- "[ 0.000420] Initializing cgroup subsys cpuset",
665
- "[ 0.000440] Initializing cgroup subsys cpu",
666
- "[ 0.000450] Initializing cgroup subsys cpuacct",
667
- "[ 0.000460] Linux agpgart interface v0.103",
668
- "[ 0.000480] PCI: pci_cache_line_size set to 64 bytes",
669
- "[ 0.000510] virtio-pci 0000:00:01.0: runtime IRQs not yet assigned",
670
- "[ 0.000680] NET: Registered PF_INET6 protocol family",
671
- "[ 0.000720] Freeing unused kernel image (initmem) memory",
672
- "[ 0.000760] Write protecting the kernel read-only data",
673
- "[ 0.000800] Run /sbin/init as init process",
674
- "[ 0.001200] systemd[1]: Detected virtualization kvm",
675
- "[ 0.001300] systemd[1]: Detected architecture x86-64",
676
- "[ 0.002000] systemd[1]: Starting Fortune GNU/Linux...",
677
- "[ 0.003000] systemd[1]: Started Journal Service",
678
- "[ 0.010000] EXT4-fs (vda): mounted filesystem",
679
- "[ 0.020000] systemd[1]: Reached target Basic System",
680
- "[ 0.030000] systemd[1]: Started Login Service",
681
- ].join("\n")}\n`,
682
- );
683
- ensureFile(vfs, "/proc/boot/version", `Linux ${props.kernel} (virtual)\n`);
684
- }
685
-
686
- // ─── /proc refresh ───────────────────────────────────────────────────────────
687
-
688
- /**
689
- * Populate and refresh `/proc` virtual entries based on host stats and
690
- * provided active sessions. Rewrites uptime, meminfo, cpuinfo, loadavg,
691
- * per-pid entries, and /proc/self.
692
- *
693
- * Safe to call repeatedly — acts as a live kernel state snapshot.
694
- */
695
- export function refreshProc(
696
- vfs: VirtualFileSystem,
697
- props: ShellProperties,
698
- hostname: string,
699
- shellStartTime: number,
700
- sessions: VirtualActiveSession[] = [],
701
- ): void {
702
- ensureDir(vfs, "/proc");
703
-
704
- const uptimeSec = Math.floor((Date.now() - shellStartTime) / 1000);
705
- const idleSec = Math.floor(uptimeSec * 0.9);
706
- write(vfs, "/proc/uptime", `${uptimeSec}.00 ${idleSec}.00\n`);
707
-
708
- // meminfo — real host values, Linux-compatible format
709
- const totalMemKb = Math.floor(os.totalmem() / 1024);
710
- const freeMemKb = Math.floor(os.freemem() / 1024);
711
- const availMemKb = Math.floor(freeMemKb * 0.95);
712
- const buffersKb = Math.floor(totalMemKb * 0.03);
713
- const cachedKb = Math.floor(totalMemKb * 0.08);
714
- const shmemKb = Math.floor(totalMemKb * 0.005);
715
- const slabKb = Math.floor(totalMemKb * 0.02);
716
- const pageTablesKb = Math.floor(totalMemKb * 0.001);
717
- write(
718
- vfs,
719
- "/proc/meminfo",
720
- `${[
721
- `MemTotal: ${String(totalMemKb).padStart(10)} kB`,
722
- `MemFree: ${String(freeMemKb).padStart(10)} kB`,
723
- `MemAvailable: ${String(availMemKb).padStart(10)} kB`,
724
- `Buffers: ${String(buffersKb).padStart(10)} kB`,
725
- `Cached: ${String(cachedKb).padStart(10)} kB`,
726
- `SwapCached: ${String(0).padStart(10)} kB`,
727
- `Active: ${String(Math.floor((buffersKb + cachedKb) * 1.2)).padStart(10)} kB`,
728
- `Inactive: ${String(Math.floor(cachedKb * 0.6)).padStart(10)} kB`,
729
- `Active(anon): ${String(Math.floor(totalMemKb * 0.001)).padStart(10)} kB`,
730
- `Inactive(anon): ${String(Math.floor(totalMemKb * 0.006)).padStart(10)} kB`,
731
- `Active(file): ${String(Math.floor(cachedKb * 1.2)).padStart(10)} kB`,
732
- `Inactive(file): ${String(Math.floor(cachedKb * 0.6)).padStart(10)} kB`,
733
- `Unevictable: ${String(0).padStart(10)} kB`,
734
- `Mlocked: ${String(0).padStart(10)} kB`,
735
- `SwapTotal: ${String(0).padStart(10)} kB`,
736
- `SwapFree: ${String(0).padStart(10)} kB`,
737
- `Zswap: ${String(0).padStart(10)} kB`,
738
- `Zswapped: ${String(0).padStart(10)} kB`,
739
- `Dirty: ${String(Math.floor(Math.random() * 64)).padStart(10)} kB`,
740
- `Writeback: ${String(0).padStart(10)} kB`,
741
- `AnonPages: ${String(Math.floor(totalMemKb * 0.001)).padStart(10)} kB`,
742
- `Mapped: ${String(Math.floor(cachedKb * 0.4)).padStart(10)} kB`,
743
- `Shmem: ${String(shmemKb).padStart(10)} kB`,
744
- `KReclaimable: ${String(Math.floor(slabKb * 0.6)).padStart(10)} kB`,
745
- `Slab: ${String(slabKb).padStart(10)} kB`,
746
- `SReclaimable: ${String(Math.floor(slabKb * 0.6)).padStart(10)} kB`,
747
- `SUnreclaim: ${String(Math.floor(slabKb * 0.4)).padStart(10)} kB`,
748
- `KernelStack: ${String(Math.floor(totalMemKb * 0.0005)).padStart(10)} kB`,
749
- `PageTables: ${String(pageTablesKb).padStart(10)} kB`,
750
- `NFS_Unstable: ${String(0).padStart(10)} kB`,
751
- `Bounce: ${String(0).padStart(10)} kB`,
752
- `WritebackTmp: ${String(0).padStart(10)} kB`,
753
- `CommitLimit: ${String(Math.floor(totalMemKb * 0.5)).padStart(10)} kB`,
754
- `Committed_AS: ${String(Math.floor(totalMemKb * 0.05)).padStart(10)} kB`,
755
- `VmallocTotal: ${String(35184372087808 / 1024).padStart(10)} kB`,
756
- `VmallocUsed: ${String(Math.floor(totalMemKb * 0.01)).padStart(10)} kB`,
757
- `VmallocChunk: ${String(0).padStart(10)} kB`,
758
- `Percpu: ${String(Math.floor(totalMemKb * 0.0001)).padStart(10)} kB`,
759
- `HardwareCorrupted: ${String(0).padStart(6)} kB`,
760
- `AnonHugePages: ${String(0).padStart(10)} kB`,
761
- `ShmemHugePages: ${String(0).padStart(10)} kB`,
762
- `ShmemPmdMapped: ${String(0).padStart(10)} kB`,
763
- `FileHugePages: ${String(0).padStart(10)} kB`,
764
- `FilePmdMapped: ${String(0).padStart(10)} kB`,
765
- `HugePages_Total: ${String(0).padStart(8)}`,
766
- `HugePages_Free: ${String(0).padStart(8)}`,
767
- `HugePages_Rsvd: ${String(0).padStart(8)}`,
768
- `HugePages_Surp: ${String(0).padStart(8)}`,
769
- `Hugepagesize: ${String(2048).padStart(10)} kB`,
770
- `Hugetlb: ${String(0).padStart(10)} kB`,
771
- `DirectMap4k: ${String(Math.floor(totalMemKb * 0.02)).padStart(10)} kB`,
772
- `DirectMap2M: ${String(Math.floor(totalMemKb * 0.98)).padStart(10)} kB`,
773
- ].join("\n")}\n`,
774
- );
775
-
776
- // cpuinfo — real host CPU passthrough + x86 feature flags matching Firecracker Xeon
777
- const cpus = os.cpus();
778
- const cpuLines: string[] = [];
779
- for (let i = 0; i < cpus.length; i++) {
780
- const c = cpus[i];
781
- if (!c) continue;
782
- cpuLines.push(
783
- `processor\t: ${i}`,
784
- `vendor_id\t: GenuineIntel`,
785
- `cpu family\t: 6`,
786
- `model\t\t: 85`,
787
- `model name\t: ${c.model}`,
788
- `stepping\t: 7`,
789
- `microcode\t: 0x1`,
790
- `cpu MHz\t\t: ${c.speed.toFixed(3)}`,
791
- `cache size\t: 33792 KB`,
792
- `physical id\t: 0`,
793
- `siblings\t: ${cpus.length}`,
794
- `core id\t\t: ${i}`,
795
- `cpu cores\t: ${cpus.length}`,
796
- `apicid\t\t: ${i}`,
797
- `initial apicid\t: ${i}`,
798
- `fpu\t\t: yes`,
799
- `fpu_exception\t: yes`,
800
- `cpuid level\t: 13`,
801
- `wp\t\t: yes`,
802
- `flags\t\t: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat umip avx512_vnni md_clear arch_capabilities`,
803
- `bugs\t\t: spectre_v1 spectre_v2 spec_store_bypass swapgs taa mmio_stale_data retbleed eibrs_pbrsb bhi ibpb_no_ret spectre_v2_user its`,
804
- `bogomips\t: ${(c.speed * 2 / 1000).toFixed(2)}`,
805
- `clflush size\t: 64`,
806
- `cache_alignment\t: 64`,
807
- `address sizes\t: 46 bits physical, 48 bits virtual`,
808
- `power management:`,
809
- "",
810
- );
811
- }
812
- write(vfs, "/proc/cpuinfo", `${cpuLines.join("\n")}\n`);
813
-
814
- write(
815
- vfs,
816
- "/proc/version",
817
- `Linux version ${props.kernel} (fortune@nyx-build) (gcc (Fortune 13.3.0-nyx1) 13.3.0, GNU ld (GNU Binutils for Fortune) 2.42) #2 SMP PREEMPT_DYNAMIC\n`,
818
- );
819
- write(vfs, "/proc/hostname", `${hostname}\n`);
820
-
821
- // loadavg
822
- const load = (Math.random() * 0.3).toFixed(2);
823
- const numProcs = 1 + sessions.length;
824
- write(vfs, "/proc/loadavg", `${load} ${load} ${load} ${numProcs}/${numProcs} 1\n`);
825
-
826
- // /proc/cmdline — Firecracker boot args
827
- write(vfs, "/proc/cmdline",
828
- `console=ttyS0 reboot=k panic=1 nomodule random.trust_cpu=1 ipv6.disable=1 swiotlb=noforce rdinit=/process_api init_on_free=1 -- --firecracker-init --addr 0.0.0.0:2024 --max-ws-buffer-size 32768 --block-local-connections\n`,
829
- );
830
-
831
- // /proc/filesystems — matching real container
832
- write(vfs, "/proc/filesystems",
833
- `${[
834
- "nodev\tsysfs",
835
- "nodev\ttmpfs",
836
- "nodev\tbdev",
837
- "nodev\tproc",
838
- "nodev\tcgroup",
839
- "nodev\tcgroup2",
840
- "nodev\tcpuset",
841
- "nodev\tdevtmpfs",
842
- "nodev\tbinfmt_misc",
843
- "nodev\tdebugfs",
844
- "nodev\tsecurityfs",
845
- "nodev\tsockfs",
846
- "nodev\tbpf",
847
- "nodev\tpipefs",
848
- "nodev\tramfs",
849
- "nodev\thugetlbfs",
850
- "nodev\trpc_pipefs",
851
- "nodev\tdevpts",
852
- "\text3",
853
- "\text2",
854
- "\text4",
855
- "\tsquashfs",
856
- "nodev\tnfs",
857
- "nodev\tnfs4",
858
- "nodev\tautofs",
859
- "\tfuseblk",
860
- "nodev\tfuse",
861
- "nodev\tfusectl",
862
- "nodev\toverlay",
863
- "\txfs",
864
- "nodev\tmqueue",
865
- "nodev\tselinuxfs",
866
- "nodev\tpstore",
867
- ].join("\n")}\n`,
868
- );
869
-
870
- // /proc/mounts — virtio block device layout
871
- const mountsContent = `${[
872
- "proc /proc proc rw,relatime 0 0",
873
- "sysfs /sys sysfs rw,relatime 0 0",
874
- "devtmpfs /dev devtmpfs rw,relatime,size=2045672k,nr_inodes=511418,mode=755 0 0",
875
- "tmpfs /dev/shm tmpfs rw,relatime 0 0",
876
- "devpts /dev/pts devpts rw,relatime,mode=600,ptmxmode=000 0 0",
877
- "tmpfs /sys/fs/cgroup tmpfs rw,relatime 0 0",
878
- "cgroup /sys/fs/cgroup/cpu cgroup rw,relatime,cpu 0 0",
879
- "cgroup /sys/fs/cgroup/cpuacct cgroup rw,relatime,cpuacct 0 0",
880
- "cgroup /sys/fs/cgroup/memory cgroup rw,relatime,memory 0 0",
881
- "cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0",
882
- "cgroup /sys/fs/cgroup/freezer cgroup rw,relatime,freezer 0 0",
883
- "cgroup /sys/fs/cgroup/blkio cgroup rw,relatime,blkio 0 0",
884
- "cgroup /sys/fs/cgroup/pids cgroup rw,relatime,pids 0 0",
885
- "cgroup2 /sys/fs/cgroup/unified cgroup2 rw,relatime 0 0",
886
- "/dev/vda / ext4 rw,relatime,resuid=65534,resgid=65534 0 0",
887
- "/dev/vdb /opt/rclone squashfs ro,relatime,errors=continue 0 0",
888
- "tmpfs /run tmpfs rw,nosuid,nodev,noexec,relatime,size=204800k,mode=755 0 0",
889
- "tmpfs /tmp tmpfs rw,nosuid,nodev,noatime 0 0",
890
- ].join("\n")}\n`;
891
- write(vfs, "/proc/mounts", mountsContent);
892
- ensureDir(vfs, "/proc/self");
893
- write(vfs, "/proc/self/mounts", mountsContent);
894
-
895
- // /proc/net
896
- ensureDir(vfs, "/proc/net");
897
- write(vfs, "/proc/net/dev",
898
- `${[
899
- "Inter-| Receive | Transmit",
900
- " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed",
901
- " lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0",
902
- " eth0: 128628 1230 0 19 0 0 0 0 52027469 2045 0 0 0 0 0 0",
903
- ].join("\n")}\n`,
904
- );
905
- write(vfs, "/proc/net/if_inet6", "");
906
- write(vfs, "/proc/net/tcp",
907
- " sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode\n",
908
- );
909
- write(vfs, "/proc/net/tcp6",
910
- " sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode\n",
911
- );
912
- write(vfs, "/proc/net/udp",
913
- " sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode\n",
914
- );
915
- write(vfs, "/proc/net/route",
916
- "Iface\tDestination\tGateway\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT\n" +
917
- "eth0\t00000000\t0101A8C0\t0003\t0\t0\t100\t00000000\t0\t0\t0\n" +
918
- "eth0\t0000A8C0\t00000000\t0001\t0\t0\t100\t00FFFFFF\t0\t0\t0\n",
919
- );
920
- write(vfs, "/proc/net/arp",
921
- "IP address HW type Flags HW address Mask Device\n",
922
- );
923
- write(vfs, "/proc/net/fib_trie", "Local:\n +-- 0.0.0.0/0 3 0 5\n");
924
- write(vfs, "/proc/net/unix",
925
- "Num RefCount Protocol Flags Type St Inode Path\n" +
926
- "0000000000000000: 00000002 00000000 00010000 0001 01 10000 /run/dbus/system_bus_socket\n",
927
- );
928
- write(vfs, "/proc/net/sockstat",
929
- "sockets: used 8\nTCP: inuse 0 orphan 0 tw 0 alloc 0 mem 0\nUDP: inuse 0 mem 0\nUDPLITE: inuse 0\nRAW: inuse 0\nFRAG: inuse 0 memory 0\n",
930
- );
931
-
932
- // /proc/partitions — virtio block devices
933
- write(
934
- vfs,
935
- "/proc/partitions",
936
- `${[
937
- "major minor #blocks name",
938
- "",
939
- " 254 0 268435456 vda",
940
- " 254 16 9664 vdb",
941
- " 254 32 656 vdc",
942
- " 254 48 5464 vdd",
943
- ].join("\n")}\n`,
944
- );
945
-
946
- // /proc/swaps — no swap (matches real env: SwapTotal 0)
947
- write(vfs, "/proc/swaps",
948
- "Filename\t\t\t\tType\t\tSize\t\tUsed\t\tPriority\n",
949
- );
950
-
951
- // /proc/diskstats — virtio block device I/O counters
952
- write(vfs, "/proc/diskstats",
953
- `${[
954
- " 254 0 vda 1000 0 8000 500 200 0 1600 100 0 600 600 0 0 0 0",
955
- " 254 16 vdb 100 0 800 50 0 0 0 0 0 50 50 0 0 0 0",
956
- " 254 32 vdc 50 0 400 25 0 0 0 0 0 25 25 0 0 0 0",
957
- " 254 48 vdd 80 0 640 40 0 0 0 0 0 40 40 0 0 0 0",
958
- ].join("\n")}\n`,
959
- );
960
-
961
- // /proc/interrupts
962
- write(vfs, "/proc/interrupts",
963
- ` CPU0\n 0: ${Math.floor(uptimeSec * 250)} IO-APIC 2-edge timer\n 1: 9 IO-APIC 1-edge i8042\n NMI: 0 Non-maskable interrupts\n ERR: 0\n MIS: 0\n PIN: 0 Posted-interrupt notification event\n NPI: 0 Nested posted-interrupt event\n PIW: 0 Posted-interrupt wakeup event\n`,
964
- );
965
-
966
- // /proc/sys — sysctl virtual tree (real values)
967
- ensureDir(vfs, "/proc/sys");
968
- ensureDir(vfs, "/proc/sys/kernel");
969
- ensureDir(vfs, "/proc/sys/net");
970
- ensureDir(vfs, "/proc/sys/net/ipv4");
971
- ensureDir(vfs, "/proc/sys/net/ipv6");
972
- ensureDir(vfs, "/proc/sys/net/core");
973
- ensureDir(vfs, "/proc/sys/vm");
974
- ensureDir(vfs, "/proc/sys/fs");
975
- ensureDir(vfs, "/proc/sys/fs/inotify");
976
-
977
- write(vfs, "/proc/sys/kernel/hostname", `${hostname}\n`);
978
- write(vfs, "/proc/sys/kernel/ostype", "Linux\n");
979
- write(vfs, "/proc/sys/kernel/osrelease", `${props.kernel}\n`);
980
- write(vfs, "/proc/sys/kernel/pid_max", "32768\n");
981
- write(vfs, "/proc/sys/kernel/threads-max", "31968\n");
982
- write(vfs, "/proc/sys/kernel/randomize_va_space", "2\n");
983
- write(vfs, "/proc/sys/kernel/dmesg_restrict", "0\n");
984
- write(vfs, "/proc/sys/kernel/kptr_restrict", "0\n");
985
- write(vfs, "/proc/sys/kernel/perf_event_paranoid", "2\n");
986
- write(vfs, "/proc/sys/kernel/printk", "4\t4\t1\t7\n");
987
- write(vfs, "/proc/sys/kernel/sysrq", "176\n");
988
- write(vfs, "/proc/sys/kernel/panic", "1\n");
989
- write(vfs, "/proc/sys/kernel/panic_on_oops", "1\n");
990
- write(vfs, "/proc/sys/kernel/core_pattern", "core\n");
991
- write(vfs, "/proc/sys/kernel/core_uses_pid", "0\n");
992
- write(vfs, "/proc/sys/kernel/ngroups_max", "65536\n");
993
- write(vfs, "/proc/sys/kernel/cap_last_cap", "40\n");
994
- write(vfs, "/proc/sys/kernel/unprivileged_userns_clone", "1\n");
995
- write(vfs, "/proc/sys/net/ipv4/ip_forward", "0\n");
996
- write(vfs, "/proc/sys/net/ipv4/tcp_syncookies", "1\n");
997
- write(vfs, "/proc/sys/net/ipv4/tcp_fin_timeout", "60\n");
998
- write(vfs, "/proc/sys/net/ipv4/tcp_keepalive_time", "7200\n");
999
- write(vfs, "/proc/sys/net/ipv4/conf/all/rp_filter", "2\n");
1000
- write(vfs, "/proc/sys/net/ipv6/conf/all/disable_ipv6", "1\n");
1001
- write(vfs, "/proc/sys/net/core/somaxconn", "4096\n");
1002
- write(vfs, "/proc/sys/net/core/rmem_max", "212992\n");
1003
- write(vfs, "/proc/sys/net/core/wmem_max", "212992\n");
1004
- write(vfs, "/proc/sys/vm/swappiness", "60\n");
1005
- write(vfs, "/proc/sys/vm/overcommit_memory", "0\n");
1006
- write(vfs, "/proc/sys/vm/overcommit_ratio", "50\n");
1007
- write(vfs, "/proc/sys/vm/dirty_ratio", "20\n");
1008
- write(vfs, "/proc/sys/vm/dirty_background_ratio", "10\n");
1009
- write(vfs, "/proc/sys/vm/min_free_kbytes", "65536\n");
1010
- write(vfs, "/proc/sys/vm/vfs_cache_pressure", "100\n");
1011
- write(vfs, "/proc/sys/fs/file-max", "1048576\n");
1012
- write(vfs, "/proc/sys/fs/inotify/max_user_watches", "524288\n");
1013
- write(vfs, "/proc/sys/fs/inotify/max_user_instances","512\n");
1014
- write(vfs, "/proc/sys/fs/inotify/max_queued_events", "16384\n");
1015
-
1016
- // /proc/cgroups — v1 hierarchy
1017
- write(vfs, "/proc/cgroups",
1018
- `${[
1019
- "#subsys_name\thierarchy\tnum_cgroups\tenabled",
1020
- "cpuset\t5\t1\t1",
1021
- "cpu\t1\t1\t1",
1022
- "cpuacct\t2\t1\t1",
1023
- "blkio\t6\t1\t1",
1024
- "memory\t3\t1\t1",
1025
- "devices\t4\t1\t1",
1026
- "freezer\t7\t1\t1",
1027
- "pids\t8\t1\t1",
1028
- ].join("\n")}\n`,
1029
- );
1030
-
1031
- // init process (PID 1)
1032
- writeProcPid(vfs, 1, "root", "pts/0", "/sbin/init", new Date(shellStartTime).toISOString(), {});
1033
-
1034
- // per-session processes
1035
- for (const session of sessions) {
1036
- const pid = ttyToPid(session.tty);
1037
- writeProcPid(vfs, pid, session.username, session.tty, "bash", session.startedAt, {
1038
- USER: session.username,
1039
- HOME: `/home/${session.username}`,
1040
- TERM: "xterm-256color",
1041
- SHELL: "/bin/bash",
1042
- LANG: "en_US.UTF-8",
1043
- PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
1044
- LOGNAME: session.username,
1045
- });
1046
- }
1047
-
1048
- // /proc/self — mirror of most recent session
1049
- const selfPid = sessions.length > 0 ? ttyToPid(sessions[sessions.length - 1]!.tty) : 1;
1050
- try { vfs.remove("/proc/self"); } catch { /* ignore */ }
1051
-
1052
- const selfSrc = `/proc/${selfPid}`;
1053
- ensureDir(vfs, "/proc/self");
1054
- ensureDir(vfs, "/proc/self/fd");
1055
- ensureDir(vfs, "/proc/self/fdinfo");
1056
- ensureDir(vfs, "/proc/self/net");
1057
-
1058
- if (vfs.exists(selfSrc)) {
1059
- for (const entry of vfs.list(selfSrc)) {
1060
- const srcPath = `${selfSrc}/${entry}`;
1061
- const dstPath = `/proc/self/${entry}`;
1062
- try {
1063
- const st = vfs.stat(srcPath);
1064
- if (st.type === "file") write(vfs, dstPath, vfs.readFile(srcPath));
1065
- } catch { /* skip */ }
1066
- }
1067
- } else {
1068
- write(vfs, "/proc/self/cmdline", "bash\0");
1069
- write(vfs, "/proc/self/comm", "bash");
1070
- write(vfs, "/proc/self/status", "Name:\tbash\nState:\tS (sleeping)\nPid:\t1\nPPid:\t0\n");
1071
- write(vfs, "/proc/self/environ", "");
1072
- write(vfs, "/proc/self/cwd", "/root\0");
1073
- write(vfs, "/proc/self/exe", "/bin/bash\0");
1074
- }
1075
- }
1076
-
1077
- // ─── /sys ─────────────────────────────────────────────────────────────────────
1078
-
1079
- function bootstrapSys(vfs: VirtualFileSystem, hostname: string, props: ShellProperties): void {
1080
- ensureDir(vfs, "/sys");
1081
-
1082
- // No real DMI in Firecracker — /sys/devices/virtual/dmi/id does not exist.
1083
- // Expose /sys/class/net, /sys/fs/cgroup, /sys/kernel only.
1084
-
1085
- ensureDir(vfs, "/sys/devices");
1086
- ensureDir(vfs, "/sys/devices/virtual");
1087
- ensureDir(vfs, "/sys/devices/system");
1088
- ensureDir(vfs, "/sys/devices/system/cpu");
1089
- ensureDir(vfs, "/sys/devices/system/cpu/cpu0");
1090
- ensureFile(vfs, "/sys/devices/system/cpu/cpu0/online", "1\n");
1091
- ensureFile(vfs, "/sys/devices/system/cpu/online", "0\n");
1092
- ensureFile(vfs, "/sys/devices/system/cpu/possible", "0\n");
1093
- ensureFile(vfs, "/sys/devices/system/cpu/present", "0\n");
1094
- ensureDir(vfs, "/sys/devices/system/node");
1095
- ensureDir(vfs, "/sys/devices/system/node/node0");
1096
- ensureFile(vfs, "/sys/devices/system/node/node0/cpumap", "1\n");
1097
-
1098
- ensureDir(vfs, "/sys/class");
1099
- ensureDir(vfs, "/sys/class/net");
1100
- ensureDir(vfs, "/sys/class/net/eth0");
1101
- ensureFile(vfs, "/sys/class/net/eth0/operstate", "up\n");
1102
- ensureFile(vfs, "/sys/class/net/eth0/carrier", "1\n");
1103
- ensureFile(vfs, "/sys/class/net/eth0/mtu", "1500\n");
1104
- ensureFile(vfs, "/sys/class/net/eth0/speed", "10000\n");
1105
- ensureFile(vfs, "/sys/class/net/eth0/duplex", "full\n");
1106
- ensureFile(vfs, "/sys/class/net/eth0/address", "aa:bb:cc:dd:ee:ff\n");
1107
- ensureFile(vfs, "/sys/class/net/eth0/tx_queue_len","1000\n");
1108
-
1109
- const seed = fnv1a(hostname);
1110
- const macSeed = seed.toString(16).padStart(8, "0");
1111
- ensureFile(vfs, "/sys/class/net/eth0/address",
1112
- `52:54:00:${macSeed.slice(0,2)}:${macSeed.slice(2,4)}:${macSeed.slice(4,6)}\n`,
1113
- );
1114
-
1115
- ensureDir(vfs, "/sys/class/net/lo");
1116
- ensureFile(vfs, "/sys/class/net/lo/operstate", "unknown\n");
1117
- ensureFile(vfs, "/sys/class/net/lo/carrier", "1\n");
1118
- ensureFile(vfs, "/sys/class/net/lo/mtu", "65536\n");
1119
- ensureFile(vfs, "/sys/class/net/lo/address", "00:00:00:00:00:00\n");
1120
-
1121
- ensureDir(vfs, "/sys/class/block");
1122
- ensureDir(vfs, "/sys/class/block/vda");
1123
- ensureFile(vfs, "/sys/class/block/vda/size", "536870912\n");
1124
- ensureFile(vfs, "/sys/class/block/vda/ro", "0\n");
1125
- ensureFile(vfs, "/sys/class/block/vda/removable","0\n");
1126
-
1127
- // cgroup fs
1128
- ensureDir(vfs, "/sys/fs");
1129
- ensureDir(vfs, "/sys/fs/cgroup");
1130
- for (const subsys of ["cpu", "cpuacct", "memory", "devices", "blkio", "pids", "freezer", "unified"]) {
1131
- ensureDir(vfs, `/sys/fs/cgroup/${subsys}`);
1132
- if (subsys !== "unified") {
1133
- ensureFile(vfs, `/sys/fs/cgroup/${subsys}/tasks`, "1\n");
1134
- ensureFile(vfs, `/sys/fs/cgroup/${subsys}/notify_on_release`, "0\n");
1135
- ensureFile(vfs, `/sys/fs/cgroup/${subsys}/release_agent`, "");
1136
- }
1137
- }
1138
- ensureFile(vfs, "/sys/fs/cgroup/memory/memory.limit_in_bytes", `${os.totalmem()}\n`);
1139
- ensureFile(vfs, "/sys/fs/cgroup/memory/memory.usage_in_bytes", `${os.totalmem() - os.freemem()}\n`);
1140
- ensureFile(vfs, "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes",`${os.totalmem()}\n`);
1141
- ensureFile(vfs, "/sys/fs/cgroup/cpu/cpu.cfs_period_us", "100000\n");
1142
- ensureFile(vfs, "/sys/fs/cgroup/cpu/cpu.cfs_quota_us", "-1\n");
1143
- ensureFile(vfs, "/sys/fs/cgroup/cpu/cpu.shares", "1024\n");
1144
-
1145
- ensureDir(vfs, "/sys/kernel");
1146
- ensureFile(vfs, "/sys/kernel/hostname", `${hostname}\n`);
1147
- ensureFile(vfs, "/sys/kernel/osrelease", `${props.kernel}\n`);
1148
- ensureFile(vfs, "/sys/kernel/ostype", "Linux\n");
1149
-
1150
- // security
1151
- ensureDir(vfs, "/sys/kernel/security");
1152
-
1153
-
1154
- // Still; we will create virtual dmi
1155
- ensureDir(vfs, "/sys/devices/virtual");
1156
- ensureDir(vfs, "/sys/devices/virtual/dmi");
1157
- ensureDir(vfs, "/sys/devices/virtual/dmi/id");
1158
- const product = `VirtualNode-${(seed % 10000).toString().padStart(4, "0")}`;
1159
-
1160
- // Full DMI table — deterministic, seeded from hostname
1161
- const dmi: Record<string, string> = {
1162
- bios_vendor: "Virtual BIOS",
1163
- bios_version: "1.0",
1164
- bios_date: "01/01/2025",
1165
- sys_vendor: "Fortune Systems",
1166
- product_name: product,
1167
- product_family: "VirtualContainer",
1168
- product_version: "v1",
1169
- product_uuid: `${seed.toString(16).padStart(8, "0")}-0000-0000-0000-000000000000`,
1170
- product_serial: `SN-${seed}`,
1171
- chassis_type: "3",
1172
- chassis_vendor: "Virtual",
1173
- chassis_version: "v1",
1174
- board_name: "fortune-board",
1175
- modalias: `dmi:bvnVirtual:bvr1.0:svnFortune:pn${product}`,
1176
- };
1177
-
1178
- for (const [k, v] of Object.entries(dmi)) {
1179
- ensureFile(vfs, `/sys/devices/virtual/dmi/id/${k}`, `${v}\n`);
1180
- }
1181
-
1182
- ensureDir(vfs, "/sys/class");
1183
- ensureDir(vfs, "/sys/class/net");
1184
- ensureDir(vfs, "/sys/kernel");
1185
-
1186
- ensureFile(vfs, "/sys/kernel/hostname", `${hostname}\n`);
1187
- ensureFile(vfs, "/sys/kernel/osrelease", `${props.kernel}\n`);
1188
- ensureFile(vfs, "/sys/kernel/ostype", "Linux\n");
1189
-
1190
- }
1191
-
1192
- // ─── /dev ─────────────────────────────────────────────────────────────────────
1193
-
1194
- function bootstrapDev(vfs: VirtualFileSystem): void {
1195
- ensureDir(vfs, "/dev");
1196
-
1197
- // character devices — matching real Firecracker container
1198
- ensureFile(vfs, "/dev/null", "", 0o666);
1199
- ensureFile(vfs, "/dev/zero", "", 0o666);
1200
- ensureFile(vfs, "/dev/full", "", 0o666);
1201
- ensureFile(vfs, "/dev/random", "", 0o444);
1202
- ensureFile(vfs, "/dev/urandom", "", 0o444);
1203
- ensureFile(vfs, "/dev/mem", "", 0o640);
1204
- ensureFile(vfs, "/dev/port", "", 0o640);
1205
- ensureFile(vfs, "/dev/kmsg", "", 0o660);
1206
- ensureFile(vfs, "/dev/hwrng", "", 0o660);
1207
- ensureFile(vfs, "/dev/fuse", "", 0o660);
1208
- ensureFile(vfs, "/dev/autofs", "", 0o660);
1209
- ensureFile(vfs, "/dev/userfaultfd", "", 0o660);
1210
- ensureFile(vfs, "/dev/cpu_dma_latency", "", 0o660);
1211
- ensureFile(vfs, "/dev/ptp0", "", 0o660);
1212
-
1213
- // snapshot (KVM-specific)
1214
- ensureFile(vfs, "/dev/snapshot", "", 0o660);
1215
-
1216
- // terminal devices
1217
- ensureFile(vfs, "/dev/console", "", 0o600);
1218
- ensureFile(vfs, "/dev/tty", "", 0o666);
1219
- ensureFile(vfs, "/dev/ttyS0", "", 0o660);
1220
- ensureFile(vfs, "/dev/ptmx", "", 0o666);
1221
-
1222
- // tty0–63 (like real env)
1223
- for (let i = 0; i <= 63; i++) {
1224
- ensureFile(vfs, `/dev/tty${i}`, "", 0o620);
1225
- }
1226
-
1227
- // vcs devices
1228
- ensureFile(vfs, "/dev/vcs", "", 0o620);
1229
- ensureFile(vfs, "/dev/vcs1", "", 0o620);
1230
- ensureFile(vfs, "/dev/vcsa", "", 0o620);
1231
- ensureFile(vfs, "/dev/vcsa1", "", 0o620);
1232
- ensureFile(vfs, "/dev/vcsu", "", 0o620);
1233
- ensureFile(vfs, "/dev/vcsu1", "", 0o620);
1234
-
1235
- // loop devices (0–7)
1236
- for (let i = 0; i < 8; i++) {
1237
- ensureFile(vfs, `/dev/loop${i}`, "", 0o660);
1238
- }
1239
- ensureDir(vfs, "/dev/loop-control");
1240
-
1241
- // virtio block devices (vda–vdd matching mounts)
1242
- ensureFile(vfs, "/dev/vda", "", 0o660);
1243
- ensureFile(vfs, "/dev/vdb", "", 0o660);
1244
- ensureFile(vfs, "/dev/vdc", "", 0o660);
1245
- ensureFile(vfs, "/dev/vdd", "", 0o660);
1246
-
1247
- // network tun
1248
- ensureDir(vfs, "/dev/net");
1249
- ensureFile(vfs, "/dev/net/tun", "", 0o660);
1250
-
1251
- // misc
1252
- ensureDir(vfs, "/dev/pts");
1253
- ensureDir(vfs, "/dev/shm");
1254
- ensureDir(vfs, "/dev/cpu");
1255
- ensureFile(vfs, "/dev/stdin", "", 0o666);
1256
- ensureFile(vfs, "/dev/stdout", "", 0o666);
1257
- ensureFile(vfs, "/dev/stderr", "", 0o666);
1258
- ensureDir(vfs, "/dev/fd");
1259
- ensureFile(vfs, "/dev/vga_arbiter", "", 0o660);
1260
- ensureFile(vfs, "/dev/vsock", "", 0o660);
1261
- }
1262
-
1263
- // ─── /usr ─────────────────────────────────────────────────────────────────────
1264
-
1265
- function bootstrapUsr(vfs: VirtualFileSystem): void {
1266
- ensureDir(vfs, "/usr");
1267
- ensureDir(vfs, "/usr/bin");
1268
- ensureDir(vfs, "/usr/sbin");
1269
- ensureDir(vfs, "/usr/local");
1270
- ensureDir(vfs, "/usr/local/bin");
1271
- ensureDir(vfs, "/usr/local/lib");
1272
- ensureDir(vfs, "/usr/local/share");
1273
- ensureDir(vfs, "/usr/local/include");
1274
- ensureDir(vfs, "/usr/local/sbin");
1275
- ensureDir(vfs, "/usr/share");
1276
- ensureDir(vfs, "/usr/share/doc");
1277
- ensureDir(vfs, "/usr/share/man");
1278
- ensureDir(vfs, "/usr/share/man/man1");
1279
- ensureDir(vfs, "/usr/share/man/man5");
1280
- ensureDir(vfs, "/usr/share/man/man8");
1281
- ensureDir(vfs, "/usr/share/common-licenses");
1282
- ensureDir(vfs, "/usr/share/ca-certificates");
1283
- ensureDir(vfs, "/usr/share/zoneinfo");
1284
- ensureDir(vfs, "/usr/lib");
1285
- ensureDir(vfs, "/usr/lib/x86_64-linux-gnu");
1286
- ensureDir(vfs, "/usr/lib/python3");
1287
- ensureDir(vfs, "/usr/lib/python3/dist-packages");
1288
- ensureDir(vfs, "/usr/lib/python3.12");
1289
- ensureDir(vfs, "/usr/lib/jvm");
1290
- ensureDir(vfs, "/usr/lib/jvm/java-21-openjdk-amd64");
1291
- ensureDir(vfs, "/usr/lib/jvm/java-21-openjdk-amd64/bin");
1292
- ensureDir(vfs, "/usr/lib/node_modules");
1293
- ensureDir(vfs, "/usr/lib/node_modules/npm");
1294
- ensureDir(vfs, "/usr/include");
1295
- ensureDir(vfs, "/usr/src");
1296
-
1297
- // builtins — all bins present in the real container
1298
- const builtins = [
1299
- "sh", "bash", "ls", "cat", "echo", "grep", "find", "sort",
1300
- "head", "tail", "cut", "tr", "sed", "awk", "wc", "tee",
1301
- "tar", "gzip", "gunzip", "touch", "mkdir", "rm", "mv", "cp",
1302
- "chmod", "ln", "pwd", "env", "date", "sleep", "id", "whoami",
1303
- "hostname", "uname", "ps", "kill", "df", "du", "curl", "wget",
1304
- "nano", "diff", "uniq", "xargs", "base64",
1305
- ];
1306
-
1307
- // From a real container
1308
- // const builtins = [
1309
- // // core
1310
- // "sh", "bash", "dash",
1311
- // "ls", "cat", "echo", "grep", "find", "sort",
1312
- // "head", "tail", "cut", "tr", "sed", "awk", "mawk", "gawk",
1313
- // "wc", "tee", "tar", "gzip", "gunzip", "bzip2", "xz",
1314
- // "touch", "mkdir", "rm", "mv", "cp", "ln", "pwd",
1315
- // "chmod", "chown", "chgrp", "env", "date", "sleep",
1316
- // "id", "whoami", "hostname", "uname", "ps", "kill",
1317
- // "df", "du", "dd", "stat", "file",
1318
- // // net
1319
- // "curl", "wget", "nc", "netcat", "ss", "ip",
1320
- // // editors
1321
- // "nano", "vi",
1322
- // // text
1323
- // "diff", "uniq", "xargs", "base64", "md5sum", "sha256sum",
1324
- // "strings", "hexdump", "od", "column", "fmt", "paste",
1325
- // "join", "comm", "split", "csplit", "fold", "expand",
1326
- // // archive
1327
- // "zip", "unzip",
1328
- // // process
1329
- // "top", "htop", "free", "uptime", "dmesg", "lsof",
1330
- // "strace", "ltrace", "pgrep", "pkill", "nohup", "nice",
1331
- // // fs
1332
- // "mount", "umount", "lsblk", "fdisk", "blkid", "e2fsck",
1333
- // // misc
1334
- // "bc", "expr", "seq", "yes", "true", "false", "test",
1335
- // "readlink", "realpath", "dirname", "basename", "mktemp",
1336
- // "install", "make",
1337
- // // dev tools
1338
- // "gcc", "gcc-13", "g++", "g++-13", "cpp", "as", "ld",
1339
- // "ar", "nm", "objdump", "objcopy", "strip", "size",
1340
- // "cc", "c++", "pkg-config",
1341
- // // package
1342
- // "apt", "apt-get", "apt-cache", "dpkg", "dpkg-query",
1343
- // "lsb_release", "add-apt-repository",
1344
- // // scripting
1345
- // "perl", "python3", "python3.12", "pipx",
1346
- // // node/npm
1347
- // "node", "npm", "npx",
1348
- // // java
1349
- // "java", "javac", "jar", "javadoc",
1350
- // // security
1351
- // "openssl", "gpg", "gpg2", "gpgv", "ssh", "ssh-keygen",
1352
- // "sudo", "su", "passwd", "adduser", "useradd",
1353
- // // misc system
1354
- // "systemctl", "journalctl", "loginctl",
1355
- // "timedatectl", "localectl",
1356
- // "lshw", "lscpu", "lsusb", "lspci",
1357
- // // text proc
1358
- // "jq", "xmllint", "pandoc",
1359
- // // multimedia
1360
- // "ffmpeg",
1361
- // ];
1362
-
1363
- for (const bin of builtins) {
1364
- ensureFile(vfs, `/usr/bin/${bin}`, `#!/bin/sh\nexec builtin ${bin} "$@"\n`, 0o755);
1365
- }
1366
-
1367
- // sbin equivalents
1368
- const sbins = [
1369
- "nologin", "useradd", "userdel", "groupadd", "groupdel",
1370
- "adduser", "deluser", "shutdown", "reboot", "halt",
1371
- "init", "service", "update-alternatives", "update-rc.d",
1372
- "depmod", "modprobe", "insmod", "rmmod", "lsmod",
1373
- "ifconfig", "route", "iptables", "ip6tables",
1374
- "arp", "iwconfig", "ethtool",
1375
- "fdisk", "parted", "mkfs.ext4", "fsck",
1376
- "ldconfig", "ldconfig.real",
1377
- ];
1378
- for (const bin of sbins) {
1379
- ensureFile(vfs, `/usr/sbin/${bin}`, `#!/bin/sh\nexec builtin ${bin} "$@"\n`, 0o755);
1380
- }
1381
-
1382
- // versioned python symlink stubs
1383
- ensureFile(vfs, "/usr/bin/python3.12", `#!/bin/sh\nexec python3 "$@"\n`, 0o755);
1384
- ensureFile(vfs, "/usr/bin/python3", `#!/bin/sh\nexec python3.12 "$@"\n`, 0o755);
1385
-
1386
- // node version stubs
1387
- ensureFile(vfs, "/usr/bin/node", `#!/bin/sh\nexec node "$@"\n`, 0o755);
1388
- ensureFile(vfs, "/usr/bin/npm", `#!/bin/sh\nexec npm "$@"\n`, 0o755);
1389
- ensureFile(vfs, "/usr/bin/npx", `#!/bin/sh\nexec npx "$@"\n`, 0o755);
1390
-
1391
- // java stubs
1392
- ensureFile(vfs, "/usr/lib/jvm/java-21-openjdk-amd64/bin/java",
1393
- `#!/bin/sh\nexec java "$@"\n`, 0o755);
1394
- ensureFile(vfs, "/usr/lib/jvm/java-21-openjdk-amd64/bin/javac",
1395
- `#!/bin/sh\nexec javac "$@"\n`, 0o755);
1396
-
1397
- // /usr/share/common-licenses stubs
1398
- ensureFile(vfs, "/usr/share/common-licenses/GPL-2", "GNU General Public License v2\n");
1399
- ensureFile(vfs, "/usr/share/common-licenses/GPL-3", "GNU General Public License v3\n");
1400
- ensureFile(vfs, "/usr/share/common-licenses/LGPL-2.1","GNU Lesser General Public License v2.1\n");
1401
- ensureFile(vfs, "/usr/share/common-licenses/Apache-2.0","Apache License 2.0\n");
1402
- ensureFile(vfs, "/usr/share/common-licenses/MIT", "MIT License\n");
1403
- }
1404
-
1405
- // ─── /var ─────────────────────────────────────────────────────────────────────
1406
-
1407
- /** Realistic dpkg status database from real container package list */
1408
- const DPKG_STATUS = `\
1409
- Package: bash
1410
- Status: install ok installed
1411
- Priority: required
1412
- Section: shells
1413
- Installed-Size: 7012
1414
- Maintainer: Fortune Maintainers <maintainers@fortune.local>
1415
- Architecture: amd64
1416
- Version: 5.2.21-2nyx1
1417
- Depends: base-files (>= 2.1.12), fortune-utils (>= 1.0)
1418
- Description: GNU Bourne Again SHell
1419
- bash is an sh-compatible command language interpreter that executes commands
1420
- read from the standard input or from a file.
1421
-
1422
- Package: coreutils
1423
- Status: install ok installed
1424
- Priority: required
1425
- Section: utils
1426
- Installed-Size: 18272
1427
- Maintainer: Fortune Maintainers <maintainers@fortune.local>
1428
- Architecture: amd64
1429
- Version: 9.4-3nyx1
1430
- Depends: libacl1 (>= 2.2.23), libattr1 (>= 1:2.4.44), libc6 (>= 2.17)
1431
- Description: GNU core utilities
1432
- This package contains the basic file, shell and text manipulation utilities.
1433
-
1434
- Package: nodejs
1435
- Status: install ok installed
1436
- Priority: optional
1437
- Section: web
1438
- Installed-Size: 107120
1439
- Maintainer: NodeSource <nodejs@nodesource.com>
1440
- Architecture: amd64
1441
- Version: 22.22.2-1nyx1
1442
- Depends: libc6 (>= 2.17), libgcc-s1 (>= 3.0), libstdc++6 (>= 9.0)
1443
- Description: Node.js event-based server-side javascript engine
1444
- Node.js is similar in design to and influenced by systems like Ruby's Twisted.
1445
-
1446
- Package: python3
1447
- Status: install ok installed
1448
- Priority: important
1449
- Section: python
1450
- Installed-Size: 68
1451
- Maintainer: Fortune Maintainers <maintainers@fortune.local>
1452
- Architecture: amd64
1453
- Version: 3.12.3-0nyx1
1454
- Depends: python3.12 (>= 3.12.3-0nyx1)
1455
- Description: interactive high-level object-oriented language (default python3)
1456
- Python, the high-level, interactive object oriented language, includes an
1457
- extensive class library with lots of goodies for network programming.
1458
-
1459
- Package: python3.12
1460
- Status: install ok installed
1461
- Priority: optional
1462
- Section: python
1463
- Installed-Size: 36
1464
- Maintainer: Fortune Maintainers <maintainers@fortune.local>
1465
- Architecture: amd64
1466
- Version: 3.12.3-1nyx1
1467
- Depends: python3.12-minimal (= 3.12.3-1nyx1), libpython3.12-stdlib
1468
- Description: Interactive high-level object-oriented language (version 3.12)
1469
- Python is a high-level, interactive, object-oriented language. Its 3.12 version
1470
- includes an extensive class library.
1471
-
1472
- Package: gcc-13
1473
- Status: install ok installed
1474
- Priority: optional
1475
- Section: devel
1476
- Installed-Size: 70460
1477
- Maintainer: Fortune GCC Maintainers <gcc@fortune.local>
1478
- Architecture: amd64
1479
- Version: 13.3.0-6nyx1
1480
- Depends: cpp-13 (= 13.3.0-6nyx1), gcc-13-base (= 13.3.0-6nyx1)
1481
- Description: GNU C compiler
1482
- This is the GNU C compiler, a fairly portable optimizing compiler for C.
1483
-
1484
- Package: openjdk-21-jre-headless
1485
- Status: install ok installed
1486
- Priority: optional
1487
- Section: java
1488
- Installed-Size: 174488
1489
- Maintainer: Fortune Maintainers <maintainers@fortune.local>
1490
- Architecture: amd64
1491
- Version: 21.0.10+7-1~nyx
1492
- Depends: libc6 (>= 2.17), libgcc-s1 (>= 3.4)
1493
- Description: OpenJDK Java runtime, using Hotspot JIT (headless)
1494
- Minimal Java runtime - needed for executing non-graphical Java programs.
1495
-
1496
- Package: curl
1497
- Status: install ok installed
1498
- Priority: standard
1499
- Section: web
1500
- Installed-Size: 544
1501
- Maintainer: Fortune Maintainers <maintainers@fortune.local>
1502
- Architecture: amd64
1503
- Version: 8.5.0-2nyx1
1504
- Depends: libcurl4 (= 8.5.0-2nyx1), zlib1g (>= 1:1.1.4)
1505
- Description: command line tool for transferring data with URL syntax
1506
- curl is a command line tool for transferring data with URL syntax, supporting
1507
- DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3,
1508
- POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET and TFTP.
1509
-
1510
- Package: git
1511
- Status: install ok installed
1512
- Priority: optional
1513
- Section: vcs
1514
- Installed-Size: 36552
1515
- Maintainer: Fortune VCS Team <vcs@fortune.local>
1516
- Architecture: amd64
1517
- Version: 1:2.43.0-1nyx1
1518
- Depends: liberror-perl, git-man, libc6 (>= 2.34), libcurl3-gnutls
1519
- Description: fast, scalable, distributed revision control system
1520
- Git is popular version control system designed to handle very large projects
1521
- with speed and efficiency; it is used mainly for various open source projects.
1522
-
1523
- Package: openssl
1524
- Status: install ok installed
1525
- Priority: optional
1526
- Section: utils
1527
- Installed-Size: 1320
1528
- Maintainer: Fortune Security Team <security@fortune.local>
1529
- Architecture: amd64
1530
- Version: 3.0.13-0nyx1
1531
- Depends: libssl3 (>= 3.0.13)
1532
- Description: Secure Sockets Layer toolkit - cryptographic utility
1533
- This package is part of the OpenSSL project's implementation of the SSL and TLS
1534
- cryptographic protocols and related technologies.
1535
-
1536
- Package: wget
1537
- Status: install ok installed
1538
- Priority: standard
1539
- Section: web
1540
- Installed-Size: 1100
1541
- Maintainer: Fortune Maintainers <maintainers@fortune.local>
1542
- Architecture: amd64
1543
- Version: 1.21.4-1nyx1
1544
- Depends: libc6 (>= 2.17), libgnutls30 (>= 3.7.9), libidn2-0 (>= 2.0.0)
1545
- Description: retrieves files from the web
1546
- GNU Wget is a program for retrieving files from the web, supporting the HTTP,
1547
- HTTPS and FTP protocols.
1548
-
1549
- Package: make
1550
- Status: install ok installed
1551
- Priority: optional
1552
- Section: devel
1553
- Installed-Size: 556
1554
- Maintainer: Fortune Maintainers <maintainers@fortune.local>
1555
- Architecture: amd64
1556
- Version: 4.3-4.1nyx1
1557
- Depends: libc6 (>= 2.17)
1558
- Description: utility for directing compilation
1559
- GNU Make is a utility which controls the generation of executables and other
1560
- target files of a program from the program's source files.
1561
-
1562
- Package: ffmpeg
1563
- Status: install ok installed
1564
- Priority: optional
1565
- Section: video
1566
- Installed-Size: 2184
1567
- Maintainer: Fortune Multimedia Team <multimedia@fortune.local>
1568
- Architecture: amd64
1569
- Version: 7:6.1.1-3nyx1
1570
- Depends: libavcodec60, libavdevice60, libavfilter9, libavformat60, libavutil58
1571
- Description: Tools for transcoding, streaming and playing of multimedia files
1572
- FFmpeg is a complete, cross-platform solution to record, convert and stream
1573
- audio and video.
1574
-
1575
- Package: pandoc
1576
- Status: install ok installed
1577
- Priority: optional
1578
- Section: text
1579
- Installed-Size: 96248
1580
- Maintainer: Fortune Haskell Group <haskell@fortune.local>
1581
- Architecture: amd64
1582
- Version: 3.1.3+ds-2
1583
- Depends: libgmp10, libgcc-s1, libffi8
1584
- Description: general markup converter
1585
- Pandoc is a Haskell library for converting from one markup format to another.
1586
-
1587
- Package: tesseract-ocr
1588
- Status: install ok installed
1589
- Priority: optional
1590
- Section: graphics
1591
- Installed-Size: 1736
1592
- Maintainer: Fortune OCR Team <ocr@fortune.local>
1593
- Architecture: amd64
1594
- Version: 5.3.4-1build5
1595
- Depends: libc6 (>= 2.14), libleptonica-dev
1596
- Description: Tesseract Open Source OCR Engine
1597
- Tesseract is an Open Source OCR Engine, originally developed by HP and now
1598
- sponsored by Google.
1599
-
1600
- Package: dpkg
1601
- Status: install ok installed
1602
- Priority: required
1603
- Section: admin
1604
- Installed-Size: 6800
1605
- Maintainer: Fortune Package Team <dpkg@fortune.local>
1606
- Architecture: amd64
1607
- Version: 1.22.6nyx1
1608
- Depends: libc6 (>= 2.17), libzstd1 (>= 1.5.5)
1609
- Description: Fortune package management system
1610
- This package provides the low-level infrastructure for handling the
1611
- installation and removal of Fortune software packages.
1612
-
1613
- Package: apt
1614
- Status: install ok installed
1615
- Priority: important
1616
- Section: admin
1617
- Installed-Size: 4236
1618
- Maintainer: Fortune Package Team <apt@fortune.local>
1619
- Architecture: amd64
1620
- Version: 2.8.3nyx1
1621
- Depends: libapt-pkg6.0 (>= 2.8.3), adduser, gpgv
1622
- Description: commandline package manager
1623
- This package provides commandline tools for searching and managing as well as
1624
- querying information about packages as a low-level access to all features of
1625
- the libapt-pkg library.
1626
-
1627
- Package: systemd
1628
- Status: install ok installed
1629
- Priority: optional
1630
- Section: admin
1631
- Installed-Size: 36476
1632
- Maintainer: Fortune System Team <systemd@fortune.local>
1633
- Architecture: amd64
1634
- Version: 255.4-1nyx1
1635
- Depends: libacl1 (>= 2.2.23), libblkid1 (>= 2.24), libc6 (>= 2.39)
1636
- Description: system and service manager
1637
- systemd is a system and service manager for Linux. It provides aggressive
1638
- parallelization capabilities, uses socket and D-Bus activation for starting
1639
- services, offers on-demand starting of daemons, keeps track of processes using
1640
- Linux cgroups, maintains mount and automount points, and implements an
1641
- elaborate transactional dependency-based service control logic.
1642
-
1643
- Package: nano
1644
- Status: install ok installed
1645
- Priority: important
1646
- Section: editors
1647
- Installed-Size: 888
1648
- Maintainer: Fortune Maintainers <maintainers@fortune.local>
1649
- Architecture: amd64
1650
- Version: 7.2-2
1651
- Depends: libc6 (>= 2.17), libncursesw6 (>= 6)
1652
- Description: small, friendly text editor inspired by Pico
1653
- GNU nano is an easy-to-use text editor originally designed as a replacement
1654
- for Pico, the ncurses-based editor from the non-free mailer package Pine.
1655
-
1656
- Package: less
1657
- Status: install ok installed
1658
- Priority: important
1659
- Section: text
1660
- Installed-Size: 344
1661
- Maintainer: Fortune Maintainers <maintainers@fortune.local>
1662
- Architecture: amd64
1663
- Version: 1:640-2build2
1664
- Depends: libc6 (>= 2.17), libtinfo6 (>= 6)
1665
- Description: pager program similar to more
1666
- This package provides the \`less\` command, which is similar to more but allows
1667
- you to move backwards through the file.
1668
-
1669
- `;
1670
-
1671
- function bootstrapVar(vfs: VirtualFileSystem): void {
1672
- ensureDir(vfs, "/var");
1673
- ensureDir(vfs, "/var/log");
1674
- ensureDir(vfs, "/var/log/apt");
1675
- ensureDir(vfs, "/var/log/journal");
1676
- ensureDir(vfs, "/var/log/private");
1677
- ensureDir(vfs, "/var/tmp");
1678
- ensureDir(vfs, "/var/cache");
1679
- ensureDir(vfs, "/var/cache/apt");
1680
- ensureDir(vfs, "/var/cache/apt/archives");
1681
- ensureDir(vfs, "/var/cache/apt/archives/partial");
1682
- ensureDir(vfs, "/var/cache/debconf");
1683
- ensureDir(vfs, "/var/cache/ldconfig");
1684
- ensureDir(vfs, "/var/cache/fontconfig");
1685
- ensureDir(vfs, "/var/cache/PackageKit");
1686
- ensureDir(vfs, "/var/lib");
1687
- ensureDir(vfs, "/var/lib/apt");
1688
- ensureDir(vfs, "/var/lib/apt/lists");
1689
- ensureDir(vfs, "/var/lib/apt/lists/partial");
1690
- ensureDir(vfs, "/var/lib/dpkg");
1691
- ensureDir(vfs, "/var/lib/dpkg/info");
1692
- ensureDir(vfs, "/var/lib/dpkg/updates");
1693
- ensureDir(vfs, "/var/lib/dpkg/alternatives");
1694
- ensureDir(vfs, "/var/lib/misc");
1695
- ensureDir(vfs, "/var/lib/systemd");
1696
- ensureDir(vfs, "/var/lib/systemd/coredump");
1697
- ensureDir(vfs, "/var/lib/pam");
1698
- ensureDir(vfs, "/var/lib/git");
1699
- ensureDir(vfs, "/var/lib/PackageKit");
1700
- ensureDir(vfs, "/var/lib/python");
1701
- ensureDir(vfs, "/var/spool");
1702
- ensureDir(vfs, "/var/spool/cron");
1703
- ensureDir(vfs, "/var/spool/mail");
1704
- ensureDir(vfs, "/var/mail");
1705
- ensureDir(vfs, "/var/backups");
1706
- ensureDir(vfs, "/var/www");
1707
-
1708
- // dpkg status — realistic package database
1709
- ensureFile(vfs, "/var/lib/dpkg/status", DPKG_STATUS);
1710
- ensureFile(vfs, "/var/lib/dpkg/available", "");
1711
- ensureFile(vfs, "/var/lib/dpkg/lock", "");
1712
- ensureFile(vfs, "/var/lib/dpkg/lock-frontend", "");
1713
-
1714
- // apt state
1715
- ensureFile(vfs, "/var/lib/apt/lists/lock", "");
1716
- ensureFile(vfs, "/var/cache/apt/pkgcache.bin", "");
1717
- ensureFile(vfs, "/var/cache/apt/srcpkgcache.bin", "");
1718
-
1719
- // syslog stubs
1720
- ensureFile(vfs, "/var/log/syslog",
1721
- `${new Date().toUTCString()} ${""} kernel: Virtual container started\n`,
1722
- );
1723
- ensureFile(vfs, "/var/log/auth.log", "");
1724
- ensureFile(vfs, "/var/log/kern.log", "");
1725
- ensureFile(vfs, "/var/log/dpkg.log", "");
1726
- ensureFile(vfs, "/var/log/apt/history.log", "");
1727
- ensureFile(vfs, "/var/log/apt/term.log", "");
1728
- ensureFile(vfs, "/var/log/faillog", "");
1729
- ensureFile(vfs, "/var/log/lastlog", "");
1730
- ensureFile(vfs, "/var/log/wtmp", "");
1731
- ensureFile(vfs, "/var/log/btmp", "");
1732
- ensureFile(vfs, "/var/log/alternatives.log", "");
1733
-
1734
- // /run
1735
- ensureDir(vfs, "/run");
1736
- ensureDir(vfs, "/run/lock");
1737
- ensureDir(vfs, "/run/lock/subsys");
1738
- ensureDir(vfs, "/run/systemd");
1739
- ensureDir(vfs, "/run/systemd/ask-password");
1740
- ensureDir(vfs, "/run/systemd/sessions");
1741
- ensureDir(vfs, "/run/systemd/users");
1742
- ensureDir(vfs, "/run/user");
1743
- ensureDir(vfs, "/run/dbus");
1744
- ensureDir(vfs, "/run/adduser");
1745
- ensureFile(vfs, "/run/utmp", "");
1746
- ensureFile(vfs, "/run/dbus/system_bus_socket", "");
1747
- }
1748
-
1749
- // ─── /bin + /sbin symlinks ────────────────────────────────────────────────────
1750
-
1751
- function bootstrapBin(vfs: VirtualFileSystem): void {
1752
- // Modern Fortune Nyx: /bin and /sbin are symlinks to /usr/bin and /usr/sbin
1753
- if (!vfs.exists("/bin")) vfs.symlink("/usr/bin", "/bin");
1754
- if (!vfs.exists("/sbin")) vfs.symlink("/usr/sbin", "/sbin");
1755
-
1756
- // /var/run → /run (systemd compat)
1757
- if (!vfs.exists("/var/run")) vfs.symlink("/run", "/var/run");
1758
-
1759
- ensureDir(vfs, "/lib");
1760
- ensureDir(vfs, "/lib64");
1761
- ensureDir(vfs, "/lib/x86_64-linux-gnu");
1762
- ensureDir(vfs, "/lib/modules");
1763
-
1764
- // lib64 symlink (standard on x86_64)
1765
- if (!vfs.exists("/lib64/ld-linux-x86-64.so.2")) {
1766
- ensureFile(vfs, "/lib64/ld-linux-x86-64.so.2", "", 0o755);
1767
- }
1768
- }
1769
-
1770
- // ─── /tmp ─────────────────────────────────────────────────────────────────────
1771
-
1772
- function bootstrapTmp(vfs: VirtualFileSystem): void {
1773
- ensureDir(vfs, "/tmp", 0o1777);
1774
- // node compile cache dir (present in real env)
1775
- ensureDir(vfs, "/tmp/node-compile-cache", 0o1777);
1776
- }
1777
-
1778
- // ─── /root home ───────────────────────────────────────────────────────────────
1779
-
1780
- function bootstrapRoot(vfs: VirtualFileSystem): void {
1781
- ensureDir(vfs, "/root", 0o700);
1782
- ensureDir(vfs, "/root/.ssh", 0o700);
1783
- ensureDir(vfs, "/root/.config", 0o755);
1784
- ensureDir(vfs, "/root/.config/pip", 0o755);
1785
- ensureDir(vfs, "/root/.local", 0o755);
1786
- ensureDir(vfs, "/root/.local/share", 0o755);
1787
- ensureFile(
1788
- vfs,
1789
- "/root/.bashrc",
1790
- `${[
1791
- "# root .bashrc",
1792
- "export PS1='\\[\\033[0;31m\\]\\u@\\h\\[\\033[0m\\]:\\[\\033[0;34m\\]\\w\\[\\033[0m\\]# '",
1793
- "export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
1794
- "export LANG=en_US.UTF-8",
1795
- "alias ll='ls -la'",
1796
- "alias la='ls -A'",
1797
- "alias l='ls -CF'",
1798
- ].join("\n")}\n`,
1799
- );
1800
- ensureFile(vfs, "/root/.profile",
1801
- "[ -f ~/.bashrc ] && . ~/.bashrc\n",
1802
- );
1803
- ensureFile(vfs, "/root/.bash_logout",
1804
- "# ~/.bash_logout\n",
1805
- );
1806
- ensureFile(vfs, "/root/.config/pip/pip.conf",
1807
- "[global]\nbreak-system-packages = true\n",
1808
- );
1809
- }
1810
-
1811
- // ─── /opt /srv /mnt /media ────────────────────────────────────────────────────
1812
-
1813
- function bootstrapMisc(vfs: VirtualFileSystem, props: ShellProperties): void {
1814
- ensureDir(vfs, "/opt");
1815
- ensureDir(vfs, "/opt/rclone");
1816
- ensureDir(vfs, "/srv");
1817
- ensureDir(vfs, "/mnt");
1818
- ensureDir(vfs, "/media");
1819
-
1820
- // /boot — no kernel images in Firecracker containers (kernel is external),
1821
- // but maintain the directory structure for tool compatibility
1822
- ensureDir(vfs, "/boot");
1823
- ensureDir(vfs, "/boot/grub");
1824
- ensureFile(vfs, "/boot/grub/grub.cfg",
1825
- `${[
1826
- "# GRUB configuration (virtual)",
1827
- "set default=0",
1828
- "set timeout=0",
1829
- "",
1830
- `menuentry "Fortune GNU/Linux" {`,
1831
- ` linux /vmlinuz-${props.kernel} root=/dev/vda rw console=ttyS0`,
1832
- ` initrd /initrd.img-${props.kernel}`,
1833
- `}`,
1834
- ].join("\n")}\n`,
1835
- );
1836
-
1837
- const kver = props.kernel;
1838
- ensureFile(vfs, `/boot/vmlinuz-${kver}`, "", 0o644);
1839
- ensureFile(vfs, `/boot/initrd.img-${kver}`, "", 0o644);
1840
- ensureFile(vfs, `/boot/System.map-${kver}`, `${kver} virtual\n`, 0o644);
1841
- ensureFile(vfs, `/boot/config-${kver}`, `# Linux kernel config ${kver}\nCONFIG_VIRTIO=y\nCONFIG_VIRTIO_BLK=y\nCONFIG_VIRTIO_NET=y\nCONFIG_KVM_GUEST=y\n`, 0o644);
1842
-
1843
- if (!vfs.exists("/vmlinuz")) vfs.symlink(`/boot/vmlinuz-${kver}`, "/vmlinuz");
1844
- if (!vfs.exists("/vmlinuz.old")) vfs.symlink(`/boot/vmlinuz-${kver}`, "/vmlinuz.old");
1845
- if (!vfs.exists("/initrd.img")) vfs.symlink(`/boot/initrd.img-${kver}`,"/initrd.img");
1846
- if (!vfs.exists("/initrd.img.old")) vfs.symlink(`/boot/initrd.img-${kver}`,"/initrd.img.old");
1847
-
1848
- // No /snap — not present in Firecracker container
1849
- // /proc/cmdline confirms: no snapd boot args
1850
-
1851
- // /lost+found — ext4 recovery
1852
- ensureDir(vfs, "/lost+found", 0o700);
1853
-
1854
- // /home — users managed by bootstrapRoot + syncEtcPasswd
1855
- ensureDir(vfs, "/home");
1856
- }
1857
-
1858
- // ── Static rootfs snapshot cache ─────────────────────────────────────────────
1859
-
1860
- const _staticRootfsCache = new Map<string, Buffer>();
1861
-
1862
- function _staticCacheKey(hostname: string, props: ShellProperties): string {
1863
- return `${hostname}|${props.kernel}|${props.os}|${props.arch}`;
1864
- }
1865
-
1866
- /**
1867
- * Build or retrieve the static rootfs VFSB snapshot for the given
1868
- * hostname + ShellProperties combination.
1869
- *
1870
- * Subsequent calls with the same key return the cached Buffer in ~0ms.
1871
- */
1872
- export function getStaticRootfsSnapshot(
1873
- hostname: string,
1874
- props: ShellProperties,
1875
- ): Buffer {
1876
- const key = _staticCacheKey(hostname, props);
1877
- const cached = _staticRootfsCache.get(key);
1878
- if (cached) return cached;
1879
-
1880
- const tmp = new VirtualFileSystem({ mode: "memory" });
1881
- bootstrapEtc(tmp, hostname, props);
1882
- bootstrapSys(tmp, hostname, props);
1883
- bootstrapDev(tmp);
1884
- bootstrapUsr(tmp);
1885
- bootstrapVar(tmp);
1886
- bootstrapBin(tmp);
1887
- bootstrapTmp(tmp);
1888
- bootstrapMisc(tmp, props);
1889
- bootProcLog(tmp, props);
1890
-
1891
- const snapshot = tmp.encodeBinary();
1892
- _staticRootfsCache.set(key, snapshot);
1893
- return snapshot;
1894
- }
1895
-
1896
- // ─── main entry point ─────────────────────────────────────────────────────────
1897
-
1898
- /**
1899
- * Bootstraps the full Linux rootfs hierarchy in the VFS.
1900
- * Safe to call multiple times — idempotent.
1901
- *
1902
- * @param vfs Target virtual filesystem.
1903
- * @param users User manager (for /etc/passwd sync).
1904
- * @param hostname Virtual hostname.
1905
- * @param props Shell properties (kernel, os, arch).
1906
- * @param shellStartTime Unix ms of shell creation (for uptime).
1907
- * @param sessions Active sessions (for /proc/<pid> population).
1908
- */
1909
- export function bootstrapLinuxRootfs(
1910
- vfs: VirtualFileSystem,
1911
- users: VirtualUserManager,
1912
- hostname: string,
1913
- props: ShellProperties,
1914
- shellStartTime: number,
1915
- sessions: VirtualActiveSession[] = [],
1916
- ): void {
1917
- const snapshot = getStaticRootfsSnapshot(hostname, props);
1918
- const hasRestoredData = vfs.getMode() === "fs" && vfs.exists("/home");
1919
-
1920
- if (hasRestoredData) {
1921
- // Snapshot was already restored — merge static rootfs without
1922
- // clobbering user files and directories.
1923
- vfs.mergeRootTree(decodeVfs(snapshot));
1924
- } else {
1925
- // Fresh start — replace the empty tree with the full static rootfs.
1926
- vfs.importRootTree(decodeVfs(snapshot));
1927
- }
1928
-
1929
- bootstrapRoot(vfs);
1930
- refreshProc(vfs, props, hostname, shellStartTime, sessions);
1931
- syncEtcPasswd(vfs, users);
1932
- }
1933
-
1934
- // ─── optional live engine ─────────────────────────────────────────────────────
1935
-
1936
- /**
1937
- * Engine for runtimes that want periodic /proc refresh (e.g. web shell
1938
- * with live `top`/`ps` output). Call `.boot()` once, then `.tick()` on
1939
- * each session change or on a timer.
1940
- *
1941
- * ```ts
1942
- * const engine = createLinuxRootfsEngine(vfs, props, hostname, Date.now());
1943
- * engine.boot(users, sessions);
1944
- * setInterval(() => engine.tick(shell.listActiveSessions()), 5000);
1945
- * ```
1946
- */
1947
- export function createLinuxRootfsEngine(
1948
- vfs: VirtualFileSystem,
1949
- props: ShellProperties,
1950
- hostname: string,
1951
- startTime: number,
1952
- ) {
1953
- return {
1954
- boot(users: VirtualUserManager, sessions: VirtualActiveSession[] = []) {
1955
- bootstrapLinuxRootfs(vfs, users, hostname, props, startTime, sessions);
1956
- },
1957
- tick(sessions: VirtualActiveSession[] = []) {
1958
- refreshProc(vfs, props, hostname, startTime, sessions);
1959
- },
1960
- };
1961
- }