...
1
2
3
4 package devices
5
6 import (
7 "context"
8 "fmt"
9 "io"
10 "net"
11 "strings"
12
13 "github.com/Microsoft/hcsshim/internal/cmd"
14 "github.com/Microsoft/hcsshim/internal/log"
15 "github.com/Microsoft/hcsshim/internal/logfields"
16 "github.com/Microsoft/hcsshim/internal/uvm"
17 "github.com/Microsoft/hcsshim/internal/winapi"
18 "github.com/pkg/errors"
19 "github.com/sirupsen/logrus"
20 )
21
22 const (
23 uvmPnpExePath = "C:\\Windows\\System32\\pnputil.exe"
24 pnputilNoMoreItemsErrorMessage = `driver not ranked higher than existing driver in UVM.
25 if drivers were not previously present in the UVM, this
26 is an expected race and can be ignored.`
27 )
28
29 var noExecOutputErr = errors.New("failed to get any pipe output")
30
31
32
33 func createPnPInstallDriverCommand(driverUVMPath string) []string {
34 dirFormatted := fmt.Sprintf("%s/*.inf", driverUVMPath)
35 args := []string{
36 "cmd",
37 "/c",
38 uvmPnpExePath,
39 "/add-driver",
40 dirFormatted,
41 "/subdirs",
42 "/install",
43 }
44 return args
45 }
46
47
48
49 func execPnPInstallDriver(ctx context.Context, vm *uvm.UtilityVM, driverDir string) error {
50 args := createPnPInstallDriverCommand(driverDir)
51 cmdReq := &cmd.CmdProcessRequest{
52 Args: args,
53 }
54 exitCode, err := cmd.ExecInUvm(ctx, vm, cmdReq)
55 if err != nil && exitCode != winapi.ERROR_NO_MORE_ITEMS {
56 return errors.Wrapf(err, "failed to install driver %s in uvm with exit code %d", driverDir, exitCode)
57 } else if exitCode == winapi.ERROR_NO_MORE_ITEMS {
58
59
60 log.G(ctx).WithFields(logrus.Fields{
61 logfields.UVMID: vm.ID(),
62 "driver": driverDir,
63 "error": pnputilNoMoreItemsErrorMessage,
64 }).Warn("expected version of driver may not have been installed")
65 }
66
67 log.G(ctx).WithField("added drivers", driverDir).Debug("installed drivers")
68 return nil
69 }
70
71
72
73
74
75 func readCsPipeOutput(l net.Listener, errChan chan<- error, result *[]string) {
76 defer close(errChan)
77 c, err := l.Accept()
78 if err != nil {
79 errChan <- errors.Wrapf(err, "failed to accept named pipe")
80 return
81 }
82 bytes, err := io.ReadAll(c)
83 if err != nil {
84 errChan <- err
85 return
86 }
87
88 elementsAsString := strings.TrimSuffix(string(bytes), "\n")
89 elements := strings.Split(elementsAsString, ",")
90 *result = append(*result, elements...)
91
92 if len(*result) == 0 {
93 errChan <- noExecOutputErr
94 return
95 }
96
97 errChan <- nil
98 }
99
100
101
102
103
104 func readAllPipeOutput(l net.Listener, errChan chan<- error, result *string) {
105 defer close(errChan)
106 c, err := l.Accept()
107 if err != nil {
108 errChan <- errors.Wrapf(err, "failed to accept named pipe")
109 return
110 }
111 bytes, err := io.ReadAll(c)
112 if err != nil {
113 errChan <- err
114 return
115 }
116
117 *result = string(bytes)
118
119 if len(*result) == 0 {
120 errChan <- noExecOutputErr
121 return
122 }
123
124 errChan <- nil
125 }
126
View as plain text