Hi all,
I am running a cli java program inside snap that asks for the terminal length and width.
Everything was great until lately(1-2 months), now when I’m building a new version of the snap and the program ask for the terminal length and width it always returns 0 for both values…
The only change in the snap was adding “base: core18” to the snapcraft.yaml because snapcraft now requires it, and building using --use-lxd or --provider=host --destructive-mode because my vm cpu doesn’t support kvm.
None of the denials seem related. I briefly suspected seccomp, but I’ve checked a simple stty size command in shell of various snaps on core/core18/core20, all seem to work correctly. AFAIK stty uses TCGETSZ and TIOCGWINSZ on stdout/stderr, and the calls are not blocked. I don’t know what mechanism JRE may use, perhaps it’s some thing Java specific.
Can you run snap run --shell <yoursnap>.<yourapp> and then inside the shell run stty size ?
I discovered that the problem is much more wider…
It seems that a lot of “terminal” features like change color of text, auto complete, etc has problems now… only under Snap.
I have created a simple example as @Igor suggested and I payed attention that the infra(jline-terminal) I’ve been using throw a warning only when it’s running under snap.
WARNING: Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)
This warning can explain why I experience lack of special features, such as bold and blinking characters.
Can you try using the standard java (openjre) to see what happens? And if you add desktop, x11 plugs?
How did you build the jar btw? I can’t fully recreate what you have as you use local sources, so if you have a fully reproducible code I could locally compile (also any special instructions you may have), that would help.
WARNING: Creating a dumb terminal
java.lang.IllegalStateException: Unable to create a system terminal
at org.jline.terminal.TerminalBuilder.doBuild(TerminalBuilder.java:219)
at org.jline.terminal.TerminalBuilder.build(TerminalBuilder.java:172)
at App.main(App.java:29)
Suppressed: java.lang.NoClassDefFoundError: com/sun/jna/Platform
at org.jline.terminal.impl.jna.JnaNativePty.current(JnaNativePty.java:39)
at org.jline.terminal.impl.jna.JnaSupportImpl.current(JnaSupportImpl.java:15)
at org.jline.terminal.TerminalBuilder.doBuild(TerminalBuilder.java:260)
... 2 more
Caused by: java.lang.ClassNotFoundException: com.sun.jna.Platform
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
... 5 more
Suppressed: java.lang.UnsupportedOperationException
at org.jline.terminal.impl.jansi.JansiSupportImpl.current(JansiSupportImpl.java:70)
at org.jline.terminal.TerminalBuilder.doBuild(TerminalBuilder.java:270)
... 2 more
Suppressed: java.io.IOException: Not a tty
at org.jline.terminal.impl.ExecPty.current(ExecPty.java:44)
at org.jline.terminal.TerminalBuilder.doBuild(TerminalBuilder.java:279)
... 2 more
Caused by: java.io.IOException: Error executing 'tty': not a tty
at org.jline.utils.ExecHelper.exec(ExecHelper.java:42)
at org.jline.terminal.impl.ExecPty.current(ExecPty.java:41)
... 3 more
Also, when I’m running snap run --shell <SnapName> and run tty command I’m getting “not a tty”.
… and then it tries to list and stat everything in /dev. From the look of it, it is trying to find a device file that has matching stat information to the stdin file descriptor (i.e. fd number 0). It first tries to read the /proc/self/fd/0 symlink and look for a file by the matching name, and then falls back to checking everything in /dev/pts and then /dev.
It fails because the snap runs under its own pseudo-terminal namespace, so the /dev/pts/3 file can’t be found. It then reports “not a tty” even though the TCGETS ioctl succeeded (indicating that the file descriptor is in fact a terminal). The irony is that the ExecPty class doesn’t seem to care what the device file name is: it’s just interested in the error message.
From the look of it, this org.jline.terminal.impl.ExecPty class is part of a fallback code path if it can’t load one of the in-process native code implementations (seems to be “jna” or “jansi”?). Maybe it’d be worth investigating why neither of those are loading? I don’t have enough recent Java experience to be any more specific than that though.