From 96e188d7c4837ff1188ab923daeb0a0f4cce31ae Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Wed, 8 Apr 2020 00:24:37 +0200 Subject: [PATCH] zfscmd: fix nil deref in waitPostLogging when command was killed fixes #301 --- zfs/zfscmd/zfscmd_logging.go | 19 ++++++++++++++++--- zfs/zfscmd/zfscmd_platform_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/zfs/zfscmd/zfscmd_logging.go b/zfs/zfscmd/zfscmd_logging.go index 200f0a8..ac637e4 100644 --- a/zfs/zfscmd/zfscmd_logging.go +++ b/zfs/zfscmd/zfscmd_logging.go @@ -1,6 +1,7 @@ package zfscmd import ( + "os/exec" "time" ) @@ -28,10 +29,22 @@ func waitPreLogging(c *Cmd, now time.Time) { } func waitPostLogging(c *Cmd, err error, now time.Time) { + + var total, system, user float64 + + total = c.Runtime().Seconds() + if ee, ok := err.(*exec.ExitError); ok { + system = ee.ProcessState.SystemTime().Seconds() + user = ee.ProcessState.UserTime().Seconds() + } else { + system = -1 + user = -1 + } + log := c.log(). - WithField("total_time_s", c.Runtime().Seconds()). - WithField("systemtime_s", c.cmd.ProcessState.SystemTime().Seconds()). - WithField("usertime_s", c.cmd.ProcessState.UserTime().Seconds()) + WithField("total_time_s", total). + WithField("systemtime_s", system). + WithField("usertime_s", user) if err == nil { log.Info("command exited without error") diff --git a/zfs/zfscmd/zfscmd_platform_test.go b/zfs/zfscmd/zfscmd_platform_test.go index 982e32e..2a34366 100644 --- a/zfs/zfscmd/zfscmd_platform_test.go +++ b/zfs/zfscmd/zfscmd_platform_test.go @@ -1,7 +1,9 @@ package zfscmd import ( + "bufio" "bytes" + "context" "io" "os/exec" "testing" @@ -58,3 +60,30 @@ func TestCmdStderrBehaviorStdoutPipe(t *testing.T) { require.True(t, ok) require.Empty(t, ee.Stderr) // !!!!! probably not what one would expect if we only redirect stdout } + +func TestCmdProcessState(t *testing.T) { + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + cmd := exec.CommandContext(ctx, "bash", "-c", "echo running; sleep 3600") + stdout, err := cmd.StdoutPipe() + require.NoError(t, err) + err = cmd.Start() + require.NoError(t, err) + + r := bufio.NewReader(stdout) + line, err := r.ReadString('\n') + require.NoError(t, err) + require.Equal(t, "running\n", line) + + // we know it's running and sleeping + cancel() + err = cmd.Wait() + t.Logf("wait err %T\n%s", err, err) + require.Error(t, err) + ee, ok := err.(*exec.ExitError) + require.True(t, ok) + require.NotNil(t, ee.ProcessState) + require.Contains(t, ee.Error(), "killed") + +}