@ai-ecoverse/slicc-kernel 1.10.0 → 1.11.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 CHANGED
@@ -183,6 +183,8 @@ Directories are renamed with `FileSystemHandle.move()` where available, else by
183
183
 
184
184
  Every process of the kernel has `/proc/<pid>/` with `cmdline`, `comm`, `stat`, `statm` and `status`, in the formats procps reads, and `/proc/self/` has the same files for the process that reads them. 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`. Pids, parents, process groups, sessions, command lines, terminals, start and boot times are real; CPU times, memory sizes, load and `MemTotal` (from `navigator.deviceMemory`, else 4 GiB) are placeholders. Only Emscripten processes see this `/proc`.
185
185
 
186
+ While OPFS has no `/etc/passwd`, `/etc/group` or `/etc/mtab`, reading them gets per-process ones: root is uid 0 and the realm user, uid 1000, is named after `USER`, or `web_user` (Emscripten's default) without one, so it matches `$USER`, with `HOME` as its home, so `id`, `whoami`, `ls -l` and `ps` show names. Nothing is written to OPFS, and a real file there wins.
187
+
186
188
  ### Metadata
187
189
 
188
190
  OPFS stores names, bytes, sizes and modification times, nothing else. Everything POSIX needs on top of that lives in an IndexedDB sidecar, so it survives reloads and new kernels:
@@ -1916,28 +1916,50 @@ function mountTable() {
1916
1916
  "\n"
1917
1917
  );
1918
1918
  }
1919
- function useMounts(Fs) {
1920
- const { writeFile } = Fs;
1919
+ function accounts(env = {}) {
1920
+ const user = env.USER ?? "web_user";
1921
+ const name = NAME.test(user) && user !== "root" ? user : "user";
1922
+ const home = env.HOME || "/home";
1923
+ return {
1924
+ passwd: `root:x:0:0:root:/root:/bin/sh
1925
+ ${name}:x:1000:1000:${name}:${home}:/bin/bash
1926
+ `,
1927
+ group: `root:x:0:
1928
+ ${name}:x:1000:
1929
+ `
1930
+ };
1931
+ }
1932
+ function useMounts(Fs, env = {}) {
1933
+ const { writeFile, mkdirTree } = Fs;
1921
1934
  if (typeof Fs.open !== "function" || typeof writeFile !== "function") return;
1935
+ const { passwd, group } = accounts(env);
1936
+ const backing = { "/etc/mtab": "/proc/mounts" };
1922
1937
  try {
1923
1938
  writeFile.call(Fs, "/proc/mounts", mountTable());
1924
1939
  } catch {
1925
1940
  return;
1926
1941
  }
1942
+ try {
1943
+ mkdirTree.call(Fs, "/dev/.etc");
1944
+ writeFile.call(Fs, "/dev/.etc/passwd", passwd);
1945
+ writeFile.call(Fs, "/dev/.etc/group", group);
1946
+ backing["/etc/passwd"] = "/dev/.etc/passwd";
1947
+ backing["/etc/group"] = "/dev/.etc/group";
1948
+ } catch {
1949
+ }
1927
1950
  const open = Fs.open.bind(Fs);
1928
1951
  Fs.open = (path, flags, mode) => {
1929
- if (path !== "/etc/mtab" || (flags & (O_ACCMODE | O_CREAT2)) !== 0) {
1930
- return open(path, flags, mode);
1931
- }
1952
+ const instead = backing[path];
1953
+ if (!instead || (flags & (O_ACCMODE | O_CREAT2)) !== 0) return open(path, flags, mode);
1932
1954
  try {
1933
1955
  return open(path, flags, mode);
1934
1956
  } catch (e) {
1935
1957
  if (e?.errno !== wasiErrno("ENOENT")) throw e;
1936
- return open("/proc/mounts", flags, mode);
1958
+ return open(instead, flags, mode);
1937
1959
  }
1938
1960
  };
1939
1961
  }
1940
- var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, EBADF, DIR_MODE, LINK_MODE, O_ACCMODE, O_CREAT2;
1962
+ var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, EBADF, DIR_MODE, LINK_MODE, O_ACCMODE, O_CREAT2, NAME;
1941
1963
  var init_process_fds = __esm({
1942
1964
  "src/process/process-fds.ts"() {
1943
1965
  "use strict";
@@ -1965,6 +1987,7 @@ var init_process_fds = __esm({
1965
1987
  LINK_MODE = 41408;
1966
1988
  O_ACCMODE = 3;
1967
1989
  O_CREAT2 = 64;
1990
+ NAME = /^[a-z_][a-z0-9_-]*$/i;
1968
1991
  }
1969
1992
  });
1970
1993
 
@@ -2960,6 +2983,8 @@ async function runWasmProcess(init, port2, deps = {}) {
2960
2983
  const restartable = () => signals.restartable();
2961
2984
  const streams = new KernelStreams(running.FS, sys, { sigpipe, restartable });
2962
2985
  trackCloseOnExec(running.FS);
2986
+ useMounts(running.FS, init.env);
2987
+ useProcfs(running.FS, sys, init.pid);
2963
2988
  if (init.fork) restoreForkedStreams(running.FS, streams, init.fork.streams ?? []);
2964
2989
  else {
2965
2990
  wireKernelStdio(running.FS, streams);
@@ -2969,8 +2994,6 @@ async function runWasmProcess(init, port2, deps = {}) {
2969
2994
  if (pipefs) streams.usePipes(pipefs);
2970
2995
  streams.useControllingTerminal();
2971
2996
  useDevFd(running.FS);
2972
- useMounts(running.FS);
2973
- useProcfs(running.FS, sys, init.pid);
2974
2997
  ownByRealmUser(running.FS);
2975
2998
  const livePath = (s) => liveNodePath(s.node);
2976
2999
  running.sliccKernel = createProcessKernel({