go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/command.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package resources
     5  
     6  import (
     7  	"errors"
     8  	"io"
     9  	"sync"
    10  
    11  	"go.mondoo.com/cnquery/llx"
    12  	"go.mondoo.com/cnquery/providers-sdk/v1/plugin"
    13  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    14  )
    15  
    16  type mqlCommandInternal struct {
    17  	lock             sync.Mutex
    18  	commandIsRunning bool
    19  }
    20  
    21  func (c *mqlCommand) id() (string, error) {
    22  	return c.Command.Data, c.Command.Error
    23  }
    24  
    25  func (c *mqlCommand) execute(cmd string) error {
    26  	c.lock.Lock()
    27  	if c.commandIsRunning {
    28  		c.lock.Unlock()
    29  		return plugin.NotReady
    30  	}
    31  	c.commandIsRunning = true
    32  	c.lock.Unlock()
    33  
    34  	x, err := c.MqlRuntime.Connection.(shared.Connection).RunCommand(cmd)
    35  	if err != nil {
    36  		c.Exitcode = plugin.TValue[int64]{Error: err, State: plugin.StateIsSet}
    37  		c.Stdout = plugin.TValue[string]{Error: err, State: plugin.StateIsSet}
    38  		c.Stderr = plugin.TValue[string]{Error: err, State: plugin.StateIsSet}
    39  		return err
    40  	}
    41  
    42  	c.Exitcode = plugin.TValue[int64]{Data: int64(x.ExitStatus), State: plugin.StateIsSet}
    43  
    44  	stdout, err := io.ReadAll(x.Stdout)
    45  	c.Stdout = plugin.TValue[string]{Data: string(stdout), Error: err, State: plugin.StateIsSet}
    46  
    47  	stderr, err := io.ReadAll(x.Stderr)
    48  	c.Stderr = plugin.TValue[string]{Data: string(stderr), Error: err, State: plugin.StateIsSet}
    49  
    50  	c.lock.Lock()
    51  	c.commandIsRunning = false
    52  	c.lock.Unlock()
    53  
    54  	return nil
    55  }
    56  
    57  func (c *mqlCommand) stdout(cmd string) (string, error) {
    58  	// note: we ignore the return value because everything is set in execute
    59  	return "", c.execute(cmd)
    60  }
    61  
    62  func (c *mqlCommand) stderr(cmd string) (string, error) {
    63  	// note: we ignore the return value because everything is set in execute
    64  	return "", c.execute(cmd)
    65  }
    66  
    67  func (c *mqlCommand) exitcode(cmd string) (int64, error) {
    68  	// note: we ignore the return value because everything is set in execute
    69  	return 0, c.execute(cmd)
    70  }
    71  
    72  func runCommand(runtime *plugin.Runtime, cmd string) (string, error) {
    73  	o, err := CreateResource(runtime, "command", map[string]*llx.RawData{
    74  		"command": llx.StringData(cmd),
    75  	})
    76  	if err != nil {
    77  		return "", err
    78  	}
    79  
    80  	command := o.(*mqlCommand)
    81  	exit := command.GetExitcode()
    82  	if exit.Error != nil {
    83  		return "", exit.Error
    84  	}
    85  	if exit.Data != 0 {
    86  		err := command.GetStderr()
    87  		if err.Error != nil {
    88  			return "", err.Error
    89  		}
    90  		return "", errors.New(err.Data)
    91  	}
    92  
    93  	out := command.GetStdout()
    94  	if out.Error != nil {
    95  		return "", out.Error
    96  	}
    97  	return out.Data, nil
    98  }