1package cmd
2
3import (
4	"context"
5	"errors"
6	"os/exec"
7
8	"github.com/Microsoft/hcsshim/internal/log"
9	"github.com/Microsoft/hcsshim/internal/logfields"
10	"github.com/Microsoft/hcsshim/internal/shimdiag"
11	"github.com/Microsoft/hcsshim/internal/uvm"
12	errorspkg "github.com/pkg/errors"
13)
14
15// ExecInUvm is a helper function used to execute commands specified in `req` inside the given UVM.
16func ExecInUvm(ctx context.Context, vm *uvm.UtilityVM, req *shimdiag.ExecProcessRequest) (int, error) {
17	if len(req.Args) == 0 {
18		return 0, errors.New("missing command")
19	}
20	np, err := NewNpipeIO(ctx, req.Stdin, req.Stdout, req.Stderr, req.Terminal)
21	if err != nil {
22		return 0, err
23	}
24	defer np.Close(ctx)
25	cmd := CommandContext(ctx, vm, req.Args[0], req.Args[1:]...)
26	if req.Workdir != "" {
27		cmd.Spec.Cwd = req.Workdir
28	}
29	if vm.OS() == "windows" {
30		cmd.Spec.User.Username = `NT AUTHORITY\SYSTEM`
31	}
32	cmd.Spec.Terminal = req.Terminal
33	cmd.Stdin = np.Stdin()
34	cmd.Stdout = np.Stdout()
35	cmd.Stderr = np.Stderr()
36	cmd.Log = log.G(ctx).WithField(logfields.UVMID, vm.ID())
37	err = cmd.Run()
38	return cmd.ExitState.ExitCode(), err
39}
40
41// ExecInShimHost is a helper function used to execute commands specified in `req` in the shim's
42// hosting system.
43func ExecInShimHost(ctx context.Context, req *shimdiag.ExecProcessRequest) (int, error) {
44	if len(req.Args) == 0 {
45		return 0, errors.New("missing command")
46	}
47	cmdArgsWithoutName := []string{""}
48	if len(req.Args) > 1 {
49		cmdArgsWithoutName = req.Args[1:]
50	}
51	cmd := exec.Command(req.Args[0], cmdArgsWithoutName...)
52	output, err := cmd.CombinedOutput()
53	if err != nil {
54		if exiterr, ok := err.(*exec.ExitError); ok {
55			return exiterr.ExitCode(), errorspkg.Wrapf(exiterr, "command output: %v", string(output))
56		}
57		return -1, errorspkg.Wrapf(err, "command output: %v", string(output))
58	}
59	return 0, nil
60}
61