Fix interruption handling in nested shells This change modifies the Shell.sh method to properly handle interruption signals in nested shells by clearing and restoring the current pipe. When a user starts a shell session, then runs the 'sh' command to create a nested shell, and then runs a command like 'ttop' in that nested shell, pressing Ctrl+C now properly interrupts the command. This complements PR #411 which made the Pipe.setCurrentPipe method public to enable this fix. Together, these changes resolve the issue reported in jline/jline3#1143 where interruption exceptions were not working for child sessions. The fix follows the same pattern implemented in the Posix.runShell method, ensuring consistent behavior across different shell creation methods.
diff --git a/gogo/jline/pom.xml b/gogo/jline/pom.xml index 68ddb50..ee5e0ed 100644 --- a/gogo/jline/pom.xml +++ b/gogo/jline/pom.xml
@@ -58,7 +58,7 @@ <dependency> <groupId>org.apache.felix</groupId> <artifactId>org.apache.felix.gogo.runtime</artifactId> - <version>1.1.0</version> + <version>1.1.7-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.felix</groupId>
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java index 9ead00c..2708f24 100644 --- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java +++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Posix.java
@@ -71,6 +71,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.felix.gogo.runtime.Pipe; import org.apache.felix.service.command.Process; import org.apache.felix.gogo.jline.Shell.Context; import org.apache.felix.service.command.CommandProcessor; @@ -811,6 +812,10 @@ private void runShell(CommandSession session, Terminal terminal) { InputStream in = terminal.input(); OutputStream out = terminal.output(); + + // Save the current pipe and clear it before creating a child shell + Pipe currentPipe = Pipe.setCurrentPipe(null); + CommandSession newSession = processor.createSession(in, out, out); newSession.put(Shell.VAR_TERMINAL, terminal); newSession.put(".tmux", session.get(".tmux")); @@ -822,11 +827,26 @@ terminal.close(); } }; + + // Register a signal handler for INT signal to properly propagate interruption + Terminal.SignalHandler prevIntHandler = terminal.handle(Terminal.Signal.INT, signal -> { + // Propagate the interrupt to the current thread + Thread.currentThread().interrupt(); + }); + try { - new Shell(context, processor).gosh(newSession, new String[]{"--login"}); + new Shell(context, processor).gosh(newSession, new String[] {"--login"}); } catch (Exception e) { e.printStackTrace(); } finally { + // Restore the previous signal handler + if (prevIntHandler != null) { + terminal.handle(Terminal.Signal.INT, prevIntHandler); + } + + // Restore the previous pipe + Pipe.setCurrentPipe(currentPipe); + try { terminal.close(); } catch (IOException e) {
diff --git a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java index eaf0901..d3da4b3 100644 --- a/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java +++ b/gogo/jline/src/main/java/org/apache/felix/gogo/jline/Shell.java
@@ -46,6 +46,7 @@ import org.apache.felix.gogo.runtime.Closure; import org.apache.felix.gogo.runtime.CommandProxy; import org.apache.felix.gogo.runtime.CommandSessionImpl; +import org.apache.felix.gogo.runtime.Pipe; import org.apache.felix.service.command.Job; import org.apache.felix.service.command.Job.Status; import org.apache.felix.gogo.runtime.Reflective; @@ -440,6 +441,16 @@ private Object runShell(final CommandSession session, Terminal terminal, LineReader reader) throws InterruptedException { + Pipe currentPipe = Pipe.setCurrentPipe(null); + try { + return doRunShell(session, terminal, reader); + } finally { + Pipe.setCurrentPipe(currentPipe); + } + } + + private Object doRunShell(final CommandSession session, Terminal terminal, + LineReader reader) throws InterruptedException { AtomicBoolean reading = new AtomicBoolean(); session.setJobListener((job, previous, current) -> { if (previous == Status.Background || current == Status.Background @@ -555,7 +566,15 @@ @Descriptor("start a new shell") public Object sh(final CommandSession session, String[] argv) throws Exception { - return gosh(session, argv); + // Save the current pipe and clear it before creating a child shell + // This ensures that interruption signals are properly propagated to the child shell + Pipe currentPipe = Pipe.setCurrentPipe(null); + try { + return gosh(session, argv); + } finally { + // Restore the previous pipe + Pipe.setCurrentPipe(currentPipe); + } } private void shutdown() throws Exception {