@ai-ecoverse/slicc-kernel 1.34.0 → 1.35.1
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 +17 -1
- package/dist/kernel-worker.js +124 -45
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-process-worker.js +246 -19
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +129 -49
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +246 -19
- package/dist/process-worker.js.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -349,7 +349,7 @@ Directories are renamed with `FileSystemHandle.move()` where available, else by
|
|
|
349
349
|
- `@ai-ecoverse/slicc-kernel/driver` exports the types and `fsError`.
|
|
350
350
|
- **Capabilities:** `readonly`, `symlinks`, `chmod`, `ranges`, `maxIo` (the largest read or write per message), `maxFile`, `listingStats`, `linkTimes`, and `attrTtl`/`entryTtl` (in ms, default 1000). `linkTimes` promises that `setattr` with `mtime` on a symlink sets the link's own time. Without it, setting a link's own times (`touch -h`, `utimensat` with `AT_SYMLINK_NOFOLLOW`) fails with `EOPNOTSUPP` and never reaches the target. tmpfs has it; hostfs does not. Setting times through a link follows it in the kernel, so `setattr` gets the target. `ranges` (driver protocol 1.1) promises that a write lands in the file at once, with no copy of the whole file on `open` or `release`, and that `setattr` takes `size`.
|
|
351
351
|
- **Caching:** the kernel caches attributes and listings for those TTLs, and a driver can push `invalidate` for changes made outside.
|
|
352
|
-
- **File contents:** on a mount with `ranges`, as `tmpfs` is, and on the root file system when it is in OPFS (in a browser with sync access handles) or an in-memory root, a program reads and writes a file in 64 KiB pages: reads come from the driver 1 MiB at a time, and changed pages go back in 1 MiB runs once 8 MiB have changed, at `fsync`, and when the file is closed (from the kernel's own descriptors also 250 ms after a write). A file of any size the mount can hold works, with memory to spare for about one more copy of it. In OPFS a write opens a sync access handle for just that write. Elsewhere (`fsa` mounts, `hostfs` with an older proxy, and a root outside OPFS), file contents are read whole when a program opens a file and written back when it closes it.
|
|
352
|
+
- **File contents:** on a mount with `ranges`, as `tmpfs` is, and on the root file system when it is in OPFS (in a browser with sync access handles) or an in-memory root, a program reads and writes a file in 64 KiB pages: reads come from the driver 1 MiB at a time, and changed pages go back in 1 MiB runs once 8 MiB have changed, at `fsync`, and when the file is closed (from the kernel's own descriptors also 250 ms after a write). A file of any size the mount can hold works, with memory to spare for about one more copy of it. In OPFS a write opens a sync access handle for just that write. Elsewhere (`fsa` mounts, `hostfs` with an older proxy, and a root outside OPFS), file contents are read whole when a program opens a file and written back when it closes it. Before a program's next call into the kernel (any wait, read of a pipe or terminal, sleep or spawn), its changed pages also go back, so other processes and the embedder see a write as soon as the writer does anything but compute: a daemon's pidfile, a log another process follows. On a whole-file mount that holds only for files of up to 64 KiB; a larger one goes back at close, fsync and exit, as before. Beyond that, both give close-to-open consistency, as NFS has. A process that ends without closing its files keeps what it wrote: on exit, on a trap, and when a signal kills it. For a killed WASI program, the kernel lets its worker write its changed pages back before `waitpid` reports the death. The only exception is a worker that makes no call into the kernel for 2 seconds after the signal; it is stopped without that write-back.
|
|
353
353
|
- **Rules on a mount:**
|
|
354
354
|
- a rename across mounts is `EXDEV`, so `mv` copies;
|
|
355
355
|
- `df` reports each mount from its driver's `statfs`;
|
|
@@ -421,6 +421,22 @@ An exec'd program takes over the pid of the process it replaces, as on Linux: `g
|
|
|
421
421
|
- **Emscripten:** `Module.sliccKernel.execve(file, argv, env, cwd)` runs `file` as this process's new image on its fds 0, 1 and 2, waits for it, and returns its wait status, or a negative errno when it cannot start. `env` and `cwd` may be `null` for this process's own. An exec shim detects it with `typeof Module.sliccKernel.execve === 'function'` and exits with the status it returns, as `execve` never returns on success. Older shims spawn the program and then call `Module.sliccKernel.execWait(pid)`; that works the same way: a new program asks the kernel for its pid before `main`, and the kernel answers once its parent has made its next call, so an image an older shim execs also reports the pid it replaced (the wait starts once the program is loaded; should the parent make no call within 100 ms after that, the kernel answers anyway, and the image may then report its own pid; `launcher.identities` counts the programs that asked and those answered by that timeout).
|
|
422
422
|
- **WASIX:** `proc_exec` does this by itself.
|
|
423
423
|
|
|
424
|
+
### File modes and the umask
|
|
425
|
+
|
|
426
|
+
Every process has a umask in the kernel, `022` for a process the embedder starts, inherited across fork, spawn and exec and shown in `/proc/<pid>/status` (`Umask:`). The kernel applies it when a program creates a file or directory, whatever its libc does: an Emscripten program's `open` with `O_CREAT`, `mkdir` and `mknod` (so `umask 077; touch f` gives `600` in a child too), and a WASI program's `path_open` with `O_CREAT` and `path_create_directory` (`0666` and `0777` less the umask).
|
|
427
|
+
|
|
428
|
+
WASI and WASIX have no call for file modes, so the kernel adds the import module `slicc_fs`, whose functions return a preview1 errno (kernels without them answer `ENOSYS`):
|
|
429
|
+
|
|
430
|
+
| Import | Does |
|
|
431
|
+
| --- | --- |
|
|
432
|
+
| `fd_chmod(fd, mode)` | `fchmod` on an open file or directory |
|
|
433
|
+
| `path_chmod(dirfd, path, path_len, mode, flags)` | `fchmodat`; with `flags & 1` (`AT_SYMLINK_NOFOLLOW`) a symlink answers `ENOTSUP` and is never followed |
|
|
434
|
+
| `umask(mask, old_out)` | sets the process's umask and writes the previous one |
|
|
435
|
+
| `fd_mode(fd, mode_out)` | the permission bits of an open file or directory |
|
|
436
|
+
| `path_mode(dirfd, path, path_len, flags, mode_out)` | those of a path, of the link itself with `flags & 1` |
|
|
437
|
+
|
|
438
|
+
Lowering a soft resource limit (`ulimit -S -n 64`) still fails with `EPERM` in Emscripten programs: their libc's `setrlimit` is a stub compiled into the program, not a call to the kernel.
|
|
439
|
+
|
|
424
440
|
### `/proc`
|
|
425
441
|
|
|
426
442
|
Every process of the kernel has `/proc/<pid>/` with `cmdline`, `comm`, `stat`, `statm` and `status`, in the formats procps reads, and `/proc/self` is a link to the `/proc/<pid>` of the process that reads it, as on Linux (`readlink /proc/self` is its pid, the one it was exec'd under included). They come from the kernel's process table when they are opened, so a terminal sees the processes of every client; an exec'd program shows under the pid its parent knows. `/proc/uptime`, `/proc/loadavg`, `/proc/stat` and `/proc/meminfo` are there too, and `/proc/mounts`. A process with no parent in the kernel (one a page, a client or the Node entry started) has parent 1, as children of init do, in `getppid()`, `/proc/<pid>/stat` and `ps` alike, and so does a process whose parent has ended, waited for or not (`getppid()` asks the kernel each time; a shell's `$PPID` keeps the value it started with, as on Linux). Pids, parents, process groups, sessions, command lines, terminals, start and boot times are real, and so is each process's memory: the size of its wasm memory (`VSZ` and `RSS` alike, as wasm has no paging), which `/proc/meminfo` counts as used. CPU times, load and `MemTotal` (from `navigator.deviceMemory`, else 4 GiB) are placeholders. Only Emscripten processes see this `/proc`.
|
package/dist/kernel-worker.js
CHANGED
|
@@ -755,6 +755,9 @@ var OpfsFs = class {
|
|
|
755
755
|
ctimeMs: now
|
|
756
756
|
}));
|
|
757
757
|
}
|
|
758
|
+
async realpath(path, follow) {
|
|
759
|
+
return (await this.locate(path, follow)).path;
|
|
760
|
+
}
|
|
758
761
|
async readlink(path) {
|
|
759
762
|
const found = await this.locate(path, false);
|
|
760
763
|
if (found.link) return found.link.link;
|
|
@@ -1144,14 +1147,6 @@ function sinkFile(onData) {
|
|
|
1144
1147
|
}
|
|
1145
1148
|
});
|
|
1146
1149
|
}
|
|
1147
|
-
function nullFile() {
|
|
1148
|
-
return new OpenFile({
|
|
1149
|
-
read: async () => new Uint8Array(0),
|
|
1150
|
-
write: async (bytes) => bytes.length,
|
|
1151
|
-
close: () => {
|
|
1152
|
-
}
|
|
1153
|
-
});
|
|
1154
|
-
}
|
|
1155
1150
|
function written(device, bytes) {
|
|
1156
1151
|
if (device === "full" && bytes.length > 0) throw new KernelError("ENOSPC");
|
|
1157
1152
|
return bytes.length;
|
|
@@ -4795,6 +4790,7 @@ function withCommandDirs(fs, names) {
|
|
|
4795
4790
|
rename: (from, to) => fs.rename(from, to),
|
|
4796
4791
|
symlink: (target, path) => fs.symlink(target, path),
|
|
4797
4792
|
readlink: (path) => fs.readlink(path),
|
|
4793
|
+
...fs.realpath ? { realpath: fs.realpath.bind(fs) } : {},
|
|
4798
4794
|
chmod: (path, mode) => fs.chmod(path, mode),
|
|
4799
4795
|
utimes: (path, atime, mtime) => fs.utimes(path, atime, mtime),
|
|
4800
4796
|
lutimes: (path, atime, mtime) => lutimesOf(fs, path, atime, mtime),
|
|
@@ -5003,7 +4999,7 @@ var ChildTable = class {
|
|
|
5003
4999
|
captured.set(n, chunks);
|
|
5004
5000
|
return sinkFile((bytes) => chunks.push(bytes));
|
|
5005
5001
|
}
|
|
5006
|
-
return
|
|
5002
|
+
return deviceFile("null");
|
|
5007
5003
|
}
|
|
5008
5004
|
async wait(pid, nohang, signal, flags = {}) {
|
|
5009
5005
|
let interrupt;
|
|
@@ -5792,6 +5788,12 @@ var MountFs = class {
|
|
|
5792
5788
|
this.table.forget(found.mount, normalizePath(path));
|
|
5793
5789
|
await found.mount.conn.call({ op: "symlink", target, path: found.rel });
|
|
5794
5790
|
}
|
|
5791
|
+
async realpath(path, follow) {
|
|
5792
|
+
if (this.at(path) || !this.base.realpath) throw errnoError("ENOSYS", path);
|
|
5793
|
+
const real = await this.base.realpath(path, follow);
|
|
5794
|
+
if (this.at(real)) throw errnoError("ENOSYS", path);
|
|
5795
|
+
return real;
|
|
5796
|
+
}
|
|
5795
5797
|
async readlink(path) {
|
|
5796
5798
|
const found = this.at(path);
|
|
5797
5799
|
if (!found) return this.base.readlink(path);
|
|
@@ -7564,9 +7566,21 @@ var VfsNodes = class {
|
|
|
7564
7566
|
}
|
|
7565
7567
|
async entryKey(path) {
|
|
7566
7568
|
const parent = parentOf5(path);
|
|
7567
|
-
const dir = await
|
|
7568
|
-
|
|
7569
|
-
|
|
7569
|
+
const dir = await this.real(parent, true, () => realDir(this.fs, parent));
|
|
7570
|
+
return joinName(dir, path.slice(path.lastIndexOf("/") + 1));
|
|
7571
|
+
}
|
|
7572
|
+
targetKey(path) {
|
|
7573
|
+
return this.real(path, true, () => realTarget(this.fs, path));
|
|
7574
|
+
}
|
|
7575
|
+
async real(path, follow, walk) {
|
|
7576
|
+
if (this.fs.realpath) {
|
|
7577
|
+
try {
|
|
7578
|
+
return await this.fs.realpath(path, follow);
|
|
7579
|
+
} catch (err) {
|
|
7580
|
+
if (errCode(err) === "ELOOP") throw err;
|
|
7581
|
+
}
|
|
7582
|
+
}
|
|
7583
|
+
return walk();
|
|
7570
7584
|
}
|
|
7571
7585
|
createExclusive(path) {
|
|
7572
7586
|
return this.onEntry(path, async () => {
|
|
@@ -7661,10 +7675,9 @@ function parentOf5(path) {
|
|
|
7661
7675
|
async function linkOf(fs, path) {
|
|
7662
7676
|
return fs.readlink?.(path).catch(() => void 0);
|
|
7663
7677
|
}
|
|
7664
|
-
async function realDir(fs, dir) {
|
|
7678
|
+
async function realDir(fs, dir, budget = { hops: 0 }) {
|
|
7665
7679
|
const queue = dir.split("/").filter(Boolean);
|
|
7666
7680
|
let at = "/";
|
|
7667
|
-
let hops = 0;
|
|
7668
7681
|
while (queue.length > 0) {
|
|
7669
7682
|
const part = queue.shift();
|
|
7670
7683
|
if (part === ".") continue;
|
|
@@ -7673,28 +7686,41 @@ async function realDir(fs, dir) {
|
|
|
7673
7686
|
continue;
|
|
7674
7687
|
}
|
|
7675
7688
|
const next = at === "/" ? `/${part}` : `${at}/${part}`;
|
|
7676
|
-
const link2 =
|
|
7689
|
+
const link2 = await linkOf(fs, next);
|
|
7677
7690
|
if (link2 === void 0) {
|
|
7678
7691
|
at = next;
|
|
7679
7692
|
continue;
|
|
7680
7693
|
}
|
|
7681
|
-
hops
|
|
7694
|
+
if (budget.hops >= MAX_LINKS5) throw fsError("ELOOP", dir);
|
|
7695
|
+
budget.hops++;
|
|
7682
7696
|
queue.unshift(...link2.split("/").filter(Boolean));
|
|
7683
7697
|
if (link2.startsWith("/")) at = "/";
|
|
7684
7698
|
}
|
|
7685
7699
|
return at;
|
|
7686
7700
|
}
|
|
7687
|
-
|
|
7688
|
-
|
|
7701
|
+
function errCode(err) {
|
|
7702
|
+
return err?.code;
|
|
7703
|
+
}
|
|
7704
|
+
function joinName(dir, name2) {
|
|
7705
|
+
return dir === "/" ? `/${name2}` : `${dir}/${name2}`;
|
|
7706
|
+
}
|
|
7707
|
+
async function realTarget(fs, path) {
|
|
7708
|
+
const budget = { hops: 0 };
|
|
7709
|
+
let dir = await realDir(fs, parentOf5(path), budget);
|
|
7689
7710
|
let name2 = path.slice(path.lastIndexOf("/") + 1);
|
|
7690
|
-
for (
|
|
7691
|
-
const link2 = await linkOf(fs, dir
|
|
7692
|
-
if (link2 === void 0)
|
|
7693
|
-
|
|
7694
|
-
|
|
7711
|
+
for (; ; ) {
|
|
7712
|
+
const link2 = await linkOf(fs, joinName(dir, name2));
|
|
7713
|
+
if (link2 === void 0) break;
|
|
7714
|
+
if (budget.hops >= MAX_LINKS5) throw fsError("ELOOP", path);
|
|
7715
|
+
budget.hops++;
|
|
7716
|
+
const target = link2.startsWith("/") ? link2 : joinName(dir, link2);
|
|
7717
|
+
dir = await realDir(fs, parentOf5(target), budget);
|
|
7695
7718
|
name2 = target.slice(target.lastIndexOf("/") + 1);
|
|
7696
7719
|
}
|
|
7697
|
-
return dir;
|
|
7720
|
+
return joinName(dir, name2);
|
|
7721
|
+
}
|
|
7722
|
+
async function targetDir(fs, path) {
|
|
7723
|
+
return parentOf5(await realTarget(fs, path).catch(() => path));
|
|
7698
7724
|
}
|
|
7699
7725
|
async function refuseReadonly(fs, path, flags, opts = {}) {
|
|
7700
7726
|
const writes = (flags & O_ACCMODE) !== 0 || opts.truncate === true;
|
|
@@ -7713,13 +7739,14 @@ function keepingOpen(fs, nodes) {
|
|
|
7713
7739
|
return {
|
|
7714
7740
|
...fs,
|
|
7715
7741
|
async rm(path, options) {
|
|
7716
|
-
const at = fs.resolvePath("/", path);
|
|
7742
|
+
const at = await nodes.entryKey(fs.resolvePath("/", path));
|
|
7717
7743
|
await nodes.unlinking(at);
|
|
7718
7744
|
await fs.rm(path, options);
|
|
7719
7745
|
nodes.unlinked(at);
|
|
7720
7746
|
},
|
|
7721
|
-
rename(from, to) {
|
|
7722
|
-
const
|
|
7747
|
+
async rename(from, to) {
|
|
7748
|
+
const a = await nodes.entryKey(fs.resolvePath("/", from));
|
|
7749
|
+
const b = await nodes.entryKey(fs.resolvePath("/", to));
|
|
7723
7750
|
return nodes.onEntry(b, async () => {
|
|
7724
7751
|
await nodes.unlinking(b);
|
|
7725
7752
|
await fs.rename(from, to);
|
|
@@ -7865,10 +7892,12 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
7865
7892
|
"fd-cloexec",
|
|
7866
7893
|
"fd-list",
|
|
7867
7894
|
"proc-alarm",
|
|
7895
|
+
"proc-umask",
|
|
7868
7896
|
"dl-log",
|
|
7869
7897
|
"fd-renumber",
|
|
7870
7898
|
"fd-promote",
|
|
7871
7899
|
"fd-open-tty",
|
|
7900
|
+
"fd-tty-names",
|
|
7872
7901
|
"tty-get",
|
|
7873
7902
|
"tty-set",
|
|
7874
7903
|
"tty-winsz",
|
|
@@ -7902,6 +7931,7 @@ function isWasmSyscall(req) {
|
|
|
7902
7931
|
return typeof op === "string" && SYSCALL_OPS.has(op);
|
|
7903
7932
|
}
|
|
7904
7933
|
var MAX_READ = 1024 * 1024;
|
|
7934
|
+
var DEFAULT_UMASK = 18;
|
|
7905
7935
|
var DYING = { ok: false, errno: "EINTR", message: "the process is being killed" };
|
|
7906
7936
|
var HOSTS_ONLY = new Resolver({ routes: new Routes() });
|
|
7907
7937
|
var WasmProcess = class {
|
|
@@ -7912,6 +7942,7 @@ var WasmProcess = class {
|
|
|
7912
7942
|
inherited = 0;
|
|
7913
7943
|
interrupt = new AbortController();
|
|
7914
7944
|
dying = false;
|
|
7945
|
+
umask = DEFAULT_UMASK;
|
|
7915
7946
|
execChild;
|
|
7916
7947
|
execTermsig;
|
|
7917
7948
|
stopped = 0;
|
|
@@ -7929,6 +7960,7 @@ var WasmProcess = class {
|
|
|
7929
7960
|
this.fds = fds;
|
|
7930
7961
|
this.options = options;
|
|
7931
7962
|
this.inherited = options.ignored ?? 0;
|
|
7963
|
+
this.umask = options.umask ?? DEFAULT_UMASK;
|
|
7932
7964
|
this.children = new ChildTable(fds, options.spawner, options.forker);
|
|
7933
7965
|
this.nodes = options.nodes ?? new VfsNodes(options.fs);
|
|
7934
7966
|
if (!options.nodes) options.openFiles?.add(this.nodes);
|
|
@@ -8001,6 +8033,11 @@ var WasmProcess = class {
|
|
|
8001
8033
|
return result;
|
|
8002
8034
|
}
|
|
8003
8035
|
}
|
|
8036
|
+
setUmask(mask) {
|
|
8037
|
+
const old = this.umask;
|
|
8038
|
+
if (mask !== void 0) this.umask = mask & 511;
|
|
8039
|
+
return old;
|
|
8040
|
+
}
|
|
8004
8041
|
die() {
|
|
8005
8042
|
if (this.dying) return;
|
|
8006
8043
|
this.dying = true;
|
|
@@ -8071,9 +8108,21 @@ var WasmProcess = class {
|
|
|
8071
8108
|
await refuseReadonly(this.options.fs, req.path, req.flags, req);
|
|
8072
8109
|
const fd = this.fds.install(heldFile(), 3);
|
|
8073
8110
|
try {
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8111
|
+
const nodes = this.nodes;
|
|
8112
|
+
const path = req.orphan ? req.path : req.exclusive ? await nodes.entryKey(req.path) : await nodes.targetKey(req.path);
|
|
8113
|
+
const open = { ...req, path };
|
|
8114
|
+
if (req.exclusive) {
|
|
8115
|
+
await nodes.createExclusive(path);
|
|
8116
|
+
this.fds.installAt(fd, this.openVfsFile(open));
|
|
8117
|
+
} else if (req.create) {
|
|
8118
|
+
await nodes.onEntry(path, async () => {
|
|
8119
|
+
this.fds.installAt(fd, this.openVfsFile(open));
|
|
8120
|
+
await this.fds.get(fd).file.stat?.();
|
|
8121
|
+
});
|
|
8122
|
+
} else {
|
|
8123
|
+
this.fds.installAt(fd, this.openVfsFile(open));
|
|
8124
|
+
}
|
|
8125
|
+
if (req.existing && !await present(this.options.fs, path, true)) {
|
|
8077
8126
|
throw new KernelError("ENOENT");
|
|
8078
8127
|
}
|
|
8079
8128
|
} catch (err) {
|
|
@@ -8152,7 +8201,7 @@ var WasmProcess = class {
|
|
|
8152
8201
|
case "fd-reserve":
|
|
8153
8202
|
return { ok: true, kind: "json", json: this.reserve(req.fd, req.min, req.meta) };
|
|
8154
8203
|
case "fd-promote":
|
|
8155
|
-
this.promote(req);
|
|
8204
|
+
await this.promote(req);
|
|
8156
8205
|
return { ok: true, kind: "void" };
|
|
8157
8206
|
case "fd-renumber":
|
|
8158
8207
|
if (req.from !== req.to) {
|
|
@@ -8165,6 +8214,8 @@ var WasmProcess = class {
|
|
|
8165
8214
|
if (!tty) throw new KernelError("ENXIO");
|
|
8166
8215
|
return { ok: true, kind: "json", json: this.fds.install(tty.file(), 3) };
|
|
8167
8216
|
}
|
|
8217
|
+
case "fd-tty-names":
|
|
8218
|
+
return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
|
|
8168
8219
|
case "fd-select": {
|
|
8169
8220
|
const { read, write, timeoutMs } = req;
|
|
8170
8221
|
const signal = this.blockingSignal();
|
|
@@ -8186,10 +8237,14 @@ var WasmProcess = class {
|
|
|
8186
8237
|
async vfsSyscall(req) {
|
|
8187
8238
|
if ("path" in req || "from" in req) {
|
|
8188
8239
|
const nodes = this.nodes;
|
|
8189
|
-
if (req.op === "fd-path-flush")
|
|
8190
|
-
|
|
8191
|
-
else if (req.op === "fd-path-
|
|
8192
|
-
|
|
8240
|
+
if (req.op === "fd-path-flush") {
|
|
8241
|
+
await nodes.flush(await nodes.targetKey(req.path).catch(() => req.path));
|
|
8242
|
+
} else if (req.op === "fd-path-unlinking")
|
|
8243
|
+
await nodes.unlinking(await nodes.entryKey(req.path));
|
|
8244
|
+
else if (req.op === "fd-path-unlinked") nodes.unlinked(await nodes.entryKey(req.path));
|
|
8245
|
+
else if (req.op === "fd-path-renamed") {
|
|
8246
|
+
nodes.renamed(await nodes.entryKey(req.from), await nodes.entryKey(req.to));
|
|
8247
|
+
}
|
|
8193
8248
|
return { ok: true, kind: "void" };
|
|
8194
8249
|
}
|
|
8195
8250
|
const file = this.fds.get(req.fd).file;
|
|
@@ -8210,17 +8265,19 @@ var WasmProcess = class {
|
|
|
8210
8265
|
return { ok: true, kind: "json", json: await file.stat() };
|
|
8211
8266
|
}
|
|
8212
8267
|
}
|
|
8213
|
-
promote(req) {
|
|
8268
|
+
async promote(req) {
|
|
8214
8269
|
if (!this.fds.get(req.fd).file.held) throw new KernelError("EBADF");
|
|
8215
8270
|
if (req.share !== void 0) {
|
|
8216
8271
|
this.fds.dup2(req.share, req.fd);
|
|
8217
8272
|
return;
|
|
8218
8273
|
}
|
|
8219
8274
|
if (req.path === void 0) throw new KernelError("EINVAL");
|
|
8275
|
+
const path = req.orphan ? req.path : await this.nodes.targetKey(req.path);
|
|
8276
|
+
if (!this.fds.get(req.fd).file.held) throw new KernelError("EBADF");
|
|
8220
8277
|
const file = vfsFile(
|
|
8221
8278
|
this.options.fs,
|
|
8222
8279
|
{
|
|
8223
|
-
path
|
|
8280
|
+
path,
|
|
8224
8281
|
flags: req.flags ?? 0,
|
|
8225
8282
|
position: req.position ?? 0,
|
|
8226
8283
|
...req.contents !== void 0 ? { contents: req.contents } : {},
|
|
@@ -8396,6 +8453,8 @@ var WasmProcess = class {
|
|
|
8396
8453
|
case "proc-alarm":
|
|
8397
8454
|
this.setAlarm(req.sig, req.firstMs ?? req.ms, req.repeat ? req.ms : 0, req.timer);
|
|
8398
8455
|
return { ok: true, kind: "void" };
|
|
8456
|
+
case "proc-umask":
|
|
8457
|
+
return { ok: true, kind: "json", json: this.setUmask(req.mask) };
|
|
8399
8458
|
case "dl-log":
|
|
8400
8459
|
if (req.append) this.dlLog.push(req.append);
|
|
8401
8460
|
return { ok: true, kind: "json", json: this.dlLog.slice(req.from) };
|
|
@@ -8545,7 +8604,7 @@ var Dying = class {
|
|
|
8545
8604
|
return [typeof reported === "number" ? reported : CRASHED, void 0];
|
|
8546
8605
|
}
|
|
8547
8606
|
};
|
|
8548
|
-
function processInit(opts, sab) {
|
|
8607
|
+
function processInit(opts, sab, umask) {
|
|
8549
8608
|
const base = {
|
|
8550
8609
|
type: WASM_PROCESS_INIT,
|
|
8551
8610
|
pid: opts.shownPid ?? opts.pid,
|
|
@@ -8554,6 +8613,7 @@ function processInit(opts, sab) {
|
|
|
8554
8613
|
env: opts.env,
|
|
8555
8614
|
cwd: opts.cwd,
|
|
8556
8615
|
sab,
|
|
8616
|
+
umask,
|
|
8557
8617
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {}
|
|
8558
8618
|
};
|
|
8559
8619
|
if (opts.program.abi === "js") {
|
|
@@ -8565,11 +8625,17 @@ function processInit(opts, sab) {
|
|
|
8565
8625
|
...opts.fork ? { fork: opts.fork } : { fds: inheritedFds(opts.fds) }
|
|
8566
8626
|
};
|
|
8567
8627
|
}
|
|
8628
|
+
function inherited(opts) {
|
|
8629
|
+
return {
|
|
8630
|
+
...opts.ignored ? { ignored: opts.ignored } : {},
|
|
8631
|
+
...opts.umask !== void 0 ? { umask: opts.umask } : {}
|
|
8632
|
+
};
|
|
8633
|
+
}
|
|
8568
8634
|
function spawnWasmProcess(opts) {
|
|
8569
8635
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
8570
8636
|
const header2 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
8571
8637
|
const process = new WasmProcess(opts.pid, opts.fds, {
|
|
8572
|
-
...opts
|
|
8638
|
+
...inherited(opts),
|
|
8573
8639
|
...opts.identity ? { identity: opts.identity } : {},
|
|
8574
8640
|
...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
|
|
8575
8641
|
spawner: opts.spawner,
|
|
@@ -8703,7 +8769,7 @@ function spawnWasmProcess(opts) {
|
|
|
8703
8769
|
};
|
|
8704
8770
|
tw.postMessage(tinit);
|
|
8705
8771
|
};
|
|
8706
|
-
const init = processInit(opts, sab);
|
|
8772
|
+
const init = processInit(opts, sab, process.umask);
|
|
8707
8773
|
worker.postMessage(init, opts.fork ? [opts.fork.memory.buffer] : []);
|
|
8708
8774
|
const signal = (sig) => {
|
|
8709
8775
|
if (process.signal(sig) !== "terminate") return;
|
|
@@ -8721,6 +8787,7 @@ function spawnWasmProcess(opts) {
|
|
|
8721
8787
|
onState: (listener) => process.onState(listener),
|
|
8722
8788
|
memory: () => Atomics.load(header2, SAB_I_MEMORY) * 65536,
|
|
8723
8789
|
ignoredSignals: (fork) => process.inheritable(fork),
|
|
8790
|
+
umask: () => process.umask,
|
|
8724
8791
|
writesBack: () => opts.program.abi === "wasi" && !done4
|
|
8725
8792
|
};
|
|
8726
8793
|
}
|
|
@@ -8826,8 +8893,13 @@ var JobTable = class {
|
|
|
8826
8893
|
return id;
|
|
8827
8894
|
}
|
|
8828
8895
|
terminalNamed(name2) {
|
|
8829
|
-
|
|
8830
|
-
|
|
8896
|
+
return this.knownTerminals().find((tty) => tty.name === name2);
|
|
8897
|
+
}
|
|
8898
|
+
terminalNames() {
|
|
8899
|
+
return this.knownTerminals().flatMap((tty) => tty.name ? [tty.name] : []);
|
|
8900
|
+
}
|
|
8901
|
+
knownTerminals() {
|
|
8902
|
+
return [.../* @__PURE__ */ new Set([...this.terminals.values(), ...this.foreground.keys()])];
|
|
8831
8903
|
}
|
|
8832
8904
|
controllingTerminal(pid) {
|
|
8833
8905
|
const member = this.members.get(pid);
|
|
@@ -10461,6 +10533,7 @@ var Launcher = class {
|
|
|
10461
10533
|
this.settling.syscall(pid, call.op);
|
|
10462
10534
|
},
|
|
10463
10535
|
...req.ignored ? { ignored: req.ignored } : {},
|
|
10536
|
+
...req.umask !== void 0 ? { umask: req.umask } : {},
|
|
10464
10537
|
program: req.program,
|
|
10465
10538
|
argv0: req.argv0,
|
|
10466
10539
|
args: req.args,
|
|
@@ -10552,7 +10625,8 @@ var Launcher = class {
|
|
|
10552
10625
|
...described,
|
|
10553
10626
|
started: (this.described.get(root.pid) ?? described).started,
|
|
10554
10627
|
state: this.processes.has(member.pid) ? "S" : "Z",
|
|
10555
|
-
memory: this.processes.get(member.pid)?.memory() ?? 0
|
|
10628
|
+
memory: this.processes.get(member.pid)?.memory() ?? 0,
|
|
10629
|
+
umask: this.umaskOf(member.pid)
|
|
10556
10630
|
});
|
|
10557
10631
|
}
|
|
10558
10632
|
return listed;
|
|
@@ -10574,6 +10648,7 @@ var Launcher = class {
|
|
|
10574
10648
|
report,
|
|
10575
10649
|
ppid,
|
|
10576
10650
|
ignored: this.ignoredBy(ppid),
|
|
10651
|
+
umask: this.umaskOf(ppid),
|
|
10577
10652
|
...exec
|
|
10578
10653
|
});
|
|
10579
10654
|
deciding?.attach();
|
|
@@ -10618,7 +10693,8 @@ var Launcher = class {
|
|
|
10618
10693
|
fds,
|
|
10619
10694
|
ppid,
|
|
10620
10695
|
fork: state,
|
|
10621
|
-
ignored: this.ignoredBy(ppid, true)
|
|
10696
|
+
ignored: this.ignoredBy(ppid, true),
|
|
10697
|
+
umask: this.umaskOf(ppid)
|
|
10622
10698
|
})
|
|
10623
10699
|
);
|
|
10624
10700
|
}
|
|
@@ -10627,6 +10703,9 @@ var Launcher = class {
|
|
|
10627
10703
|
const foreground = () => this.jobs.tcgetpgrp(tty, fallback);
|
|
10628
10704
|
this.settling.deliver(sig, pgid, send, tty.reading ? void 0 : foreground);
|
|
10629
10705
|
}
|
|
10706
|
+
umaskOf(pid) {
|
|
10707
|
+
return this.processes.get(pid)?.umask?.() ?? DEFAULT_UMASK;
|
|
10708
|
+
}
|
|
10630
10709
|
ignoredBy(pid, fork = false) {
|
|
10631
10710
|
return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
|
|
10632
10711
|
}
|
|
@@ -10873,7 +10952,7 @@ var Launcher = class {
|
|
|
10873
10952
|
return { status: NOT_FOUND, stdout: concat5(out), stderr: concat5(err) };
|
|
10874
10953
|
}
|
|
10875
10954
|
const fds = new FdTable();
|
|
10876
|
-
fds.installAt(0, options.stdin ? bytesSource(options.stdin) :
|
|
10955
|
+
fds.installAt(0, options.stdin ? bytesSource(options.stdin) : deviceFile("null"));
|
|
10877
10956
|
fds.installAt(1, sinkFile(stdout));
|
|
10878
10957
|
fds.installAt(2, sinkFile(stderr));
|
|
10879
10958
|
const group = options.pgid !== void 0 ? { pgid: options.pgid } : {};
|