Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/lib/libnoderawfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ addToLibrary({
return { path, node: { id: st.ino, mode, node_ops: NODERAWFS, path }};
},
createStandardStreams() {
FS.createStream({ nfd: 0, position: 0, path: '/dev/stdin', flags: 0, seekable: false }, 0);
FS.createStream({ nfd: 0, position: 0, path: '/dev/stdin', flags: 0 }, 0);
var paths = [,'/dev/stdout', '/dev/stderr'];
for (var i = 1; i < 3; i++) {
FS.createStream({ nfd: i, position: 0, path: paths[i], flags: {{{ cDefs.O_TRUNC | cDefs.O_CREAT | cDefs.O_WRONLY }}}, seekable: false }, i);
FS.createStream({ nfd: i, position: 0, path: paths[i], flags: {{{ cDefs.O_TRUNC | cDefs.O_CREAT | cDefs.O_WRONLY }}} }, i);
}
},
// generic function for all node creation
Expand Down Expand Up @@ -203,6 +203,7 @@ addToLibrary({
rtn.shared.refcnt++;
if (nodeTTY.isatty(rtn.nfd)) {
rtn.tty = { ops: TTY.default_tty_ops };
rtn.seekable = false;
}
}
return rtn;
Expand Down
3 changes: 3 additions & 0 deletions src/lib/libtty.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ addToLibrary({
if (result === null || result === undefined) break;
bytesRead++;
buffer[offset+i] = result;
// We currently only support canonical mode (ICANON), where
// read(2) returns as soon as a line delimiter is read.
if (result === {{{ charCode('\n') }}}) break;
}
if (bytesRead) {
stream.node.atime = Date.now();
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_ctors1.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 19208,
"a.out.js.gz": 8121,
"a.out.js": 19224,
"a.out.js.gz": 8124,
"a.out.nodebug.wasm": 134735,
"a.out.nodebug.wasm.gz": 51558,
"total": 153943,
"total_gz": 59679,
"total": 153959,
"total_gz": 59682,
"sent": [
"__cxa_throw",
"_abort_js",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_ctors2.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 19185,
"a.out.js.gz": 8104,
"a.out.js": 19201,
"a.out.js.gz": 8107,
"a.out.nodebug.wasm": 134164,
"a.out.nodebug.wasm.gz": 51206,
"total": 153349,
"total_gz": 59310,
"total": 153365,
"total_gz": 59313,
"sent": [
"__cxa_throw",
"_abort_js",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_except.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 22901,
"a.out.js.gz": 9079,
"a.out.js": 22917,
"a.out.js.gz": 9078,
"a.out.nodebug.wasm": 177192,
"a.out.nodebug.wasm.gz": 59082,
"total": 200093,
"total_gz": 68161,
"total": 200109,
"total_gz": 68160,
"sent": [
"__cxa_begin_catch",
"__cxa_end_catch",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_except_wasm.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 19007,
"a.out.js.gz": 8036,
"a.out.js": 19023,
"a.out.js.gz": 8039,
"a.out.nodebug.wasm": 150448,
"a.out.nodebug.wasm.gz": 56601,
"total": 169455,
"total_gz": 64637,
"total": 169471,
"total_gz": 64640,
"sent": [
"_abort_js",
"_tzset_js",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_except_wasm_legacy.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 19085,
"a.out.js.gz": 8060,
"a.out.js": 19101,
"a.out.js.gz": 8065,
"a.out.nodebug.wasm": 148230,
"a.out.nodebug.wasm.gz": 56281,
"total": 167315,
"total_gz": 64341,
"total": 167331,
"total_gz": 64346,
"sent": [
"_abort_js",
"_tzset_js",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_lto.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 18552,
"a.out.js.gz": 7814,
"a.out.js": 18568,
"a.out.js.gz": 7818,
"a.out.nodebug.wasm": 100987,
"a.out.nodebug.wasm.gz": 38221,
"total": 119539,
"total_gz": 46035,
"total": 119555,
"total_gz": 46039,
"sent": [
"a (emscripten_resize_heap)",
"b (_setitimer_js)",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_mangle.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 22951,
"a.out.js.gz": 9099,
"a.out.js": 22967,
"a.out.js.gz": 9098,
"a.out.nodebug.wasm": 243472,
"a.out.nodebug.wasm.gz": 81286,
"total": 266423,
"total_gz": 90385,
"total": 266439,
"total_gz": 90384,
"sent": [
"__cxa_begin_catch",
"__cxa_end_catch",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_cxx_noexcept.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 19208,
"a.out.js.gz": 8121,
"a.out.js": 19224,
"a.out.js.gz": 8124,
"a.out.nodebug.wasm": 136645,
"a.out.nodebug.wasm.gz": 52165,
"total": 155853,
"total_gz": 60286,
"total": 155869,
"total_gz": 60289,
"sent": [
"__cxa_throw",
"_abort_js",
Expand Down
3 changes: 3 additions & 0 deletions test/codesize/test_codesize_file_preload.expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,9 @@ var TTY = {
if (result === null || result === undefined) break;
bytesRead++;
buffer[offset + i] = result;
// We currently only support canonical mode (ICANON), where
// read(2) returns as soon as a line delimiter is read.
if (result === 10) break;
}
if (bytesRead) {
stream.node.atime = Date.now();
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_file_preload.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 22187,
"a.out.js.gz": 9259,
"a.out.js": 22203,
"a.out.js.gz": 9267,
"a.out.nodebug.wasm": 1666,
"a.out.nodebug.wasm.gz": 945,
"total": 23853,
"total_gz": 10204,
"total": 23869,
"total_gz": 10212,
"sent": [
"a (fd_write)"
],
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_files_js_fs.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 17855,
"a.out.js.gz": 7462,
"a.out.js": 17871,
"a.out.js.gz": 7460,
"a.out.nodebug.wasm": 381,
"a.out.nodebug.wasm.gz": 258,
"total": 18236,
"total_gz": 7720,
"total": 18252,
"total_gz": 7718,
"sent": [
"a (fd_write)",
"b (fd_read)",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_hello_dylink.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 26242,
"a.out.js.gz": 11203,
"a.out.js": 26258,
"a.out.js.gz": 11211,
"a.out.nodebug.wasm": 17854,
"a.out.nodebug.wasm.gz": 9021,
"total": 44096,
"total_gz": 20224,
"total": 44112,
"total_gz": 20232,
"sent": [
"__syscall_stat64",
"emscripten_resize_heap",
Expand Down
8 changes: 5 additions & 3 deletions test/codesize/test_codesize_hello_dylink_all.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"a.out.js": 270568,
"a.out.nodebug.wasm": 588318,
"total": 858886,
"a.out.js": 270584,
"a.out.nodebug.wasm": 588573,
"total": 859157,
"sent": [
"IMG_Init",
"IMG_Load",
Expand Down Expand Up @@ -2829,6 +2829,7 @@
"getopt_long",
"getopt_long_only",
"getpagesize",
"getpass",
"getpeername",
"getpgid",
"getpgrp",
Expand Down Expand Up @@ -4671,6 +4672,7 @@
"$getopt_long",
"$getopt_long_only",
"$getpagesize",
"$getpass",
"$getpeername",
"$getpgid",
"$getpriority",
Expand Down
2 changes: 2 additions & 0 deletions test/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ def disabled(note=''):

needs_make = skip_if('tool not available on windows bots', lambda _: WINDOWS)

requires_login_tty = skip_if_simple('requires os.login_tty (python 3.11+)', lambda _: not hasattr(os, 'login_tty'))


def requires_node(func):
assert callable(func)
Expand Down
49 changes: 40 additions & 9 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# found in the LICENSE file.


import errno
import glob
import hashlib
import importlib
Expand All @@ -14,7 +15,6 @@
import platform
import random
import re
import select
import shlex
import shutil
import struct
Expand Down Expand Up @@ -84,6 +84,7 @@
parameterized,
requires_dev_dependency,
requires_jspi,
requires_login_tty,
requires_native_clang,
requires_network,
requires_node,
Expand Down Expand Up @@ -332,23 +333,44 @@ def assertIsWasmDylib(self, filename):
def do_other_test(self, testname, cflags=None, **kwargs):
return self.do_runf_out_file(test_file('other', testname), cflags=cflags, **kwargs)

def run_on_pty(self, cmd):
def run_on_pty(self, cmd, input=None):
master, slave = os.openpty()
output = []
print(cmd)

if input:
assert hasattr(os, 'login_tty'), 'passing input to run_on_pty requires os.login_tty (python 3.11+)'
if isinstance(input, str):
input = input.encode('utf-8')
os.write(master, input)

try:
with env_modify({'TERM': 'xterm-color'}):
proc = subprocess.Popen(cmd, stdout=slave, stderr=slave)
while proc.poll() is None:
r, _w, _x = select.select([master], [], [], 1)
if r:
output.append(os.read(master, 1024))
return (proc.returncode, b''.join(output))
if hasattr(os, 'login_tty'):
proc = subprocess.Popen(cmd, preexec_fn=lambda: os.login_tty(slave), close_fds=True) # ruff: ignore[subprocess-popen-preexec-fn]
else:
proc = subprocess.Popen(cmd, stdout=slave, stderr=slave, close_fds=True)
finally:
os.close(master)
os.close(slave)

try:
while True:
try:
data = os.read(master, 1024)
if not data:
break
output.append(data)
except OSError as e:
# On Linux, once all slave descriptors are closed and all buffered
# output has been consumed, reading from master raises EIO (EOF).
if e.errno == errno.EIO:
break
raise
proc.wait()
return (proc.returncode, b''.join(output))
finally:
os.close(master)

def create_huge_file(self, name, length):
f = open(name, "wb")
f.seek(length - 1)
Expand Down Expand Up @@ -9702,6 +9724,15 @@ def test_noderawfs_readfile_prerun(self):
self.add_pre_run("console.log(FS.readFile('foo', { encoding: 'utf8' }));")
self.do_runf('hello_world.c', 'bar', cflags=['-sNODERAWFS', '-sFORCE_FILESYSTEM'])

@also_with_noderawfs
@no_windows('ptys and select are not available on windows')
@requires_login_tty
def test_getpass(self):
self.run_process([EMCC, test_file('unistd/getpass.c'), '-sFORCE_FILESYSTEM'] + self.get_cflags())
returncode, output = self.run_on_pty(config.NODE_JS + ['a.out.js'], input='secret\n')
self.assertEqual(returncode, 0)
self.assertIn(b'done', output)

@disabled('https://github.com/nodejs/node/issues/18265')
def test_node_code_caching(self):
self.run_process([EMCC, test_file('hello_world.c'),
Expand Down
19 changes: 19 additions & 0 deletions test/unistd/getpass.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2026 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main() {
char* pass = getpass("Password: ");
assert(pass != NULL);
assert(strcmp(pass, "secret") == 0);
puts("done");
return 0;
}
1 change: 1 addition & 0 deletions tools/native_sigs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,7 @@
'getopt': '__pp',
'getopt_long': '__pppp',
'getopt_long_only': '__pppp',
'getpass': 'pp',
'getpeername': '__pp',
'getpwent': 'p',
'getpwnam': 'pp',
Expand Down
2 changes: 1 addition & 1 deletion tools/system_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1341,7 +1341,7 @@ def get_files(self):

libc_files += files_in_path(
path='system/lib/libc/musl/src/legacy',
filenames=['getpagesize.c', 'err.c', 'euidaccess.c'])
filenames=['getpagesize.c', 'err.c', 'euidaccess.c', 'getpass.c'])

libc_files += files_in_path(
path='system/lib/libc/musl/src/linux',
Expand Down
Loading