@ai-ecoverse/slicc-kernel 1.114.0 → 1.115.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/README.md +18 -0
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +220 -42
- package/dist/kernel-worker.js.map +4 -4
- package/dist/meta.js.map +2 -2
- package/dist/node-process-worker.js +90 -13
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +220 -42
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +93 -16
- package/dist/process-worker.js.map +3 -3
- package/dist/types/fs/meta.d.ts +1 -0
- package/dist/types/fs/types.d.ts +2 -0
- package/dist/types/kernel/fd-table.d.ts +1 -0
- package/dist/types/kernel/fifo.d.ts +13 -0
- package/dist/types/kernel/host.d.ts +2 -0
- package/dist/types/kernel/process.d.ts +4 -0
- package/dist/types/kernel/protocol.d.ts +2 -0
- package/dist/types/launcher.d.ts +1 -0
- package/dist/types/process/kernel-streams.d.ts +3 -0
- package/dist/types/process/process-fds.d.ts +1 -0
- package/dist/types/process/wasi/wasi-fds.d.ts +3 -0
- package/dist/types/realm/live-vfs-fs.d.ts +1 -0
- package/dist/types/realm/sync-fs-dispatch.d.ts +1 -0
- package/dist/types/realm/sync-fs-wire.d.ts +3 -1
- package/package.json +2 -1
package/dist/node.js
CHANGED
|
@@ -473,8 +473,8 @@ async function access(fs, cred, path, want, options = {}) {
|
|
|
473
473
|
if (await present(fs, walked.path, false)) return { ...walked, denied: walked.path };
|
|
474
474
|
return { ...walked, missing: true };
|
|
475
475
|
}
|
|
476
|
-
function refused(path,
|
|
477
|
-
return fsError(
|
|
476
|
+
function refused(path, errno3 = "EACCES") {
|
|
477
|
+
return fsError(errno3, path);
|
|
478
478
|
}
|
|
479
479
|
|
|
480
480
|
// src/fs/dac.ts
|
|
@@ -534,9 +534,9 @@ var Created = class {
|
|
|
534
534
|
function linked(g, options) {
|
|
535
535
|
return g.links === void 0 ? options : { ...options, links: g.links };
|
|
536
536
|
}
|
|
537
|
-
function deny(g, op, path,
|
|
537
|
+
function deny(g, op, path, errno3 = "EACCES") {
|
|
538
538
|
const tag = g.tag === void 0 ? {} : { tag: g.tag };
|
|
539
|
-
g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno:
|
|
539
|
+
g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno: errno3, ...tag });
|
|
540
540
|
}
|
|
541
541
|
var TTY_MODE = 400;
|
|
542
542
|
function ttyOpenable(g, tty) {
|
|
@@ -1249,7 +1249,7 @@ var WASI_SIGNAL_TO_POSIX = Object.fromEntries(
|
|
|
1249
1249
|
|
|
1250
1250
|
// src/process/wasi-errno.ts
|
|
1251
1251
|
var WASI_ERRNO = {
|
|
1252
|
-
...Object.fromEntries(Object.entries(E).map(([name2,
|
|
1252
|
+
...Object.fromEntries(Object.entries(E).map(([name2, errno3]) => [`E${name2}`, errno3])),
|
|
1253
1253
|
EWOULDBLOCK: E.AGAIN,
|
|
1254
1254
|
ENOTSUP: 138,
|
|
1255
1255
|
EOPNOTSUPP: 138,
|
|
@@ -1489,7 +1489,7 @@ function dialError(e, timedOut, closed) {
|
|
|
1489
1489
|
if (timedOut) return new KernelError("ETIMEDOUT");
|
|
1490
1490
|
if (closed) return new KernelError("ECONNABORTED");
|
|
1491
1491
|
const code = e?.code;
|
|
1492
|
-
const known = DIAL_ERRORS.find((
|
|
1492
|
+
const known = DIAL_ERRORS.find((errno3) => errno3 === code);
|
|
1493
1493
|
return new KernelError(known ?? "EHOSTUNREACH");
|
|
1494
1494
|
}
|
|
1495
1495
|
function isLoopback(host) {
|
|
@@ -4102,6 +4102,7 @@ var S_IFDIR = 16384;
|
|
|
4102
4102
|
var S_IFREG = 32768;
|
|
4103
4103
|
var S_IFLNK = 40960;
|
|
4104
4104
|
var S_IFSOCK = 49152;
|
|
4105
|
+
var S_IFIFO = 4096;
|
|
4105
4106
|
var PERM_MASK = 4095;
|
|
4106
4107
|
var S_ISGID3 = 1024;
|
|
4107
4108
|
var READ_ATTEMPTS = 3;
|
|
@@ -4381,7 +4382,10 @@ var OpfsFs = class {
|
|
|
4381
4382
|
}
|
|
4382
4383
|
async stampNew(path, owner, directory) {
|
|
4383
4384
|
const owned4 = await this.newFields(path, owner, directory);
|
|
4384
|
-
|
|
4385
|
+
if (owner?.socket && owner.fifo) throw new Error("a new node is a socket or a FIFO, not both");
|
|
4386
|
+
const kind = directory ? void 0 : owner?.socket ? "socket" : owner?.fifo ? "fifo" : void 0;
|
|
4387
|
+
const unique = kind === "fifo" ? { ino: inodeOf(`${path}\0${crypto.randomUUID()}`) } : {};
|
|
4388
|
+
const fields = kind ? { ...owned4, ...unique, [kind]: true } : owned4;
|
|
4385
4389
|
if (fields) await this.meta.update(path, (entry) => ({ ...entry, path, ...fields }));
|
|
4386
4390
|
}
|
|
4387
4391
|
guarded = [];
|
|
@@ -4623,7 +4627,7 @@ var OpfsFs = class {
|
|
|
4623
4627
|
}
|
|
4624
4628
|
mode(path, directory, meta) {
|
|
4625
4629
|
const fallback = directory || EXECUTABLE.test(path) ? 493 : 420;
|
|
4626
|
-
const type = directory ? S_IFDIR : meta?.socket ? S_IFSOCK : S_IFREG;
|
|
4630
|
+
const type = directory ? S_IFDIR : meta?.socket ? S_IFSOCK : meta?.fifo ? S_IFIFO : S_IFREG;
|
|
4627
4631
|
return type | (meta?.mode ?? fallback);
|
|
4628
4632
|
}
|
|
4629
4633
|
id = crypto.randomUUID();
|
|
@@ -4724,11 +4728,13 @@ var OpfsFs = class {
|
|
|
4724
4728
|
const kept = meta?.mtimeMs !== void 0 && meta.mtimeFor === modified ? meta.mtimeMs : modified;
|
|
4725
4729
|
const mtime = touched ?? kept;
|
|
4726
4730
|
const socket = !directory && meta?.socket === true;
|
|
4731
|
+
const fifo = !directory && meta?.fifo === true;
|
|
4727
4732
|
return {
|
|
4728
|
-
isFile: !directory && !socket,
|
|
4733
|
+
isFile: !directory && !socket && !fifo,
|
|
4729
4734
|
isDirectory: directory,
|
|
4730
4735
|
isSymbolicLink: false,
|
|
4731
4736
|
...socket ? { isSocket: true } : {},
|
|
4737
|
+
...fifo ? { isFifo: true } : {},
|
|
4732
4738
|
size: file?.size ?? 0,
|
|
4733
4739
|
mode: this.mode(path, directory, meta),
|
|
4734
4740
|
mtime: new Date(mtime),
|
|
@@ -6539,7 +6545,7 @@ function satisfies(version, range2) {
|
|
|
6539
6545
|
}
|
|
6540
6546
|
|
|
6541
6547
|
// src/version.ts
|
|
6542
|
-
var KERNEL_VERSION = true ? "1.
|
|
6548
|
+
var KERNEL_VERSION = true ? "1.115.0" : "0.0.0-dev";
|
|
6543
6549
|
var OS_RELEASE = "6.0.0-slicc";
|
|
6544
6550
|
function procVersion() {
|
|
6545
6551
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9542,6 +9548,139 @@ var TicketBook = class {
|
|
|
9542
9548
|
}
|
|
9543
9549
|
};
|
|
9544
9550
|
|
|
9551
|
+
// src/kernel/fifo.ts
|
|
9552
|
+
function errno(e) {
|
|
9553
|
+
return e instanceof KernelError ? e : new KernelError(e.code ?? "EIO");
|
|
9554
|
+
}
|
|
9555
|
+
var FifoTable = class {
|
|
9556
|
+
fifos = /* @__PURE__ */ new Map();
|
|
9557
|
+
size() {
|
|
9558
|
+
return this.fifos.size;
|
|
9559
|
+
}
|
|
9560
|
+
async open(key, path, access2, nonblock, signal) {
|
|
9561
|
+
const fifo = this.entry(key);
|
|
9562
|
+
if (access2 === "write" && nonblock && fifo.readers === 0) {
|
|
9563
|
+
this.drop(key, fifo);
|
|
9564
|
+
throw new KernelError("ENXIO");
|
|
9565
|
+
}
|
|
9566
|
+
const reads = access2 !== "write";
|
|
9567
|
+
const writes = access2 !== "read";
|
|
9568
|
+
const seen = { readOpens: fifo.readOpens, writeOpens: fifo.writeOpens };
|
|
9569
|
+
if (reads) this.count(fifo, "readers", 1);
|
|
9570
|
+
if (writes) this.count(fifo, "writers", 1);
|
|
9571
|
+
this.notify(fifo);
|
|
9572
|
+
try {
|
|
9573
|
+
if (!nonblock && access2 === "read") {
|
|
9574
|
+
while (fifo.writers === 0 && fifo.writeOpens === seen.writeOpens) {
|
|
9575
|
+
await this.changed(fifo, signal);
|
|
9576
|
+
}
|
|
9577
|
+
}
|
|
9578
|
+
if (!nonblock && access2 === "write") {
|
|
9579
|
+
while (fifo.readers === 0 && fifo.readOpens === seen.readOpens) {
|
|
9580
|
+
await this.changed(fifo, signal);
|
|
9581
|
+
}
|
|
9582
|
+
}
|
|
9583
|
+
} catch (e) {
|
|
9584
|
+
this.release(key, fifo, reads, writes);
|
|
9585
|
+
throw errno(e);
|
|
9586
|
+
}
|
|
9587
|
+
return this.end(key, path, fifo, reads, writes);
|
|
9588
|
+
}
|
|
9589
|
+
entry(key) {
|
|
9590
|
+
let fifo = this.fifos.get(key);
|
|
9591
|
+
if (!fifo) {
|
|
9592
|
+
fifo = {
|
|
9593
|
+
pipe: new KernelPipe(),
|
|
9594
|
+
readers: 0,
|
|
9595
|
+
writers: 0,
|
|
9596
|
+
readOpens: 0,
|
|
9597
|
+
writeOpens: 0,
|
|
9598
|
+
waiters: []
|
|
9599
|
+
};
|
|
9600
|
+
this.fifos.set(key, fifo);
|
|
9601
|
+
}
|
|
9602
|
+
return fifo;
|
|
9603
|
+
}
|
|
9604
|
+
count(fifo, side, by) {
|
|
9605
|
+
fifo[side] += by;
|
|
9606
|
+
if (side === "readers") {
|
|
9607
|
+
if (by > 0) {
|
|
9608
|
+
fifo.readOpens += 1;
|
|
9609
|
+
fifo.pipe.openRead();
|
|
9610
|
+
} else fifo.pipe.closeRead();
|
|
9611
|
+
} else if (by > 0) {
|
|
9612
|
+
fifo.writeOpens += 1;
|
|
9613
|
+
fifo.pipe.openWrite();
|
|
9614
|
+
} else fifo.pipe.closeWrite();
|
|
9615
|
+
}
|
|
9616
|
+
notify(fifo) {
|
|
9617
|
+
const waiters = fifo.waiters;
|
|
9618
|
+
fifo.waiters = [];
|
|
9619
|
+
for (const wake of waiters) wake();
|
|
9620
|
+
}
|
|
9621
|
+
changed(fifo, signal) {
|
|
9622
|
+
if (signal.aborted) return Promise.reject(new KernelError("EINTR"));
|
|
9623
|
+
return new Promise((resolve2, reject) => {
|
|
9624
|
+
const onAbort = () => {
|
|
9625
|
+
fifo.waiters = fifo.waiters.filter((w) => w !== wake);
|
|
9626
|
+
reject(new KernelError("EINTR"));
|
|
9627
|
+
};
|
|
9628
|
+
const wake = () => {
|
|
9629
|
+
signal.removeEventListener("abort", onAbort);
|
|
9630
|
+
resolve2();
|
|
9631
|
+
};
|
|
9632
|
+
fifo.waiters.push(wake);
|
|
9633
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
9634
|
+
});
|
|
9635
|
+
}
|
|
9636
|
+
release(key, fifo, reads, writes) {
|
|
9637
|
+
if (reads) this.count(fifo, "readers", -1);
|
|
9638
|
+
if (writes) this.count(fifo, "writers", -1);
|
|
9639
|
+
this.notify(fifo);
|
|
9640
|
+
this.drop(key, fifo);
|
|
9641
|
+
}
|
|
9642
|
+
drop(key, fifo) {
|
|
9643
|
+
const idle = fifo.readers === 0 && fifo.writers === 0 && fifo.waiters.length === 0;
|
|
9644
|
+
if (idle && this.fifos.get(key) === fifo) this.fifos.delete(key);
|
|
9645
|
+
}
|
|
9646
|
+
end(key, path, fifo, reads, writes) {
|
|
9647
|
+
const { pipe } = fifo;
|
|
9648
|
+
let open = true;
|
|
9649
|
+
return new OpenFile({
|
|
9650
|
+
fifo: path,
|
|
9651
|
+
...reads ? {
|
|
9652
|
+
read: async (max, signal) => {
|
|
9653
|
+
try {
|
|
9654
|
+
return await pipe.read(max, signal);
|
|
9655
|
+
} catch (e) {
|
|
9656
|
+
throw errno(e);
|
|
9657
|
+
}
|
|
9658
|
+
}
|
|
9659
|
+
} : {},
|
|
9660
|
+
...writes ? {
|
|
9661
|
+
write: async (bytes, signal) => {
|
|
9662
|
+
try {
|
|
9663
|
+
return await pipe.write(bytes, signal);
|
|
9664
|
+
} catch (e) {
|
|
9665
|
+
throw errno(e);
|
|
9666
|
+
}
|
|
9667
|
+
}
|
|
9668
|
+
} : {},
|
|
9669
|
+
close: () => {
|
|
9670
|
+
if (!open) return;
|
|
9671
|
+
open = false;
|
|
9672
|
+
this.release(key, fifo, reads, writes);
|
|
9673
|
+
},
|
|
9674
|
+
poll: () => ({
|
|
9675
|
+
readable: reads && pipe.readReady,
|
|
9676
|
+
writable: writes && pipe.writeReady,
|
|
9677
|
+
hangup: reads ? pipe.writersGone : pipe.readersGone
|
|
9678
|
+
}),
|
|
9679
|
+
changed: (signal) => pipe.changed(signal)
|
|
9680
|
+
});
|
|
9681
|
+
}
|
|
9682
|
+
};
|
|
9683
|
+
|
|
9545
9684
|
// src/mount/protocol.ts
|
|
9546
9685
|
var DRIVER_PROTOCOL = [1, 2];
|
|
9547
9686
|
function driverVersionError(theirs) {
|
|
@@ -10402,6 +10541,7 @@ var MountFs = class _MountFs {
|
|
|
10402
10541
|
}
|
|
10403
10542
|
const { mount, rel: rel2 } = found;
|
|
10404
10543
|
this.writable(mount, real);
|
|
10544
|
+
if (owner?.fifo) throw errnoError("EPERM", `${real}: this mount has no FIFOs`);
|
|
10405
10545
|
const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
10406
10546
|
if (mount.maxFile > 0 && bytes.length > mount.maxFile) {
|
|
10407
10547
|
throw errnoError(
|
|
@@ -11007,6 +11147,7 @@ var SYNC_FS_OPS = [
|
|
|
11007
11147
|
"statfs",
|
|
11008
11148
|
"hold",
|
|
11009
11149
|
"create",
|
|
11150
|
+
"mkfifo",
|
|
11010
11151
|
"kept",
|
|
11011
11152
|
"pread",
|
|
11012
11153
|
"pwrite",
|
|
@@ -11039,6 +11180,7 @@ function statJson(s) {
|
|
|
11039
11180
|
isFile: s.isFile,
|
|
11040
11181
|
isSymbolicLink: s.isSymbolicLink,
|
|
11041
11182
|
...s.isSocket ? { isSocket: true } : {},
|
|
11183
|
+
...s.isFifo ? { isFifo: true } : {},
|
|
11042
11184
|
size: s.size,
|
|
11043
11185
|
mode: s.mode,
|
|
11044
11186
|
mtimeMs: s.mtime.getTime(),
|
|
@@ -11188,6 +11330,12 @@ async function run(entry, path, req) {
|
|
|
11188
11330
|
case "symlink":
|
|
11189
11331
|
await fs.symlink(req.arg2 ?? "", path, ownerFor2(entry));
|
|
11190
11332
|
return done;
|
|
11333
|
+
case "mkfifo": {
|
|
11334
|
+
const owner = ownerFor2(entry, req.mode ?? 438) ?? { uid: 0, gid: 0 };
|
|
11335
|
+
await createExclusive(fs, path, { ...owner, fifo: true });
|
|
11336
|
+
entry.fresh?.(path);
|
|
11337
|
+
return done;
|
|
11338
|
+
}
|
|
11191
11339
|
case "create":
|
|
11192
11340
|
await createExclusive(fs, path, ownerFor2(entry, req.mode ?? 438));
|
|
11193
11341
|
if (req.opening) entry.created?.add(path);
|
|
@@ -11266,9 +11414,10 @@ async function guard(g, path, req, cwd) {
|
|
|
11266
11414
|
return { path: await walkSafe(g, path, false) };
|
|
11267
11415
|
}
|
|
11268
11416
|
case "create":
|
|
11417
|
+
case "mkfifo":
|
|
11269
11418
|
case "symlink":
|
|
11270
11419
|
await inParent(g, op, path);
|
|
11271
|
-
return { path: await walkSafe(g, path, op
|
|
11420
|
+
return { path: await walkSafe(g, path, op !== "symlink") };
|
|
11272
11421
|
case "unlink":
|
|
11273
11422
|
case "rmdir": {
|
|
11274
11423
|
await inParent(g, op, path, true);
|
|
@@ -11356,6 +11505,7 @@ async function accessOp(entry, path, req) {
|
|
|
11356
11505
|
var CHANGING = /* @__PURE__ */ new Set([
|
|
11357
11506
|
"mkdir",
|
|
11358
11507
|
"create",
|
|
11508
|
+
"mkfifo",
|
|
11359
11509
|
"symlink",
|
|
11360
11510
|
"unlink",
|
|
11361
11511
|
"rmdir",
|
|
@@ -11550,7 +11700,13 @@ async function guardAndResolve(entry, path, req) {
|
|
|
11550
11700
|
};
|
|
11551
11701
|
}
|
|
11552
11702
|
var REMOVALS = /* @__PURE__ */ new Set(["unlink", "rmdir", "rm"]);
|
|
11553
|
-
var CREATIONS = /* @__PURE__ */ new Set([
|
|
11703
|
+
var CREATIONS = /* @__PURE__ */ new Set([
|
|
11704
|
+
"write",
|
|
11705
|
+
"mkdir",
|
|
11706
|
+
"symlink",
|
|
11707
|
+
"create",
|
|
11708
|
+
"mkfifo"
|
|
11709
|
+
]);
|
|
11554
11710
|
var NAMING = /* @__PURE__ */ new Set(["link", "rename"]);
|
|
11555
11711
|
async function newDevName(entry, path, req) {
|
|
11556
11712
|
const named = NAMING.has(req.op);
|
|
@@ -13297,16 +13453,16 @@ var TOKEN3 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
|
13297
13453
|
var SAFE_VALUE = /^[^\r\n\0]*$/;
|
|
13298
13454
|
var CLOSE_WAIT_MS3 = 5e3;
|
|
13299
13455
|
var MAX_UNREAD = 16 * 1024 * 1024;
|
|
13300
|
-
function
|
|
13456
|
+
function errno2(code, message3) {
|
|
13301
13457
|
return Object.assign(new Error(`${code}: ${message3}`), { code });
|
|
13302
13458
|
}
|
|
13303
13459
|
function requestHead(method, url, headers, extra, first = []) {
|
|
13304
|
-
if (!TOKEN3.test(method)) throw
|
|
13460
|
+
if (!TOKEN3.test(method)) throw errno2("EINVAL", `method ${method}`);
|
|
13305
13461
|
const lines2 = [`${method} ${url.pathname}${url.search} HTTP/1.1`, `host: ${url.host}`];
|
|
13306
13462
|
for (const [name2, value2] of first) lines2.push(`${name2}: ${value2}`);
|
|
13307
13463
|
for (const [name2, value2] of headers) {
|
|
13308
13464
|
if (OWN_HEADERS.has(name2.toLowerCase())) continue;
|
|
13309
|
-
if (!TOKEN3.test(name2) || !SAFE_VALUE.test(value2)) throw
|
|
13465
|
+
if (!TOKEN3.test(name2) || !SAFE_VALUE.test(value2)) throw errno2("EINVAL", `header ${name2}`);
|
|
13310
13466
|
lines2.push(`${name2}: ${value2}`);
|
|
13311
13467
|
}
|
|
13312
13468
|
for (const [name2, value2] of extra) lines2.push(`${name2}: ${value2}`);
|
|
@@ -13317,7 +13473,7 @@ function requestHead(method, url, headers, extra, first = []) {
|
|
|
13317
13473
|
function parseHead(bytes) {
|
|
13318
13474
|
const [statusLine = "", ...lines2] = latin1(bytes).split(/\r?\n/);
|
|
13319
13475
|
const match = /^HTTP\/1\.[01] (\d{3})(?: (.*))?$/.exec(statusLine);
|
|
13320
|
-
if (!match) throw
|
|
13476
|
+
if (!match) throw errno2("EPROTO", `not an HTTP/1.x response: ${statusLine.slice(0, 80)}`);
|
|
13321
13477
|
const headers = [];
|
|
13322
13478
|
for (const line of lines2) {
|
|
13323
13479
|
const colon = line.indexOf(":");
|
|
@@ -13332,9 +13488,9 @@ async function readHead(incoming, signal) {
|
|
|
13332
13488
|
raw = await incoming.head(MAX_HEAD2, signal);
|
|
13333
13489
|
} catch (err) {
|
|
13334
13490
|
if (err instanceof KernelError) throw err;
|
|
13335
|
-
throw
|
|
13491
|
+
throw errno2("EPROTO", "the response head is malformed or too large");
|
|
13336
13492
|
}
|
|
13337
|
-
if (!raw) throw
|
|
13493
|
+
if (!raw) throw errno2("ECONNRESET", "the connection closed before a response");
|
|
13338
13494
|
const head = parseHead(raw);
|
|
13339
13495
|
if (head.status < 100 || head.status >= 200 || head.status === 101) return head;
|
|
13340
13496
|
}
|
|
@@ -13343,20 +13499,20 @@ async function* chunked(incoming, signal) {
|
|
|
13343
13499
|
for (; ; ) {
|
|
13344
13500
|
const line = await incoming.line(4096, signal);
|
|
13345
13501
|
const size = /^([0-9A-Fa-f]{1,12})[ \t]*(;.*)?$/.exec(line);
|
|
13346
|
-
if (!size) throw
|
|
13502
|
+
if (!size) throw errno2("EPROTO", "a malformed chunk size");
|
|
13347
13503
|
const n = Number.parseInt(size[1], 16);
|
|
13348
13504
|
if (n === 0) {
|
|
13349
13505
|
while (await incoming.line(MAX_HEAD2, signal) !== "") ;
|
|
13350
13506
|
return;
|
|
13351
13507
|
}
|
|
13352
13508
|
yield await incoming.exactly(n, signal);
|
|
13353
|
-
if (await incoming.line(2, signal) !== "") throw
|
|
13509
|
+
if (await incoming.line(2, signal) !== "") throw errno2("EPROTO", "a malformed chunk");
|
|
13354
13510
|
}
|
|
13355
13511
|
}
|
|
13356
13512
|
async function* counted(incoming, length2, signal) {
|
|
13357
13513
|
for (let left = length2; left > 0; ) {
|
|
13358
13514
|
const data = await incoming.some(Math.min(left, 64 * 1024), signal);
|
|
13359
|
-
if (data.length === 0) throw
|
|
13515
|
+
if (data.length === 0) throw errno2("EPROTO", "the body ended early");
|
|
13360
13516
|
left -= data.length;
|
|
13361
13517
|
yield data;
|
|
13362
13518
|
}
|
|
@@ -13377,7 +13533,7 @@ function bodyOf(incoming, head, method, signal) {
|
|
|
13377
13533
|
if (lengths.length === 0) return untilClose(incoming, signal);
|
|
13378
13534
|
const length2 = lengths[0]?.trim() ?? "";
|
|
13379
13535
|
if (!/^\d{1,15}$/.test(length2) || lengths.some((l) => l.trim() !== length2)) {
|
|
13380
|
-
throw
|
|
13536
|
+
throw errno2("EPROTO", `a malformed Content-Length: ${lengths.join(", ")}`);
|
|
13381
13537
|
}
|
|
13382
13538
|
return counted(incoming, Number(length2), signal);
|
|
13383
13539
|
}
|
|
@@ -13395,7 +13551,7 @@ var KernelLoopback = class {
|
|
|
13395
13551
|
}
|
|
13396
13552
|
async connect(url, port, signal) {
|
|
13397
13553
|
if (url.protocol === "https:" || url.protocol === "wss:") {
|
|
13398
|
-
throw
|
|
13554
|
+
throw errno2("ENOTSUP", `TLS to the kernel's loopback is not supported: ${url.origin}`);
|
|
13399
13555
|
}
|
|
13400
13556
|
signal.throwIfAborted();
|
|
13401
13557
|
const socket = this.net.socket("inet");
|
|
@@ -13410,7 +13566,7 @@ var KernelLoopback = class {
|
|
|
13410
13566
|
} catch (err) {
|
|
13411
13567
|
socket.close();
|
|
13412
13568
|
const refused2 = err instanceof KernelError && err.code === "ECONNREFUSED";
|
|
13413
|
-
throw refused2 ?
|
|
13569
|
+
throw refused2 ? errno2("ECONNREFUSED", `nothing listens on the kernel's port ${port}`) : err;
|
|
13414
13570
|
}
|
|
13415
13571
|
signal.addEventListener("abort", () => socket.close(), { once: true });
|
|
13416
13572
|
return socket;
|
|
@@ -13456,7 +13612,7 @@ var KernelLoopback = class {
|
|
|
13456
13612
|
const incoming = new Incoming(socket);
|
|
13457
13613
|
const head = await readHead(incoming, req.signal);
|
|
13458
13614
|
if (head.status !== 101) {
|
|
13459
|
-
throw
|
|
13615
|
+
throw errno2(
|
|
13460
13616
|
"EPROTO",
|
|
13461
13617
|
`the server answered the upgrade with ${head.status}${head.statusText ? ` ${head.statusText}` : ""}`
|
|
13462
13618
|
);
|
|
@@ -13464,10 +13620,10 @@ var KernelLoopback = class {
|
|
|
13464
13620
|
const upgraded = fieldTokens(head.headers, "upgrade").includes("websocket") && fieldTokens(head.headers, "connection").includes("upgrade");
|
|
13465
13621
|
const accept2 = fieldValues(head.headers, "sec-websocket-accept")[0];
|
|
13466
13622
|
if (!upgraded || accept2 !== await acceptFor(key)) {
|
|
13467
|
-
throw
|
|
13623
|
+
throw errno2("EPROTO", "the server did not accept the WebSocket key");
|
|
13468
13624
|
}
|
|
13469
13625
|
if (fieldValues(head.headers, "sec-websocket-extensions").length > 0) {
|
|
13470
|
-
throw
|
|
13626
|
+
throw errno2("EPROTO", "the server offered an unsolicited extension");
|
|
13471
13627
|
}
|
|
13472
13628
|
const protocol = fieldValues(head.headers, "sec-websocket-protocol")[0] ?? "";
|
|
13473
13629
|
return new LoopbackWebSocket(socket, incoming, protocol);
|
|
@@ -13485,7 +13641,7 @@ async function* closing(chunks2, socket) {
|
|
|
13485
13641
|
yield* chunks2;
|
|
13486
13642
|
} catch (err) {
|
|
13487
13643
|
if (typeof err?.code === "string") throw err;
|
|
13488
|
-
throw
|
|
13644
|
+
throw errno2("EPROTO", err instanceof Error ? err.message : String(err));
|
|
13489
13645
|
} finally {
|
|
13490
13646
|
socket.close();
|
|
13491
13647
|
}
|
|
@@ -13614,7 +13770,7 @@ var LoopbackWebSocket = class {
|
|
|
13614
13770
|
this.write(clientFrame(OP_CLOSE, payload));
|
|
13615
13771
|
}
|
|
13616
13772
|
send(data) {
|
|
13617
|
-
if (this.sentClose) throw
|
|
13773
|
+
if (this.sentClose) throw errno2("EPIPE", "the websocket is closing");
|
|
13618
13774
|
const text = typeof data === "string";
|
|
13619
13775
|
const payload = text ? new TextEncoder().encode(data) : data;
|
|
13620
13776
|
this.write(clientFrame(text ? OP_TEXT : OP_BINARY, payload));
|
|
@@ -14306,8 +14462,8 @@ function errnoOf(e) {
|
|
|
14306
14462
|
const code = e?.code;
|
|
14307
14463
|
return typeof code === "string" && ERRNO.test(code) ? code : "ECONNREFUSED";
|
|
14308
14464
|
}
|
|
14309
|
-
function fail(
|
|
14310
|
-
return { ok: false, errno:
|
|
14465
|
+
function fail(errno3, text) {
|
|
14466
|
+
return { ok: false, errno: errno3, message: text };
|
|
14311
14467
|
}
|
|
14312
14468
|
var WsHandles = class {
|
|
14313
14469
|
transport;
|
|
@@ -14581,8 +14737,8 @@ var HttpHandles = class {
|
|
|
14581
14737
|
const status = e.status;
|
|
14582
14738
|
if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
|
|
14583
14739
|
const code = codeOf2(e);
|
|
14584
|
-
const
|
|
14585
|
-
return { ok: false, errno:
|
|
14740
|
+
const errno3 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
|
|
14741
|
+
return { ok: false, errno: errno3, message: text };
|
|
14586
14742
|
}
|
|
14587
14743
|
entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
|
|
14588
14744
|
return this.headOf(handle, req.url, {
|
|
@@ -15677,7 +15833,7 @@ var UNREACHABLE = ["EACCES", "ENETUNREACH", "EHOSTUNREACH"];
|
|
|
15677
15833
|
function sendError(e) {
|
|
15678
15834
|
if (e instanceof KernelError) return e;
|
|
15679
15835
|
const code = e?.code;
|
|
15680
|
-
return new KernelError(SEND_ERRORS.find((
|
|
15836
|
+
return new KernelError(SEND_ERRORS.find((errno3) => errno3 === code) ?? "EHOSTUNREACH");
|
|
15681
15837
|
}
|
|
15682
15838
|
function sameAddr(a, b) {
|
|
15683
15839
|
return a.port === b.port && canonicalHost(a.host) === canonicalHost(b.host);
|
|
@@ -15806,7 +15962,7 @@ var KernelDgram = class {
|
|
|
15806
15962
|
}
|
|
15807
15963
|
unreachable(error, from) {
|
|
15808
15964
|
if (!this.peer || !sameAddr(this.peer, from)) return;
|
|
15809
|
-
this.pending = UNREACHABLE.find((
|
|
15965
|
+
this.pending = UNREACHABLE.find((errno3) => errno3 === error) ?? "EHOSTUNREACH";
|
|
15810
15966
|
this.changes.wake();
|
|
15811
15967
|
}
|
|
15812
15968
|
deliver(datagram2) {
|
|
@@ -17138,6 +17294,7 @@ function isWasmSyscall(req) {
|
|
|
17138
17294
|
return typeof op === "string" && SYSCALL_OPS.has(op);
|
|
17139
17295
|
}
|
|
17140
17296
|
var MAX_READ = 1024 * 1024;
|
|
17297
|
+
var O_NONBLOCK = 2048;
|
|
17141
17298
|
var WRITE_ACCESS = 3;
|
|
17142
17299
|
var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
|
|
17143
17300
|
var DEFAULT_UMASK2 = 18;
|
|
@@ -17635,7 +17792,7 @@ var WasmProcess = class {
|
|
|
17635
17792
|
this.options.hasPending?.() ? AbortSignal.abort() : this.cancelSignal(cancelled)
|
|
17636
17793
|
);
|
|
17637
17794
|
}
|
|
17638
|
-
async openVfs(req) {
|
|
17795
|
+
async openVfs(req, cancelled) {
|
|
17639
17796
|
if (inProc(req.path)) return this.openProc(req, req.path);
|
|
17640
17797
|
const device = req.orphan ? void 0 : deviceAt(req.path);
|
|
17641
17798
|
if (device) return this.openDevice(req, device);
|
|
@@ -17646,6 +17803,10 @@ var WasmProcess = class {
|
|
|
17646
17803
|
await refuseReadonly(this.options.fs, req.path, req.flags, req);
|
|
17647
17804
|
if (this.writesAt(req)) await this.options.fs.mayChange?.(req.path, !req.exclusive);
|
|
17648
17805
|
await this.mayOpen(req);
|
|
17806
|
+
if (req.fifo && !req.exclusive) {
|
|
17807
|
+
const opened2 = await this.openFifo(req, cancelled);
|
|
17808
|
+
if (opened2 !== void 0) return opened2;
|
|
17809
|
+
}
|
|
17649
17810
|
const marked = await this.markedPath(req);
|
|
17650
17811
|
await this.sourceOpen(marked === void 0 ? req : { ...req, path: marked });
|
|
17651
17812
|
const fs = marked === void 0 ? this.options.fs : this.options.noLinks;
|
|
@@ -17687,6 +17848,19 @@ var WasmProcess = class {
|
|
|
17687
17848
|
}
|
|
17688
17849
|
return fd;
|
|
17689
17850
|
}
|
|
17851
|
+
async openFifo(req, cancelled) {
|
|
17852
|
+
const fifos = this.options.fifos;
|
|
17853
|
+
const path = await this.nodes.targetKey(req.path);
|
|
17854
|
+
const st = await this.heldFs().stat(path);
|
|
17855
|
+
if (!st.isFifo) return void 0;
|
|
17856
|
+
if (!fifos) throw new KernelError("ENXIO");
|
|
17857
|
+
const access2 = openAccess(req.flags);
|
|
17858
|
+
const nonblock = (req.flags & O_NONBLOCK) !== 0;
|
|
17859
|
+
const blocks = !nonblock && access2 !== "both";
|
|
17860
|
+
const signal = blocks ? this.blockingSignal(cancelled) : cancelled;
|
|
17861
|
+
const end = await fifos.open(`${st.dev ?? 0}:${st.ino}`, path, access2, nonblock, signal);
|
|
17862
|
+
return this.fds.install(end, 3);
|
|
17863
|
+
}
|
|
17690
17864
|
openDevice(req, device) {
|
|
17691
17865
|
if (req.exclusive) throw Object.assign(new Error(req.path), { code: "EEXIST" });
|
|
17692
17866
|
const access2 = req.flags & WRITE_ACCESS;
|
|
@@ -17886,7 +18060,7 @@ var WasmProcess = class {
|
|
|
17886
18060
|
case "fd-poll":
|
|
17887
18061
|
return { ok: true, kind: "json", json: pollFile(this.fds.get(req.fd).file) };
|
|
17888
18062
|
case "fd-open-vfs":
|
|
17889
|
-
return { ok: true, kind: "json", json: await this.openVfs(req) };
|
|
18063
|
+
return { ok: true, kind: "json", json: await this.openVfs(req, cancelled) };
|
|
17890
18064
|
case "fd-info":
|
|
17891
18065
|
return { ok: true, kind: "json", json: this.fdInfo(req.fd) };
|
|
17892
18066
|
case "fd-list":
|
|
@@ -18546,7 +18720,8 @@ function inheritedFds(fds) {
|
|
|
18546
18720
|
...kind === "device" && meta && "device" in meta ? { device: meta } : {},
|
|
18547
18721
|
...flags2 !== void 0 ? { flags: flags2 } : {},
|
|
18548
18722
|
...fds.closesOnExec(fd) ? { cloexec: true } : {},
|
|
18549
|
-
...kind === "stream" ? { desc: descId(open) } : {}
|
|
18723
|
+
...kind === "stream" ? { desc: descId(open) } : {},
|
|
18724
|
+
...open.file.fifo ? { fifo: open.file.fifo } : {}
|
|
18550
18725
|
};
|
|
18551
18726
|
});
|
|
18552
18727
|
}
|
|
@@ -18752,6 +18927,7 @@ function processOptions(opts, header4, hooks, created3) {
|
|
|
18752
18927
|
net: opts.net,
|
|
18753
18928
|
http: opts.http,
|
|
18754
18929
|
locks: opts.locks,
|
|
18930
|
+
fifos: opts.fifos,
|
|
18755
18931
|
...opts.sems ? { sems: opts.sems } : {},
|
|
18756
18932
|
onReap: opts.onReap,
|
|
18757
18933
|
resolver: opts.resolver,
|
|
@@ -20690,9 +20866,9 @@ var HostfsClient = class {
|
|
|
20690
20866
|
throw fsError2("ESTALE", "the folder was granted again, so its open files are gone");
|
|
20691
20867
|
return this.send(path, init, false, true);
|
|
20692
20868
|
}
|
|
20693
|
-
const
|
|
20869
|
+
const errno3 = response.headers.get("X-Hostfs-Errno") ?? "EIO";
|
|
20694
20870
|
const body = await response.json().catch(() => ({}));
|
|
20695
|
-
throw fsError2(
|
|
20871
|
+
throw fsError2(errno3, typeof body.message === "string" ? body.message : errno3);
|
|
20696
20872
|
}
|
|
20697
20873
|
async call(op, body = {}, handle = false) {
|
|
20698
20874
|
const response = await this.send(
|
|
@@ -21849,8 +22025,8 @@ var RULE = new RegExp(
|
|
|
21849
22025
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
21850
22026
|
var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
21851
22027
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
21852
|
-
function failed2(
|
|
21853
|
-
return { error, errno:
|
|
22028
|
+
function failed2(errno3, error) {
|
|
22029
|
+
return { error, errno: errno3 };
|
|
21854
22030
|
}
|
|
21855
22031
|
function unescaped(double) {
|
|
21856
22032
|
return double.replace(/\\(["\\$`])/g, "$1");
|
|
@@ -22507,6 +22683,7 @@ var Launcher = class {
|
|
|
22507
22683
|
sudoer;
|
|
22508
22684
|
jobs = new JobTable();
|
|
22509
22685
|
locks = new LockTable();
|
|
22686
|
+
fifos = new FifoTable();
|
|
22510
22687
|
sems = new SemTable();
|
|
22511
22688
|
settling = new SettlingChildren((pid) => this.jobs.pgidOf(pid));
|
|
22512
22689
|
ptys = new PtyTable(
|
|
@@ -23504,6 +23681,7 @@ var Launcher = class {
|
|
|
23504
23681
|
net: this.net,
|
|
23505
23682
|
http: new HttpHandles(this.transport, pid, this.loopbackFor(pid)),
|
|
23506
23683
|
locks: this.locks,
|
|
23684
|
+
fifos: this.fifos,
|
|
23507
23685
|
sems: this.sems,
|
|
23508
23686
|
resolver: this.resolver,
|
|
23509
23687
|
onReap: (child) => this.reaped(child, pid),
|