Skip to content

Commit

Permalink
RemoteProcess: add ExitSignal. (#233)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmds authored Sep 26, 2024
1 parent 03d1a5e commit f9ae42a
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 10 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ class RemoteProcess : IDisposable

// Exit code.
int ExitCode { get; }
// Exit signal (if terminated by a signal).
string? ExitSignal { get; }
}
class SshDataStream : Stream
{
Expand Down
1 change: 1 addition & 0 deletions src/Tmds.Ssh/ISshChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ interface ISshChannel
int SendMaxPacket { get; }
CancellationToken ChannelAborted { get; }
int? ExitCode { get; }
string? ExitSignal { get; }

void Dispose();
void Abort(Exception exception);
Expand Down
31 changes: 23 additions & 8 deletions src/Tmds.Ssh/RemoteProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,19 +202,34 @@ public int ExitCode
{
get
{
if (_readMode == ReadMode.Disposed)
{
ThrowObjectDisposedException();
}
else if (_readMode != ReadMode.Exited)
{
throw new InvalidOperationException("The process has not yet exited.");
}
EnsureExited();

return _channel.ExitCode!.Value;
}
}

public string? ExitSignal
{
get
{
EnsureExited();

return _channel.ExitSignal;
}
}

private void EnsureExited()
{
if (_readMode == ReadMode.Disposed)
{
ThrowObjectDisposedException();
}
else if (_readMode != ReadMode.Exited)
{
throw new InvalidOperationException("The process has not yet exited.");
}
}

public CancellationToken ExecutionAborted
=> _channel.ChannelAborted;

Expand Down
44 changes: 42 additions & 2 deletions src/Tmds.Ssh/SshChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public CancellationToken ChannelAborted
}
}
public int? ExitCode { get; private set; }
public string? ExitSignal { get; private set; }
public int SendMaxPacket { get; private set; }
public int ReceiveMaxPacket => Constants.MaxDataPacketSize;
private int MaxWindowSize => Constants.DefaultWindowSize;
Expand Down Expand Up @@ -527,8 +528,8 @@ boolean core dumped
string error message in ISO-10646 UTF-8 encoding
string language tag [RFC3066]
*/
string exitSignal = reader.ReadUtf8String();
ExitCode = 128; // TODO: assign based on exitSignal.
ExitSignal = reader.ReadUtf8String();
ExitCode = 128 + SignalToInt(ExitSignal);
reader.SkipBoolean();
reader.SkipString();
reader.SkipString();
Expand All @@ -539,6 +540,45 @@ string language tag [RFC3066]
return want_reply;
}

private static int SignalToInt(string signal) =>
signal switch
{
"HUP" => 1,
"INT" => 2,
"QUIT" => 3,
"ILL" => 4,
"TRAP" => 5,
"ABRT" => 6,
"IOT" => 6,
"BUS" => 7,
"FPE" => 8,
"KILL" => 9,
"USR1" => 10,
"SEGV" => 11,
"USR2" => 12,
"PIPE" => 13,
"ALRM" => 14,
"TERM" => 15,
"STKFLT" => 16,
"CHLD" => 17,
"CONT" => 18,
"STOP" => 19,
"TSTP" => 20,
"TTIN" => 21,
"TTOU" => 22,
"URG" => 23,
"XCPU" => 24,
"XFSZ" => 25,
"VTALRM" => 26,
"PROF" => 27,
"WINCH" => 28,
"IO" => 29,
"POLL" => 29,
"PWR" => 30,
"SYS" => 31,
_ => 32,
};

private void ThrowIfDisposed()
{
if (_disposed != 0)
Expand Down
14 changes: 14 additions & 0 deletions test/Tmds.Ssh.Tests/RemoteProcessTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,20 @@ public async Task ExitCode(int exitCode)
Assert.Equal(0, bytesRead);

Assert.Equal(exitCode, process.ExitCode);
Assert.Null(process.ExitSignal);
}

[Theory]
[InlineData("TERM", 128 + 15)]
[InlineData("KILL", 128 + 9)]
public async Task ExitCodeSignal(string signal, int expectedExitCode)
{
using var client = await _sshServer.CreateClientAsync();
using var process = await client.ExecuteAsync($"kill -s {signal} $$");
await process.WaitForExitAsync();

Assert.Equal(signal, process.ExitSignal);
Assert.Equal(expectedExitCode, process.ExitCode);
}

[Fact]
Expand Down

0 comments on commit f9ae42a

Please sign in to comment.