fakechroot icon indicating copy to clipboard operation
fakechroot copied to clipboard

nodejs can't work

Open zaoqi opened this issue 6 years ago • 4 comments

zaoqi avatar Jun 08 '19 09:06 zaoqi

Probably statx is missing

dex4er avatar Jun 14 '19 13:06 dex4er

Hi @dex4er, can you expand what's missing for nodejs to function?

I was able to run node --version, node -e "console.log(1 + 1)" and even node inspect, so clearly some subset of the node runtime is functional. The problem seems to be some internal loader isn't able to load any scripts. For example, npm (which just a wrapper over node /path/to/npm.js) fails with:

 internal/modules/cjs/loader.js:983
   throw err;
   ^

 Error: Cannot find module '/usr/local/bin/npm'
     at Function.Module._resolveFilename (internal/modules/cjs/loader.js:980:15)
     at Function.Module._load (internal/modules/cjs/loader.js:862:27)
     at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)
     at internal/main/run_main_module.js:18:47 {
   code: 'MODULE_NOT_FOUND',
   requireStack: []
 }

hinshun avatar Apr 23 '20 17:04 hinshun

For others that are reading this, I found out that nodejs uses libuv, which in turns usually uses glibc wrappers for syscalls. However, a recent change from last year made it start using statx, a relatively new syscall. Fakechroot works by shimming glibc calls using LD_PRELOAD so it can't shim the syscall libuv is calling directly.

So if you want to run nodejs in fakechroot you have three options:

  1. If nodejs is dynamically linked to libuv (via --shared-libuv build flag), then you can patch libuv.
  2. If nodejs is statically linked to libuv (the much more common one), then you have to patch libuv in the nodejs repository, and build node yourself. I built one for node v12.6.2 and I pushed the binary to DockerHub openllb/node:fakechroot for my usage.
  3. The proper way is to contribute to libuv. Glibc 2.28 already had statx support, so we just need to update libuv to that, and then bump libuv in nodejs.

Here's a gist to the git patch I applied, as well as stacktraces on how I determined the fix: https://gist.github.com/hinshun/ba1a8a7d32e8e974dcd60cbce64438d6

hinshun avatar Apr 30 '20 05:04 hinshun

I also commented on the libuv issue but, while libuv could work around this limitation in fakechroot, it's IMO better to teach it about syscall() - syscall(__NR_statx) in particular.

Libuv also uses syscall() for other things it can't rely on being available from libc:

$ git grep -n 'syscall[(]' src/
src/unix/core.c:531:  return syscall(SYS_close, fd);
src/unix/linux-syscalls.c:136:  return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags);
src/unix/linux-syscalls.c:149:  return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout);
src/unix/linux-syscalls.c:158:  return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
src/unix/linux-syscalls.c:167:  return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
src/unix/linux-syscalls.c:176:  return syscall(__NR_dup3, oldfd, newfd, flags);
src/unix/linux-syscalls.c:192:  return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
src/unix/linux-syscalls.c:201:  return syscall(__NR_getrandom, buf, buflen, flags);
src/unix/random-sysctl-linux.c:71:    if (syscall(SYS__sysctl, &args) == -1)

(SYS_close is used because glibc's close() is a cancellation point.)

bnoordhuis avatar Apr 30 '20 09:04 bnoordhuis