typescript-virtual-container 1.4.9 → 1.5.0
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.
- package/.vscode/settings.json +1 -1
- package/README.md +117 -79
- package/builds/self-standalone.mjs +1768 -0
- package/builds/standalone-wo-sftp.js +735 -267
- package/builds/standalone.cjs +735 -267
- package/bun.lock +3 -3
- package/dist/SSHMimic/exec.js +2 -2
- package/dist/SSHMimic/exec.js.map +1 -1
- package/dist/SSHMimic/index.d.ts.map +1 -1
- package/dist/SSHMimic/index.js +2 -1
- package/dist/SSHMimic/index.js.map +1 -1
- package/dist/SSHMimic/sftp.d.ts.map +1 -1
- package/dist/SSHMimic/sftp.js +4 -3
- package/dist/SSHMimic/sftp.js.map +1 -1
- package/dist/VirtualFileSystem/index.d.ts +14 -0
- package/dist/VirtualFileSystem/index.d.ts.map +1 -1
- package/dist/VirtualFileSystem/index.js +51 -3
- package/dist/VirtualFileSystem/index.js.map +1 -1
- package/dist/VirtualFileSystem/journal.d.ts.map +1 -1
- package/dist/VirtualFileSystem/journal.js +11 -5
- package/dist/VirtualFileSystem/journal.js.map +1 -1
- package/dist/VirtualShell/shell.js +12 -12
- package/dist/VirtualShell/shell.js.map +1 -1
- package/dist/VirtualUserManager/index.js +8 -11
- package/dist/VirtualUserManager/index.js.map +1 -1
- package/dist/commands/apt.js +3 -3
- package/dist/commands/apt.js.map +1 -1
- package/dist/commands/cd.d.ts.map +1 -1
- package/dist/commands/cd.js +2 -1
- package/dist/commands/cd.js.map +1 -1
- package/dist/commands/helpers.d.ts +1 -1
- package/dist/commands/helpers.d.ts.map +1 -1
- package/dist/commands/helpers.js +3 -2
- package/dist/commands/helpers.js.map +1 -1
- package/dist/commands/index.d.ts +1 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -1
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/lsb-release.js +1 -1
- package/dist/commands/lsb-release.js.map +1 -1
- package/dist/commands/runtime.d.ts +2 -0
- package/dist/commands/runtime.d.ts.map +1 -1
- package/dist/commands/runtime.js +5 -1
- package/dist/commands/runtime.js.map +1 -1
- package/dist/modules/linuxRootfs.d.ts +9 -5
- package/dist/modules/linuxRootfs.d.ts.map +1 -1
- package/dist/modules/linuxRootfs.js +1079 -148
- package/dist/modules/linuxRootfs.js.map +1 -1
- package/dist/self-standalone.js +22 -12
- package/dist/self-standalone.js.map +1 -1
- package/docs/assets/hierarchy.js +1 -1
- package/docs/classes/HoneyPot.html +9 -9
- package/docs/classes/IdleManager.html +8 -8
- package/docs/classes/SshClient.html +18 -18
- package/docs/classes/VirtualFileSystem.html +34 -34
- package/docs/classes/VirtualPackageManager.html +13 -13
- package/docs/classes/VirtualSftpServer.html +3 -3
- package/docs/classes/VirtualShell.html +28 -28
- package/docs/classes/VirtualSshServer.html +5 -5
- package/docs/classes/VirtualUserManager.html +27 -27
- package/docs/functions/assertDiff.html +2 -2
- package/docs/functions/diffSnapshots.html +2 -2
- package/docs/functions/formatDiff.html +2 -2
- package/docs/functions/getArg.html +2 -2
- package/docs/functions/getFlag.html +2 -2
- package/docs/functions/ifFlag.html +2 -2
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +10 -8
- package/docs/interfaces/AuditLogEntry.html +3 -3
- package/docs/interfaces/CommandContext.html +12 -12
- package/docs/interfaces/CommandResult.html +13 -13
- package/docs/interfaces/ExecStream.html +6 -6
- package/docs/interfaces/HoneyPotStats.html +3 -3
- package/docs/interfaces/IdleManagerOptions.html +3 -3
- package/docs/interfaces/InstalledPackage.html +11 -11
- package/docs/interfaces/NanoEditorSession.html +5 -5
- package/docs/interfaces/PackageDefinition.html +14 -14
- package/docs/interfaces/PackageFile.html +5 -5
- package/docs/interfaces/PasswordChallenge.html +9 -9
- package/docs/interfaces/RemoveOptions.html +3 -3
- package/docs/interfaces/ShellEnv.html +4 -4
- package/docs/interfaces/ShellModule.html +8 -8
- package/docs/interfaces/ShellProperties.html +5 -5
- package/docs/interfaces/ShellStream.html +7 -7
- package/docs/interfaces/SudoChallenge.html +9 -9
- package/docs/interfaces/VfsBaseNode.html +7 -7
- package/docs/interfaces/VfsDiff.html +6 -6
- package/docs/interfaces/VfsDiffEntry.html +4 -4
- package/docs/interfaces/VfsDiffModified.html +6 -6
- package/docs/interfaces/VfsDirectoryNode.html +8 -8
- package/docs/interfaces/VfsFileNode.html +9 -9
- package/docs/interfaces/VfsOptions.html +6 -6
- package/docs/interfaces/VfsSnapshot.html +3 -3
- package/docs/interfaces/VfsSnapshotBaseNode.html +4 -4
- package/docs/interfaces/VfsSnapshotDirectoryNode.html +5 -5
- package/docs/interfaces/VfsSnapshotFileNode.html +6 -6
- package/docs/interfaces/VirtualActiveSession.html +7 -7
- package/docs/interfaces/VirtualSftpServerOptions.html +3 -3
- package/docs/interfaces/VirtualShellVfsLike.html +3 -3
- package/docs/interfaces/VirtualShellVfsOptions.html +3 -3
- package/docs/interfaces/WriteFileOptions.html +4 -4
- package/docs/modules.html +1 -1
- package/docs/types/ArgParseOptions.html +3 -3
- package/docs/types/CommandMode.html +2 -2
- package/docs/types/CommandOutcome.html +2 -2
- package/docs/types/IdleState.html +1 -1
- package/docs/types/VfsNodeStats.html +2 -2
- package/docs/types/VfsNodeType.html +2 -2
- package/docs/types/VfsPersistenceMode.html +2 -2
- package/docs/types/VfsSnapshotNode.html +2 -2
- package/package.json +3 -3
- package/src/SSHMimic/exec.ts +2 -2
- package/src/SSHMimic/index.ts +2 -1
- package/src/SSHMimic/sftp.ts +4 -3
- package/src/VirtualFileSystem/index.ts +46 -3
- package/src/VirtualFileSystem/journal.ts +10 -5
- package/src/VirtualShell/shell.ts +12 -12
- package/src/VirtualUserManager/index.ts +11 -11
- package/src/commands/apt.ts +3 -3
- package/src/commands/cd.ts +2 -1
- package/src/commands/helpers.ts +3 -2
- package/src/commands/index.ts +1 -1
- package/src/commands/lsb-release.ts +1 -1
- package/src/commands/runtime.ts +6 -1
- package/src/modules/linuxRootfs.ts +1293 -207
- package/src/self-standalone.ts +26 -12
- package/tests/new-features.test.ts +2 -2
- package/tests/sftp.test.ts +13 -13
- package/builds/self-standalone.js +0 -1299
|
@@ -6,12 +6,16 @@
|
|
|
6
6
|
* Called once during VirtualShell initialization. Idempotent — skips
|
|
7
7
|
* paths that already exist so FS-mode snapshots survive restarts.
|
|
8
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
|
+
*
|
|
9
14
|
* Public API:
|
|
10
|
-
* - bootstrapLinuxRootfs()
|
|
11
|
-
* - refreshProc()
|
|
12
|
-
* - syncEtcPasswd()
|
|
13
|
-
* - createLinuxRootfsEngine()
|
|
14
|
-
* runtimes that want a live refresh loop
|
|
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
|
|
15
19
|
*/
|
|
16
20
|
|
|
17
21
|
import * as os from "node:os";
|
|
@@ -33,7 +37,6 @@ function ensureFile(
|
|
|
33
37
|
content: string,
|
|
34
38
|
mode = 0o644,
|
|
35
39
|
): void {
|
|
36
|
-
// Use lazy stub — no Buffer allocated until the file is actually read or overwritten
|
|
37
40
|
vfs.writeStub(path, content, mode);
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -60,7 +63,7 @@ function bootstrapEtc(
|
|
|
60
63
|
): void {
|
|
61
64
|
ensureDir(vfs, "/etc");
|
|
62
65
|
|
|
63
|
-
// os-release —
|
|
66
|
+
// os-release — Fortune Nyx identity
|
|
64
67
|
ensureFile(
|
|
65
68
|
vfs,
|
|
66
69
|
"/etc/os-release",
|
|
@@ -70,42 +73,60 @@ function bootstrapEtc(
|
|
|
70
73
|
`ID=fortune`,
|
|
71
74
|
`ID_LIKE=debian`,
|
|
72
75
|
`HOME_URL="https://github.com/itsrealfortune/typescript-virtual-container"`,
|
|
73
|
-
`VERSION_CODENAME=
|
|
74
|
-
`VERSION_ID="
|
|
76
|
+
`VERSION_CODENAME=nyx`,
|
|
77
|
+
`VERSION_ID="24.04"`,
|
|
78
|
+
`FORTUNE_CODENAME=nyx`,
|
|
75
79
|
].join("\n")}\n`,
|
|
76
80
|
);
|
|
77
81
|
|
|
78
|
-
ensureFile(vfs, "/etc/debian_version", "
|
|
82
|
+
ensureFile(vfs, "/etc/debian_version", "nyx/stable\n");
|
|
79
83
|
ensureFile(vfs, "/etc/hostname", `${hostname}\n`);
|
|
80
|
-
ensureFile(
|
|
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
|
+
);
|
|
81
89
|
ensureFile(
|
|
82
90
|
vfs,
|
|
83
91
|
"/etc/profile",
|
|
84
92
|
`${[
|
|
85
|
-
"export PATH=/usr/local/bin:/usr/bin:/bin",
|
|
93
|
+
"export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
|
86
94
|
"export PS1='\\u@\\h:\\w\\$ '",
|
|
87
95
|
].join("\n")}\n`,
|
|
88
96
|
);
|
|
89
97
|
|
|
90
|
-
ensureFile(vfs, "/etc/issue", "Fortune GNU/Linux
|
|
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");
|
|
91
100
|
ensureFile(
|
|
92
101
|
vfs,
|
|
93
102
|
"/etc/motd",
|
|
94
103
|
["", `Welcome to ${props.os}`, `Kernel: ${props.kernel}`, ""].join("\n"),
|
|
95
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
|
+
);
|
|
96
113
|
|
|
97
|
-
// APT sources
|
|
114
|
+
// APT — Fortune Nyx sources
|
|
98
115
|
ensureDir(vfs, "/etc/apt");
|
|
99
116
|
ensureDir(vfs, "/etc/apt/sources.list.d");
|
|
117
|
+
ensureDir(vfs, "/etc/apt/trusted.gpg.d");
|
|
118
|
+
ensureDir(vfs, "/etc/apt/keyrings");
|
|
100
119
|
ensureFile(
|
|
101
120
|
vfs,
|
|
102
121
|
"/etc/apt/sources.list",
|
|
103
122
|
`${[
|
|
104
|
-
"# Fortune GNU/Linux package sources",
|
|
105
|
-
"deb [virtual] fortune://packages.fortune.local
|
|
106
|
-
"deb [virtual] fortune://
|
|
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",
|
|
107
127
|
].join("\n")}\n`,
|
|
108
128
|
);
|
|
129
|
+
ensureFile(vfs, "/etc/apt/apt.conf.d/70debconf", `// debconf config\n`);
|
|
109
130
|
|
|
110
131
|
// network
|
|
111
132
|
ensureDir(vfs, "/etc/network");
|
|
@@ -120,6 +141,18 @@ function bootstrapEtc(
|
|
|
120
141
|
"iface eth0 inet dhcp",
|
|
121
142
|
].join("\n")}\n`,
|
|
122
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
|
+
);
|
|
123
156
|
|
|
124
157
|
ensureFile(vfs, "/etc/resolv.conf", "nameserver 1.1.1.1\nnameserver 8.8.8.8\n");
|
|
125
158
|
|
|
@@ -130,29 +163,56 @@ function bootstrapEtc(
|
|
|
130
163
|
"127.0.0.1 localhost",
|
|
131
164
|
`127.0.1.1 ${hostname}`,
|
|
132
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",
|
|
133
184
|
].join("\n")}\n`,
|
|
134
185
|
);
|
|
135
186
|
|
|
136
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");
|
|
137
192
|
ensureDir(vfs, "/etc/init.d");
|
|
138
193
|
ensureDir(vfs, "/etc/systemd");
|
|
139
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
|
+
);
|
|
140
200
|
|
|
141
|
-
// fstab
|
|
201
|
+
// fstab — virtio block devices matching Firecracker layout
|
|
142
202
|
ensureFile(
|
|
143
203
|
vfs,
|
|
144
204
|
"/etc/fstab",
|
|
145
205
|
`${[
|
|
146
|
-
"# <file system> <mount point> <type>
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"tmpfs
|
|
151
|
-
"tmpfs
|
|
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",
|
|
152
212
|
].join("\n")}\n`,
|
|
153
213
|
);
|
|
154
214
|
|
|
155
|
-
// login.defs
|
|
215
|
+
// login.defs
|
|
156
216
|
ensureFile(
|
|
157
217
|
vfs,
|
|
158
218
|
"/etc/login.defs",
|
|
@@ -174,32 +234,167 @@ function bootstrapEtc(
|
|
|
174
234
|
|
|
175
235
|
// security + pam
|
|
176
236
|
ensureDir(vfs, "/etc/security");
|
|
177
|
-
ensureFile(vfs, "/etc/security/limits.conf",
|
|
237
|
+
ensureFile(vfs, "/etc/security/limits.conf",
|
|
238
|
+
"# /etc/security/limits.conf\n* soft nofile 1024\n* hard nofile 65536\n",
|
|
239
|
+
);
|
|
178
240
|
ensureFile(vfs, "/etc/security/access.conf", "# /etc/security/access.conf\n");
|
|
179
241
|
|
|
180
242
|
ensureDir(vfs, "/etc/pam.d");
|
|
181
|
-
ensureFile(vfs, "/etc/pam.d/common-auth",
|
|
182
|
-
|
|
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
|
+
);
|
|
183
249
|
ensureFile(vfs, "/etc/pam.d/common-password",
|
|
184
|
-
"password
|
|
185
|
-
|
|
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
|
+
);
|
|
186
255
|
ensureFile(vfs, "/etc/pam.d/sshd",
|
|
187
|
-
"@include common-auth\n@include common-account\n@include common-session\n"
|
|
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
|
+
);
|
|
188
264
|
|
|
189
|
-
// sudo
|
|
265
|
+
// sudo
|
|
190
266
|
ensureDir(vfs, "/etc/sudoers.d");
|
|
191
267
|
ensureFile(vfs, "/etc/sudoers",
|
|
192
|
-
"
|
|
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
|
+
);
|
|
193
275
|
|
|
194
276
|
// ld
|
|
195
277
|
ensureFile(vfs, "/etc/ld.so.conf", "include /etc/ld.so.conf.d/*.conf\n");
|
|
196
278
|
ensureDir(vfs, "/etc/ld.so.conf.d");
|
|
197
|
-
ensureFile(vfs, "/etc/ld.so.conf.d/x86_64-linux-gnu.conf",
|
|
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
|
+
);
|
|
198
285
|
|
|
199
286
|
// locale + timezone
|
|
200
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");
|
|
201
290
|
ensureFile(vfs, "/etc/timezone", "UTC\n");
|
|
202
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
|
+
);
|
|
203
398
|
}
|
|
204
399
|
|
|
205
400
|
// ─── /etc/passwd + /etc/group + /etc/shadow ─────────────────────────────────
|
|
@@ -217,8 +412,26 @@ export function syncEtcPasswd(
|
|
|
217
412
|
const passwdLines = [
|
|
218
413
|
"root:x:0:0:root:/root:/bin/bash",
|
|
219
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",
|
|
220
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",
|
|
221
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",
|
|
222
435
|
];
|
|
223
436
|
|
|
224
437
|
let uid = 1000;
|
|
@@ -230,19 +443,65 @@ export function syncEtcPasswd(
|
|
|
230
443
|
|
|
231
444
|
vfs.writeFile("/etc/passwd", `${passwdLines.join("\n")}\n`);
|
|
232
445
|
|
|
446
|
+
const sudoers = userList.filter((u) => users.isSudoer(u)).join(",");
|
|
447
|
+
const nonRootUsers = userList.filter((u) => u !== "root").join(",");
|
|
448
|
+
|
|
233
449
|
const groupLines = [
|
|
234
450
|
"root:x:0:",
|
|
235
451
|
"daemon:x:1:",
|
|
236
|
-
|
|
237
|
-
|
|
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}`,
|
|
238
488
|
"nogroup:x:65534:",
|
|
489
|
+
"messagebus:x:106:",
|
|
490
|
+
"systemd-network:x:998:",
|
|
491
|
+
"systemd-resolve:x:999:",
|
|
492
|
+
"polkitd:x:997:",
|
|
239
493
|
];
|
|
240
494
|
vfs.writeFile("/etc/group", `${groupLines.join("\n")}\n`);
|
|
241
495
|
|
|
242
|
-
// shadow — fake hashes, never real credentials
|
|
243
496
|
const shadowLines = [
|
|
244
497
|
"root:*:19000:0:99999:7:::",
|
|
245
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:::::::",
|
|
246
505
|
];
|
|
247
506
|
for (const u of userList) {
|
|
248
507
|
if (u === "root") continue;
|
|
@@ -253,13 +512,11 @@ export function syncEtcPasswd(
|
|
|
253
512
|
|
|
254
513
|
// ─── /proc helpers ───────────────────────────────────────────────────────────
|
|
255
514
|
|
|
256
|
-
/** Derive a stable virtual PID from a tty string e.g. "pts/0" → 1000 */
|
|
257
515
|
function ttyToPid(tty: string): number {
|
|
258
516
|
const match = tty.match(/(\d+)$/);
|
|
259
517
|
return 1000 + (match?.[1] ? parseInt(match[1], 10) : 0);
|
|
260
518
|
}
|
|
261
519
|
|
|
262
|
-
/** Write /proc/<pid>/ subtree for a single virtual process */
|
|
263
520
|
function writeProcPid(
|
|
264
521
|
vfs: VirtualFileSystem,
|
|
265
522
|
pid: number,
|
|
@@ -273,6 +530,7 @@ function writeProcPid(
|
|
|
273
530
|
ensureDir(vfs, dir);
|
|
274
531
|
ensureDir(vfs, `${dir}/fd`);
|
|
275
532
|
ensureDir(vfs, `${dir}/fdinfo`);
|
|
533
|
+
ensureDir(vfs, `${dir}/net`);
|
|
276
534
|
|
|
277
535
|
const uptimeSec = Math.floor((Date.now() - new Date(startedAt).getTime()) / 1000);
|
|
278
536
|
const comm = cmdline.split(/\s+/)[0] ?? "bash";
|
|
@@ -284,20 +542,57 @@ function writeProcPid(
|
|
|
284
542
|
`${dir}/status`,
|
|
285
543
|
`${[
|
|
286
544
|
`Name: ${comm}`,
|
|
545
|
+
`Umask: 0022`,
|
|
287
546
|
`State: S (sleeping)`,
|
|
547
|
+
`Tgid: ${pid}`,
|
|
288
548
|
`Pid: ${pid}`,
|
|
289
549
|
`PPid: 1`,
|
|
550
|
+
`TracerPid: 0`,
|
|
290
551
|
`Uid: 0\t0\t0\t0`,
|
|
291
552
|
`Gid: 0\t0\t0\t0`,
|
|
292
|
-
`
|
|
293
|
-
`
|
|
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`,
|
|
294
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`,
|
|
295
585
|
].join("\n")}\n`,
|
|
296
586
|
);
|
|
297
587
|
write(
|
|
298
588
|
vfs,
|
|
299
589
|
`${dir}/stat`,
|
|
300
|
-
`${pid} (${comm}) S 1 ${pid} ${pid} 0 -1 4194304 0 0 0 0 ${uptimeSec} 0 0 0 20 0 1 0 0
|
|
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`,
|
|
301
596
|
);
|
|
302
597
|
write(
|
|
303
598
|
vfs,
|
|
@@ -306,10 +601,48 @@ function writeProcPid(
|
|
|
306
601
|
);
|
|
307
602
|
write(vfs, `${dir}/cwd`, `/home/${username}\0`);
|
|
308
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");
|
|
309
640
|
|
|
310
|
-
// Standard fd stubs (stdin/stdout/stderr)
|
|
311
641
|
for (const fd of ["0", "1", "2"]) {
|
|
312
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
|
+
);
|
|
313
646
|
}
|
|
314
647
|
}
|
|
315
648
|
|
|
@@ -321,11 +654,30 @@ function bootProcLog(vfs: VirtualFileSystem, props: ShellProperties): void {
|
|
|
321
654
|
vfs,
|
|
322
655
|
"/proc/boot/log",
|
|
323
656
|
`${[
|
|
324
|
-
|
|
325
|
-
"[ 0.
|
|
326
|
-
"[ 0.
|
|
327
|
-
"[ 0.
|
|
328
|
-
"[ 0.
|
|
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",
|
|
329
681
|
].join("\n")}\n`,
|
|
330
682
|
);
|
|
331
683
|
ensureFile(vfs, "/proc/boot/version", `Linux ${props.kernel} (virtual)\n`);
|
|
@@ -350,13 +702,18 @@ export function refreshProc(
|
|
|
350
702
|
ensureDir(vfs, "/proc");
|
|
351
703
|
|
|
352
704
|
const uptimeSec = Math.floor((Date.now() - shellStartTime) / 1000);
|
|
353
|
-
const idleSec
|
|
705
|
+
const idleSec = Math.floor(uptimeSec * 0.9);
|
|
354
706
|
write(vfs, "/proc/uptime", `${uptimeSec}.00 ${idleSec}.00\n`);
|
|
355
707
|
|
|
356
708
|
// meminfo — real host values, Linux-compatible format
|
|
357
|
-
const totalMemKb
|
|
358
|
-
const freeMemKb
|
|
359
|
-
const availMemKb
|
|
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);
|
|
360
717
|
write(
|
|
361
718
|
vfs,
|
|
362
719
|
"/proc/meminfo",
|
|
@@ -364,14 +721,59 @@ export function refreshProc(
|
|
|
364
721
|
`MemTotal: ${String(totalMemKb).padStart(10)} kB`,
|
|
365
722
|
`MemFree: ${String(freeMemKb).padStart(10)} kB`,
|
|
366
723
|
`MemAvailable: ${String(availMemKb).padStart(10)} kB`,
|
|
367
|
-
`Buffers: ${String(
|
|
368
|
-
`Cached: ${String(
|
|
369
|
-
`
|
|
370
|
-
`
|
|
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`,
|
|
371
773
|
].join("\n")}\n`,
|
|
372
774
|
);
|
|
373
775
|
|
|
374
|
-
// cpuinfo — real host CPU passthrough
|
|
776
|
+
// cpuinfo — real host CPU passthrough + x86 feature flags matching Firecracker Xeon
|
|
375
777
|
const cpus = os.cpus();
|
|
376
778
|
const cpuLines: string[] = [];
|
|
377
779
|
for (let i = 0; i < cpus.length; i++) {
|
|
@@ -379,9 +781,31 @@ export function refreshProc(
|
|
|
379
781
|
if (!c) continue;
|
|
380
782
|
cpuLines.push(
|
|
381
783
|
`processor\t: ${i}`,
|
|
784
|
+
`vendor_id\t: GenuineIntel`,
|
|
785
|
+
`cpu family\t: 6`,
|
|
786
|
+
`model\t\t: 85`,
|
|
382
787
|
`model name\t: ${c.model}`,
|
|
788
|
+
`stepping\t: 7`,
|
|
789
|
+
`microcode\t: 0x1`,
|
|
383
790
|
`cpu MHz\t\t: ${c.speed.toFixed(3)}`,
|
|
384
|
-
`cache size\t:
|
|
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:`,
|
|
385
809
|
"",
|
|
386
810
|
);
|
|
387
811
|
}
|
|
@@ -390,95 +814,219 @@ export function refreshProc(
|
|
|
390
814
|
write(
|
|
391
815
|
vfs,
|
|
392
816
|
"/proc/version",
|
|
393
|
-
`Linux version ${props.kernel} (fortune@build) (gcc
|
|
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`,
|
|
394
818
|
);
|
|
395
819
|
write(vfs, "/proc/hostname", `${hostname}\n`);
|
|
396
820
|
|
|
397
|
-
// loadavg
|
|
398
|
-
const load
|
|
821
|
+
// loadavg
|
|
822
|
+
const load = (Math.random() * 0.3).toFixed(2);
|
|
399
823
|
const numProcs = 1 + sessions.length;
|
|
400
824
|
write(vfs, "/proc/loadavg", `${load} ${load} ${load} ${numProcs}/${numProcs} 1\n`);
|
|
401
825
|
|
|
402
|
-
// /proc/
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
vfs,
|
|
406
|
-
"/proc/net/dev",
|
|
407
|
-
`${[
|
|
408
|
-
"Inter-| Receive | Transmit",
|
|
409
|
-
" face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed",
|
|
410
|
-
" lo: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0",
|
|
411
|
-
" eth0: 131072 1024 0 0 0 0 0 0 65536 512 0 0 0 0 0 0",
|
|
412
|
-
].join("\n")}\n`,
|
|
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`,
|
|
413
829
|
);
|
|
414
|
-
ensureFile(vfs, "/proc/net/if_inet6", "");
|
|
415
|
-
ensureFile(vfs, "/proc/net/tcp", " sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode\n");
|
|
416
|
-
ensureFile(vfs, "/proc/net/tcp6", " sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode\n");
|
|
417
|
-
|
|
418
|
-
// /proc/cmdline — kernel boot args
|
|
419
|
-
write(vfs, "/proc/cmdline", `BOOT_IMAGE=/boot/vmlinuz-${props.kernel} root=/dev/sda2 ro quiet splash\n`);
|
|
420
830
|
|
|
421
|
-
// /proc/filesystems
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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`,
|
|
426
868
|
);
|
|
427
869
|
|
|
428
|
-
// /proc/mounts
|
|
870
|
+
// /proc/mounts — virtio block device layout
|
|
429
871
|
const mountsContent = `${[
|
|
430
|
-
"
|
|
431
|
-
"
|
|
432
|
-
"devtmpfs /dev devtmpfs rw,
|
|
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",
|
|
433
888
|
"tmpfs /run tmpfs rw,nosuid,nodev,noexec,relatime,size=204800k,mode=755 0 0",
|
|
434
889
|
"tmpfs /tmp tmpfs rw,nosuid,nodev,noatime 0 0",
|
|
435
|
-
"/dev/sda2 / ext4 rw,relatime,errors=remount-ro 0 0",
|
|
436
|
-
"/dev/sda1 /boot ext4 rw,relatime 0 0",
|
|
437
|
-
"tmpfs /dev/shm tmpfs rw,nosuid,nodev 0 0",
|
|
438
|
-
"devpts /dev/pts devpts rw,nosuid,noexec,relatime,mode=620,ptmxmode=000 0 0",
|
|
439
|
-
"squashfs /snap/core squashfs ro,nodev,relatime 0 0",
|
|
440
890
|
].join("\n")}\n`;
|
|
441
891
|
write(vfs, "/proc/mounts", mountsContent);
|
|
442
892
|
ensureDir(vfs, "/proc/self");
|
|
443
893
|
write(vfs, "/proc/self/mounts", mountsContent);
|
|
444
894
|
|
|
445
|
-
// /proc/
|
|
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
|
|
446
933
|
write(
|
|
447
934
|
vfs,
|
|
448
935
|
"/proc/partitions",
|
|
449
936
|
`${[
|
|
450
937
|
"major minor #blocks name",
|
|
451
938
|
"",
|
|
452
|
-
"
|
|
453
|
-
"
|
|
454
|
-
"
|
|
455
|
-
"
|
|
939
|
+
" 254 0 268435456 vda",
|
|
940
|
+
" 254 16 9664 vdb",
|
|
941
|
+
" 254 32 656 vdc",
|
|
942
|
+
" 254 48 5464 vdd",
|
|
456
943
|
].join("\n")}\n`,
|
|
457
944
|
);
|
|
458
945
|
|
|
459
|
-
// /proc/swaps
|
|
460
|
-
write(
|
|
461
|
-
|
|
462
|
-
"/proc/swaps",
|
|
463
|
-
"Filename\t\t\t\tType\t\tSize\t\tUsed\t\tPriority\n" +
|
|
464
|
-
`/dev/sda3\t\t\t\tpartition\t${Math.floor(os.totalmem() / 2048)}\t\t0\t\t-2\n`,
|
|
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",
|
|
465
949
|
);
|
|
466
950
|
|
|
467
|
-
// /proc/
|
|
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)
|
|
468
967
|
ensureDir(vfs, "/proc/sys");
|
|
469
968
|
ensureDir(vfs, "/proc/sys/kernel");
|
|
470
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");
|
|
471
973
|
ensureDir(vfs, "/proc/sys/vm");
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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
|
+
);
|
|
482
1030
|
|
|
483
1031
|
// init process (PID 1)
|
|
484
1032
|
writeProcPid(vfs, 1, "root", "pts/0", "/sbin/init", new Date(shellStartTime).toISOString(), {});
|
|
@@ -487,23 +1035,25 @@ export function refreshProc(
|
|
|
487
1035
|
for (const session of sessions) {
|
|
488
1036
|
const pid = ttyToPid(session.tty);
|
|
489
1037
|
writeProcPid(vfs, pid, session.username, session.tty, "bash", session.startedAt, {
|
|
490
|
-
USER:
|
|
491
|
-
HOME:
|
|
492
|
-
TERM:
|
|
493
|
-
SHELL:
|
|
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,
|
|
494
1045
|
});
|
|
495
1046
|
}
|
|
496
1047
|
|
|
497
|
-
// /proc/self — mirror of most recent session
|
|
1048
|
+
// /proc/self — mirror of most recent session
|
|
498
1049
|
const selfPid = sessions.length > 0 ? ttyToPid(sessions[sessions.length - 1]!.tty) : 1;
|
|
499
|
-
|
|
500
|
-
if (vfs.exists("/proc/self")) {
|
|
501
|
-
try { vfs.remove("/proc/self"); } catch { /* ignore */ }
|
|
502
|
-
}
|
|
1050
|
+
try { vfs.remove("/proc/self"); } catch { /* ignore */ }
|
|
503
1051
|
|
|
504
1052
|
const selfSrc = `/proc/${selfPid}`;
|
|
505
1053
|
ensureDir(vfs, "/proc/self");
|
|
506
1054
|
ensureDir(vfs, "/proc/self/fd");
|
|
1055
|
+
ensureDir(vfs, "/proc/self/fdinfo");
|
|
1056
|
+
ensureDir(vfs, "/proc/self/net");
|
|
507
1057
|
|
|
508
1058
|
if (vfs.exists(selfSrc)) {
|
|
509
1059
|
for (const entry of vfs.list(selfSrc)) {
|
|
@@ -512,16 +1062,15 @@ export function refreshProc(
|
|
|
512
1062
|
try {
|
|
513
1063
|
const st = vfs.stat(srcPath);
|
|
514
1064
|
if (st.type === "file") write(vfs, dstPath, vfs.readFile(srcPath));
|
|
515
|
-
} catch { /* skip
|
|
1065
|
+
} catch { /* skip */ }
|
|
516
1066
|
}
|
|
517
1067
|
} else {
|
|
518
|
-
|
|
519
|
-
write(vfs, "/proc/self/
|
|
520
|
-
write(vfs, "/proc/self/
|
|
521
|
-
write(vfs, "/proc/self/
|
|
522
|
-
write(vfs, "/proc/self/
|
|
523
|
-
write(vfs, "/proc/self/
|
|
524
|
-
write(vfs, "/proc/self/exe", "/bin/bash\0");
|
|
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");
|
|
525
1074
|
}
|
|
526
1075
|
}
|
|
527
1076
|
|
|
@@ -529,12 +1078,83 @@ export function refreshProc(
|
|
|
529
1078
|
|
|
530
1079
|
function bootstrapSys(vfs: VirtualFileSystem, hostname: string, props: ShellProperties): void {
|
|
531
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
|
+
|
|
532
1085
|
ensureDir(vfs, "/sys/devices");
|
|
533
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");
|
|
534
1156
|
ensureDir(vfs, "/sys/devices/virtual/dmi");
|
|
535
1157
|
ensureDir(vfs, "/sys/devices/virtual/dmi/id");
|
|
536
|
-
|
|
537
|
-
const seed = fnv1a(hostname);
|
|
538
1158
|
const product = `VirtualNode-${(seed % 10000).toString().padStart(4, "0")}`;
|
|
539
1159
|
|
|
540
1160
|
// Full DMI table — deterministic, seeded from hostname
|
|
@@ -566,6 +1186,7 @@ function bootstrapSys(vfs: VirtualFileSystem, hostname: string, props: ShellProp
|
|
|
566
1186
|
ensureFile(vfs, "/sys/kernel/hostname", `${hostname}\n`);
|
|
567
1187
|
ensureFile(vfs, "/sys/kernel/osrelease", `${props.kernel}\n`);
|
|
568
1188
|
ensureFile(vfs, "/sys/kernel/ostype", "Linux\n");
|
|
1189
|
+
|
|
569
1190
|
}
|
|
570
1191
|
|
|
571
1192
|
// ─── /dev ─────────────────────────────────────────────────────────────────────
|
|
@@ -573,38 +1194,70 @@ function bootstrapSys(vfs: VirtualFileSystem, hostname: string, props: ShellProp
|
|
|
573
1194
|
function bootstrapDev(vfs: VirtualFileSystem): void {
|
|
574
1195
|
ensureDir(vfs, "/dev");
|
|
575
1196
|
|
|
576
|
-
// character devices
|
|
577
|
-
ensureFile(vfs, "/dev/null",
|
|
578
|
-
ensureFile(vfs, "/dev/zero",
|
|
579
|
-
ensureFile(vfs, "/dev/full",
|
|
580
|
-
ensureFile(vfs, "/dev/random",
|
|
581
|
-
ensureFile(vfs, "/dev/urandom",
|
|
582
|
-
ensureFile(vfs, "/dev/mem",
|
|
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);
|
|
583
1215
|
|
|
584
1216
|
// terminal devices
|
|
585
|
-
ensureFile(vfs, "/dev/console",
|
|
586
|
-
ensureFile(vfs, "/dev/tty",
|
|
587
|
-
ensureFile(vfs, "/dev/
|
|
588
|
-
ensureFile(vfs, "/dev/
|
|
589
|
-
|
|
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
|
+
}
|
|
590
1226
|
|
|
591
|
-
//
|
|
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)
|
|
592
1236
|
for (let i = 0; i < 8; i++) {
|
|
593
1237
|
ensureFile(vfs, `/dev/loop${i}`, "", 0o660);
|
|
594
1238
|
}
|
|
595
1239
|
ensureDir(vfs, "/dev/loop-control");
|
|
596
1240
|
|
|
597
|
-
// block
|
|
598
|
-
ensureFile(vfs, "/dev/
|
|
599
|
-
ensureFile(vfs, "/dev/
|
|
600
|
-
ensureFile(vfs, "/dev/
|
|
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);
|
|
601
1250
|
|
|
602
1251
|
// misc
|
|
603
1252
|
ensureDir(vfs, "/dev/pts");
|
|
604
1253
|
ensureDir(vfs, "/dev/shm");
|
|
1254
|
+
ensureDir(vfs, "/dev/cpu");
|
|
605
1255
|
ensureFile(vfs, "/dev/stdin", "", 0o666);
|
|
606
1256
|
ensureFile(vfs, "/dev/stdout", "", 0o666);
|
|
607
1257
|
ensureFile(vfs, "/dev/stderr", "", 0o666);
|
|
1258
|
+
ensureDir(vfs, "/dev/fd");
|
|
1259
|
+
ensureFile(vfs, "/dev/vga_arbiter", "", 0o660);
|
|
1260
|
+
ensureFile(vfs, "/dev/vsock", "", 0o660);
|
|
608
1261
|
}
|
|
609
1262
|
|
|
610
1263
|
// ─── /usr ─────────────────────────────────────────────────────────────────────
|
|
@@ -617,13 +1270,31 @@ function bootstrapUsr(vfs: VirtualFileSystem): void {
|
|
|
617
1270
|
ensureDir(vfs, "/usr/local/bin");
|
|
618
1271
|
ensureDir(vfs, "/usr/local/lib");
|
|
619
1272
|
ensureDir(vfs, "/usr/local/share");
|
|
1273
|
+
ensureDir(vfs, "/usr/local/include");
|
|
1274
|
+
ensureDir(vfs, "/usr/local/sbin");
|
|
620
1275
|
ensureDir(vfs, "/usr/share");
|
|
621
1276
|
ensureDir(vfs, "/usr/share/doc");
|
|
622
1277
|
ensureDir(vfs, "/usr/share/man");
|
|
623
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");
|
|
624
1284
|
ensureDir(vfs, "/usr/lib");
|
|
625
|
-
|
|
626
|
-
|
|
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
|
|
627
1298
|
const builtins = [
|
|
628
1299
|
"sh", "bash", "ls", "cat", "echo", "grep", "find", "sort",
|
|
629
1300
|
"head", "tail", "cut", "tr", "sed", "awk", "wc", "tee",
|
|
@@ -633,58 +1304,452 @@ function bootstrapUsr(vfs: VirtualFileSystem): void {
|
|
|
633
1304
|
"nano", "diff", "uniq", "xargs", "base64",
|
|
634
1305
|
];
|
|
635
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
|
+
|
|
636
1363
|
for (const bin of builtins) {
|
|
637
1364
|
ensureFile(vfs, `/usr/bin/${bin}`, `#!/bin/sh\nexec builtin ${bin} "$@"\n`, 0o755);
|
|
638
1365
|
}
|
|
639
1366
|
|
|
640
|
-
|
|
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");
|
|
641
1403
|
}
|
|
642
1404
|
|
|
643
1405
|
// ─── /var ─────────────────────────────────────────────────────────────────────
|
|
644
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
|
+
|
|
645
1671
|
function bootstrapVar(vfs: VirtualFileSystem): void {
|
|
646
1672
|
ensureDir(vfs, "/var");
|
|
647
1673
|
ensureDir(vfs, "/var/log");
|
|
648
1674
|
ensureDir(vfs, "/var/log/apt");
|
|
1675
|
+
ensureDir(vfs, "/var/log/journal");
|
|
1676
|
+
ensureDir(vfs, "/var/log/private");
|
|
649
1677
|
ensureDir(vfs, "/var/tmp");
|
|
650
1678
|
ensureDir(vfs, "/var/cache");
|
|
651
1679
|
ensureDir(vfs, "/var/cache/apt");
|
|
652
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");
|
|
653
1686
|
ensureDir(vfs, "/var/lib");
|
|
654
1687
|
ensureDir(vfs, "/var/lib/apt");
|
|
655
1688
|
ensureDir(vfs, "/var/lib/apt/lists");
|
|
1689
|
+
ensureDir(vfs, "/var/lib/apt/lists/partial");
|
|
656
1690
|
ensureDir(vfs, "/var/lib/dpkg");
|
|
657
1691
|
ensureDir(vfs, "/var/lib/dpkg/info");
|
|
1692
|
+
ensureDir(vfs, "/var/lib/dpkg/updates");
|
|
1693
|
+
ensureDir(vfs, "/var/lib/dpkg/alternatives");
|
|
658
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");
|
|
659
1701
|
ensureDir(vfs, "/var/spool");
|
|
660
1702
|
ensureDir(vfs, "/var/spool/cron");
|
|
1703
|
+
ensureDir(vfs, "/var/spool/mail");
|
|
661
1704
|
ensureDir(vfs, "/var/mail");
|
|
1705
|
+
ensureDir(vfs, "/var/backups");
|
|
1706
|
+
ensureDir(vfs, "/var/www");
|
|
662
1707
|
|
|
663
|
-
// dpkg status —
|
|
664
|
-
ensureFile(vfs, "/var/lib/dpkg/status",
|
|
1708
|
+
// dpkg status — realistic package database
|
|
1709
|
+
ensureFile(vfs, "/var/lib/dpkg/status", DPKG_STATUS);
|
|
665
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", "");
|
|
666
1718
|
|
|
667
1719
|
// syslog stubs
|
|
668
|
-
ensureFile(vfs, "/var/log/syslog",
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
ensureFile(vfs, "/var/log/
|
|
672
|
-
ensureFile(vfs, "/var/log/
|
|
673
|
-
ensureFile(vfs, "/var/log/
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
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
|
|
677
1735
|
ensureDir(vfs, "/run");
|
|
678
1736
|
ensureDir(vfs, "/run/lock");
|
|
1737
|
+
ensureDir(vfs, "/run/lock/subsys");
|
|
679
1738
|
ensureDir(vfs, "/run/systemd");
|
|
1739
|
+
ensureDir(vfs, "/run/systemd/ask-password");
|
|
1740
|
+
ensureDir(vfs, "/run/systemd/sessions");
|
|
1741
|
+
ensureDir(vfs, "/run/systemd/users");
|
|
680
1742
|
ensureDir(vfs, "/run/user");
|
|
1743
|
+
ensureDir(vfs, "/run/dbus");
|
|
1744
|
+
ensureDir(vfs, "/run/adduser");
|
|
681
1745
|
ensureFile(vfs, "/run/utmp", "");
|
|
1746
|
+
ensureFile(vfs, "/run/dbus/system_bus_socket", "");
|
|
682
1747
|
}
|
|
683
1748
|
|
|
684
1749
|
// ─── /bin + /sbin symlinks ────────────────────────────────────────────────────
|
|
685
1750
|
|
|
686
1751
|
function bootstrapBin(vfs: VirtualFileSystem): void {
|
|
687
|
-
// Modern
|
|
1752
|
+
// Modern Fortune Nyx: /bin and /sbin are symlinks to /usr/bin and /usr/sbin
|
|
688
1753
|
if (!vfs.exists("/bin")) vfs.symlink("/usr/bin", "/bin");
|
|
689
1754
|
if (!vfs.exists("/sbin")) vfs.symlink("/usr/sbin", "/sbin");
|
|
690
1755
|
|
|
@@ -695,18 +1760,30 @@ function bootstrapBin(vfs: VirtualFileSystem): void {
|
|
|
695
1760
|
ensureDir(vfs, "/lib64");
|
|
696
1761
|
ensureDir(vfs, "/lib/x86_64-linux-gnu");
|
|
697
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
|
+
}
|
|
698
1768
|
}
|
|
699
1769
|
|
|
700
1770
|
// ─── /tmp ─────────────────────────────────────────────────────────────────────
|
|
701
1771
|
|
|
702
1772
|
function bootstrapTmp(vfs: VirtualFileSystem): void {
|
|
703
1773
|
ensureDir(vfs, "/tmp", 0o1777);
|
|
1774
|
+
// node compile cache dir (present in real env)
|
|
1775
|
+
ensureDir(vfs, "/tmp/node-compile-cache", 0o1777);
|
|
704
1776
|
}
|
|
705
1777
|
|
|
706
1778
|
// ─── /root home ───────────────────────────────────────────────────────────────
|
|
707
1779
|
|
|
708
1780
|
function bootstrapRoot(vfs: VirtualFileSystem): void {
|
|
709
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);
|
|
710
1787
|
ensureFile(
|
|
711
1788
|
vfs,
|
|
712
1789
|
"/root/.bashrc",
|
|
@@ -714,66 +1791,71 @@ function bootstrapRoot(vfs: VirtualFileSystem): void {
|
|
|
714
1791
|
"# root .bashrc",
|
|
715
1792
|
"export PS1='\\[\\033[0;31m\\]\\u@\\h\\[\\033[0m\\]:\\[\\033[0;34m\\]\\w\\[\\033[0m\\]# '",
|
|
716
1793
|
"export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
|
1794
|
+
"export LANG=en_US.UTF-8",
|
|
717
1795
|
"alias ll='ls -la'",
|
|
718
1796
|
"alias la='ls -A'",
|
|
1797
|
+
"alias l='ls -CF'",
|
|
719
1798
|
].join("\n")}\n`,
|
|
720
1799
|
);
|
|
721
|
-
ensureFile(vfs, "/root/.profile",
|
|
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
|
+
);
|
|
722
1809
|
}
|
|
723
1810
|
|
|
724
|
-
// ─── /opt /srv /mnt /media
|
|
1811
|
+
// ─── /opt /srv /mnt /media ────────────────────────────────────────────────────
|
|
725
1812
|
|
|
726
1813
|
function bootstrapMisc(vfs: VirtualFileSystem, props: ShellProperties): void {
|
|
727
1814
|
ensureDir(vfs, "/opt");
|
|
1815
|
+
ensureDir(vfs, "/opt/rclone");
|
|
728
1816
|
ensureDir(vfs, "/srv");
|
|
729
1817
|
ensureDir(vfs, "/mnt");
|
|
730
1818
|
ensureDir(vfs, "/media");
|
|
731
|
-
ensureDir(vfs, "/home");
|
|
732
1819
|
|
|
733
|
-
// /boot —
|
|
1820
|
+
// /boot — no kernel images in Firecracker containers (kernel is external),
|
|
1821
|
+
// but maintain the directory structure for tool compatibility
|
|
734
1822
|
ensureDir(vfs, "/boot");
|
|
735
1823
|
ensureDir(vfs, "/boot/grub");
|
|
736
|
-
|
|
737
|
-
ensureFile(
|
|
738
|
-
vfs,
|
|
739
|
-
"/boot/grub/grub.cfg",
|
|
1824
|
+
ensureFile(vfs, "/boot/grub/grub.cfg",
|
|
740
1825
|
`${[
|
|
741
1826
|
"# GRUB configuration (virtual)",
|
|
742
1827
|
"set default=0",
|
|
743
|
-
"set timeout=
|
|
1828
|
+
"set timeout=0",
|
|
744
1829
|
"",
|
|
745
1830
|
`menuentry "Fortune GNU/Linux" {`,
|
|
746
|
-
` linux /vmlinuz root=/dev/
|
|
747
|
-
` initrd /initrd.img`,
|
|
1831
|
+
` linux /vmlinuz-${props.kernel} root=/dev/vda rw console=ttyS0`,
|
|
1832
|
+
` initrd /initrd.img-${props.kernel}`,
|
|
748
1833
|
`}`,
|
|
749
1834
|
].join("\n")}\n`,
|
|
750
1835
|
);
|
|
751
|
-
|
|
1836
|
+
|
|
752
1837
|
const kver = props.kernel;
|
|
753
|
-
ensureFile(vfs, `/boot/vmlinuz-${kver}`,
|
|
754
|
-
ensureFile(vfs, `/boot/initrd.img-${kver}`,
|
|
755
|
-
ensureFile(vfs, `/boot/System.map-${kver}`,
|
|
756
|
-
ensureFile(vfs, `/boot/config-${kver}`,
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
if (!vfs.exists("/vmlinuz"))
|
|
760
|
-
if (!vfs.exists("/
|
|
761
|
-
if (!vfs.exists("/initrd.img"))
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
// /
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
// /lost+found — ext4 fsck recovery dir (mode 0o700, root only)
|
|
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
|
|
769
1852
|
ensureDir(vfs, "/lost+found", 0o700);
|
|
1853
|
+
|
|
1854
|
+
// /home — users managed by bootstrapRoot + syncEtcPasswd
|
|
1855
|
+
ensureDir(vfs, "/home");
|
|
770
1856
|
}
|
|
771
1857
|
|
|
772
1858
|
// ── Static rootfs snapshot cache ─────────────────────────────────────────────
|
|
773
|
-
// The static parts of the rootfs (dev, usr, var, bin, tmp, etc, sys, misc)
|
|
774
|
-
// are identical for all shells sharing the same hostname+props.
|
|
775
|
-
// We build them once, serialise to VFSB binary, and clone via decodeVfs()
|
|
776
|
-
// for each new shell — avoiding ~250 JS object allocations per instance.
|
|
777
1859
|
|
|
778
1860
|
const _staticRootfsCache = new Map<string, Buffer>();
|
|
779
1861
|
|
|
@@ -791,11 +1873,10 @@ export function getStaticRootfsSnapshot(
|
|
|
791
1873
|
hostname: string,
|
|
792
1874
|
props: ShellProperties,
|
|
793
1875
|
): Buffer {
|
|
794
|
-
const key
|
|
1876
|
+
const key = _staticCacheKey(hostname, props);
|
|
795
1877
|
const cached = _staticRootfsCache.get(key);
|
|
796
1878
|
if (cached) return cached;
|
|
797
1879
|
|
|
798
|
-
// Build the static subset into a temporary VFS
|
|
799
1880
|
const tmp = new VirtualFileSystem({ mode: "memory" });
|
|
800
1881
|
bootstrapEtc(tmp, hostname, props);
|
|
801
1882
|
bootstrapSys(tmp, hostname, props);
|
|
@@ -812,7 +1893,6 @@ export function getStaticRootfsSnapshot(
|
|
|
812
1893
|
return snapshot;
|
|
813
1894
|
}
|
|
814
1895
|
|
|
815
|
-
|
|
816
1896
|
// ─── main entry point ─────────────────────────────────────────────────────────
|
|
817
1897
|
|
|
818
1898
|
/**
|
|
@@ -834,15 +1914,21 @@ export function bootstrapLinuxRootfs(
|
|
|
834
1914
|
shellStartTime: number,
|
|
835
1915
|
sessions: VirtualActiveSession[] = [],
|
|
836
1916
|
): void {
|
|
837
|
-
// Fast path: clone the cached static rootfs snapshot (VFSB decode ~0.07ms)
|
|
838
|
-
// instead of rebuilding ~250 JS objects from scratch each time.
|
|
839
1917
|
const snapshot = getStaticRootfsSnapshot(hostname, props);
|
|
840
|
-
vfs.
|
|
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
|
+
}
|
|
841
1928
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
syncEtcPasswd(vfs, users); // /etc/passwd|group|shadow
|
|
1929
|
+
bootstrapRoot(vfs);
|
|
1930
|
+
refreshProc(vfs, props, hostname, shellStartTime, sessions);
|
|
1931
|
+
syncEtcPasswd(vfs, users);
|
|
846
1932
|
}
|
|
847
1933
|
|
|
848
1934
|
// ─── optional live engine ─────────────────────────────────────────────────────
|