vendor: fix containerd/cgroups dependency

Gopkg.lock says it's "dbea6f2bd41658b84b00417ceefa416b979cbf10"
but it is actually "5017d4e9a9cf2d4381db99eacd9baf84b95bfb14".

We need to make sure Gopkg.lock does not lie otherwise `dep ensure`
would really fetch the locked revision and it causes build failure
due to API changes.

Introduced by: 76d9db3e0b (vendor: Add github.com/gogo/protobuf).

While at it, constraint containerd/cgroups to a working revision.

Fixes: #1447

Signed-off-by: Peng Tao <bergwolf@hyper.sh>
This commit is contained in:
Peng Tao
2019-03-29 03:32:00 -07:00
parent 25d21060e3
commit 0e2be42514
146 changed files with 9990 additions and 4751 deletions

5
Gopkg.lock generated
View File

@@ -84,12 +84,11 @@
revision = "3a0bb77429bd3a61596f5e8a3172445844342120" revision = "3a0bb77429bd3a61596f5e8a3172445844342120"
[[projects]] [[projects]]
branch = "master" digest = "1:73f5d6c006826b458d9ab942581ed24486a3b3c69f5b3e6794f8bdfe8e306080"
digest = "1:a6f5d43cbf707438b7d6e071c8574a043be3100071092d4c64f4981ed9641e87"
name = "github.com/containerd/cgroups" name = "github.com/containerd/cgroups"
packages = ["."] packages = ["."]
pruneopts = "NUT" pruneopts = "NUT"
revision = "dbea6f2bd41658b84b00417ceefa416b979cbf10" revision = "5017d4e9a9cf2d4381db99eacd9baf84b95bfb14"
[[projects]] [[projects]]
branch = "master" branch = "master"

View File

@@ -88,5 +88,5 @@
unused-packages = true unused-packages = true
[[constraint]] [[constraint]]
branch = "master" revision = "5017d4e9a9cf2d4381db99eacd9baf84b95bfb14"
name = "github.com/containerd/cgroups" name = "github.com/containerd/cgroups"

View File

@@ -1,14 +1,21 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE The MIT License (MIT)
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> Copyright (c) 2013 TOML authors
Everyone is permitted to copy and distribute verbatim or modified Permission is hereby granted, free of charge, to any person obtaining a copy
copies of this license document, and changing it is allowed as long of this software and associated documentation files (the "Software"), to deal
as the name is changed. in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE The above copyright notice and this permission notice shall be included in
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION all copies or substantial portions of the Software.
0. You just DO WHAT THE FUCK YOU WANT TO.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,14 +1,21 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE The MIT License (MIT)
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> Copyright (c) 2013 TOML authors
Everyone is permitted to copy and distribute verbatim or modified Permission is hereby granted, free of charge, to any person obtaining a copy
copies of this license document, and changing it is allowed as long of this software and associated documentation files (the "Software"), to deal
as the name is changed. in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE The above copyright notice and this permission notice shall be included in
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION all copies or substantial portions of the Software.
0. You just DO WHAT THE FUCK YOU WANT TO.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,14 +1,21 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE The MIT License (MIT)
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> Copyright (c) 2013 TOML authors
Everyone is permitted to copy and distribute verbatim or modified Permission is hereby granted, free of charge, to any person obtaining a copy
copies of this license document, and changing it is allowed as long of this software and associated documentation files (the "Software"), to deal
as the name is changed. in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE The above copyright notice and this permission notice shall be included in
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION all copies or substantial portions of the Software.
0. You just DO WHAT THE FUCK YOU WANT TO.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,14 +1,21 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE The MIT License (MIT)
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> Copyright (c) 2013 TOML authors
Everyone is permitted to copy and distribute verbatim or modified Permission is hereby granted, free of charge, to any person obtaining a copy
copies of this license document, and changing it is allowed as long of this software and associated documentation files (the "Software"), to deal
as the name is changed. in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE The above copyright notice and this permission notice shall be included in
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION all copies or substantial portions of the Software.
0. You just DO WHAT THE FUCK YOU WANT TO.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -775,7 +775,7 @@ func lexDatetime(lx *lexer) stateFn {
return lexDatetime return lexDatetime
} }
switch r { switch r {
case '-', 'T', ':', '.', 'Z': case '-', 'T', ':', '.', 'Z', '+':
return lexDatetime return lexDatetime
} }

View File

@@ -37,8 +37,8 @@ func GetPolicyListByID(policyListID string) (*PolicyList, error) {
} }
// AddLoadBalancer policy list for the specified endpoints // AddLoadBalancer policy list for the specified endpoints
func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, isDSR bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) { func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
return hns.AddLoadBalancer(endpoints, isILB, isDSR, sourceVIP, vip, protocol, internalPort, externalPort) return hns.AddLoadBalancer(endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort)
} }
// AddRoute adds route policy list for the specified endpoints // AddRoute adds route policy list for the specified endpoints

View File

@@ -1,6 +1,8 @@
package guestrequest package guestrequest
import "github.com/Microsoft/hcsshim/internal/schema2" import (
"github.com/Microsoft/hcsshim/internal/schema2"
)
// Arguably, many of these (at least CombinedLayers) should have been generated // Arguably, many of these (at least CombinedLayers) should have been generated
// by swagger. // by swagger.
@@ -47,6 +49,19 @@ type LCOWMappedVPMemDevice struct {
MountPath string `json:"MountPath,omitempty"` // /tmp/pN MountPath string `json:"MountPath,omitempty"` // /tmp/pN
} }
type LCOWNetworkAdapter struct {
NamespaceID string `json:",omitempty"`
ID string `json:",omitempty"`
MacAddress string `json:",omitempty"`
IPAddress string `json:",omitempty"`
PrefixLength uint8 `json:",omitempty"`
GatewayAddress string `json:",omitempty"`
DNSSuffix string `json:",omitempty"`
DNSServerList string `json:",omitempty"`
EnableLowMetric bool `json:",omitempty"`
EncapOverhead uint16 `json:",omitempty"`
}
type ResourceType string type ResourceType string
const ( const (

View File

@@ -5,6 +5,7 @@ import (
"syscall" "syscall"
"github.com/Microsoft/hcsshim/internal/interop" "github.com/Microsoft/hcsshim/internal/interop"
"github.com/sirupsen/logrus"
) )
var ( var (
@@ -15,11 +16,20 @@ var (
notificationWatcherCallback = syscall.NewCallback(notificationWatcher) notificationWatcherCallback = syscall.NewCallback(notificationWatcher)
// Notifications for HCS_SYSTEM handles // Notifications for HCS_SYSTEM handles
hcsNotificationSystemExited hcsNotification = 0x00000001 hcsNotificationSystemExited hcsNotification = 0x00000001
hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002 hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002
hcsNotificationSystemStartCompleted hcsNotification = 0x00000003 hcsNotificationSystemStartCompleted hcsNotification = 0x00000003
hcsNotificationSystemPauseCompleted hcsNotification = 0x00000004 hcsNotificationSystemPauseCompleted hcsNotification = 0x00000004
hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005 hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005
hcsNotificationSystemCrashReport hcsNotification = 0x00000006
hcsNotificationSystemSiloJobCreated hcsNotification = 0x00000007
hcsNotificationSystemSaveCompleted hcsNotification = 0x00000008
hcsNotificationSystemRdpEnhancedModeStateChanged hcsNotification = 0x00000009
hcsNotificationSystemShutdownFailed hcsNotification = 0x0000000A
hcsNotificationSystemGetPropertiesCompleted hcsNotification = 0x0000000B
hcsNotificationSystemModifyCompleted hcsNotification = 0x0000000C
hcsNotificationSystemCrashInitiated hcsNotification = 0x0000000D
hcsNotificationSystemGuestConnectionClosed hcsNotification = 0x0000000E
// Notifications for HCS_PROCESS handles // Notifications for HCS_PROCESS handles
hcsNotificationProcessExited hcsNotification = 0x00010000 hcsNotificationProcessExited hcsNotification = 0x00010000
@@ -49,16 +59,23 @@ func newChannels() notificationChannels {
channels[hcsNotificationSystemResumeCompleted] = make(notificationChannel, 1) channels[hcsNotificationSystemResumeCompleted] = make(notificationChannel, 1)
channels[hcsNotificationProcessExited] = make(notificationChannel, 1) channels[hcsNotificationProcessExited] = make(notificationChannel, 1)
channels[hcsNotificationServiceDisconnect] = make(notificationChannel, 1) channels[hcsNotificationServiceDisconnect] = make(notificationChannel, 1)
channels[hcsNotificationSystemCrashReport] = make(notificationChannel, 1)
channels[hcsNotificationSystemSiloJobCreated] = make(notificationChannel, 1)
channels[hcsNotificationSystemSaveCompleted] = make(notificationChannel, 1)
channels[hcsNotificationSystemRdpEnhancedModeStateChanged] = make(notificationChannel, 1)
channels[hcsNotificationSystemShutdownFailed] = make(notificationChannel, 1)
channels[hcsNotificationSystemGetPropertiesCompleted] = make(notificationChannel, 1)
channels[hcsNotificationSystemModifyCompleted] = make(notificationChannel, 1)
channels[hcsNotificationSystemCrashInitiated] = make(notificationChannel, 1)
channels[hcsNotificationSystemGuestConnectionClosed] = make(notificationChannel, 1)
return channels return channels
} }
func closeChannels(channels notificationChannels) { func closeChannels(channels notificationChannels) {
close(channels[hcsNotificationSystemExited]) for _, c := range channels {
close(channels[hcsNotificationSystemCreateCompleted]) close(c)
close(channels[hcsNotificationSystemStartCompleted]) }
close(channels[hcsNotificationSystemPauseCompleted])
close(channels[hcsNotificationSystemResumeCompleted])
close(channels[hcsNotificationProcessExited])
close(channels[hcsNotificationServiceDisconnect])
} }
func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr { func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr {
@@ -75,7 +92,13 @@ func notificationWatcher(notificationType hcsNotification, callbackNumber uintpt
return 0 return 0
} }
context.channels[notificationType] <- result if channel, ok := context.channels[notificationType]; ok {
channel <- result
} else {
logrus.WithFields(logrus.Fields{
"notification-type": notificationType,
}).Warn("Received a callback of an unsupported type")
}
return 0 return 0
} }

View File

@@ -7,6 +7,7 @@ import (
"syscall" "syscall"
"github.com/Microsoft/hcsshim/internal/interop" "github.com/Microsoft/hcsshim/internal/interop"
"github.com/Microsoft/hcsshim/internal/logfields"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@@ -72,6 +73,9 @@ var (
// ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message // ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
ErrVmcomputeUnknownMessage = syscall.Errno(0xc037010b) ErrVmcomputeUnknownMessage = syscall.Errno(0xc037010b)
// ErrVmcomputeUnexpectedExit is an error encountered when the compute system terminates unexpectedly
ErrVmcomputeUnexpectedExit = syscall.Errno(0xC0370106)
// ErrNotSupported is an error encountered when hcs doesn't support the request // ErrNotSupported is an error encountered when hcs doesn't support the request
ErrPlatformNotSupported = errors.New("unsupported platform request") ErrPlatformNotSupported = errors.New("unsupported platform request")
) )
@@ -116,10 +120,14 @@ func (ev *ErrorEvent) String() string {
func processHcsResult(resultp *uint16) []ErrorEvent { func processHcsResult(resultp *uint16) []ErrorEvent {
if resultp != nil { if resultp != nil {
resultj := interop.ConvertAndFreeCoTaskMemString(resultp) resultj := interop.ConvertAndFreeCoTaskMemString(resultp)
logrus.Debugf("Result: %s", resultj) logrus.WithField(logfields.JSON, resultj).
Debug("HCS Result")
result := &hcsResult{} result := &hcsResult{}
if err := json.Unmarshal([]byte(resultj), result); err != nil { if err := json.Unmarshal([]byte(resultj), result); err != nil {
logrus.Warnf("Could not unmarshal HCS result %s: %s", resultj, err) logrus.WithFields(logrus.Fields{
logfields.JSON: resultj,
logrus.ErrorKey: err,
}).Warning("Could not unmarshal HCS result")
return nil return nil
} }
return result.ErrorEvents return result.ErrorEvents

View File

@@ -0,0 +1,20 @@
package hcs
import "github.com/sirupsen/logrus"
func logOperationBegin(ctx logrus.Fields, msg string) {
logrus.WithFields(ctx).Debug(msg)
}
func logOperationEnd(ctx logrus.Fields, msg string, err error) {
// Copy the log and fields first.
log := logrus.WithFields(ctx)
if err == nil {
log.Debug(msg)
} else {
// Edit only the copied field data to avoid race conditions on the
// write.
log.Data[logrus.ErrorKey] = err
log.Error(msg)
}
}

View File

@@ -2,7 +2,6 @@ package hcs
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"sync" "sync"
"syscall" "syscall"
@@ -10,6 +9,7 @@ import (
"github.com/Microsoft/hcsshim/internal/guestrequest" "github.com/Microsoft/hcsshim/internal/guestrequest"
"github.com/Microsoft/hcsshim/internal/interop" "github.com/Microsoft/hcsshim/internal/interop"
"github.com/Microsoft/hcsshim/internal/logfields"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@@ -21,6 +21,20 @@ type Process struct {
system *System system *System
cachedPipes *cachedPipes cachedPipes *cachedPipes
callbackNumber uintptr callbackNumber uintptr
logctx logrus.Fields
}
func newProcess(process hcsProcess, processID int, computeSystem *System) *Process {
return &Process{
handle: process,
processID: processID,
system: computeSystem,
logctx: logrus.Fields{
logfields.ContainerID: computeSystem.ID(),
logfields.ProcessID: processID,
},
}
} }
type cachedPipes struct { type cachedPipes struct {
@@ -72,13 +86,34 @@ func (process *Process) SystemID() string {
return process.system.ID() return process.system.ID()
} }
func (process *Process) logOperationBegin(operation string) {
logOperationBegin(
process.logctx,
operation+" - Begin Operation")
}
func (process *Process) logOperationEnd(operation string, err error) {
var result string
if err == nil {
result = "Success"
} else {
result = "Error"
}
logOperationEnd(
process.logctx,
operation+" - End Operation - "+result,
err)
}
// Signal signals the process with `options`. // Signal signals the process with `options`.
func (process *Process) Signal(options guestrequest.SignalProcessOptions) error { func (process *Process) Signal(options guestrequest.SignalProcessOptions) (err error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "Signal"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::Signal"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(operation, err) }()
if process.handle == 0 { if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil) return makeProcessError(process, operation, ErrAlreadyClosed, nil)
@@ -92,83 +127,79 @@ func (process *Process) Signal(options guestrequest.SignalProcessOptions) error
optionsStr := string(optionsb) optionsStr := string(optionsb)
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(process.logctx, func() {
go syscallWatcher(fmt.Sprintf("SignalProcess %s: %d", process.SystemID(), process.Pid()), &completed) err = hcsSignalProcess(process.handle, optionsStr, &resultp)
err = hcsSignalProcess(process.handle, optionsStr, &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return makeProcessError(process, operation, err, events) return makeProcessError(process, operation, err, events)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
// Kill signals the process to terminate but does not wait for it to finish terminating. // Kill signals the process to terminate but does not wait for it to finish terminating.
func (process *Process) Kill() error { func (process *Process) Kill() (err error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "Kill"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::Kill"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(operation, err) }()
if process.handle == 0 { if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil) return makeProcessError(process, operation, ErrAlreadyClosed, nil)
} }
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(process.logctx, func() {
go syscallWatcher(fmt.Sprintf("TerminateProcess %s: %d", process.SystemID(), process.Pid()), &completed) err = hcsTerminateProcess(process.handle, &resultp)
err := hcsTerminateProcess(process.handle, &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return makeProcessError(process, operation, err, events) return makeProcessError(process, operation, err, events)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
// Wait waits for the process to exit. // Wait waits for the process to exit.
func (process *Process) Wait() error { func (process *Process) Wait() (err error) {
operation := "Wait" operation := "hcsshim::Process::Wait"
title := "hcsshim::Process::" + operation process.logOperationBegin(operation)
logrus.Debugf(title+" processid=%d", process.processID) defer func() { process.logOperationEnd(operation, err) }()
err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil) err = waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil)
if err != nil { if err != nil {
return makeProcessError(process, operation, err, nil) return makeProcessError(process, operation, err, nil)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
// WaitTimeout waits for the process to exit or the duration to elapse. It returns // WaitTimeout waits for the process to exit or the duration to elapse. It returns
// false if timeout occurs. // false if timeout occurs.
func (process *Process) WaitTimeout(timeout time.Duration) error { func (process *Process) WaitTimeout(timeout time.Duration) (err error) {
operation := "WaitTimeout" operation := "hcssshim::Process::WaitTimeout"
title := "hcsshim::Process::" + operation process.logOperationBegin(operation)
logrus.Debugf(title+" processid=%d", process.processID) defer func() { process.logOperationEnd(operation, err) }()
err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout) err = waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout)
if err != nil { if err != nil {
return makeProcessError(process, operation, err, nil) return makeProcessError(process, operation, err, nil)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
// ResizeConsole resizes the console of the process. // ResizeConsole resizes the console of the process.
func (process *Process) ResizeConsole(width, height uint16) error { func (process *Process) ResizeConsole(width, height uint16) (err error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "ResizeConsole"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::ResizeConsole"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(operation, err) }()
if process.handle == 0 { if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil) return makeProcessError(process, operation, ErrAlreadyClosed, nil)
@@ -196,16 +227,16 @@ func (process *Process) ResizeConsole(width, height uint16) error {
return makeProcessError(process, operation, err, events) return makeProcessError(process, operation, err, events)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
func (process *Process) Properties() (*ProcessStatus, error) { func (process *Process) Properties() (_ *ProcessStatus, err error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "Properties"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::Properties"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(operation, err) }()
if process.handle == 0 { if process.handle == 0 {
return nil, makeProcessError(process, operation, ErrAlreadyClosed, nil) return nil, makeProcessError(process, operation, ErrAlreadyClosed, nil)
@@ -215,10 +246,9 @@ func (process *Process) Properties() (*ProcessStatus, error) {
resultp *uint16 resultp *uint16
propertiesp *uint16 propertiesp *uint16
) )
completed := false syscallWatcher(process.logctx, func() {
go syscallWatcher(fmt.Sprintf("GetProcessProperties %s: %d", process.SystemID(), process.Pid()), &completed) err = hcsGetProcessProperties(process.handle, &propertiesp, &resultp)
err := hcsGetProcessProperties(process.handle, &propertiesp, &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, makeProcessError(process, operation, err, events) return nil, makeProcessError(process, operation, err, events)
@@ -234,14 +264,16 @@ func (process *Process) Properties() (*ProcessStatus, error) {
return nil, makeProcessError(process, operation, err, nil) return nil, makeProcessError(process, operation, err, nil)
} }
logrus.Debugf(title+" succeeded processid=%d, properties=%s", process.processID, propertiesRaw)
return properties, nil return properties, nil
} }
// ExitCode returns the exit code of the process. The process must have // ExitCode returns the exit code of the process. The process must have
// already terminated. // already terminated.
func (process *Process) ExitCode() (int, error) { func (process *Process) ExitCode() (_ int, err error) {
operation := "ExitCode" operation := "hcsshim::Process::ExitCode"
process.logOperationBegin(operation)
defer func() { process.logOperationEnd(operation, err) }()
properties, err := process.Properties() properties, err := process.Properties()
if err != nil { if err != nil {
return 0, makeProcessError(process, operation, err, nil) return 0, makeProcessError(process, operation, err, nil)
@@ -261,12 +293,13 @@ func (process *Process) ExitCode() (int, error) {
// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing // Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
// these pipes does not close the underlying pipes; it should be possible to // these pipes does not close the underlying pipes; it should be possible to
// call this multiple times to get multiple interfaces. // call this multiple times to get multiple interfaces.
func (process *Process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) { func (process *Process) Stdio() (_ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "Stdio"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::Stdio"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(operation, err) }()
if process.handle == 0 { if process.handle == 0 {
return nil, nil, nil, makeProcessError(process, operation, ErrAlreadyClosed, nil) return nil, nil, nil, makeProcessError(process, operation, ErrAlreadyClosed, nil)
@@ -279,7 +312,7 @@ func (process *Process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, e
processInfo hcsProcessInformation processInfo hcsProcessInformation
resultp *uint16 resultp *uint16
) )
err := hcsGetProcessInfo(process.handle, &processInfo, &resultp) err = hcsGetProcessInfo(process.handle, &processInfo, &resultp)
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, nil, nil, makeProcessError(process, operation, err, events) return nil, nil, nil, makeProcessError(process, operation, err, events)
@@ -299,18 +332,18 @@ func (process *Process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, e
return nil, nil, nil, makeProcessError(process, operation, err, nil) return nil, nil, nil, makeProcessError(process, operation, err, nil)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return pipes[0], pipes[1], pipes[2], nil return pipes[0], pipes[1], pipes[2], nil
} }
// CloseStdin closes the write side of the stdin pipe so that the process is // CloseStdin closes the write side of the stdin pipe so that the process is
// notified on the read side that there is no more data in stdin. // notified on the read side that there is no more data in stdin.
func (process *Process) CloseStdin() error { func (process *Process) CloseStdin() (err error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "CloseStdin"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::CloseStdin"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(operation, err) }()
if process.handle == 0 { if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil) return makeProcessError(process, operation, ErrAlreadyClosed, nil)
@@ -337,35 +370,34 @@ func (process *Process) CloseStdin() error {
return makeProcessError(process, operation, err, events) return makeProcessError(process, operation, err, events)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }
// Close cleans up any state associated with the process but does not kill // Close cleans up any state associated with the process but does not kill
// or wait on it. // or wait on it.
func (process *Process) Close() error { func (process *Process) Close() (err error) {
process.handleLock.Lock() process.handleLock.Lock()
defer process.handleLock.Unlock() defer process.handleLock.Unlock()
operation := "Close"
title := "hcsshim::Process::" + operation operation := "hcsshim::Process::Close"
logrus.Debugf(title+" processid=%d", process.processID) process.logOperationBegin(operation)
defer func() { process.logOperationEnd(operation, err) }()
// Don't double free this // Don't double free this
if process.handle == 0 { if process.handle == 0 {
return nil return nil
} }
if err := process.unregisterCallback(); err != nil { if err = process.unregisterCallback(); err != nil {
return makeProcessError(process, operation, err, nil) return makeProcessError(process, operation, err, nil)
} }
if err := hcsCloseProcess(process.handle); err != nil { if err = hcsCloseProcess(process.handle); err != nil {
return makeProcessError(process, operation, err, nil) return makeProcessError(process, operation, err, nil)
} }
process.handle = 0 process.handle = 0
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return nil return nil
} }

View File

@@ -2,7 +2,6 @@ package hcs
import ( import (
"encoding/json" "encoding/json"
"fmt"
"os" "os"
"strconv" "strconv"
"sync" "sync"
@@ -10,6 +9,7 @@ import (
"time" "time"
"github.com/Microsoft/hcsshim/internal/interop" "github.com/Microsoft/hcsshim/internal/interop"
"github.com/Microsoft/hcsshim/internal/logfields"
"github.com/Microsoft/hcsshim/internal/schema1" "github.com/Microsoft/hcsshim/internal/schema1"
"github.com/Microsoft/hcsshim/internal/timeout" "github.com/Microsoft/hcsshim/internal/timeout"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@@ -41,16 +41,46 @@ type System struct {
handle hcsSystem handle hcsSystem
id string id string
callbackNumber uintptr callbackNumber uintptr
logctx logrus.Fields
}
func newSystem(id string) *System {
return &System{
id: id,
logctx: logrus.Fields{
logfields.ContainerID: id,
},
}
}
func (computeSystem *System) logOperationBegin(operation string) {
logOperationBegin(
computeSystem.logctx,
operation+" - Begin Operation")
}
func (computeSystem *System) logOperationEnd(operation string, err error) {
var result string
if err == nil {
result = "Success"
} else {
result = "Error"
}
logOperationEnd(
computeSystem.logctx,
operation+" - End Operation - "+result,
err)
} }
// CreateComputeSystem creates a new compute system with the given configuration but does not start it. // CreateComputeSystem creates a new compute system with the given configuration but does not start it.
func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (*System, error) { func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (_ *System, err error) {
operation := "CreateComputeSystem" operation := "hcsshim::CreateComputeSystem"
title := "hcsshim::" + operation
computeSystem := &System{ computeSystem := newSystem(id)
id: id, computeSystem.logOperationBegin(operation)
} defer func() { computeSystem.logOperationEnd(operation, err) }()
hcsDocumentB, err := json.Marshal(hcsDocumentInterface) hcsDocumentB, err := json.Marshal(hcsDocumentInterface)
if err != nil { if err != nil {
@@ -58,19 +88,22 @@ func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (*System,
} }
hcsDocument := string(hcsDocumentB) hcsDocument := string(hcsDocumentB)
logrus.Debugf(title+" ID=%s config=%s", id, hcsDocument)
logrus.WithFields(computeSystem.logctx).
WithField(logfields.JSON, hcsDocument).
Debug("HCS ComputeSystem Document")
var ( var (
resultp *uint16 resultp *uint16
identity syscall.Handle identity syscall.Handle
createError error
) )
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("CreateCompleteSystem %s: %s", id, hcsDocument), &completed) createError = hcsCreateComputeSystem(id, hcsDocument, identity, &computeSystem.handle, &resultp)
createError := hcsCreateComputeSystem(id, hcsDocument, identity, &computeSystem.handle, &resultp) })
completed = true
if createError == nil || IsPending(createError) { if createError == nil || IsPending(createError) {
if err := computeSystem.registerCallback(); err != nil { if err = computeSystem.registerCallback(); err != nil {
// Terminate the compute system if it still exists. We're okay to // Terminate the compute system if it still exists. We're okay to
// ignore a failure here. // ignore a failure here.
computeSystem.Terminate() computeSystem.Terminate()
@@ -88,25 +121,28 @@ func CreateComputeSystem(id string, hcsDocumentInterface interface{}) (*System,
return nil, makeSystemError(computeSystem, operation, hcsDocument, err, events) return nil, makeSystemError(computeSystem, operation, hcsDocument, err, events)
} }
logrus.Debugf(title+" succeeded id=%s handle=%d", id, computeSystem.handle)
return computeSystem, nil return computeSystem, nil
} }
// OpenComputeSystem opens an existing compute system by ID. // OpenComputeSystem opens an existing compute system by ID.
func OpenComputeSystem(id string) (*System, error) { func OpenComputeSystem(id string) (_ *System, err error) {
operation := "OpenComputeSystem" operation := "hcsshim::OpenComputeSystem"
title := "hcsshim::" + operation
logrus.Debugf(title+" ID=%s", id)
computeSystem := &System{ computeSystem := newSystem(id)
id: id, computeSystem.logOperationBegin(operation)
} defer func() {
if IsNotExist(err) {
computeSystem.logOperationEnd(operation, nil)
} else {
computeSystem.logOperationEnd(operation, err)
}
}()
var ( var (
handle hcsSystem handle hcsSystem
resultp *uint16 resultp *uint16
) )
err := hcsOpenComputeSystem(id, &handle, &resultp) err = hcsOpenComputeSystem(id, &handle, &resultp)
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, makeSystemError(computeSystem, operation, "", err, events) return nil, makeSystemError(computeSystem, operation, "", err, events)
@@ -114,18 +150,34 @@ func OpenComputeSystem(id string) (*System, error) {
computeSystem.handle = handle computeSystem.handle = handle
if err := computeSystem.registerCallback(); err != nil { if err = computeSystem.registerCallback(); err != nil {
return nil, makeSystemError(computeSystem, operation, "", err, nil) return nil, makeSystemError(computeSystem, operation, "", err, nil)
} }
logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle)
return computeSystem, nil return computeSystem, nil
} }
// GetComputeSystems gets a list of the compute systems on the system that match the query // GetComputeSystems gets a list of the compute systems on the system that match the query
func GetComputeSystems(q schema1.ComputeSystemQuery) ([]schema1.ContainerProperties, error) { func GetComputeSystems(q schema1.ComputeSystemQuery) (_ []schema1.ContainerProperties, err error) {
operation := "GetComputeSystems" operation := "hcsshim::GetComputeSystems"
title := "hcsshim::" + operation fields := logrus.Fields{}
logOperationBegin(
fields,
operation+" - Begin Operation")
defer func() {
var result string
if err == nil {
result = "Success"
} else {
result = "Error"
}
logOperationEnd(
fields,
operation+" - End Operation - "+result,
err)
}()
queryb, err := json.Marshal(q) queryb, err := json.Marshal(q)
if err != nil { if err != nil {
@@ -133,16 +185,19 @@ func GetComputeSystems(q schema1.ComputeSystemQuery) ([]schema1.ContainerPropert
} }
query := string(queryb) query := string(queryb)
logrus.Debugf(title+" query=%s", query)
logrus.WithFields(fields).
WithField(logfields.JSON, query).
Debug("HCS ComputeSystem Query")
var ( var (
resultp *uint16 resultp *uint16
computeSystemsp *uint16 computeSystemsp *uint16
) )
completed := false
go syscallWatcher(fmt.Sprintf("GetComputeSystems %s:", query), &completed) syscallWatcher(fields, func() {
err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp) err = hcsEnumerateComputeSystems(query, &computeSystemsp, &resultp)
completed = true })
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, &HcsError{Op: operation, Err: err, Events: events} return nil, &HcsError{Op: operation, Err: err, Events: events}
@@ -153,20 +208,21 @@ func GetComputeSystems(q schema1.ComputeSystemQuery) ([]schema1.ContainerPropert
} }
computeSystemsRaw := interop.ConvertAndFreeCoTaskMemBytes(computeSystemsp) computeSystemsRaw := interop.ConvertAndFreeCoTaskMemBytes(computeSystemsp)
computeSystems := []schema1.ContainerProperties{} computeSystems := []schema1.ContainerProperties{}
if err := json.Unmarshal(computeSystemsRaw, &computeSystems); err != nil { if err = json.Unmarshal(computeSystemsRaw, &computeSystems); err != nil {
return nil, err return nil, err
} }
logrus.Debugf(title + " succeeded")
return computeSystems, nil return computeSystems, nil
} }
// Start synchronously starts the computeSystem. // Start synchronously starts the computeSystem.
func (computeSystem *System) Start() error { func (computeSystem *System) Start() (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::Start ID=" + computeSystem.ID()
logrus.Debugf(title) operation := "hcsshim::ComputeSystem::Start"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, "Start", "", ErrAlreadyClosed, nil) return makeSystemError(computeSystem, "Start", "", ErrAlreadyClosed, nil)
@@ -199,16 +255,14 @@ func (computeSystem *System) Start() error {
} }
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("StartComputeSystem %s:", computeSystem.ID()), &completed) err = hcsStartComputeSystem(computeSystem.handle, "", &resultp)
err := hcsStartComputeSystem(computeSystem.handle, "", &resultp) })
completed = true
events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemStartCompleted, &timeout.SystemStart) events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemStartCompleted, &timeout.SystemStart)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Start", "", err, events) return makeSystemError(computeSystem, "Start", "", err, events)
} }
logrus.Debugf(title + " succeeded")
return nil return nil
} }
@@ -219,98 +273,133 @@ func (computeSystem *System) ID() string {
// Shutdown requests a compute system shutdown, if IsPending() on the error returned is true, // Shutdown requests a compute system shutdown, if IsPending() on the error returned is true,
// it may not actually be shut down until Wait() succeeds. // it may not actually be shut down until Wait() succeeds.
func (computeSystem *System) Shutdown() error { func (computeSystem *System) Shutdown() (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::Shutdown"
logrus.Debugf(title) operation := "hcsshim::ComputeSystem::Shutdown"
computeSystem.logOperationBegin(operation)
defer func() {
if IsAlreadyStopped(err) {
computeSystem.logOperationEnd(operation, nil)
} else {
computeSystem.logOperationEnd(operation, err)
}
}()
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, "Shutdown", "", ErrAlreadyClosed, nil) return makeSystemError(computeSystem, "Shutdown", "", ErrAlreadyClosed, nil)
} }
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("ShutdownComputeSystem %s:", computeSystem.ID()), &completed) err = hcsShutdownComputeSystem(computeSystem.handle, "", &resultp)
err := hcsShutdownComputeSystem(computeSystem.handle, "", &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Shutdown", "", err, events) return makeSystemError(computeSystem, "Shutdown", "", err, events)
} }
logrus.Debugf(title + " succeeded")
return nil return nil
} }
// Terminate requests a compute system terminate, if IsPending() on the error returned is true, // Terminate requests a compute system terminate, if IsPending() on the error returned is true,
// it may not actually be shut down until Wait() succeeds. // it may not actually be shut down until Wait() succeeds.
func (computeSystem *System) Terminate() error { func (computeSystem *System) Terminate() (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::Terminate ID=" + computeSystem.ID()
logrus.Debugf(title) operation := "hcsshim::ComputeSystem::Terminate"
computeSystem.logOperationBegin(operation)
defer func() {
if IsPending(err) {
computeSystem.logOperationEnd(operation, nil)
} else {
computeSystem.logOperationEnd(operation, err)
}
}()
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, "Terminate", "", ErrAlreadyClosed, nil) return makeSystemError(computeSystem, "Terminate", "", ErrAlreadyClosed, nil)
} }
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("TerminateComputeSystem %s:", computeSystem.ID()), &completed) err = hcsTerminateComputeSystem(computeSystem.handle, "", &resultp)
err := hcsTerminateComputeSystem(computeSystem.handle, "", &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil && err != ErrVmcomputeAlreadyStopped {
return makeSystemError(computeSystem, "Terminate", "", err, events) return makeSystemError(computeSystem, "Terminate", "", err, events)
} }
logrus.Debugf(title + " succeeded")
return nil return nil
} }
// Wait synchronously waits for the compute system to shutdown or terminate. // Wait synchronously waits for the compute system to shutdown or terminate.
func (computeSystem *System) Wait() error { func (computeSystem *System) Wait() (err error) {
title := "hcsshim::ComputeSystem::Wait ID=" + computeSystem.ID() operation := "hcsshim::ComputeSystem::Wait"
logrus.Debugf(title) computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
err := waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, nil) err = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, nil)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Wait", "", err, nil) return makeSystemError(computeSystem, "Wait", "", err, nil)
} }
logrus.Debugf(title + " succeeded") return nil
}
// WaitExpectedError synchronously waits for the compute system to shutdown or
// terminate, and ignores the passed error if it occurs.
func (computeSystem *System) WaitExpectedError(expected error) (err error) {
operation := "hcsshim::ComputeSystem::WaitExpectedError"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
err = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, nil)
if err != nil && getInnerError(err) != expected {
return makeSystemError(computeSystem, "WaitExpectedError", "", err, nil)
}
return nil return nil
} }
// WaitTimeout synchronously waits for the compute system to terminate or the duration to elapse. // WaitTimeout synchronously waits for the compute system to terminate or the duration to elapse.
// If the timeout expires, IsTimeout(err) == true // If the timeout expires, IsTimeout(err) == true
func (computeSystem *System) WaitTimeout(timeout time.Duration) error { func (computeSystem *System) WaitTimeout(timeout time.Duration) (err error) {
title := "hcsshim::ComputeSystem::WaitTimeout ID=" + computeSystem.ID() operation := "hcsshim::ComputeSystem::WaitTimeout"
logrus.Debugf(title) computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
err := waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, &timeout) err = waitForNotification(computeSystem.callbackNumber, hcsNotificationSystemExited, &timeout)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "WaitTimeout", "", err, nil) return makeSystemError(computeSystem, "WaitTimeout", "", err, nil)
} }
logrus.Debugf(title + " succeeded")
return nil return nil
} }
func (computeSystem *System) Properties(types ...schema1.PropertyType) (*schema1.ContainerProperties, error) { func (computeSystem *System) Properties(types ...schema1.PropertyType) (_ *schema1.ContainerProperties, err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
operation := "hcsshim::ComputeSystem::Properties"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
queryj, err := json.Marshal(schema1.PropertyQuery{types}) queryj, err := json.Marshal(schema1.PropertyQuery{types})
if err != nil { if err != nil {
return nil, makeSystemError(computeSystem, "Properties", "", err, nil) return nil, makeSystemError(computeSystem, "Properties", "", err, nil)
} }
logrus.WithFields(computeSystem.logctx).
WithField(logfields.JSON, queryj).
Debug("HCS ComputeSystem Properties Query")
var resultp, propertiesp *uint16 var resultp, propertiesp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("GetComputeSystemProperties %s:", computeSystem.ID()), &completed) err = hcsGetComputeSystemProperties(computeSystem.handle, string(queryj), &propertiesp, &resultp)
err = hcsGetComputeSystemProperties(computeSystem.handle, string(queryj), &propertiesp, &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, makeSystemError(computeSystem, "Properties", "", err, events) return nil, makeSystemError(computeSystem, "Properties", "", err, events)
@@ -324,64 +413,69 @@ func (computeSystem *System) Properties(types ...schema1.PropertyType) (*schema1
if err := json.Unmarshal(propertiesRaw, properties); err != nil { if err := json.Unmarshal(propertiesRaw, properties); err != nil {
return nil, makeSystemError(computeSystem, "Properties", "", err, nil) return nil, makeSystemError(computeSystem, "Properties", "", err, nil)
} }
return properties, nil return properties, nil
} }
// Pause pauses the execution of the computeSystem. This feature is not enabled in TP5. // Pause pauses the execution of the computeSystem. This feature is not enabled in TP5.
func (computeSystem *System) Pause() error { func (computeSystem *System) Pause() (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::Pause ID=" + computeSystem.ID()
logrus.Debugf(title) operation := "hcsshim::ComputeSystem::Pause"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, "Pause", "", ErrAlreadyClosed, nil) return makeSystemError(computeSystem, "Pause", "", ErrAlreadyClosed, nil)
} }
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("PauseComputeSystem %s:", computeSystem.ID()), &completed) err = hcsPauseComputeSystem(computeSystem.handle, "", &resultp)
err := hcsPauseComputeSystem(computeSystem.handle, "", &resultp) })
completed = true
events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemPauseCompleted, &timeout.SystemPause) events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemPauseCompleted, &timeout.SystemPause)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Pause", "", err, events) return makeSystemError(computeSystem, "Pause", "", err, events)
} }
logrus.Debugf(title + " succeeded")
return nil return nil
} }
// Resume resumes the execution of the computeSystem. This feature is not enabled in TP5. // Resume resumes the execution of the computeSystem. This feature is not enabled in TP5.
func (computeSystem *System) Resume() error { func (computeSystem *System) Resume() (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::Resume ID=" + computeSystem.ID()
logrus.Debugf(title) operation := "hcsshim::ComputeSystem::Resume"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, "Resume", "", ErrAlreadyClosed, nil) return makeSystemError(computeSystem, "Resume", "", ErrAlreadyClosed, nil)
} }
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("ResumeComputeSystem %s:", computeSystem.ID()), &completed) err = hcsResumeComputeSystem(computeSystem.handle, "", &resultp)
err := hcsResumeComputeSystem(computeSystem.handle, "", &resultp) })
completed = true
events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemResumeCompleted, &timeout.SystemResume) events, err := processAsyncHcsResult(err, resultp, computeSystem.callbackNumber, hcsNotificationSystemResumeCompleted, &timeout.SystemResume)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Resume", "", err, events) return makeSystemError(computeSystem, "Resume", "", err, events)
} }
logrus.Debugf(title + " succeeded")
return nil return nil
} }
// CreateProcess launches a new process within the computeSystem. // CreateProcess launches a new process within the computeSystem.
func (computeSystem *System) CreateProcess(c interface{}) (*Process, error) { func (computeSystem *System) CreateProcess(c interface{}) (_ *Process, err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::CreateProcess ID=" + computeSystem.ID()
operation := "hcsshim::ComputeSystem::CreateProcess"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
var ( var (
processInfo hcsProcessInformation processInfo hcsProcessInformation
processHandle hcsProcess processHandle hcsProcess
@@ -398,42 +492,50 @@ func (computeSystem *System) CreateProcess(c interface{}) (*Process, error) {
} }
configuration := string(configurationb) configuration := string(configurationb)
logrus.Debugf(title+" config=%s", configuration)
completed := false logrus.WithFields(computeSystem.logctx).
go syscallWatcher(fmt.Sprintf("CreateProcess %s: %s", computeSystem.ID(), configuration), &completed) WithField(logfields.JSON, configuration).
err = hcsCreateProcess(computeSystem.handle, configuration, &processInfo, &processHandle, &resultp) Debug("HCS ComputeSystem Process Document")
completed = true
syscallWatcher(computeSystem.logctx, func() {
err = hcsCreateProcess(computeSystem.handle, configuration, &processInfo, &processHandle, &resultp)
})
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, makeSystemError(computeSystem, "CreateProcess", configuration, err, events) return nil, makeSystemError(computeSystem, "CreateProcess", configuration, err, events)
} }
process := &Process{ logrus.WithFields(computeSystem.logctx).
handle: processHandle, WithField(logfields.ProcessID, processInfo.ProcessId).
processID: int(processInfo.ProcessId), Debug("HCS ComputeSystem CreateProcess PID")
system: computeSystem,
cachedPipes: &cachedPipes{ process := newProcess(processHandle, int(processInfo.ProcessId), computeSystem)
stdIn: processInfo.StdInput, process.cachedPipes = &cachedPipes{
stdOut: processInfo.StdOutput, stdIn: processInfo.StdInput,
stdErr: processInfo.StdError, stdOut: processInfo.StdOutput,
}, stdErr: processInfo.StdError,
} }
if err := process.registerCallback(); err != nil { if err = process.registerCallback(); err != nil {
return nil, makeSystemError(computeSystem, "CreateProcess", "", err, nil) return nil, makeSystemError(computeSystem, "CreateProcess", "", err, nil)
} }
logrus.Debugf(title+" succeeded processid=%d", process.processID)
return process, nil return process, nil
} }
// OpenProcess gets an interface to an existing process within the computeSystem. // OpenProcess gets an interface to an existing process within the computeSystem.
func (computeSystem *System) OpenProcess(pid int) (*Process, error) { func (computeSystem *System) OpenProcess(pid int) (_ *Process, err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::ComputeSystem::OpenProcess ID=" + computeSystem.ID()
logrus.Debugf(title+" processid=%d", pid) // Add PID for the context of this operation
computeSystem.logctx[logfields.ProcessID] = pid
defer delete(computeSystem.logctx, logfields.ProcessID)
operation := "hcsshim::ComputeSystem::OpenProcess"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
var ( var (
processHandle hcsProcess processHandle hcsProcess
resultp *uint16 resultp *uint16
@@ -443,56 +545,49 @@ func (computeSystem *System) OpenProcess(pid int) (*Process, error) {
return nil, makeSystemError(computeSystem, "OpenProcess", "", ErrAlreadyClosed, nil) return nil, makeSystemError(computeSystem, "OpenProcess", "", ErrAlreadyClosed, nil)
} }
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("OpenProcess %s: %d", computeSystem.ID(), pid), &completed) err = hcsOpenProcess(computeSystem.handle, uint32(pid), &processHandle, &resultp)
err := hcsOpenProcess(computeSystem.handle, uint32(pid), &processHandle, &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return nil, makeSystemError(computeSystem, "OpenProcess", "", err, events) return nil, makeSystemError(computeSystem, "OpenProcess", "", err, events)
} }
process := &Process{ process := newProcess(processHandle, pid, computeSystem)
handle: processHandle, if err = process.registerCallback(); err != nil {
processID: pid,
system: computeSystem,
}
if err := process.registerCallback(); err != nil {
return nil, makeSystemError(computeSystem, "OpenProcess", "", err, nil) return nil, makeSystemError(computeSystem, "OpenProcess", "", err, nil)
} }
logrus.Debugf(title+" succeeded processid=%s", process.processID)
return process, nil return process, nil
} }
// Close cleans up any state associated with the compute system but does not terminate or wait for it. // Close cleans up any state associated with the compute system but does not terminate or wait for it.
func (computeSystem *System) Close() error { func (computeSystem *System) Close() (err error) {
computeSystem.handleLock.Lock() computeSystem.handleLock.Lock()
defer computeSystem.handleLock.Unlock() defer computeSystem.handleLock.Unlock()
title := "hcsshim::ComputeSystem::Close ID=" + computeSystem.ID()
logrus.Debugf(title) operation := "hcsshim::ComputeSystem::Close"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
// Don't double free this // Don't double free this
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return nil return nil
} }
if err := computeSystem.unregisterCallback(); err != nil { if err = computeSystem.unregisterCallback(); err != nil {
return makeSystemError(computeSystem, "Close", "", err, nil) return makeSystemError(computeSystem, "Close", "", err, nil)
} }
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("CloseComputeSystem %s:", computeSystem.ID()), &completed) err = hcsCloseComputeSystem(computeSystem.handle)
err := hcsCloseComputeSystem(computeSystem.handle) })
completed = true
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Close", "", err, nil) return makeSystemError(computeSystem, "Close", "", err, nil)
} }
computeSystem.handle = 0 computeSystem.handle = 0
logrus.Debugf(title + " succeeded")
return nil return nil
} }
@@ -553,11 +648,14 @@ func (computeSystem *System) unregisterCallback() error {
return nil return nil
} }
// Modifies the System by sending a request to HCS // Modify the System by sending a request to HCS
func (computeSystem *System) Modify(config interface{}) error { func (computeSystem *System) Modify(config interface{}) (err error) {
computeSystem.handleLock.RLock() computeSystem.handleLock.RLock()
defer computeSystem.handleLock.RUnlock() defer computeSystem.handleLock.RUnlock()
title := "hcsshim::Modify ID=" + computeSystem.id
operation := "hcsshim::ComputeSystem::Modify"
computeSystem.logOperationBegin(operation)
defer func() { computeSystem.logOperationEnd(operation, err) }()
if computeSystem.handle == 0 { if computeSystem.handle == 0 {
return makeSystemError(computeSystem, "Modify", "", ErrAlreadyClosed, nil) return makeSystemError(computeSystem, "Modify", "", ErrAlreadyClosed, nil)
@@ -569,17 +667,19 @@ func (computeSystem *System) Modify(config interface{}) error {
} }
requestString := string(requestJSON) requestString := string(requestJSON)
logrus.Debugf(title + " " + requestString)
logrus.WithFields(computeSystem.logctx).
WithField(logfields.JSON, requestString).
Debug("HCS ComputeSystem Modify Document")
var resultp *uint16 var resultp *uint16
completed := false syscallWatcher(computeSystem.logctx, func() {
go syscallWatcher(fmt.Sprintf("ModifyComputeSystem %s: %s", computeSystem.ID(), requestString), &completed) err = hcsModifyComputeSystem(computeSystem.handle, requestString, &resultp)
err = hcsModifyComputeSystem(computeSystem.handle, requestString, &resultp) })
completed = true
events := processHcsResult(resultp) events := processHcsResult(resultp)
if err != nil { if err != nil {
return makeSystemError(computeSystem, "Modify", requestString, err, events) return makeSystemError(computeSystem, "Modify", requestString, err, events)
} }
logrus.Debugf(title + " succeeded ")
return nil return nil
} }

View File

@@ -1,8 +1,9 @@
package hcs package hcs
import ( import (
"time" "context"
"github.com/Microsoft/hcsshim/internal/logfields"
"github.com/Microsoft/hcsshim/internal/timeout" "github.com/Microsoft/hcsshim/internal/timeout"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@@ -16,15 +17,25 @@ import (
// //
// Usage is: // Usage is:
// //
// completed := false // syscallWatcher(logContext, func() {
// go syscallWatcher("some description", &completed) // err = <syscall>(args...)
// <syscall> // })
// completed = true
// //
func syscallWatcher(description string, syscallCompleted *bool) {
time.Sleep(timeout.SyscallWatcher) func syscallWatcher(logContext logrus.Fields, syscallLambda func()) {
if *syscallCompleted { ctx, cancel := context.WithTimeout(context.Background(), timeout.SyscallWatcher)
return defer cancel()
} go watchFunc(ctx, logContext)
logrus.Warnf("%s: Did not complete within %s. This may indicate a platform issue. If it appears to be making no forward progress, obtain the stacks and see is there is a syscall stuck in the platform API for a significant length of time.", description, timeout.SyscallWatcher) syscallLambda()
}
func watchFunc(ctx context.Context, logContext logrus.Fields) {
select {
case <-ctx.Done():
if ctx.Err() != context.Canceled {
logrus.WithFields(logContext).
WithField(logfields.Timeout, timeout.SyscallWatcher).
Warning("Syscall did not complete within operation timeout. This may indicate a platform issue. If it appears to be making no forward progress, obtain the stacks and see if there is a syscall stuck in the platform API for a significant length of time.")
}
}
} }

View File

@@ -1,4 +1,4 @@
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT // Code generated mksyscall_windows.exe DO NOT EDIT
package hcs package hcs
@@ -6,7 +6,6 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/Microsoft/hcsshim/internal/interop"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@@ -81,7 +80,10 @@ func _hcsEnumerateComputeSystems(query *uint16, computeSystems **uint16, result
} }
r0, _, _ := syscall.Syscall(procHcsEnumerateComputeSystems.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(computeSystems)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsEnumerateComputeSystems.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(computeSystems)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -106,7 +108,10 @@ func _hcsCreateComputeSystem(id *uint16, configuration *uint16, identity syscall
} }
r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(identity), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0) r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(identity), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -126,7 +131,10 @@ func _hcsOpenComputeSystem(id *uint16, computeSystem *hcsSystem, result **uint16
} }
r0, _, _ := syscall.Syscall(procHcsOpenComputeSystem.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsOpenComputeSystem.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -137,7 +145,10 @@ func hcsCloseComputeSystem(computeSystem hcsSystem) (hr error) {
} }
r0, _, _ := syscall.Syscall(procHcsCloseComputeSystem.Addr(), 1, uintptr(computeSystem), 0, 0) r0, _, _ := syscall.Syscall(procHcsCloseComputeSystem.Addr(), 1, uintptr(computeSystem), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -157,7 +168,10 @@ func _hcsStartComputeSystem(computeSystem hcsSystem, options *uint16, result **u
} }
r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -177,7 +191,10 @@ func _hcsShutdownComputeSystem(computeSystem hcsSystem, options *uint16, result
} }
r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -197,7 +214,10 @@ func _hcsTerminateComputeSystem(computeSystem hcsSystem, options *uint16, result
} }
r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -217,7 +237,10 @@ func _hcsPauseComputeSystem(computeSystem hcsSystem, options *uint16, result **u
} }
r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -237,7 +260,10 @@ func _hcsResumeComputeSystem(computeSystem hcsSystem, options *uint16, result **
} }
r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -257,7 +283,10 @@ func _hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery *uint
} }
r0, _, _ := syscall.Syscall6(procHcsGetComputeSystemProperties.Addr(), 4, uintptr(computeSystem), uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0) r0, _, _ := syscall.Syscall6(procHcsGetComputeSystemProperties.Addr(), 4, uintptr(computeSystem), uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -277,7 +306,10 @@ func _hcsModifyComputeSystem(computeSystem hcsSystem, configuration *uint16, res
} }
r0, _, _ := syscall.Syscall(procHcsModifyComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsModifyComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -288,7 +320,10 @@ func hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr,
} }
r0, _, _ := syscall.Syscall6(procHcsRegisterComputeSystemCallback.Addr(), 4, uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) r0, _, _ := syscall.Syscall6(procHcsRegisterComputeSystemCallback.Addr(), 4, uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -299,7 +334,10 @@ func hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) {
} }
r0, _, _ := syscall.Syscall(procHcsUnregisterComputeSystemCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) r0, _, _ := syscall.Syscall(procHcsUnregisterComputeSystemCallback.Addr(), 1, uintptr(callbackHandle), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -319,7 +357,10 @@ func _hcsCreateProcess(computeSystem hcsSystem, processParameters *uint16, proce
} }
r0, _, _ := syscall.Syscall6(procHcsCreateProcess.Addr(), 5, uintptr(computeSystem), uintptr(unsafe.Pointer(processParameters)), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0) r0, _, _ := syscall.Syscall6(procHcsCreateProcess.Addr(), 5, uintptr(computeSystem), uintptr(unsafe.Pointer(processParameters)), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -330,7 +371,10 @@ func hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, re
} }
r0, _, _ := syscall.Syscall6(procHcsOpenProcess.Addr(), 4, uintptr(computeSystem), uintptr(pid), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0, 0) r0, _, _ := syscall.Syscall6(procHcsOpenProcess.Addr(), 4, uintptr(computeSystem), uintptr(pid), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -341,7 +385,10 @@ func hcsCloseProcess(process hcsProcess) (hr error) {
} }
r0, _, _ := syscall.Syscall(procHcsCloseProcess.Addr(), 1, uintptr(process), 0, 0) r0, _, _ := syscall.Syscall(procHcsCloseProcess.Addr(), 1, uintptr(process), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -352,7 +399,10 @@ func hcsTerminateProcess(process hcsProcess, result **uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 2, uintptr(process), uintptr(unsafe.Pointer(result)), 0) r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 2, uintptr(process), uintptr(unsafe.Pointer(result)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -372,7 +422,10 @@ func _hcsSignalProcess(process hcsProcess, options *uint16, result **uint16) (hr
} }
r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -383,7 +436,10 @@ func hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInforma
} }
r0, _, _ := syscall.Syscall(procHcsGetProcessInfo.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsGetProcessInfo.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -394,7 +450,10 @@ func hcsGetProcessProperties(process hcsProcess, processProperties **uint16, res
} }
r0, _, _ := syscall.Syscall(procHcsGetProcessProperties.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processProperties)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsGetProcessProperties.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processProperties)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -414,7 +473,10 @@ func _hcsModifyProcess(process hcsProcess, settings *uint16, result **uint16) (h
} }
r0, _, _ := syscall.Syscall(procHcsModifyProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsModifyProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -434,7 +496,10 @@ func _hcsGetServiceProperties(propertyQuery *uint16, properties **uint16, result
} }
r0, _, _ := syscall.Syscall(procHcsGetServiceProperties.Addr(), 3, uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result))) r0, _, _ := syscall.Syscall(procHcsGetServiceProperties.Addr(), 3, uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -445,7 +510,10 @@ func hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context ui
} }
r0, _, _ := syscall.Syscall6(procHcsRegisterProcessCallback.Addr(), 4, uintptr(process), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0) r0, _, _ := syscall.Syscall6(procHcsRegisterProcessCallback.Addr(), 4, uintptr(process), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -456,7 +524,10 @@ func hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) {
} }
r0, _, _ := syscall.Syscall(procHcsUnregisterProcessCallback.Addr(), 1, uintptr(callbackHandle), 0, 0) r0, _, _ := syscall.Syscall(procHcsUnregisterProcessCallback.Addr(), 1, uintptr(callbackHandle), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }

View File

@@ -36,10 +36,6 @@ func New(err error, title, rest string) error {
return &HcsError{title, rest, err} return &HcsError{title, rest, err}
} }
func Errorf(err error, title, format string, a ...interface{}) error {
return New(err, title, fmt.Sprintf(format, a...))
}
func Win32FromError(err error) uint32 { func Win32FromError(err error) uint32 {
if herr, ok := err.(*HcsError); ok { if herr, ok := err.(*HcsError); ok {
return Win32FromError(herr.Err) return Win32FromError(herr.Err)

View File

@@ -23,7 +23,9 @@ type HNSEndpoint struct {
DisableICC bool `json:",omitempty"` DisableICC bool `json:",omitempty"`
PrefixLength uint8 `json:",omitempty"` PrefixLength uint8 `json:",omitempty"`
IsRemoteEndpoint bool `json:",omitempty"` IsRemoteEndpoint bool `json:",omitempty"`
EnableLowMetric bool `json:",omitempty"`
Namespace *Namespace `json:",omitempty"` Namespace *Namespace `json:",omitempty"`
EncapOverhead uint16 `json:",omitempty"`
} }
//SystemType represents the type of the system on which actions are done //SystemType represents the type of the system on which actions are done

View File

@@ -140,7 +140,7 @@ func (policylist *PolicyList) RemoveEndpoint(endpoint *HNSEndpoint) (*PolicyList
} }
// AddLoadBalancer policy list for the specified endpoints // AddLoadBalancer policy list for the specified endpoints
func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, isDSR bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) { func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
operation := "AddLoadBalancer" operation := "AddLoadBalancer"
title := "hcsshim::PolicyList::" + operation title := "hcsshim::PolicyList::" + operation
logrus.Debugf(title+" endpointId=%v, isILB=%v, sourceVIP=%s, vip=%s, protocol=%v, internalPort=%v, externalPort=%v", endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort) logrus.Debugf(title+" endpointId=%v, isILB=%v, sourceVIP=%s, vip=%s, protocol=%v, internalPort=%v, externalPort=%v", endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort)
@@ -150,7 +150,6 @@ func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, isDSR bool, sourceVIP,
elbPolicy := &ELBPolicy{ elbPolicy := &ELBPolicy{
SourceVIP: sourceVIP, SourceVIP: sourceVIP,
ILB: isILB, ILB: isILB,
DSR: isDSR,
} }
if len(vip) > 0 { if len(vip) > 0 {

View File

@@ -1,4 +1,4 @@
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT // Code generated mksyscall_windows.exe DO NOT EDIT
package hns package hns
@@ -6,7 +6,6 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/Microsoft/hcsshim/internal/interop"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@@ -68,7 +67,10 @@ func __hnsCall(method *uint16, path *uint16, object *uint16, response **uint16)
} }
r0, _, _ := syscall.Syscall6(procHNSCall.Addr(), 4, uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)), 0, 0) r0, _, _ := syscall.Syscall6(procHNSCall.Addr(), 4, uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }

View File

@@ -5,9 +5,9 @@ import (
"unsafe" "unsafe"
) )
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go interop.go //go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go interop.go
//sys coTaskMemFree(buffer unsafe.Pointer) = ole32.CoTaskMemFree //sys coTaskMemFree(buffer unsafe.Pointer) = api_ms_win_core_com_l1_1_0.CoTaskMemFree
func ConvertAndFreeCoTaskMemString(buffer *uint16) string { func ConvertAndFreeCoTaskMemString(buffer *uint16) string {
str := syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(buffer))[:]) str := syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(buffer))[:])

View File

@@ -1,4 +1,4 @@
// Code generated by 'go generate'; DO NOT EDIT. // Code generated mksyscall_windows.exe DO NOT EDIT
package interop package interop
@@ -37,9 +37,9 @@ func errnoErr(e syscall.Errno) error {
} }
var ( var (
modole32 = windows.NewLazySystemDLL("ole32.dll") modapi_ms_win_core_com_l1_1_0 = windows.NewLazySystemDLL("api-ms-win-core-com-l1-1-0.dll")
procCoTaskMemFree = modole32.NewProc("CoTaskMemFree") procCoTaskMemFree = modapi_ms_win_core_com_l1_1_0.NewProc("CoTaskMemFree")
) )
func coTaskMemFree(buffer unsafe.Pointer) { func coTaskMemFree(buffer unsafe.Pointer) {

View File

@@ -0,0 +1,32 @@
package logfields
const (
// Identifiers
ContainerID = "cid"
UVMID = "uvm-id"
ProcessID = "pid"
// Common Misc
// Timeout represents an operation timeout.
Timeout = "timeout"
JSON = "json"
// Keys/values
Field = "field"
OCIAnnotation = "oci-annotation"
Value = "value"
// Golang type's
ExpectedType = "expected-type"
Bool = "bool"
Uint32 = "uint32"
Uint64 = "uint64"
// runhcs
VMShimOperation = "vmshim-op"
)

View File

@@ -87,7 +87,7 @@ func OpenRoot(path string) (*os.File, error) {
func ntRelativePath(path string) ([]uint16, error) { func ntRelativePath(path string) ([]uint16, error) {
path = filepath.Clean(path) path = filepath.Clean(path)
if strings.Contains(":", path) { if strings.Contains(path, ":") {
// Since alternate data streams must follow the file they // Since alternate data streams must follow the file they
// are attached to, finding one here (out of order) is invalid. // are attached to, finding one here (out of order) is invalid.
return nil, errors.New("path contains invalid character `:`") return nil, errors.New("path contains invalid character `:`")

View File

@@ -10,7 +10,6 @@
package hcsschema package hcsschema
type Chipset struct { type Chipset struct {
Uefi *Uefi `json:"Uefi,omitempty"` Uefi *Uefi `json:"Uefi,omitempty"`
IsNumLockDisabled bool `json:"IsNumLockDisabled,omitempty"` IsNumLockDisabled bool `json:"IsNumLockDisabled,omitempty"`
@@ -22,4 +21,7 @@ type Chipset struct {
ChassisAssetTag string `json:"ChassisAssetTag,omitempty"` ChassisAssetTag string `json:"ChassisAssetTag,omitempty"`
UseUtc bool `json:"UseUtc,omitempty"` UseUtc bool `json:"UseUtc,omitempty"`
// LinuxKernelDirect - Added in v2.2 Builds >=181117
LinuxKernelDirect *LinuxKernelDirect `json:"LinuxKernelDirect,omitempty"`
} }

View File

@@ -0,0 +1,18 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.2
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
type LinuxKernelDirect struct {
KernelFilePath string `json:"KernelFilePath,omitempty"`
InitRdPath string `json:"InitRdPath,omitempty"`
KernelCmdLine string `json:"KernelCmdLine,omitempty"`
}

View File

@@ -20,6 +20,13 @@ type Plan9Share struct {
Port int32 `json:"Port,omitempty"` Port int32 `json:"Port,omitempty"`
// Flags are marked private. Until they are exported correctly
//
// ReadOnly 0x00000001
// LinuxMetadata 0x00000004
// CaseSensitive 0x00000008
Flags int32 `json:"Flags,omitempty"`
ReadOnly bool `json:"ReadOnly,omitempty"` ReadOnly bool `json:"ReadOnly,omitempty"`
UseShareRootIdentity bool `json:"UseShareRootIdentity,omitempty"` UseShareRootIdentity bool `json:"UseShareRootIdentity,omitempty"`

View File

@@ -11,6 +11,9 @@ package hcsschema
type VirtualMachine struct { type VirtualMachine struct {
// StopOnReset is private in the schema. If regenerated need to put back.
StopOnReset bool `json:"StopOnReset,omitempty"`
Chipset *Chipset `json:"Chipset,omitempty"` Chipset *Chipset `json:"Chipset,omitempty"`
ComputeTopology *Topology `json:"ComputeTopology,omitempty"` ComputeTopology *Topology `json:"ComputeTopology,omitempty"`

View File

@@ -9,17 +9,24 @@ import (
// For a read/write layer, the mounted filesystem will appear as a volume on the // For a read/write layer, the mounted filesystem will appear as a volume on the
// host, while a read-only layer is generally expected to be a no-op. // host, while a read-only layer is generally expected to be a no-op.
// An activated layer must later be deactivated via DeactivateLayer. // An activated layer must later be deactivated via DeactivateLayer.
func ActivateLayer(path string) error { func ActivateLayer(path string) (err error) {
title := "hcsshim::ActivateLayer " title := "hcsshim::ActivateLayer"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
err := activateLayer(&stdDriverInfo, path)
if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title+" - succeeded path=%s", path) err = activateLayer(&stdDriverInfo, path)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
return nil return nil
} }

View File

@@ -7,17 +7,25 @@ import (
// CreateLayer creates a new, empty, read-only layer on the filesystem based on // CreateLayer creates a new, empty, read-only layer on the filesystem based on
// the parent layer provided. // the parent layer provided.
func CreateLayer(path, parent string) error { func CreateLayer(path, parent string) (err error) {
title := "hcsshim::CreateLayer " title := "hcsshim::CreateLayer"
logrus.Debugf(title+"ID %s parent %s", path, parent) fields := logrus.Fields{
"parent": parent,
err := createLayer(&stdDriverInfo, path, parent) "path": path,
if err != nil {
err = hcserror.Errorf(err, title, "path=%s parent=%s", path, parent)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title+"- succeeded path=%s parent=%s", path, parent) err = createLayer(&stdDriverInfo, path, parent)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
return nil return nil
} }

View File

@@ -9,9 +9,20 @@ import (
// This requires both the id of the direct parent layer, as well as the full list // This requires both the id of the direct parent layer, as well as the full list
// of paths to all parent layers up to the base (and including the direct parent // of paths to all parent layers up to the base (and including the direct parent
// whose id was provided). // whose id was provided).
func CreateScratchLayer(path string, parentLayerPaths []string) error { func CreateScratchLayer(path string, parentLayerPaths []string) (err error) {
title := "hcsshim::CreateScratchLayer " title := "hcsshim::CreateScratchLayer"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
// Generate layer descriptors // Generate layer descriptors
layers, err := layerPathsToDescriptors(parentLayerPaths) layers, err := layerPathsToDescriptors(parentLayerPaths)
@@ -21,11 +32,7 @@ func CreateScratchLayer(path string, parentLayerPaths []string) error {
err = createSandboxLayer(&stdDriverInfo, path, 0, layers) err = createSandboxLayer(&stdDriverInfo, path, 0, layers)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path) return hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return err
} }
logrus.Debugf(title+"- succeeded path=%s", path)
return nil return nil
} }

View File

@@ -6,17 +6,24 @@ import (
) )
// DeactivateLayer will dismount a layer that was mounted via ActivateLayer. // DeactivateLayer will dismount a layer that was mounted via ActivateLayer.
func DeactivateLayer(path string) error { func DeactivateLayer(path string) (err error) {
title := "hcsshim::DeactivateLayer " title := "hcsshim::DeactivateLayer"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
err := deactivateLayer(&stdDriverInfo, path)
if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title+"succeeded path=%s", path) err = deactivateLayer(&stdDriverInfo, path)
if err != nil {
return hcserror.New(err, title+"- failed", "")
}
return nil return nil
} }

View File

@@ -7,17 +7,24 @@ import (
// DestroyLayer will remove the on-disk files representing the layer with the given // DestroyLayer will remove the on-disk files representing the layer with the given
// path, including that layer's containing folder, if any. // path, including that layer's containing folder, if any.
func DestroyLayer(path string) error { func DestroyLayer(path string) (err error) {
title := "hcsshim::DestroyLayer " title := "hcsshim::DestroyLayer"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
err := destroyLayer(&stdDriverInfo, path)
if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title+"succeeded path=%s", path) err = destroyLayer(&stdDriverInfo, path)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
return nil return nil
} }

View File

@@ -6,17 +6,25 @@ import (
) )
// ExpandScratchSize expands the size of a layer to at least size bytes. // ExpandScratchSize expands the size of a layer to at least size bytes.
func ExpandScratchSize(path string, size uint64) error { func ExpandScratchSize(path string, size uint64) (err error) {
title := "hcsshim::ExpandScratchSize " title := "hcsshim::ExpandScratchSize"
logrus.Debugf(title+"path=%s size=%d", path, size) fields := logrus.Fields{
"path": path,
err := expandSandboxSize(&stdDriverInfo, path, size) "size": size,
if err != nil {
err = hcserror.Errorf(err, title, "path=%s size=%d", path, size)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title+"- succeeded path=%s size=%d", path, size) err = expandSandboxSize(&stdDriverInfo, path, size)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
return nil return nil
} }

View File

@@ -1,14 +1,11 @@
package wclayer package wclayer
import ( import (
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"syscall"
"github.com/Microsoft/go-winio" "github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim/internal/hcserror" "github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/Microsoft/hcsshim/internal/interop"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@@ -17,9 +14,21 @@ import (
// format includes any metadata required for later importing the layer (using // format includes any metadata required for later importing the layer (using
// ImportLayer), and requires the full list of parent layer paths in order to // ImportLayer), and requires the full list of parent layer paths in order to
// perform the export. // perform the export.
func ExportLayer(path string, exportFolderPath string, parentLayerPaths []string) error { func ExportLayer(path string, exportFolderPath string, parentLayerPaths []string) (err error) {
title := "hcsshim::ExportLayer " title := "hcsshim::ExportLayer"
logrus.Debugf(title+"path %s folder %s", path, exportFolderPath) fields := logrus.Fields{
"path": path,
"exportFolderPath": exportFolderPath,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
// Generate layer descriptors // Generate layer descriptors
layers, err := layerPathsToDescriptors(parentLayerPaths) layers, err := layerPathsToDescriptors(parentLayerPaths)
@@ -29,12 +38,8 @@ func ExportLayer(path string, exportFolderPath string, parentLayerPaths []string
err = exportLayer(&stdDriverInfo, path, exportFolderPath, layers) err = exportLayer(&stdDriverInfo, path, exportFolderPath, layers)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "path=%s folder=%s", path, exportFolderPath) return hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return err
} }
logrus.Debugf(title+"succeeded path=%s folder=%s", path, exportFolderPath)
return nil return nil
} }
@@ -44,96 +49,20 @@ type LayerReader interface {
Close() error Close() error
} }
// FilterLayerReader provides an interface for extracting the contents of an on-disk layer.
type FilterLayerReader struct {
context uintptr
}
// Next reads the next available file from a layer, ensuring that parent directories are always read
// before child files and directories.
//
// Next returns the file's relative path, size, and basic file metadata. Read() should be used to
// extract a Win32 backup stream with the remainder of the metadata and the data.
func (r *FilterLayerReader) Next() (string, int64, *winio.FileBasicInfo, error) {
var fileNamep *uint16
fileInfo := &winio.FileBasicInfo{}
var deleted uint32
var fileSize int64
err := exportLayerNext(r.context, &fileNamep, fileInfo, &fileSize, &deleted)
if err != nil {
if err == syscall.ERROR_NO_MORE_FILES {
err = io.EOF
} else {
err = hcserror.New(err, "ExportLayerNext", "")
}
return "", 0, nil, err
}
fileName := interop.ConvertAndFreeCoTaskMemString(fileNamep)
if deleted != 0 {
fileInfo = nil
}
if fileName[0] == '\\' {
fileName = fileName[1:]
}
return fileName, fileSize, fileInfo, nil
}
// Read reads from the current file's Win32 backup stream.
func (r *FilterLayerReader) Read(b []byte) (int, error) {
var bytesRead uint32
err := exportLayerRead(r.context, b, &bytesRead)
if err != nil {
return 0, hcserror.New(err, "ExportLayerRead", "")
}
if bytesRead == 0 {
return 0, io.EOF
}
return int(bytesRead), nil
}
// Close frees resources associated with the layer reader. It will return an
// error if there was an error while reading the layer or of the layer was not
// completely read.
func (r *FilterLayerReader) Close() (err error) {
if r.context != 0 {
err = exportLayerEnd(r.context)
if err != nil {
err = hcserror.New(err, "ExportLayerEnd", "")
}
r.context = 0
}
return
}
// NewLayerReader returns a new layer reader for reading the contents of an on-disk layer. // NewLayerReader returns a new layer reader for reading the contents of an on-disk layer.
// The caller must have taken the SeBackupPrivilege privilege // The caller must have taken the SeBackupPrivilege privilege
// to call this and any methods on the resulting LayerReader. // to call this and any methods on the resulting LayerReader.
func NewLayerReader(path string, parentLayerPaths []string) (LayerReader, error) { func NewLayerReader(path string, parentLayerPaths []string) (LayerReader, error) {
if procExportLayerBegin.Find() != nil { exportPath, err := ioutil.TempDir("", "hcs")
// The new layer reader is not available on this Windows build. Fall back to the
// legacy export code path.
exportPath, err := ioutil.TempDir("", "hcs")
if err != nil {
return nil, err
}
err = ExportLayer(path, exportPath, parentLayerPaths)
if err != nil {
os.RemoveAll(exportPath)
return nil, err
}
return &legacyLayerReaderWrapper{newLegacyLayerReader(exportPath)}, nil
}
layers, err := layerPathsToDescriptors(parentLayerPaths)
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := &FilterLayerReader{} err = ExportLayer(path, exportPath, parentLayerPaths)
err = exportLayerBegin(&stdDriverInfo, path, layers, &r.context)
if err != nil { if err != nil {
return nil, hcserror.New(err, "ExportLayerBegin", "") os.RemoveAll(exportPath)
return nil, err
} }
return r, err return &legacyLayerReaderWrapper{newLegacyLayerReader(exportPath)}, nil
} }
type legacyLayerReaderWrapper struct { type legacyLayerReaderWrapper struct {

View File

@@ -11,20 +11,29 @@ import (
// the path at which that layer can be accessed. This path may be a volume path // the path at which that layer can be accessed. This path may be a volume path
// if the layer is a mounted read-write layer, otherwise it is expected to be the // if the layer is a mounted read-write layer, otherwise it is expected to be the
// folder path at which the layer is stored. // folder path at which the layer is stored.
func GetLayerMountPath(path string) (string, error) { func GetLayerMountPath(path string) (_ string, err error) {
title := "hcsshim::GetLayerMountPath " title := "hcsshim::GetLayerMountPath"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
var mountPathLength uintptr var mountPathLength uintptr
mountPathLength = 0 mountPathLength = 0
// Call the procedure itself. // Call the procedure itself.
logrus.Debugf("Calling proc (1)") logrus.WithFields(fields).Debug("Calling proc (1)")
err := getLayerMountPath(&stdDriverInfo, path, &mountPathLength, nil) err = getLayerMountPath(&stdDriverInfo, path, &mountPathLength, nil)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "(first call) path=%s", path) return "", hcserror.New(err, title+" - failed", "(first call)")
logrus.Error(err)
return "", err
} }
// Allocate a mount path of the returned length. // Allocate a mount path of the returned length.
@@ -35,15 +44,13 @@ func GetLayerMountPath(path string) (string, error) {
mountPathp[0] = 0 mountPathp[0] = 0
// Call the procedure again // Call the procedure again
logrus.Debugf("Calling proc (2)") logrus.WithFields(fields).Debug("Calling proc (2)")
err = getLayerMountPath(&stdDriverInfo, path, &mountPathLength, &mountPathp[0]) err = getLayerMountPath(&stdDriverInfo, path, &mountPathLength, &mountPathp[0])
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "(second call) path=%s", path) return "", hcserror.New(err, title+" - failed", "(second call)")
logrus.Error(err)
return "", err
} }
mountPath := syscall.UTF16ToString(mountPathp[0:]) mountPath := syscall.UTF16ToString(mountPathp[0:])
logrus.Debugf(title+"succeeded path=%s mountPath=%s", path, mountPath) fields["mountPath"] = mountPath
return mountPath, nil return mountPath, nil
} }

View File

@@ -10,17 +10,20 @@ import (
// image store and return descriptive info about those images for the purpose // image store and return descriptive info about those images for the purpose
// of registering them with the graphdriver, graph, and tagstore. // of registering them with the graphdriver, graph, and tagstore.
func GetSharedBaseImages() (imageData string, err error) { func GetSharedBaseImages() (imageData string, err error) {
title := "hcsshim::GetSharedBaseImages " title := "hcsshim::GetSharedBaseImages"
logrus.Debug(title)
defer func() {
if err != nil {
logrus.WithError(err).Error(err)
} else {
logrus.WithField("imageData", imageData).Debug(title + " - succeeded")
}
}()
logrus.Debugf("Calling proc")
var buffer *uint16 var buffer *uint16
err = getBaseImages(&buffer) err = getBaseImages(&buffer)
if err != nil { if err != nil {
err = hcserror.New(err, title, "") return "", hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return
} }
imageData = interop.ConvertAndFreeCoTaskMemString(buffer) return interop.ConvertAndFreeCoTaskMemString(buffer), nil
logrus.Debugf(title+" - succeeded output=%s", imageData)
return
} }

View File

@@ -1,24 +1,30 @@
package wclayer package wclayer
import ( import (
"fmt"
"github.com/Microsoft/hcsshim/internal/hcserror" "github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// GrantVmAccess adds access to a file for a given VM // GrantVmAccess adds access to a file for a given VM
func GrantVmAccess(vmid string, filepath string) error { func GrantVmAccess(vmid string, filepath string) (err error) {
title := fmt.Sprintf("hcsshim::GrantVmAccess id:%s path:%s ", vmid, filepath) title := "hcsshim::GrantVmAccess"
logrus.Debugf(title) fields := logrus.Fields{
"vm-id": vmid,
err := grantVmAccess(vmid, filepath) "path": filepath,
if err != nil {
err = hcserror.Errorf(err, title, "path=%s", filepath)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title + " - succeeded") err = grantVmAccess(vmid, filepath)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
return nil return nil
} }

View File

@@ -1,7 +1,6 @@
package wclayer package wclayer
import ( import (
"errors"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@@ -16,9 +15,21 @@ import (
// that into a layer with the id layerId. Note that in order to correctly populate // that into a layer with the id layerId. Note that in order to correctly populate
// the layer and interperet the transport format, all parent layers must already // the layer and interperet the transport format, all parent layers must already
// be present on the system at the paths provided in parentLayerPaths. // be present on the system at the paths provided in parentLayerPaths.
func ImportLayer(path string, importFolderPath string, parentLayerPaths []string) error { func ImportLayer(path string, importFolderPath string, parentLayerPaths []string) (err error) {
title := "hcsshim::ImportLayer " title := "hcsshim::ImportLayer"
logrus.Debugf(title+"path %s folder %s", path, importFolderPath) fields := logrus.Fields{
"path": path,
"importFolderPath": importFolderPath,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
// Generate layer descriptors // Generate layer descriptors
layers, err := layerPathsToDescriptors(parentLayerPaths) layers, err := layerPathsToDescriptors(parentLayerPaths)
@@ -28,12 +39,8 @@ func ImportLayer(path string, importFolderPath string, parentLayerPaths []string
err = importLayer(&stdDriverInfo, path, importFolderPath, layers) err = importLayer(&stdDriverInfo, path, importFolderPath, layers)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "path=%s folder=%s", path, importFolderPath) return hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return err
} }
logrus.Debugf(title+"succeeded path=%s folder=%s", path, importFolderPath)
return nil return nil
} }
@@ -52,69 +59,6 @@ type LayerWriter interface {
Close() error Close() error
} }
// FilterLayerWriter provides an interface to write the contents of a layer to the file system.
type FilterLayerWriter struct {
context uintptr
}
// Add adds a file or directory to the layer. The file's parent directory must have already been added.
//
// name contains the file's relative path. fileInfo contains file times and file attributes; the rest
// of the file metadata and the file data must be written as a Win32 backup stream to the Write() method.
// winio.BackupStreamWriter can be used to facilitate this.
func (w *FilterLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) error {
if name[0] != '\\' {
name = `\` + name
}
err := importLayerNext(w.context, name, fileInfo)
if err != nil {
return hcserror.New(err, "ImportLayerNext", "")
}
return nil
}
// AddLink adds a hard link to the layer. The target of the link must have already been added.
func (w *FilterLayerWriter) AddLink(name string, target string) error {
return errors.New("hard links not yet supported")
}
// Remove removes a file from the layer. The file must have been present in the parent layer.
//
// name contains the file's relative path.
func (w *FilterLayerWriter) Remove(name string) error {
if name[0] != '\\' {
name = `\` + name
}
err := importLayerNext(w.context, name, nil)
if err != nil {
return hcserror.New(err, "ImportLayerNext", "")
}
return nil
}
// Write writes more backup stream data to the current file.
func (w *FilterLayerWriter) Write(b []byte) (int, error) {
err := importLayerWrite(w.context, b)
if err != nil {
err = hcserror.New(err, "ImportLayerWrite", "")
return 0, err
}
return len(b), err
}
// Close completes the layer write operation. The error must be checked to ensure that the
// operation was successful.
func (w *FilterLayerWriter) Close() (err error) {
if w.context != 0 {
err = importLayerEnd(w.context)
if err != nil {
err = hcserror.New(err, "ImportLayerEnd", "")
}
w.context = 0
}
return
}
type legacyLayerWriterWrapper struct { type legacyLayerWriterWrapper struct {
*legacyLayerWriter *legacyLayerWriter
path string path string
@@ -175,32 +119,17 @@ func NewLayerWriter(path string, parentLayerPaths []string) (LayerWriter, error)
}, nil }, nil
} }
if procImportLayerBegin.Find() != nil { importPath, err := ioutil.TempDir("", "hcs")
// The new layer reader is not available on this Windows build. Fall back to the
// legacy export code path.
importPath, err := ioutil.TempDir("", "hcs")
if err != nil {
return nil, err
}
w, err := newLegacyLayerWriter(importPath, parentLayerPaths, path)
if err != nil {
return nil, err
}
return &legacyLayerWriterWrapper{
legacyLayerWriter: w,
path: importPath,
parentLayerPaths: parentLayerPaths,
}, nil
}
layers, err := layerPathsToDescriptors(parentLayerPaths)
if err != nil { if err != nil {
return nil, err return nil, err
} }
w, err := newLegacyLayerWriter(importPath, parentLayerPaths, path)
w := &FilterLayerWriter{}
err = importLayerBegin(&stdDriverInfo, path, layers, &w.context)
if err != nil { if err != nil {
return nil, hcserror.New(err, "ImportLayerStart", "") return nil, err
} }
return w, nil return &legacyLayerWriterWrapper{
legacyLayerWriter: w,
path: importPath,
parentLayerPaths: parentLayerPaths,
}, nil
} }

View File

@@ -7,19 +7,27 @@ import (
// LayerExists will return true if a layer with the given id exists and is known // LayerExists will return true if a layer with the given id exists and is known
// to the system. // to the system.
func LayerExists(path string) (bool, error) { func LayerExists(path string) (_ bool, err error) {
title := "hcsshim::LayerExists " title := "hcsshim::LayerExists"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
// Call the procedure itself. // Call the procedure itself.
var exists uint32 var exists uint32
err := layerExists(&stdDriverInfo, path, &exists) err = layerExists(&stdDriverInfo, path, &exists)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path) return false, hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return false, err
} }
fields["layer-exists"] = exists != 0
logrus.Debugf(title+"succeeded path=%s exists=%d", path, exists)
return exists != 0, nil return exists != 0, nil
} }

View File

@@ -75,13 +75,13 @@ func layerPathsToDescriptors(parentLayerPaths []string) ([]WC_LAYER_DESCRIPTOR,
for i := 0; i < len(parentLayerPaths); i++ { for i := 0; i < len(parentLayerPaths); i++ {
g, err := LayerID(parentLayerPaths[i]) g, err := LayerID(parentLayerPaths[i])
if err != nil { if err != nil {
logrus.Debugf("Failed to convert name to guid %s", err) logrus.WithError(err).Debug("Failed to convert name to guid")
return nil, err return nil, err
} }
p, err := syscall.UTF16PtrFromString(parentLayerPaths[i]) p, err := syscall.UTF16PtrFromString(parentLayerPaths[i])
if err != nil { if err != nil {
logrus.Debugf("Failed conversion of parentLayerPath to pointer %s", err) logrus.WithError(err).Debug("Failed conversion of parentLayerPath to pointer")
return nil, err return nil, err
} }

View File

@@ -10,15 +10,25 @@ import (
// Host Compute Service, ensuring GUIDs generated with the same string are common // Host Compute Service, ensuring GUIDs generated with the same string are common
// across all clients. // across all clients.
func NameToGuid(name string) (id guid.GUID, err error) { func NameToGuid(name string) (id guid.GUID, err error) {
title := "hcsshim::NameToGuid " title := "hcsshim::NameToGuid"
fields := logrus.Fields{
"name": name,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
err = nameToGuid(name, &id) err = nameToGuid(name, &id)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "name=%s", name) err = hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return return
} }
fields["guid"] = id.String()
logrus.Debugf(title+"name:%s guid:%s", name, id.String())
return return
} }

View File

@@ -14,9 +14,20 @@ var prepareLayerLock sync.Mutex
// parent layers, and is necessary in order to view or interact with the layer // parent layers, and is necessary in order to view or interact with the layer
// as an actual filesystem (reading and writing files, creating directories, etc). // as an actual filesystem (reading and writing files, creating directories, etc).
// Disabling the filter must be done via UnprepareLayer. // Disabling the filter must be done via UnprepareLayer.
func PrepareLayer(path string, parentLayerPaths []string) error { func PrepareLayer(path string, parentLayerPaths []string) (err error) {
title := "hcsshim::PrepareLayer " title := "hcsshim::PrepareLayer"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
}
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
// Generate layer descriptors // Generate layer descriptors
layers, err := layerPathsToDescriptors(parentLayerPaths) layers, err := layerPathsToDescriptors(parentLayerPaths)
@@ -30,11 +41,7 @@ func PrepareLayer(path string, parentLayerPaths []string) error {
defer prepareLayerLock.Unlock() defer prepareLayerLock.Unlock()
err = prepareLayer(&stdDriverInfo, path, layers) err = prepareLayer(&stdDriverInfo, path, layers)
if err != nil { if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path) return hcserror.New(err, title+" - failed", "")
logrus.Error(err)
return err
} }
logrus.Debugf(title+"succeeded path=%s", path)
return nil return nil
} }

View File

@@ -7,17 +7,24 @@ import (
// UnprepareLayer disables the filesystem filter for the read-write layer with // UnprepareLayer disables the filesystem filter for the read-write layer with
// the given id. // the given id.
func UnprepareLayer(path string) error { func UnprepareLayer(path string) (err error) {
title := "hcsshim::UnprepareLayer " title := "hcsshim::UnprepareLayer"
logrus.Debugf(title+"path %s", path) fields := logrus.Fields{
"path": path,
err := unprepareLayer(&stdDriverInfo, path)
if err != nil {
err = hcserror.Errorf(err, title, "path=%s", path)
logrus.Error(err)
return err
} }
logrus.WithFields(fields).Debug(title)
defer func() {
if err != nil {
fields[logrus.ErrorKey] = err
logrus.WithFields(fields).Error(err)
} else {
logrus.WithFields(fields).Debug(title + " - succeeded")
}
}()
logrus.Debugf(title+"succeeded path=%s", path) err = unprepareLayer(&stdDriverInfo, path)
if err != nil {
return hcserror.New(err, title+" - failed", "")
}
return nil return nil
} }

View File

@@ -2,7 +2,7 @@ package wclayer
import "github.com/Microsoft/hcsshim/internal/guid" import "github.com/Microsoft/hcsshim/internal/guid"
//go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go -winio wclayer.go //go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go wclayer.go
//sys activateLayer(info *driverInfo, id string) (hr error) = vmcompute.ActivateLayer? //sys activateLayer(info *driverInfo, id string) (hr error) = vmcompute.ActivateLayer?
//sys copyLayer(info *driverInfo, srcId string, dstId string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CopyLayer? //sys copyLayer(info *driverInfo, srcId string, dstId string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CopyLayer?
@@ -22,16 +22,6 @@ import "github.com/Microsoft/hcsshim/internal/guid"
//sys processBaseImage(path string) (hr error) = vmcompute.ProcessBaseImage? //sys processBaseImage(path string) (hr error) = vmcompute.ProcessBaseImage?
//sys processUtilityImage(path string) (hr error) = vmcompute.ProcessUtilityImage? //sys processUtilityImage(path string) (hr error) = vmcompute.ProcessUtilityImage?
//sys importLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) = vmcompute.ImportLayerBegin?
//sys importLayerNext(context uintptr, fileName string, fileInfo *winio.FileBasicInfo) (hr error) = vmcompute.ImportLayerNext?
//sys importLayerWrite(context uintptr, buffer []byte) (hr error) = vmcompute.ImportLayerWrite?
//sys importLayerEnd(context uintptr) (hr error) = vmcompute.ImportLayerEnd?
//sys exportLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) = vmcompute.ExportLayerBegin?
//sys exportLayerNext(context uintptr, fileName **uint16, fileInfo *winio.FileBasicInfo, fileSize *int64, deleted *uint32) (hr error) = vmcompute.ExportLayerNext?
//sys exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) = vmcompute.ExportLayerRead?
//sys exportLayerEnd(context uintptr) (hr error) = vmcompute.ExportLayerEnd?
//sys grantVmAccess(vmid string, filepath string) (hr error) = vmcompute.GrantVmAccess? //sys grantVmAccess(vmid string, filepath string) (hr error) = vmcompute.GrantVmAccess?
type _guid = guid.GUID type _guid = guid.GUID

View File

@@ -1,4 +1,4 @@
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT // Code generated mksyscall_windows.exe DO NOT EDIT
package wclayer package wclayer
@@ -6,8 +6,6 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/Microsoft/go-winio"
"github.com/Microsoft/hcsshim/internal/interop"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@@ -58,14 +56,6 @@ var (
procUnprepareLayer = modvmcompute.NewProc("UnprepareLayer") procUnprepareLayer = modvmcompute.NewProc("UnprepareLayer")
procProcessBaseImage = modvmcompute.NewProc("ProcessBaseImage") procProcessBaseImage = modvmcompute.NewProc("ProcessBaseImage")
procProcessUtilityImage = modvmcompute.NewProc("ProcessUtilityImage") procProcessUtilityImage = modvmcompute.NewProc("ProcessUtilityImage")
procImportLayerBegin = modvmcompute.NewProc("ImportLayerBegin")
procImportLayerNext = modvmcompute.NewProc("ImportLayerNext")
procImportLayerWrite = modvmcompute.NewProc("ImportLayerWrite")
procImportLayerEnd = modvmcompute.NewProc("ImportLayerEnd")
procExportLayerBegin = modvmcompute.NewProc("ExportLayerBegin")
procExportLayerNext = modvmcompute.NewProc("ExportLayerNext")
procExportLayerRead = modvmcompute.NewProc("ExportLayerRead")
procExportLayerEnd = modvmcompute.NewProc("ExportLayerEnd")
procGrantVmAccess = modvmcompute.NewProc("GrantVmAccess") procGrantVmAccess = modvmcompute.NewProc("GrantVmAccess")
) )
@@ -84,7 +74,10 @@ func _activateLayer(info *driverInfo, id *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procActivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0) r0, _, _ := syscall.Syscall(procActivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -113,7 +106,10 @@ func _copyLayer(info *driverInfo, srcId *uint16, dstId *uint16, descriptors []WC
} }
r0, _, _ := syscall.Syscall6(procCopyLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(srcId)), uintptr(unsafe.Pointer(dstId)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0) r0, _, _ := syscall.Syscall6(procCopyLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(srcId)), uintptr(unsafe.Pointer(dstId)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -138,7 +134,10 @@ func _createLayer(info *driverInfo, id *uint16, parent *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procCreateLayer.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent))) r0, _, _ := syscall.Syscall(procCreateLayer.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -162,7 +161,10 @@ func _createSandboxLayer(info *driverInfo, id *uint16, parent uintptr, descripto
} }
r0, _, _ := syscall.Syscall6(procCreateSandboxLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(parent), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0) r0, _, _ := syscall.Syscall6(procCreateSandboxLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(parent), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -182,7 +184,10 @@ func _expandSandboxSize(info *driverInfo, id *uint16, size uint64) (hr error) {
} }
r0, _, _ := syscall.Syscall(procExpandSandboxSize.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(size)) r0, _, _ := syscall.Syscall(procExpandSandboxSize.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(size))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -202,7 +207,10 @@ func _deactivateLayer(info *driverInfo, id *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procDeactivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0) r0, _, _ := syscall.Syscall(procDeactivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -222,7 +230,10 @@ func _destroyLayer(info *driverInfo, id *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procDestroyLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0) r0, _, _ := syscall.Syscall(procDestroyLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -251,7 +262,10 @@ func _exportLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_L
} }
r0, _, _ := syscall.Syscall6(procExportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0) r0, _, _ := syscall.Syscall6(procExportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -271,7 +285,10 @@ func _getLayerMountPath(info *driverInfo, id *uint16, length *uintptr, buffer *u
} }
r0, _, _ := syscall.Syscall6(procGetLayerMountPath.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(length)), uintptr(unsafe.Pointer(buffer)), 0, 0) r0, _, _ := syscall.Syscall6(procGetLayerMountPath.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(length)), uintptr(unsafe.Pointer(buffer)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -282,7 +299,10 @@ func getBaseImages(buffer **uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procGetBaseImages.Addr(), 1, uintptr(unsafe.Pointer(buffer)), 0, 0) r0, _, _ := syscall.Syscall(procGetBaseImages.Addr(), 1, uintptr(unsafe.Pointer(buffer)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -311,7 +331,10 @@ func _importLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_L
} }
r0, _, _ := syscall.Syscall6(procImportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0) r0, _, _ := syscall.Syscall6(procImportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -331,7 +354,10 @@ func _layerExists(info *driverInfo, id *uint16, exists *uint32) (hr error) {
} }
r0, _, _ := syscall.Syscall(procLayerExists.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(exists))) r0, _, _ := syscall.Syscall(procLayerExists.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(exists)))
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -351,7 +377,10 @@ func _nameToGuid(name *uint16, guid *_guid) (hr error) {
} }
r0, _, _ := syscall.Syscall(procNameToGuid.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(guid)), 0) r0, _, _ := syscall.Syscall(procNameToGuid.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(guid)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -375,7 +404,10 @@ func _prepareLayer(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPT
} }
r0, _, _ := syscall.Syscall6(procPrepareLayer.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0, 0) r0, _, _ := syscall.Syscall6(procPrepareLayer.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -395,7 +427,10 @@ func _unprepareLayer(info *driverInfo, id *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procUnprepareLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0) r0, _, _ := syscall.Syscall(procUnprepareLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -415,7 +450,10 @@ func _processBaseImage(path *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procProcessBaseImage.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) r0, _, _ := syscall.Syscall(procProcessBaseImage.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }
@@ -435,138 +473,10 @@ func _processUtilityImage(path *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procProcessUtilityImage.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0) r0, _, _ := syscall.Syscall(procProcessUtilityImage.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
} r0 &= 0xffff
return }
} hr = syscall.Errno(r0)
func importLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(id)
if hr != nil {
return
}
return _importLayerBegin(info, _p0, descriptors, context)
}
func _importLayerBegin(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
var _p1 *WC_LAYER_DESCRIPTOR
if len(descriptors) > 0 {
_p1 = &descriptors[0]
}
if hr = procImportLayerBegin.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall6(procImportLayerBegin.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), uintptr(unsafe.Pointer(context)), 0)
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func importLayerNext(context uintptr, fileName string, fileInfo *winio.FileBasicInfo) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(fileName)
if hr != nil {
return
}
return _importLayerNext(context, _p0, fileInfo)
}
func _importLayerNext(context uintptr, fileName *uint16, fileInfo *winio.FileBasicInfo) (hr error) {
if hr = procImportLayerNext.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procImportLayerNext.Addr(), 3, uintptr(context), uintptr(unsafe.Pointer(fileName)), uintptr(unsafe.Pointer(fileInfo)))
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func importLayerWrite(context uintptr, buffer []byte) (hr error) {
var _p0 *byte
if len(buffer) > 0 {
_p0 = &buffer[0]
}
if hr = procImportLayerWrite.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procImportLayerWrite.Addr(), 3, uintptr(context), uintptr(unsafe.Pointer(_p0)), uintptr(len(buffer)))
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func importLayerEnd(context uintptr) (hr error) {
if hr = procImportLayerEnd.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procImportLayerEnd.Addr(), 1, uintptr(context), 0, 0)
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func exportLayerBegin(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(id)
if hr != nil {
return
}
return _exportLayerBegin(info, _p0, descriptors, context)
}
func _exportLayerBegin(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPTOR, context *uintptr) (hr error) {
var _p1 *WC_LAYER_DESCRIPTOR
if len(descriptors) > 0 {
_p1 = &descriptors[0]
}
if hr = procExportLayerBegin.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall6(procExportLayerBegin.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), uintptr(unsafe.Pointer(context)), 0)
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func exportLayerNext(context uintptr, fileName **uint16, fileInfo *winio.FileBasicInfo, fileSize *int64, deleted *uint32) (hr error) {
if hr = procExportLayerNext.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall6(procExportLayerNext.Addr(), 5, uintptr(context), uintptr(unsafe.Pointer(fileName)), uintptr(unsafe.Pointer(fileInfo)), uintptr(unsafe.Pointer(fileSize)), uintptr(unsafe.Pointer(deleted)), 0)
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func exportLayerRead(context uintptr, buffer []byte, bytesRead *uint32) (hr error) {
var _p0 *byte
if len(buffer) > 0 {
_p0 = &buffer[0]
}
if hr = procExportLayerRead.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall6(procExportLayerRead.Addr(), 4, uintptr(context), uintptr(unsafe.Pointer(_p0)), uintptr(len(buffer)), uintptr(unsafe.Pointer(bytesRead)), 0, 0)
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
}
return
}
func exportLayerEnd(context uintptr) (hr error) {
if hr = procExportLayerEnd.Find(); hr != nil {
return
}
r0, _, _ := syscall.Syscall(procExportLayerEnd.Addr(), 1, uintptr(context), 0, 0)
if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0)
} }
return return
} }
@@ -591,7 +501,10 @@ func _grantVmAccess(vmid *uint16, filepath *uint16) (hr error) {
} }
r0, _, _ := syscall.Syscall(procGrantVmAccess.Addr(), 2, uintptr(unsafe.Pointer(vmid)), uintptr(unsafe.Pointer(filepath)), 0) r0, _, _ := syscall.Syscall(procGrantVmAccess.Addr(), 2, uintptr(unsafe.Pointer(vmid)), uintptr(unsafe.Pointer(filepath)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }

View File

@@ -5,7 +5,6 @@ import (
"path/filepath" "path/filepath"
"github.com/Microsoft/hcsshim/internal/guid" "github.com/Microsoft/hcsshim/internal/guid"
"github.com/Microsoft/hcsshim/internal/wclayer" "github.com/Microsoft/hcsshim/internal/wclayer"
) )
@@ -74,9 +73,6 @@ type DriverInfo struct {
HomeDir string HomeDir string
} }
type FilterLayerReader = wclayer.FilterLayerReader
type FilterLayerWriter = wclayer.FilterLayerWriter
type GUID [16]byte type GUID [16]byte
func NameToGuid(name string) (id GUID, err error) { func NameToGuid(name string) (id GUID, err error) {

View File

@@ -300,7 +300,10 @@ func (r *Rets) SetErrorCode() string {
%s = %sErrno(r0) %s = %sErrno(r0)
}` }`
const hrCode = `if int32(r0) < 0 { const hrCode = `if int32(r0) < 0 {
%s = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
%s = %sErrno(r0)
}` }`
if r.Name == "" && !r.ReturnsError { if r.Name == "" && !r.ReturnsError {
return "" return ""
@@ -310,7 +313,7 @@ func (r *Rets) SetErrorCode() string {
} }
if r.Type == "error" { if r.Type == "error" {
if r.Name == "hr" { if r.Name == "hr" {
return fmt.Sprintf(hrCode, r.Name) return fmt.Sprintf(hrCode, r.Name, syscalldot())
} else { } else {
return fmt.Sprintf(code, r.Name, syscalldot()) return fmt.Sprintf(code, r.Name, syscalldot())
} }
@@ -773,7 +776,6 @@ func (src *Source) Generate(w io.Writer) error {
src.ExternalImport("golang.org/x/sys/windows") src.ExternalImport("golang.org/x/sys/windows")
} }
} }
src.ExternalImport("github.com/Microsoft/hcsshim/internal/interop")
if *winio { if *winio {
src.ExternalImport("github.com/Microsoft/go-winio") src.ExternalImport("github.com/Microsoft/go-winio")
} }
@@ -788,6 +790,9 @@ func (src *Source) Generate(w io.Writer) error {
if !*systemDLL { if !*systemDLL {
return syscalldot() + "NewLazyDLL(" + arg + ")" return syscalldot() + "NewLazyDLL(" + arg + ")"
} }
if strings.HasPrefix(dll, "api_") || strings.HasPrefix(dll, "ext_") {
arg = strings.Replace(arg, "_", "-", -1)
}
switch pkgtype { switch pkgtype {
case pkgStd: case pkgStd:
return syscalldot() + "NewLazyDLL(sysdll.Add(" + arg + "))" return syscalldot() + "NewLazyDLL(sysdll.Add(" + arg + "))"
@@ -847,7 +852,7 @@ func main() {
// TODO: use println instead to print in the following template // TODO: use println instead to print in the following template
const srcTemplate = ` const srcTemplate = `
{{define "main"}}// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT {{define "main"}}// Code generated mksyscall_windows.exe DO NOT EDIT
package {{packagename}} package {{packagename}}

View File

@@ -1,4 +1,4 @@
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT // Code generated mksyscall_windows.exe DO NOT EDIT
package hcsshim package hcsshim
@@ -6,7 +6,6 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
"github.com/Microsoft/hcsshim/internal/interop"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@@ -46,7 +45,10 @@ var (
func SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) { func SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) {
r0, _, _ := syscall.Syscall(procSetCurrentThreadCompartmentId.Addr(), 1, uintptr(compartmentId), 0, 0) r0, _, _ := syscall.Syscall(procSetCurrentThreadCompartmentId.Addr(), 1, uintptr(compartmentId), 0, 0)
if int32(r0) < 0 { if int32(r0) < 0 {
hr = interop.Win32FromHresult(r0) if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff
}
hr = syscall.Errno(r0)
} }
return return
} }

View File

@@ -299,7 +299,7 @@ func sortQuery(u *url.URL) {
if len(q) > 0 { if len(q) > 0 {
arKeys := make([]string, len(q)) arKeys := make([]string, len(q))
i := 0 i := 0
for k, _ := range q { for k := range q {
arKeys[i] = k arKeys[i] = k
i++ i++
} }

116
vendor/github.com/containerd/fifo/raw.go generated vendored Normal file
View File

@@ -0,0 +1,116 @@
// +build go1.12
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fifo
import (
"syscall"
"github.com/pkg/errors"
)
// SyscallConn provides raw access to the fifo's underlying filedescrptor.
// See syscall.Conn for guarentees provided by this interface.
func (f *fifo) SyscallConn() (syscall.RawConn, error) {
// deterministic check for closed
select {
case <-f.closed:
return nil, errors.New("fifo closed")
default:
}
select {
case <-f.closed:
return nil, errors.New("fifo closed")
case <-f.opened:
return f.file.SyscallConn()
default:
}
// Not opened and not closed, this means open is non-blocking AND it's not open yet
// Use rawConn to deal with non-blocking open.
rc := &rawConn{f: f, ready: make(chan struct{})}
go func() {
select {
case <-f.closed:
return
case <-f.opened:
rc.raw, rc.err = f.file.SyscallConn()
close(rc.ready)
}
}()
return rc, nil
}
type rawConn struct {
f *fifo
ready chan struct{}
raw syscall.RawConn
err error
}
func (r *rawConn) Control(f func(fd uintptr)) error {
select {
case <-r.f.closed:
return errors.New("control of closed fifo")
case <-r.ready:
}
if r.err != nil {
return r.err
}
return r.raw.Control(f)
}
func (r *rawConn) Read(f func(fd uintptr) (done bool)) error {
if r.f.flag&syscall.O_WRONLY > 0 {
return errors.New("reading from write-only fifo")
}
select {
case <-r.f.closed:
return errors.New("reading of a closed fifo")
case <-r.ready:
}
if r.err != nil {
return r.err
}
return r.raw.Read(f)
}
func (r *rawConn) Write(f func(fd uintptr) (done bool)) error {
if r.f.flag&(syscall.O_WRONLY|syscall.O_RDWR) == 0 {
return errors.New("writing to read-only fifo")
}
select {
case <-r.f.closed:
return errors.New("writing to a closed fifo")
case <-r.ready:
}
if r.err != nil {
return r.err
}
return r.raw.Write(f)
}

View File

@@ -24,6 +24,7 @@ import (
"strings" "strings"
"sync" "sync"
"syscall" "syscall"
"time"
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
"github.com/pkg/errors" "github.com/pkg/errors"
@@ -86,6 +87,10 @@ func (c *Client) Call(ctx context.Context, service, method string, req, resp int
cresp = &Response{} cresp = &Response{}
) )
if dl, ok := ctx.Deadline(); ok {
creq.TimeoutNano = dl.Sub(time.Now()).Nanoseconds()
}
if err := c.dispatch(ctx, creq, cresp); err != nil { if err := c.dispatch(ctx, creq, cresp); err != nil {
return err return err
} }
@@ -104,6 +109,7 @@ func (c *Client) Call(ctx context.Context, service, method string, req, resp int
func (c *Client) dispatch(ctx context.Context, req *Request, resp *Response) error { func (c *Client) dispatch(ctx context.Context, req *Request, resp *Response) error {
errs := make(chan error, 1) errs := make(chan error, 1)
call := &callRequest{ call := &callRequest{
ctx: ctx,
req: req, req: req,
resp: resp, resp: resp,
errs: errs, errs: errs,
@@ -249,7 +255,7 @@ func (c *Client) recv(resp *Response, msg *message) error {
} }
if msg.Type != messageTypeResponse { if msg.Type != messageTypeResponse {
return errors.New("unkown message type received") return errors.New("unknown message type received")
} }
defer c.channel.putmbuf(msg.p) defer c.channel.putmbuf(msg.p)

View File

@@ -414,6 +414,9 @@ func (c *serverConn) run(sctx context.Context) {
case request := <-requests: case request := <-requests:
active++ active++
go func(id uint32) { go func(id uint32) {
ctx, cancel := getRequestContext(ctx, request.req)
defer cancel()
p, status := c.server.services.call(ctx, request.req.Service, request.req.Method, request.req.Payload) p, status := c.server.services.call(ctx, request.req.Service, request.req.Method, request.req.Payload)
resp := &Response{ resp := &Response{
Status: status.Proto(), Status: status.Proto(),
@@ -454,3 +457,15 @@ func (c *serverConn) run(sctx context.Context) {
} }
} }
} }
var noopFunc = func() {}
func getRequestContext(ctx context.Context, req *Request) (retCtx context.Context, cancel func()) {
cancel = noopFunc
if req.TimeoutNano == 0 {
return ctx, cancel
}
ctx, cancel = context.WithTimeout(ctx, time.Duration(req.TimeoutNano))
return ctx, cancel
}

View File

@@ -76,7 +76,7 @@ func (s *serviceSet) dispatch(ctx context.Context, serviceName, methodName strin
switch v := obj.(type) { switch v := obj.(type) {
case proto.Message: case proto.Message:
if err := proto.Unmarshal(p, v); err != nil { if err := proto.Unmarshal(p, v); err != nil {
return status.Errorf(codes.Internal, "ttrpc: error unmarshaling payload: %v", err.Error()) return status.Errorf(codes.Internal, "ttrpc: error unmarshalling payload: %v", err.Error())
} }
default: default:
return status.Errorf(codes.Internal, "ttrpc: error unsupported request type: %T", v) return status.Errorf(codes.Internal, "ttrpc: error unsupported request type: %T", v)

View File

@@ -23,9 +23,10 @@ import (
) )
type Request struct { type Request struct {
Service string `protobuf:"bytes,1,opt,name=service,proto3"` Service string `protobuf:"bytes,1,opt,name=service,proto3"`
Method string `protobuf:"bytes,2,opt,name=method,proto3"` Method string `protobuf:"bytes,2,opt,name=method,proto3"`
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3"` Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3"`
TimeoutNano int64 `protobuf:"varint,4,opt,name=timeout_nano,proto3"`
} }
func (r *Request) Reset() { *r = Request{} } func (r *Request) Reset() { *r = Request{} }

83
vendor/github.com/containerd/typeurl/doc.go generated vendored Normal file
View File

@@ -0,0 +1,83 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package typeurl
// Package typeurl assists with managing the registration, marshaling, and
// unmarshaling of types encoded as protobuf.Any.
//
// A protobuf.Any is a proto message that can contain any arbitrary data. It
// consists of two components, a TypeUrl and a Value, and its proto definition
// looks like this:
//
// message Any {
// string type_url = 1;
// bytes value = 2;
// }
//
// The TypeUrl is used to distinguish the contents from other proto.Any
// messages. This typeurl library manages these URLs to enable automagic
// marshaling and unmarshaling of the contents.
//
// For example, consider this go struct:
//
// type Foo struct {
// Field1 string
// Field2 string
// }
//
// To use typeurl, types must first be registered. This is typically done in
// the init function
//
// func init() {
// typeurl.Register(&Foo{}, "Foo")
// }
//
// This will register the type Foo with the url path "Foo". The arguments to
// Register are variadic, and are used to construct a url path. Consider this
// example, from the github.com/containerd/containerd/client package:
//
// func init() {
// const prefix = "types.containerd.io"
// // register TypeUrls for commonly marshaled external types
// major := strconv.Itoa(specs.VersionMajor)
// typeurl.Register(&specs.Spec{}, prefix, "opencontainers/runtime-spec", major, "Spec")
// // this function has more Register calls, which are elided.
// }
//
// This registers several types under a more complex url, which ends up mapping
// to `types.containerd.io/opencontainers/runtime-spec/1/Spec` (or some other
// value for major).
//
// Once a type is registered, it can be marshaled to a proto.Any message simply
// by calling `MarshalAny`, like this:
//
// foo := &Foo{Field1: "value1", Field2: "value2"}
// anyFoo, err := typeurl.MarshalAny(foo)
//
// MarshalAny will resolve the correct URL for the type. If the type in
// question implements the proto.Message interface, then it will be marshaled
// as a proto message. Otherwise, it will be marshaled as json. This means that
// typeurl will work on any arbitrary data, whether or not it has a proto
// definition, as long as it can be serialized to json.
//
// To unmarshal, the process is simply inverse:
//
// iface, err := typeurl.UnmarshalAny(anyFoo)
// foo := iface.(*Foo)
//
// The correct type is automatically chosen from the type registry, and the
// returned interface can be cast straight to that type.

View File

@@ -78,7 +78,10 @@ func Is(any *types.Any, v interface{}) bool {
return any.TypeUrl == url return any.TypeUrl == url
} }
// MarshalAny marshals the value v into an any with the correct TypeUrl // MarshalAny marshals the value v into an any with the correct TypeUrl.
// If the provided object is already a proto.Any message, then it will be
// returned verbatim. If it is of type proto.Message, it will be marshaled as a
// protocol buffer. Otherwise, the object will be marshaled to json.
func MarshalAny(v interface{}) (*types.Any, error) { func MarshalAny(v interface{}) (*types.Any, error) {
var marshal func(v interface{}) ([]byte, error) var marshal func(v interface{}) ([]byte, error)
switch t := v.(type) { switch t := v.(type) {

View File

@@ -143,7 +143,7 @@ func NewUserConnection() (*Conn, error) {
func NewSystemdConnection() (*Conn, error) { func NewSystemdConnection() (*Conn, error) {
return NewConnection(func() (*dbus.Conn, error) { return NewConnection(func() (*dbus.Conn, error) {
// We skip Hello when talking directly to systemd. // We skip Hello when talking directly to systemd.
return dbusAuthConnection(func() (*dbus.Conn, error) { return dbusAuthConnection(func(opts ...dbus.ConnOption) (*dbus.Conn, error) {
return dbus.Dial("unix:path=/run/systemd/private") return dbus.Dial("unix:path=/run/systemd/private")
}) })
}) })
@@ -201,7 +201,7 @@ func (c *Conn) GetManagerProperty(prop string) (string, error) {
return variant.String(), nil return variant.String(), nil
} }
func dbusAuthConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { func dbusAuthConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) {
conn, err := createBus() conn, err := createBus()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -221,7 +221,7 @@ func dbusAuthConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error
return conn, nil return conn, nil
} }
func dbusAuthHelloConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { func dbusAuthHelloConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) {
conn, err := dbusAuthConnection(createBus) conn, err := dbusAuthConnection(createBus)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -291,6 +291,8 @@ func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) {
// ListUnits returns an array with all currently loaded units. Note that // ListUnits returns an array with all currently loaded units. Note that
// units may be known by multiple names at the same time, and hence there might // units may be known by multiple names at the same time, and hence there might
// be more unit names loaded than actual units behind them. // be more unit names loaded than actual units behind them.
// Also note that a unit is only loaded if it is active and/or enabled.
// Units that are both disabled and inactive will thus not be returned.
func (c *Conn) ListUnits() ([]UnitStatus, error) { func (c *Conn) ListUnits() ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store) return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store)
} }

View File

@@ -2,7 +2,7 @@ ISC License
Copyright (c) 2012-2016 Dave Collins <dave@davec.name> Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
Permission to use, copy, modify, and distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies. copyright notice and this permission notice appear in all copies.

View File

@@ -16,7 +16,9 @@
// when the code is not running on Google App Engine, compiled by GopherJS, and // when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe" // "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used. // tag is deprecated and thus should not be used.
// +build !js,!appengine,!safe,!disableunsafe // Go versions prior to 1.4 are disabled because they use a different layout
// for interfaces which make the implementation of unsafeReflectValue more complex.
// +build !js,!appengine,!safe,!disableunsafe,go1.4
package spew package spew
@@ -34,80 +36,49 @@ const (
ptrSize = unsafe.Sizeof((*byte)(nil)) ptrSize = unsafe.Sizeof((*byte)(nil))
) )
var ( type flag uintptr
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
// internal reflect.Value fields. These values are valid before golang
// commit ecccf07e7f9d which changed the format. The are also valid
// after commit 82f48826c6c7 which changed the format again to mirror
// the original format. Code in the init function updates these offsets
// as necessary.
offsetPtr = uintptr(ptrSize)
offsetScalar = uintptr(0)
offsetFlag = uintptr(ptrSize * 2)
// flagKindWidth and flagKindShift indicate various bits that the var (
// reflect package uses internally to track kind information. // flagRO indicates whether the value field of a reflect.Value
// // is read-only.
// flagRO indicates whether or not the value field of a reflect.Value is flagRO flag
// read-only.
// // flagAddr indicates whether the address of the reflect.Value's
// flagIndir indicates whether the value field of a reflect.Value is // value may be taken.
// the actual data or a pointer to the data. flagAddr flag
//
// These values are valid before golang commit 90a7c3c86944 which
// changed their positions. Code in the init function updates these
// flags as necessary.
flagKindWidth = uintptr(5)
flagKindShift = uintptr(flagKindWidth - 1)
flagRO = uintptr(1 << 0)
flagIndir = uintptr(1 << 1)
) )
func init() { // flagKindMask holds the bits that make up the kind
// Older versions of reflect.Value stored small integers directly in the // part of the flags field. In all the supported versions,
// ptr field (which is named val in the older versions). Versions // it is in the lower 5 bits.
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named const flagKindMask = flag(0x1f)
// scalar for this purpose which unfortunately came before the flag
// field, so the offset of the flag field is different for those
// versions.
//
// This code constructs a new reflect.Value from a known small integer
// and checks if the size of the reflect.Value struct indicates it has
// the scalar field. When it does, the offsets are updated accordingly.
vv := reflect.ValueOf(0xf00)
if unsafe.Sizeof(vv) == (ptrSize * 4) {
offsetScalar = ptrSize * 2
offsetFlag = ptrSize * 3
}
// Commit 90a7c3c86944 changed the flag positions such that the low // Different versions of Go have used different
// order bits are the kind. This code extracts the kind from the flags // bit layouts for the flags type. This table
// field and ensures it's the correct type. When it's not, the flag // records the known combinations.
// order has been changed to the newer format, so the flags are updated var okFlags = []struct {
// accordingly. ro, addr flag
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag) }{{
upfv := *(*uintptr)(upf) // From Go 1.4 to 1.5
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift) ro: 1 << 5,
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) { addr: 1 << 7,
flagKindShift = 0 }, {
flagRO = 1 << 5 // Up to Go tip.
flagIndir = 1 << 6 ro: 1<<5 | 1<<6,
addr: 1 << 8,
}}
// Commit adf9b30e5594 modified the flags to separate the var flagValOffset = func() uintptr {
// flagRO flag into two bits which specifies whether or not the field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
// field is embedded. This causes flagIndir to move over a bit if !ok {
// and means that flagRO is the combination of either of the panic("reflect.Value has no flag field")
// original flagRO bit and the new bit.
//
// This code detects the change by extracting what used to be
// the indirect bit to ensure it's set. When it's not, the flag
// order has been changed to the newer format, so the flags are
// updated accordingly.
if upfv&flagIndir == 0 {
flagRO = 3 << 5
flagIndir = 1 << 7
}
} }
return field.Offset
}()
// flagField returns a pointer to the flag field of a reflect.Value.
func flagField(v *reflect.Value) *flag {
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
} }
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses // unsafeReflectValue converts the passed reflect.Value into a one that bypasses
@@ -119,34 +90,56 @@ func init() {
// This allows us to check for implementations of the Stringer and error // This allows us to check for implementations of the Stringer and error
// interfaces to be used for pretty printing ordinarily unaddressable and // interfaces to be used for pretty printing ordinarily unaddressable and
// inaccessible values such as unexported struct fields. // inaccessible values such as unexported struct fields.
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) { func unsafeReflectValue(v reflect.Value) reflect.Value {
indirects := 1 if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
vt := v.Type() return v
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) }
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag)) flagFieldPtr := flagField(&v)
if rvf&flagIndir != 0 { *flagFieldPtr &^= flagRO
vt = reflect.PtrTo(v.Type()) *flagFieldPtr |= flagAddr
indirects++ return v
} else if offsetScalar != 0 { }
// The value is in the scalar field when it's not one of the
// reference types. // Sanity checks against future reflect package changes
switch vt.Kind() { // to the type or semantics of the Value.flag field.
case reflect.Uintptr: func init() {
case reflect.Chan: field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
case reflect.Func: if !ok {
case reflect.Map: panic("reflect.Value has no flag field")
case reflect.Ptr: }
case reflect.UnsafePointer: if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
default: panic("reflect.Value flag field has changed kind")
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + }
offsetScalar) type t0 int
var t struct {
A t0
// t0 will have flagEmbedRO set.
t0
// a will have flagStickyRO set
a t0
}
vA := reflect.ValueOf(t).FieldByName("A")
va := reflect.ValueOf(t).FieldByName("a")
vt0 := reflect.ValueOf(t).FieldByName("t0")
// Infer flagRO from the difference between the flags
// for the (otherwise identical) fields in t.
flagPublic := *flagField(&vA)
flagWithRO := *flagField(&va) | *flagField(&vt0)
flagRO = flagPublic ^ flagWithRO
// Infer flagAddr from the difference between a value
// taken from a pointer and not.
vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
flagNoPtr := *flagField(&vA)
flagPtr := *flagField(&vPtrA)
flagAddr = flagNoPtr ^ flagPtr
// Check that the inferred flags tally with one of the known versions.
for _, f := range okFlags {
if flagRO == f.ro && flagAddr == f.addr {
return
} }
} }
panic("reflect.Value read-only flag has changed semantics")
pv := reflect.NewAt(vt, upv)
rv = pv
for i := 0; i < indirects; i++ {
rv = rv.Elem()
}
return rv
} }

View File

@@ -16,7 +16,7 @@
// when the code is running on Google App Engine, compiled by GopherJS, or // when the code is running on Google App Engine, compiled by GopherJS, or
// "-tags safe" is added to the go build command line. The "disableunsafe" // "-tags safe" is added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used. // tag is deprecated and thus should not be used.
// +build js appengine safe disableunsafe // +build js appengine safe disableunsafe !go1.4
package spew package spew

View File

@@ -180,7 +180,7 @@ func printComplex(w io.Writer, c complex128, floatPrecision int) {
w.Write(closeParenBytes) w.Write(closeParenBytes)
} }
// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x' // printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
// prefix to Writer w. // prefix to Writer w.
func printHexPtr(w io.Writer, p uintptr) { func printHexPtr(w io.Writer, p uintptr) {
// Null pointer. // Null pointer.

View File

@@ -35,16 +35,16 @@ var (
// cCharRE is a regular expression that matches a cgo char. // cCharRE is a regular expression that matches a cgo char.
// It is used to detect character arrays to hexdump them. // It is used to detect character arrays to hexdump them.
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$") cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
// cUnsignedCharRE is a regular expression that matches a cgo unsigned // cUnsignedCharRE is a regular expression that matches a cgo unsigned
// char. It is used to detect unsigned character arrays to hexdump // char. It is used to detect unsigned character arrays to hexdump
// them. // them.
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$") cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
// cUint8tCharRE is a regular expression that matches a cgo uint8_t. // cUint8tCharRE is a regular expression that matches a cgo uint8_t.
// It is used to detect uint8_t arrays to hexdump them. // It is used to detect uint8_t arrays to hexdump them.
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$") cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
) )
// dumpState contains information about the state of a dump operation. // dumpState contains information about the state of a dump operation.
@@ -143,10 +143,10 @@ func (d *dumpState) dumpPtr(v reflect.Value) {
// Display dereferenced value. // Display dereferenced value.
d.w.Write(openParenBytes) d.w.Write(openParenBytes)
switch { switch {
case nilFound == true: case nilFound:
d.w.Write(nilAngleBytes) d.w.Write(nilAngleBytes)
case cycleFound == true: case cycleFound:
d.w.Write(circularBytes) d.w.Write(circularBytes)
default: default:

View File

@@ -182,10 +182,10 @@ func (f *formatState) formatPtr(v reflect.Value) {
// Display dereferenced value. // Display dereferenced value.
switch { switch {
case nilFound == true: case nilFound:
f.fs.Write(nilAngleBytes) f.fs.Write(nilAngleBytes)
case cycleFound == true: case cycleFound:
f.fs.Write(circularShortBytes) f.fs.Write(circularShortBytes)
default: default:

View File

@@ -104,6 +104,38 @@ func (p *patternAnalysis) addSchemaPattern(key, pattern string) {
p.addPattern(key, pattern) p.addPattern(key, pattern)
} }
type enumAnalysis struct {
parameters map[string][]interface{}
headers map[string][]interface{}
items map[string][]interface{}
schemas map[string][]interface{}
allEnums map[string][]interface{}
}
func (p *enumAnalysis) addEnum(key string, enum []interface{}) {
p.allEnums["#"+key] = enum
}
func (p *enumAnalysis) addParameterEnum(key string, enum []interface{}) {
p.parameters["#"+key] = enum
p.addEnum(key, enum)
}
func (p *enumAnalysis) addHeaderEnum(key string, enum []interface{}) {
p.headers["#"+key] = enum
p.addEnum(key, enum)
}
func (p *enumAnalysis) addItemsEnum(key string, enum []interface{}) {
p.items["#"+key] = enum
p.addEnum(key, enum)
}
func (p *enumAnalysis) addSchemaEnum(key string, enum []interface{}) {
p.schemas["#"+key] = enum
p.addEnum(key, enum)
}
// New takes a swagger spec object and returns an analyzed spec document. // New takes a swagger spec object and returns an analyzed spec document.
// The analyzed document contains a number of indices that make it easier to // The analyzed document contains a number of indices that make it easier to
// reason about semantics of a swagger specification for use in code generation // reason about semantics of a swagger specification for use in code generation
@@ -134,6 +166,13 @@ func New(doc *spec.Swagger) *Spec {
schemas: make(map[string]string, 150), schemas: make(map[string]string, 150),
allPatterns: make(map[string]string, 150), allPatterns: make(map[string]string, 150),
}, },
enums: enumAnalysis{
parameters: make(map[string][]interface{}, 150),
headers: make(map[string][]interface{}, 150),
items: make(map[string][]interface{}, 150),
schemas: make(map[string][]interface{}, 150),
allEnums: make(map[string][]interface{}, 150),
},
} }
a.initialize() a.initialize()
return a return a
@@ -149,6 +188,7 @@ type Spec struct {
operations map[string]map[string]*spec.Operation operations map[string]map[string]*spec.Operation
references referenceAnalysis references referenceAnalysis
patterns patternAnalysis patterns patternAnalysis
enums enumAnalysis
allSchemas map[string]SchemaRef allSchemas map[string]SchemaRef
allOfs map[string]SchemaRef allOfs map[string]SchemaRef
} }
@@ -173,6 +213,11 @@ func (s *Spec) reset() {
s.patterns.items = make(map[string]string, 150) s.patterns.items = make(map[string]string, 150)
s.patterns.schemas = make(map[string]string, 150) s.patterns.schemas = make(map[string]string, 150)
s.patterns.allPatterns = make(map[string]string, 150) s.patterns.allPatterns = make(map[string]string, 150)
s.enums.parameters = make(map[string][]interface{}, 150)
s.enums.headers = make(map[string][]interface{}, 150)
s.enums.items = make(map[string][]interface{}, 150)
s.enums.schemas = make(map[string][]interface{}, 150)
s.enums.allEnums = make(map[string][]interface{}, 150)
} }
func (s *Spec) reload() { func (s *Spec) reload() {
@@ -207,6 +252,9 @@ func (s *Spec) initialize() {
if parameter.Pattern != "" { if parameter.Pattern != "" {
s.patterns.addParameterPattern(refPref, parameter.Pattern) s.patterns.addParameterPattern(refPref, parameter.Pattern)
} }
if len(parameter.Enum) > 0 {
s.enums.addParameterEnum(refPref, parameter.Enum)
}
} }
for name, response := range s.spec.Responses { for name, response := range s.spec.Responses {
@@ -219,6 +267,9 @@ func (s *Spec) initialize() {
if v.Pattern != "" { if v.Pattern != "" {
s.patterns.addHeaderPattern(hRefPref, v.Pattern) s.patterns.addHeaderPattern(hRefPref, v.Pattern)
} }
if len(v.Enum) > 0 {
s.enums.addHeaderEnum(hRefPref, v.Enum)
}
} }
if response.Schema != nil { if response.Schema != nil {
s.analyzeSchema("schema", *response.Schema, refPref) s.analyzeSchema("schema", *response.Schema, refPref)
@@ -256,6 +307,9 @@ func (s *Spec) analyzeOperations(path string, pi *spec.PathItem) {
if param.Pattern != "" { if param.Pattern != "" {
s.patterns.addParameterPattern(refPref, param.Pattern) s.patterns.addParameterPattern(refPref, param.Pattern)
} }
if len(param.Enum) > 0 {
s.enums.addParameterEnum(refPref, param.Enum)
}
if param.Items != nil { if param.Items != nil {
s.analyzeItems("items", param.Items, refPref, "parameter") s.analyzeItems("items", param.Items, refPref, "parameter")
} }
@@ -277,6 +331,9 @@ func (s *Spec) analyzeItems(name string, items *spec.Items, prefix, location str
if items.Pattern != "" { if items.Pattern != "" {
s.patterns.addItemsPattern(refPref, items.Pattern) s.patterns.addItemsPattern(refPref, items.Pattern)
} }
if len(items.Enum) > 0 {
s.enums.addItemsEnum(refPref, items.Enum)
}
} }
func (s *Spec) analyzeOperation(method, path string, op *spec.Operation) { func (s *Spec) analyzeOperation(method, path string, op *spec.Operation) {
@@ -308,6 +365,9 @@ func (s *Spec) analyzeOperation(method, path string, op *spec.Operation) {
if param.Pattern != "" { if param.Pattern != "" {
s.patterns.addParameterPattern(refPref, param.Pattern) s.patterns.addParameterPattern(refPref, param.Pattern)
} }
if len(param.Enum) > 0 {
s.enums.addParameterEnum(refPref, param.Enum)
}
s.analyzeItems("items", param.Items, refPref, "parameter") s.analyzeItems("items", param.Items, refPref, "parameter")
if param.In == "body" && param.Schema != nil { if param.In == "body" && param.Schema != nil {
s.analyzeSchema("schema", *param.Schema, refPref) s.analyzeSchema("schema", *param.Schema, refPref)
@@ -341,6 +401,9 @@ func (s *Spec) analyzeOperation(method, path string, op *spec.Operation) {
if v.Pattern != "" { if v.Pattern != "" {
s.patterns.addHeaderPattern(hRefPref, v.Pattern) s.patterns.addHeaderPattern(hRefPref, v.Pattern)
} }
if len(v.Enum) > 0 {
s.enums.addHeaderEnum(hRefPref, v.Enum)
}
} }
if res.Schema != nil { if res.Schema != nil {
s.analyzeSchema("schema", *res.Schema, refPref) s.analyzeSchema("schema", *res.Schema, refPref)
@@ -366,6 +429,9 @@ func (s *Spec) analyzeSchema(name string, schema spec.Schema, prefix string) {
if schema.Pattern != "" { if schema.Pattern != "" {
s.patterns.addSchemaPattern(refURI, schema.Pattern) s.patterns.addSchemaPattern(refURI, schema.Pattern)
} }
if len(schema.Enum) > 0 {
s.enums.addSchemaEnum(refURI, schema.Enum)
}
for k, v := range schema.Definitions { for k, v := range schema.Definitions {
s.analyzeSchema(k, v, slashpath.Join(refURI, "definitions")) s.analyzeSchema(k, v, slashpath.Join(refURI, "definitions"))
@@ -861,6 +927,14 @@ func cloneStringMap(source map[string]string) map[string]string {
return res return res
} }
func cloneEnumMap(source map[string][]interface{}) map[string][]interface{} {
res := make(map[string][]interface{}, len(source))
for k, v := range source {
res[k] = v
}
return res
}
// ParameterPatterns returns all the patterns found in parameters // ParameterPatterns returns all the patterns found in parameters
// the map is cloned to avoid accidental changes // the map is cloned to avoid accidental changes
func (s *Spec) ParameterPatterns() map[string]string { func (s *Spec) ParameterPatterns() map[string]string {
@@ -890,3 +964,33 @@ func (s *Spec) SchemaPatterns() map[string]string {
func (s *Spec) AllPatterns() map[string]string { func (s *Spec) AllPatterns() map[string]string {
return cloneStringMap(s.patterns.allPatterns) return cloneStringMap(s.patterns.allPatterns)
} }
// ParameterEnums returns all the enums found in parameters
// the map is cloned to avoid accidental changes
func (s *Spec) ParameterEnums() map[string][]interface{} {
return cloneEnumMap(s.enums.parameters)
}
// HeaderEnums returns all the enums found in response headers
// the map is cloned to avoid accidental changes
func (s *Spec) HeaderEnums() map[string][]interface{} {
return cloneEnumMap(s.enums.headers)
}
// ItemsEnums returns all the enums found in simple array items
// the map is cloned to avoid accidental changes
func (s *Spec) ItemsEnums() map[string][]interface{} {
return cloneEnumMap(s.enums.items)
}
// SchemaEnums returns all the enums found in schemas
// the map is cloned to avoid accidental changes
func (s *Spec) SchemaEnums() map[string][]interface{} {
return cloneEnumMap(s.enums.schemas)
}
// AllEnums returns all the enums found in the spec
// the map is cloned to avoid accidental changes
func (s *Spec) AllEnums() map[string][]interface{} {
return cloneEnumMap(s.enums.allEnums)
}

View File

@@ -75,12 +75,14 @@ type newRef struct {
type context struct { type context struct {
newRefs map[string]*newRef newRefs map[string]*newRef
warnings []string warnings []string
resolved map[string]string
} }
func newContext() *context { func newContext() *context {
return &context{ return &context{
newRefs: make(map[string]*newRef, 150), newRefs: make(map[string]*newRef, 150),
warnings: make([]string, 0), warnings: make([]string, 0),
resolved: make(map[string]string, 50),
} }
} }
@@ -141,8 +143,9 @@ func Flatten(opts FlattenOpts) error {
opts.flattenContext = newContext() opts.flattenContext = newContext()
// recursively expand responses, parameters, path items and items in simple schemas // recursively expand responses, parameters, path items and items in simple schemas.
// TODO: we should not expand discriminated types // This simplifies the spec and leaves $ref only into schema objects.
//
if err := swspec.ExpandSpec(opts.Swagger(), opts.ExpandOpts(!opts.Expand)); err != nil { if err := swspec.ExpandSpec(opts.Swagger(), opts.ExpandOpts(!opts.Expand)); err != nil {
return err return err
} }
@@ -163,10 +166,13 @@ func Flatten(opts FlattenOpts) error {
opts.Spec.reload() // re-analyze opts.Spec.reload() // re-analyze
// at this point there are no other references left but schemas // at this point there are no other references left but schemas
if err := importExternalReferences(&opts); err != nil { for imported := false; !imported; {
return err var err error
if imported, err = importExternalReferences(&opts); err != nil {
return err
}
opts.Spec.reload() // re-analyze
} }
opts.Spec.reload() // re-analyze
if !opts.Minimal && !opts.Expand { if !opts.Minimal && !opts.Expand {
// full flattening: rewrite inline schemas (schemas that aren't simple types or arrays or maps) // full flattening: rewrite inline schemas (schemas that aren't simple types or arrays or maps)
@@ -176,7 +182,6 @@ func Flatten(opts FlattenOpts) error {
opts.Spec.reload() // re-analyze opts.Spec.reload() // re-analyze
} }
// rewrite JSON pointers other than $ref to named definitions // rewrite JSON pointers other than $ref to named definitions
// and attempts to resolve conflicting names // and attempts to resolve conflicting names
if err := stripPointersAndOAIGen(&opts); err != nil { if err := stripPointersAndOAIGen(&opts); err != nil {
@@ -512,7 +517,10 @@ const (
definitionsPath = "#/definitions" definitionsPath = "#/definitions"
) )
var ignoredKeys map[string]struct{} var (
ignoredKeys map[string]struct{}
validMethods map[string]struct{}
)
func init() { func init() {
ignoredKeys = map[string]struct{}{ ignoredKeys = map[string]struct{}{
@@ -522,6 +530,16 @@ func init() {
"anyOf": {}, "anyOf": {},
"oneOf": {}, "oneOf": {},
} }
validMethods = map[string]struct{}{
"GET": {},
"HEAD": {},
"OPTIONS": {},
"PATCH": {},
"POST": {},
"PUT": {},
"DELETE": {},
}
} }
type splitKey []string type splitKey []string
@@ -619,26 +637,12 @@ func (s splitKey) ResponseName() string {
return "" return ""
} }
var validMethods map[string]struct{}
func init() {
validMethods = map[string]struct{}{
"GET": {},
"HEAD": {},
"OPTIONS": {},
"PATCH": {},
"POST": {},
"PUT": {},
"DELETE": {},
}
}
func (s splitKey) PathItemRef() swspec.Ref { func (s splitKey) PathItemRef() swspec.Ref {
if len(s) < 3 { if len(s) < 3 {
return swspec.Ref{} return swspec.Ref{}
} }
pth, method := s[1], s[2] pth, method := s[1], s[2]
if _, validMethod := validMethods[strings.ToUpper(method)]; !validMethod && !strings.HasPrefix(method, "x-") { if _, isValidMethod := validMethods[strings.ToUpper(method)]; !isValidMethod && !strings.HasPrefix(method, "x-") {
return swspec.Ref{} return swspec.Ref{}
} }
return swspec.MustCreateRef("#" + slashpath.Join("/", paths, jsonpointer.Escape(pth), strings.ToUpper(method))) return swspec.MustCreateRef("#" + slashpath.Join("/", paths, jsonpointer.Escape(pth), strings.ToUpper(method)))
@@ -777,9 +781,12 @@ func cloneSchema(schema *swspec.Schema) (*swspec.Schema, error) {
return &sch, nil return &sch, nil
} }
func importExternalReferences(opts *FlattenOpts) error { func importExternalReferences(opts *FlattenOpts) (bool, error) {
groupedRefs := reverseIndexForSchemaRefs(opts) groupedRefs := reverseIndexForSchemaRefs(opts)
sortedRefStr := make([]string, 0, len(groupedRefs)) sortedRefStr := make([]string, 0, len(groupedRefs))
if opts.flattenContext == nil {
opts.flattenContext = newContext()
}
// sort $ref resolution to ensure deterministic name conflict resolution // sort $ref resolution to ensure deterministic name conflict resolution
for refStr := range groupedRefs { for refStr := range groupedRefs {
@@ -787,35 +794,53 @@ func importExternalReferences(opts *FlattenOpts) error {
} }
sort.Strings(sortedRefStr) sort.Strings(sortedRefStr)
complete := true
for _, refStr := range sortedRefStr { for _, refStr := range sortedRefStr {
entry := groupedRefs[refStr] entry := groupedRefs[refStr]
if !entry.Ref.HasFragmentOnly { if !entry.Ref.HasFragmentOnly {
debugLog("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr) complete = false
// resolve to actual schema var isOAIGen bool
sch := new(swspec.Schema)
sch.Ref = entry.Ref
if err := swspec.ExpandSchemaWithBasePath(sch, nil, opts.ExpandOpts(false)); err != nil {
return err
}
if sch == nil {
return fmt.Errorf("no schema found at %s for [%s]", refStr, strings.Join(entry.Keys, ", "))
}
debugLog("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr)
// generate a unique name - isOAIGen means that a naming conflict was resolved by changing the name newName := opts.flattenContext.resolved[refStr]
newName, isOAIGen := uniqifyName(opts.Swagger().Definitions, nameFromRef(entry.Ref)) if newName != "" {
debugLog("new name for [%s]: %s - with name conflict:%t", // rewrite ref with already resolved external ref (useful for cyclicali refs)
strings.Join(entry.Keys, ", "), newName, isOAIGen) debugLog("resolving known ref [%s] to %s", refStr, newName)
// rewrite the external refs to local ones
// rewrite the external refs to local ones for _, key := range entry.Keys {
for _, key := range entry.Keys { if err := updateRef(opts.Swagger(), key,
if err := updateRef(opts.Swagger(), key, swspec.MustCreateRef(slashpath.Join(definitionsPath, newName))); err != nil {
swspec.MustCreateRef(slashpath.Join(definitionsPath, newName))); err != nil { return false, err
return err }
} }
} else {
debugLog("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr)
// keep track of created refs // resolve to actual schema
if opts.flattenContext != nil { sch := new(swspec.Schema)
sch.Ref = entry.Ref
if err := swspec.ExpandSchemaWithBasePath(sch, nil, opts.ExpandOpts(false)); err != nil {
return false, err
}
if sch == nil {
return false, fmt.Errorf("no schema found at %s for [%s]", refStr, strings.Join(entry.Keys, ", "))
}
debugLog("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr)
// generate a unique name - isOAIGen means that a naming conflict was resolved by changing the name
newName, isOAIGen = uniqifyName(opts.Swagger().Definitions, nameFromRef(entry.Ref))
debugLog("new name for [%s]: %s - with name conflict:%t",
strings.Join(entry.Keys, ", "), newName, isOAIGen)
opts.flattenContext.resolved[refStr] = newName
// rewrite the external refs to local ones
for _, key := range entry.Keys {
if err := updateRef(opts.Swagger(), key,
swspec.MustCreateRef(slashpath.Join(definitionsPath, newName))); err != nil {
return false, err
}
// keep track of created refs
resolved := false resolved := false
if _, ok := opts.flattenContext.newRefs[key]; ok { if _, ok := opts.flattenContext.newRefs[key]; ok {
resolved = opts.flattenContext.newRefs[key].resolved resolved = opts.flattenContext.newRefs[key].resolved
@@ -829,13 +854,13 @@ func importExternalReferences(opts *FlattenOpts) error {
schema: sch, schema: sch,
} }
} }
}
// add the resolved schema to the definitions // add the resolved schema to the definitions
saveSchema(opts.Swagger(), newName, sch) saveSchema(opts.Swagger(), newName, sch)
}
} }
} }
return nil return complete, nil
} }
type refRevIdx struct { type refRevIdx struct {
@@ -1259,7 +1284,6 @@ func croak(opts *FlattenOpts) {
func namePointers(opts *FlattenOpts) error { func namePointers(opts *FlattenOpts) error {
debugLog("name pointers") debugLog("name pointers")
refsToReplace := make(map[string]SchemaRef, len(opts.Spec.references.schemas)) refsToReplace := make(map[string]SchemaRef, len(opts.Spec.references.schemas))
//for k, ref := range opts.Spec.references.schemas {
for k, ref := range opts.Spec.references.allRefs { for k, ref := range opts.Spec.references.allRefs {
if slashpath.Dir(ref.String()) == definitionsPath { if slashpath.Dir(ref.String()) == definitionsPath {
// this a ref to a top-level definition: ok // this a ref to a top-level definition: ok
@@ -1377,6 +1401,7 @@ func namePointers(opts *FlattenOpts) error {
// NOTE: all external $ref's are assumed to be already expanded at this stage. // NOTE: all external $ref's are assumed to be already expanded at this stage.
func deepestRef(opts *FlattenOpts, ref swspec.Ref) (swspec.Ref, *swspec.Schema, error) { func deepestRef(opts *FlattenOpts, ref swspec.Ref) (swspec.Ref, *swspec.Schema, error) {
if !ref.HasFragmentOnly { if !ref.HasFragmentOnly {
// we found an external $ref, which is odd
// does nothing on external $refs // does nothing on external $refs
return ref, nil, nil return ref, nil, nil
} }

View File

@@ -1,6 +1,8 @@
package analysis package analysis
import ( import (
"fmt"
"github.com/go-openapi/spec" "github.com/go-openapi/spec"
"github.com/go-openapi/strfmt" "github.com/go-openapi/strfmt"
) )
@@ -16,6 +18,10 @@ type SchemaOpts struct {
// Schema analysis, will classify the schema according to known // Schema analysis, will classify the schema according to known
// patterns. // patterns.
func Schema(opts SchemaOpts) (*AnalyzedSchema, error) { func Schema(opts SchemaOpts) (*AnalyzedSchema, error) {
if opts.Schema == nil {
return nil, fmt.Errorf("no schema to analyze")
}
a := &AnalyzedSchema{ a := &AnalyzedSchema{
schema: opts.Schema, schema: opts.Schema,
root: opts.Root, root: opts.Root,

View File

@@ -134,26 +134,26 @@ func ServeError(rw http.ResponseWriter, r *http.Request, err error) {
rw.Header().Add("Allow", strings.Join(err.(*MethodNotAllowedError).Allowed, ",")) rw.Header().Add("Allow", strings.Join(err.(*MethodNotAllowedError).Allowed, ","))
rw.WriteHeader(asHTTPCode(int(e.Code()))) rw.WriteHeader(asHTTPCode(int(e.Code())))
if r == nil || r.Method != head { if r == nil || r.Method != head {
rw.Write(errorAsJSON(e)) _, _ = rw.Write(errorAsJSON(e))
} }
case Error: case Error:
value := reflect.ValueOf(e) value := reflect.ValueOf(e)
if value.Kind() == reflect.Ptr && value.IsNil() { if value.Kind() == reflect.Ptr && value.IsNil() {
rw.WriteHeader(http.StatusInternalServerError) rw.WriteHeader(http.StatusInternalServerError)
rw.Write(errorAsJSON(New(http.StatusInternalServerError, "Unknown error"))) _, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, "Unknown error")))
return return
} }
rw.WriteHeader(asHTTPCode(int(e.Code()))) rw.WriteHeader(asHTTPCode(int(e.Code())))
if r == nil || r.Method != head { if r == nil || r.Method != head {
rw.Write(errorAsJSON(e)) _, _ = rw.Write(errorAsJSON(e))
} }
case nil: case nil:
rw.WriteHeader(http.StatusInternalServerError) rw.WriteHeader(http.StatusInternalServerError)
rw.Write(errorAsJSON(New(http.StatusInternalServerError, "Unknown error"))) _, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, "Unknown error")))
default: default:
rw.WriteHeader(http.StatusInternalServerError) rw.WriteHeader(http.StatusInternalServerError)
if r == nil || r.Method != head { if r == nil || r.Method != head {
rw.Write(errorAsJSON(New(http.StatusInternalServerError, err.Error()))) _, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, err.Error())))
} }
} }
} }

View File

@@ -54,7 +54,7 @@ const (
// InvalidContentType error for an invalid content type // InvalidContentType error for an invalid content type
func InvalidContentType(value string, allowed []string) *Validation { func InvalidContentType(value string, allowed []string) *Validation {
var values []interface{} values := make([]interface{}, 0, len(allowed))
for _, v := range allowed { for _, v := range allowed {
values = append(values, v) values = append(values, v)
} }
@@ -70,7 +70,7 @@ func InvalidContentType(value string, allowed []string) *Validation {
// InvalidResponseFormat error for an unacceptable response format request // InvalidResponseFormat error for an unacceptable response format request
func InvalidResponseFormat(value string, allowed []string) *Validation { func InvalidResponseFormat(value string, allowed []string) *Validation {
var values []interface{} values := make([]interface{}, 0, len(allowed))
for _, v := range allowed { for _, v := range allowed {
values = append(values, v) values = append(values, v)
} }

21
vendor/github.com/go-openapi/loads/doc.go generated vendored Normal file
View File

@@ -0,0 +1,21 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Package loads provides document loading methods for swagger (OAI) specifications.
It is used by other go-openapi packages to load and run analysis on local or remote spec documents.
*/
package loads

View File

@@ -16,6 +16,7 @@ package loads
import ( import (
"bytes" "bytes"
"encoding/gob"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/url" "net/url"
@@ -50,6 +51,10 @@ func init() {
loaders = defaultLoader loaders = defaultLoader
spec.PathLoader = loaders.Fn spec.PathLoader = loaders.Fn
AddLoader(swag.YAMLMatcher, swag.YAMLDoc) AddLoader(swag.YAMLMatcher, swag.YAMLDoc)
gob.Register(map[string]interface{}{})
gob.Register([]interface{}{})
//gob.Register(spec.Refable{})
} }
// AddLoader for a document // AddLoader for a document
@@ -76,7 +81,7 @@ func JSONSpec(path string) (*Document, error) {
return nil, err return nil, err
} }
// convert to json // convert to json
return Analyzed(json.RawMessage(data), "") return Analyzed(data, "")
} }
// Document represents a swagger spec document // Document represents a swagger spec document
@@ -120,9 +125,9 @@ func Spec(path string) (*Document, error) {
lastErr = err2 lastErr = err2
continue continue
} }
doc, err := Analyzed(b, "") doc, err3 := Analyzed(b, "")
if err != nil { if err3 != nil {
return nil, err return nil, err3
} }
if doc != nil { if doc != nil {
doc.specFilePath = path doc.specFilePath = path
@@ -176,8 +181,8 @@ func Analyzed(data json.RawMessage, version string) (*Document, error) {
return nil, err return nil, err
} }
origsqspec := new(spec.Swagger) origsqspec, err := cloneSpec(swspec)
if err := json.Unmarshal(raw, origsqspec); err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -252,6 +257,7 @@ func (d *Document) Raw() json.RawMessage {
return d.raw return d.raw
} }
// OrigSpec yields the original spec
func (d *Document) OrigSpec() *spec.Swagger { func (d *Document) OrigSpec() *spec.Swagger {
return d.origSpec return d.origSpec
} }
@@ -277,3 +283,16 @@ func (d *Document) Pristine() *Document {
func (d *Document) SpecFilePath() string { func (d *Document) SpecFilePath() string {
return d.specFilePath return d.specFilePath
} }
func cloneSpec(src *spec.Swagger) (*spec.Swagger, error) {
var b bytes.Buffer
if err := gob.NewEncoder(&b).Encode(src); err != nil {
return nil, err
}
var dst spec.Swagger
if err := gob.NewDecoder(&b).Decode(&dst); err != nil {
return nil, err
}
return &dst, nil
}

View File

@@ -32,6 +32,7 @@ func JSONConsumer() Consumer {
func JSONProducer() Producer { func JSONProducer() Producer {
return ProducerFunc(func(writer io.Writer, data interface{}) error { return ProducerFunc(func(writer io.Writer, data interface{}) error {
enc := json.NewEncoder(writer) enc := json.NewEncoder(writer)
enc.SetEscapeHTML(false)
return enc.Encode(data) return enc.Encode(data)
}) })
} }

View File

@@ -15,12 +15,20 @@
package spec package spec
import ( import (
"bytes"
"encoding/gob"
"encoding/json" "encoding/json"
"github.com/go-openapi/jsonpointer" "github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag" "github.com/go-openapi/swag"
) )
func init() {
//gob.Register(map[string][]interface{}{})
gob.Register(map[string]interface{}{})
gob.Register([]interface{}{})
}
// OperationProps describes an operation // OperationProps describes an operation
type OperationProps struct { type OperationProps struct {
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
@@ -257,3 +265,126 @@ func (o *Operation) RespondsWith(code int, response *Response) *Operation {
o.Responses.StatusCodeResponses[code] = *response o.Responses.StatusCodeResponses[code] = *response
return o return o
} }
type opsAlias OperationProps
type gobAlias struct {
Security []map[string]struct {
List []string
Pad bool
}
Alias *opsAlias
SecurityIsEmpty bool
}
// GobEncode provides a safe gob encoder for Operation, including empty security requirements
func (o Operation) GobEncode() ([]byte, error) {
raw := struct {
Ext VendorExtensible
Props OperationProps
}{
Ext: o.VendorExtensible,
Props: o.OperationProps,
}
var b bytes.Buffer
err := gob.NewEncoder(&b).Encode(raw)
return b.Bytes(), err
}
// GobDecode provides a safe gob decoder for Operation, including empty security requirements
func (o *Operation) GobDecode(b []byte) error {
var raw struct {
Ext VendorExtensible
Props OperationProps
}
buf := bytes.NewBuffer(b)
err := gob.NewDecoder(buf).Decode(&raw)
if err != nil {
return err
}
o.VendorExtensible = raw.Ext
o.OperationProps = raw.Props
return nil
}
// GobEncode provides a safe gob encoder for Operation, including empty security requirements
func (op OperationProps) GobEncode() ([]byte, error) {
raw := gobAlias{
Alias: (*opsAlias)(&op),
}
var b bytes.Buffer
if op.Security == nil {
// nil security requirement
err := gob.NewEncoder(&b).Encode(raw)
return b.Bytes(), err
}
if len(op.Security) == 0 {
// empty, but non-nil security requirement
raw.SecurityIsEmpty = true
raw.Alias.Security = nil
err := gob.NewEncoder(&b).Encode(raw)
return b.Bytes(), err
}
raw.Security = make([]map[string]struct {
List []string
Pad bool
}, 0, len(op.Security))
for _, req := range op.Security {
v := make(map[string]struct {
List []string
Pad bool
}, len(req))
for k, val := range req {
v[k] = struct {
List []string
Pad bool
}{
List: val,
}
}
raw.Security = append(raw.Security, v)
}
err := gob.NewEncoder(&b).Encode(raw)
return b.Bytes(), err
}
// GobDecode provides a safe gob decoder for Operation, including empty security requirements
func (op *OperationProps) GobDecode(b []byte) error {
var raw gobAlias
buf := bytes.NewBuffer(b)
err := gob.NewDecoder(buf).Decode(&raw)
if err != nil {
return err
}
if raw.Alias == nil {
return nil
}
switch {
case raw.SecurityIsEmpty:
// empty, but non-nil security requirement
raw.Alias.Security = []map[string][]string{}
case len(raw.Alias.Security) == 0:
// nil security requirement
raw.Alias.Security = nil
default:
raw.Alias.Security = make([]map[string][]string, 0, len(raw.Security))
for _, req := range raw.Security {
v := make(map[string][]string, len(req))
for k, val := range req {
v[k] = make([]string, 0, len(val.List))
v[k] = append(v[k], val.List...)
}
raw.Alias.Security = append(raw.Alias.Security, v)
}
}
*op = *(*OperationProps)(raw.Alias)
return nil
}

View File

@@ -15,6 +15,8 @@
package spec package spec
import ( import (
"bytes"
"encoding/gob"
"encoding/json" "encoding/json"
"net/http" "net/http"
"os" "os"
@@ -148,6 +150,28 @@ func (r *Ref) UnmarshalJSON(d []byte) error {
return r.fromMap(v) return r.fromMap(v)
} }
// GobEncode provides a safe gob encoder for Ref
func (r Ref) GobEncode() ([]byte, error) {
var b bytes.Buffer
raw, err := r.MarshalJSON()
if err != nil {
return nil, err
}
err = gob.NewEncoder(&b).Encode(raw)
return b.Bytes(), err
}
// GobDecode provides a safe gob decoder for Ref
func (r *Ref) GobDecode(b []byte) error {
var raw []byte
buf := bytes.NewBuffer(b)
err := gob.NewDecoder(buf).Decode(&raw)
if err != nil {
return err
}
return json.Unmarshal(raw, r)
}
func (r *Ref) fromMap(v map[string]interface{}) error { func (r *Ref) fromMap(v map[string]interface{}) error {
if v == nil { if v == nil {
return nil return nil

View File

@@ -49,7 +49,7 @@ const (
// <subdomain> ::= <label> | <subdomain> "." <label> // <subdomain> ::= <label> | <subdomain> "." <label>
// var subdomain = /^[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?(\.[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?)*$/; // var subdomain = /^[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?(\.[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?)*$/;
// <domain> ::= <subdomain> | " " // <domain> ::= <subdomain> | " "
HostnamePattern = `^[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?(\.[a-zA-Z](([-0-9a-zA-Z]+)?[0-9a-zA-Z])?)*$` HostnamePattern = `^[a-zA-Z0-9\p{S}\p{L}](([a-zA-Z0-9-\p{S}\p{L}]{0,63})(\.)){1,6}([a-zA-Z\p{L}]){2,}$`
// UUIDPattern Regex for UUID that allows uppercase // UUIDPattern Regex for UUID that allows uppercase
UUIDPattern = `(?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$` UUIDPattern = `(?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$`
// UUID3Pattern Regex for UUID3 that allows uppercase // UUID3Pattern Regex for UUID3 that allows uppercase
@@ -112,7 +112,7 @@ func IsUUID5(str string) bool {
return rxUUID5.MatchString(str) return rxUUID5.MatchString(str)
} }
// Validates an email address. // IsEmail validates an email address.
func IsEmail(str string) bool { func IsEmail(str string) bool {
addr, e := mail.ParseAddress(str) addr, e := mail.ParseAddress(str)
return e == nil && addr.Address != "" return e == nil && addr.Address != ""
@@ -197,13 +197,7 @@ func init() {
Default.Add("password", &pw, func(_ string) bool { return true }) Default.Add("password", &pw, func(_ string) bool { return true })
} }
/* unused: // Base64 represents a base64 encoded string, using URLEncoding alphabet
var formatCheckers = map[string]Validator{
"byte": govalidator.IsBase64,
}
*/
// Base64 represents a base64 encoded string
// //
// swagger:strfmt byte // swagger:strfmt byte
type Base64 []byte type Base64 []byte

View File

@@ -121,7 +121,7 @@ func ParseDuration(cand string) (time.Duration, error) {
if ok { if ok {
return dur, nil return dur, nil
} }
return 0, fmt.Errorf("Unable to parse %s as duration", cand) return 0, fmt.Errorf("unable to parse %s as duration", cand)
} }
// Scan reads a Duration value from database driver type. // Scan reads a Duration value from database driver type.

View File

@@ -1,3 +1,17 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package swag package swag
import ( import (

View File

@@ -1,3 +1,17 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build go1.8 // +build go1.8
package swag package swag

View File

@@ -1,3 +1,17 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build go1.9 // +build go1.9
package swag package swag

View File

@@ -1,3 +1,17 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !go1.8 // +build !go1.8
package swag package swag

View File

@@ -1,3 +1,17 @@
// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !go1.9 // +build !go1.9
package swag package swag

View File

@@ -33,6 +33,12 @@ var once sync.Once
var isInitialism func(string) bool var isInitialism func(string) bool
var (
splitRex1 *regexp.Regexp
splitRex2 *regexp.Regexp
splitReplacer *strings.Replacer
)
func init() { func init() {
// Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769 // Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769
var configuredInitialisms = map[string]bool{ var configuredInitialisms = map[string]bool{
@@ -167,35 +173,36 @@ func (s byLength) Less(i, j int) bool {
// Prepares strings by splitting by caps, spaces, dashes, and underscore // Prepares strings by splitting by caps, spaces, dashes, and underscore
func split(str string) []string { func split(str string) []string {
repl := strings.NewReplacer( // check if consecutive single char things make up an initialism
"@", "At ", once.Do(func() {
"&", "And ", splitRex1 = regexp.MustCompile(`(\p{Lu})`)
"|", "Pipe ", splitRex2 = regexp.MustCompile(`(\pL|\pM|\pN|\p{Pc})+`)
"$", "Dollar ", splitReplacer = strings.NewReplacer(
"!", "Bang ", "@", "At ",
"-", " ", "&", "And ",
"_", " ", "|", "Pipe ",
) "$", "Dollar ",
"!", "Bang ",
rex1 := regexp.MustCompile(`(\p{Lu})`) "-", " ",
rex2 := regexp.MustCompile(`(\pL|\pM|\pN|\p{Pc})+`) "_", " ",
)
ensureSorted()
})
str = trim(str) str = trim(str)
// Convert dash and underscore to spaces // Convert dash and underscore to spaces
str = repl.Replace(str) str = splitReplacer.Replace(str)
// Split when uppercase is found (needed for Snake) // Split when uppercase is found (needed for Snake)
str = rex1.ReplaceAllString(str, " $1") str = splitRex1.ReplaceAllString(str, " $1")
// check if consecutive single char things make up an initialism
once.Do(ensureSorted)
for _, k := range initialisms { for _, k := range initialisms {
str = strings.Replace(str, rex1.ReplaceAllString(k, " $1"), " "+k, -1) str = strings.Replace(str, splitRex1.ReplaceAllString(k, " $1"), " "+k, -1)
} }
// Get the final list of words // Get the final list of words
//words = rex2.FindAllString(str, -1) //words = rex2.FindAllString(str, -1)
return rex2.FindAllString(str, -1) return splitRex2.FindAllString(str, -1)
} }
// Removes leading whitespaces // Removes leading whitespaces

View File

@@ -22,7 +22,6 @@ import (
"github.com/mailru/easyjson/jlexer" "github.com/mailru/easyjson/jlexer"
"github.com/mailru/easyjson/jwriter" "github.com/mailru/easyjson/jwriter"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )

View File

@@ -116,7 +116,6 @@ func (conn *Conn) Auth(methods []Auth) error {
return err return err
} }
go conn.inWorker() go conn.inWorker()
go conn.outWorker()
return nil return nil
} }
} }

16
vendor/github.com/godbus/dbus/auth_anonymous.go generated vendored Normal file
View File

@@ -0,0 +1,16 @@
package dbus
// AuthAnonymous returns an Auth that uses the ANONYMOUS mechanism.
func AuthAnonymous() Auth {
return &authAnonymous{}
}
type authAnonymous struct{}
func (a *authAnonymous) FirstData() (name, resp []byte, status AuthStatus) {
return []byte("ANONYMOUS"), nil, AuthOk
}
func (a *authAnonymous) HandleData(data []byte) (resp []byte, status AuthStatus) {
return nil, AuthError
}

View File

@@ -1,9 +1,12 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
) )
var errSignature = errors.New("dbus: mismatched signature")
// Call represents a pending or completed method call. // Call represents a pending or completed method call.
type Call struct { type Call struct {
Destination string Destination string
@@ -20,9 +23,25 @@ type Call struct {
// Holds the response once the call is done. // Holds the response once the call is done.
Body []interface{} Body []interface{}
// tracks context and canceler
ctx context.Context
ctxCanceler context.CancelFunc
} }
var errSignature = errors.New("dbus: mismatched signature") func (c *Call) Context() context.Context {
if c.ctx == nil {
return context.Background()
}
return c.ctx
}
func (c *Call) ContextCancel() {
if c.ctxCanceler != nil {
c.ctxCanceler()
}
}
// Store stores the body of the reply into the provided pointers. It returns // Store stores the body of the reply into the provided pointers. It returns
// an error if the signatures of the body and retvalues don't match, or if // an error if the signatures of the body and retvalues don't match, or if
@@ -34,3 +53,8 @@ func (c *Call) Store(retvalues ...interface{}) error {
return Store(c.Body, retvalues...) return Store(c.Body, retvalues...)
} }
func (c *Call) done() {
c.Done <- c
c.ContextCancel()
}

616
vendor/github.com/godbus/dbus/conn.go generated vendored
View File

@@ -1,6 +1,7 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
"io" "io"
"os" "os"
@@ -14,7 +15,6 @@ var (
systemBusLck sync.Mutex systemBusLck sync.Mutex
sessionBus *Conn sessionBus *Conn
sessionBusLck sync.Mutex sessionBusLck sync.Mutex
sessionEnvLck sync.Mutex
) )
// ErrClosed is the error returned by calls on a closed connection. // ErrClosed is the error returned by calls on a closed connection.
@@ -35,23 +35,13 @@ type Conn struct {
unixFD bool unixFD bool
uuid string uuid string
names []string handler Handler
namesLck sync.RWMutex
serialLck sync.Mutex
nextSerial uint32
serialUsed map[uint32]bool
calls map[uint32]*Call
callsLck sync.RWMutex
handler Handler
out chan *Message
closed bool
outLck sync.RWMutex
signalHandler SignalHandler signalHandler SignalHandler
serialGen SerialGenerator
names *nameTracker
calls *callTracker
outHandler *outputHandler
eavesdropped chan<- *Message eavesdropped chan<- *Message
eavesdroppedLck sync.Mutex eavesdroppedLck sync.Mutex
@@ -87,32 +77,31 @@ func SessionBus() (conn *Conn, err error) {
} }
func getSessionBusAddress() (string, error) { func getSessionBusAddress() (string, error) {
sessionEnvLck.Lock() if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" {
defer sessionEnvLck.Unlock() return address, nil
address := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
if address != "" && address != "autolaunch:" { } else if address := tryDiscoverDbusSessionBusAddress(); address != "" {
os.Setenv("DBUS_SESSION_BUS_ADDRESS", address)
return address, nil return address, nil
} }
return getSessionBusPlatformAddress() return getSessionBusPlatformAddress()
} }
// SessionBusPrivate returns a new private connection to the session bus. // SessionBusPrivate returns a new private connection to the session bus.
func SessionBusPrivate() (*Conn, error) { func SessionBusPrivate(opts ...ConnOption) (*Conn, error) {
address, err := getSessionBusAddress() address, err := getSessionBusAddress()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return Dial(address) return Dial(address, opts...)
} }
// SessionBusPrivate returns a new private connection to the session bus. // SessionBusPrivate returns a new private connection to the session bus.
//
// Deprecated: use SessionBusPrivate with options instead.
func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) { func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
address, err := getSessionBusAddress() return SessionBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler))
if err != nil {
return nil, err
}
return DialHandler(address, handler, signalHandler)
} }
// SystemBus returns a shared connection to the system bus, connecting to it if // SystemBus returns a shared connection to the system bus, connecting to it if
@@ -145,53 +134,93 @@ func SystemBus() (conn *Conn, err error) {
} }
// SystemBusPrivate returns a new private connection to the system bus. // SystemBusPrivate returns a new private connection to the system bus.
func SystemBusPrivate() (*Conn, error) { func SystemBusPrivate(opts ...ConnOption) (*Conn, error) {
return Dial(getSystemBusPlatformAddress()) return Dial(getSystemBusPlatformAddress(), opts...)
} }
// SystemBusPrivateHandler returns a new private connection to the system bus, using the provided handlers. // SystemBusPrivateHandler returns a new private connection to the system bus, using the provided handlers.
//
// Deprecated: use SystemBusPrivate with options instead.
func SystemBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) { func SystemBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
return DialHandler(getSystemBusPlatformAddress(), handler, signalHandler) return SystemBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler))
} }
// Dial establishes a new private connection to the message bus specified by address. // Dial establishes a new private connection to the message bus specified by address.
func Dial(address string) (*Conn, error) { func Dial(address string, opts ...ConnOption) (*Conn, error) {
tr, err := getTransport(address) tr, err := getTransport(address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newConn(tr, NewDefaultHandler(), NewDefaultSignalHandler()) return newConn(tr, opts...)
} }
// DialHandler establishes a new private connection to the message bus specified by address, using the supplied handlers. // DialHandler establishes a new private connection to the message bus specified by address, using the supplied handlers.
//
// Deprecated: use Dial with options instead.
func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) { func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) {
tr, err := getTransport(address) return Dial(address, WithSignalHandler(signalHandler))
if err != nil { }
return nil, err
// ConnOption is a connection option.
type ConnOption func(conn *Conn) error
// WithHandler overrides the default handler.
func WithHandler(handler Handler) ConnOption {
return func(conn *Conn) error {
conn.handler = handler
return nil
}
}
// WithSignalHandler overrides the default signal handler.
func WithSignalHandler(handler SignalHandler) ConnOption {
return func(conn *Conn) error {
conn.signalHandler = handler
return nil
}
}
// WithSerialGenerator overrides the default signals generator.
func WithSerialGenerator(gen SerialGenerator) ConnOption {
return func(conn *Conn) error {
conn.serialGen = gen
return nil
} }
return newConn(tr, handler, signalHandler)
} }
// NewConn creates a new private *Conn from an already established connection. // NewConn creates a new private *Conn from an already established connection.
func NewConn(conn io.ReadWriteCloser) (*Conn, error) { func NewConn(conn io.ReadWriteCloser, opts ...ConnOption) (*Conn, error) {
return NewConnHandler(conn, NewDefaultHandler(), NewDefaultSignalHandler()) return newConn(genericTransport{conn}, opts...)
} }
// NewConnHandler creates a new private *Conn from an already established connection, using the supplied handlers. // NewConnHandler creates a new private *Conn from an already established connection, using the supplied handlers.
//
// Deprecated: use NewConn with options instead.
func NewConnHandler(conn io.ReadWriteCloser, handler Handler, signalHandler SignalHandler) (*Conn, error) { func NewConnHandler(conn io.ReadWriteCloser, handler Handler, signalHandler SignalHandler) (*Conn, error) {
return newConn(genericTransport{conn}, handler, signalHandler) return NewConn(genericTransport{conn}, WithHandler(handler), WithSignalHandler(signalHandler))
} }
// newConn creates a new *Conn from a transport. // newConn creates a new *Conn from a transport.
func newConn(tr transport, handler Handler, signalHandler SignalHandler) (*Conn, error) { func newConn(tr transport, opts ...ConnOption) (*Conn, error) {
conn := new(Conn) conn := new(Conn)
conn.transport = tr conn.transport = tr
conn.calls = make(map[uint32]*Call) for _, opt := range opts {
conn.out = make(chan *Message, 10) if err := opt(conn); err != nil {
conn.handler = handler return nil, err
conn.signalHandler = signalHandler }
conn.nextSerial = 1 }
conn.serialUsed = map[uint32]bool{0: true} conn.calls = newCallTracker()
if conn.handler == nil {
conn.handler = NewDefaultHandler()
}
if conn.signalHandler == nil {
conn.signalHandler = NewDefaultSignalHandler()
}
if conn.serialGen == nil {
conn.serialGen = newSerialGenerator()
}
conn.outHandler = &outputHandler{conn: conn}
conn.names = newNameTracker()
conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
return conn, nil return conn, nil
} }
@@ -206,18 +235,7 @@ func (conn *Conn) BusObject() BusObject {
// and the channels passed to Eavesdrop and Signal are closed. This method must // and the channels passed to Eavesdrop and Signal are closed. This method must
// not be called on shared connections. // not be called on shared connections.
func (conn *Conn) Close() error { func (conn *Conn) Close() error {
conn.outLck.Lock() conn.outHandler.close()
if conn.closed {
// inWorker calls Close on read error, the read error may
// be caused by another caller calling Close to shutdown the
// dbus connection, a double-close scenario we prevent here.
conn.outLck.Unlock()
return nil
}
close(conn.out)
conn.closed = true
conn.outLck.Unlock()
if term, ok := conn.signalHandler.(Terminator); ok { if term, ok := conn.signalHandler.(Terminator); ok {
term.Terminate() term.Terminate()
} }
@@ -249,17 +267,9 @@ func (conn *Conn) Eavesdrop(ch chan<- *Message) {
conn.eavesdroppedLck.Unlock() conn.eavesdroppedLck.Unlock()
} }
// getSerial returns an unused serial. // GetSerial returns an unused serial.
func (conn *Conn) getSerial() uint32 { func (conn *Conn) getSerial() uint32 {
conn.serialLck.Lock() return conn.serialGen.GetSerial()
defer conn.serialLck.Unlock()
n := conn.nextSerial
for conn.serialUsed[n] {
n++
}
conn.serialUsed[n] = true
conn.nextSerial = n + 1
return n
} }
// Hello sends the initial org.freedesktop.DBus.Hello call. This method must be // Hello sends the initial org.freedesktop.DBus.Hello call. This method must be
@@ -271,10 +281,7 @@ func (conn *Conn) Hello() error {
if err != nil { if err != nil {
return err return err
} }
conn.namesLck.Lock() conn.names.acquireUniqueConnectionName(s)
conn.names = make([]string, 1)
conn.names[0] = s
conn.namesLck.Unlock()
return nil return nil
} }
@@ -283,109 +290,48 @@ func (conn *Conn) Hello() error {
func (conn *Conn) inWorker() { func (conn *Conn) inWorker() {
for { for {
msg, err := conn.ReadMessage() msg, err := conn.ReadMessage()
if err == nil { if err != nil {
conn.eavesdroppedLck.Lock() if _, ok := err.(InvalidMessageError); !ok {
if conn.eavesdropped != nil { // Some read error occured (usually EOF); we can't really do
select { // anything but to shut down all stuff and returns errors to all
case conn.eavesdropped <- msg: // pending replies.
default: conn.Close()
} conn.calls.finalizeAllWithError(err)
conn.eavesdroppedLck.Unlock() return
continue }
// invalid messages are ignored
continue
}
conn.eavesdroppedLck.Lock()
if conn.eavesdropped != nil {
select {
case conn.eavesdropped <- msg:
default:
} }
conn.eavesdroppedLck.Unlock() conn.eavesdroppedLck.Unlock()
dest, _ := msg.Headers[FieldDestination].value.(string) continue
found := false
if dest == "" {
found = true
} else {
conn.namesLck.RLock()
if len(conn.names) == 0 {
found = true
}
for _, v := range conn.names {
if dest == v {
found = true
break
}
}
conn.namesLck.RUnlock()
}
if !found {
// Eavesdropped a message, but no channel for it is registered.
// Ignore it.
continue
}
switch msg.Type {
case TypeMethodReply, TypeError:
serial := msg.Headers[FieldReplySerial].value.(uint32)
conn.callsLck.Lock()
if c, ok := conn.calls[serial]; ok {
if msg.Type == TypeError {
name, _ := msg.Headers[FieldErrorName].value.(string)
c.Err = Error{name, msg.Body}
} else {
c.Body = msg.Body
}
c.Done <- c
conn.serialLck.Lock()
delete(conn.serialUsed, serial)
conn.serialLck.Unlock()
delete(conn.calls, serial)
}
conn.callsLck.Unlock()
case TypeSignal:
iface := msg.Headers[FieldInterface].value.(string)
member := msg.Headers[FieldMember].value.(string)
// as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
// sender is optional for signals.
sender, _ := msg.Headers[FieldSender].value.(string)
if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" {
if member == "NameLost" {
// If we lost the name on the bus, remove it from our
// tracking list.
name, ok := msg.Body[0].(string)
if !ok {
panic("Unable to read the lost name")
}
conn.namesLck.Lock()
for i, v := range conn.names {
if v == name {
conn.names = append(conn.names[:i],
conn.names[i+1:]...)
}
}
conn.namesLck.Unlock()
} else if member == "NameAcquired" {
// If we acquired the name on the bus, add it to our
// tracking list.
name, ok := msg.Body[0].(string)
if !ok {
panic("Unable to read the acquired name")
}
conn.namesLck.Lock()
conn.names = append(conn.names, name)
conn.namesLck.Unlock()
}
}
conn.handleSignal(msg)
case TypeMethodCall:
go conn.handleCall(msg)
}
} else if _, ok := err.(InvalidMessageError); !ok {
// Some read error occured (usually EOF); we can't really do
// anything but to shut down all stuff and returns errors to all
// pending replies.
conn.Close()
conn.callsLck.RLock()
for _, v := range conn.calls {
v.Err = err
v.Done <- v
}
conn.callsLck.RUnlock()
return
} }
// invalid messages are ignored conn.eavesdroppedLck.Unlock()
dest, _ := msg.Headers[FieldDestination].value.(string)
found := dest == "" ||
!conn.names.uniqueNameIsKnown() ||
conn.names.isKnownName(dest)
if !found {
// Eavesdropped a message, but no channel for it is registered.
// Ignore it.
continue
}
switch msg.Type {
case TypeError:
conn.serialGen.RetireSerial(conn.calls.handleDBusError(msg))
case TypeMethodReply:
conn.serialGen.RetireSerial(conn.calls.handleReply(msg))
case TypeSignal:
conn.handleSignal(msg)
case TypeMethodCall:
go conn.handleCall(msg)
}
} }
} }
@@ -395,6 +341,25 @@ func (conn *Conn) handleSignal(msg *Message) {
// as per http://dbus.freedesktop.org/doc/dbus-specification.html , // as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
// sender is optional for signals. // sender is optional for signals.
sender, _ := msg.Headers[FieldSender].value.(string) sender, _ := msg.Headers[FieldSender].value.(string)
if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" {
if member == "NameLost" {
// If we lost the name on the bus, remove it from our
// tracking list.
name, ok := msg.Body[0].(string)
if !ok {
panic("Unable to read the lost name")
}
conn.names.loseName(name)
} else if member == "NameAcquired" {
// If we acquired the name on the bus, add it to our
// tracking list.
name, ok := msg.Body[0].(string)
if !ok {
panic("Unable to read the acquired name")
}
conn.names.acquireName(name)
}
}
signal := &Signal{ signal := &Signal{
Sender: sender, Sender: sender,
Path: msg.Headers[FieldPath].value.(ObjectPath), Path: msg.Headers[FieldPath].value.(ObjectPath),
@@ -408,12 +373,7 @@ func (conn *Conn) handleSignal(msg *Message) {
// connection. The slice is always at least one element long, the first element // connection. The slice is always at least one element long, the first element
// being the unique name of the connection. // being the unique name of the connection.
func (conn *Conn) Names() []string { func (conn *Conn) Names() []string {
conn.namesLck.RLock() return conn.names.listKnownNames()
// copy the slice so it can't be modified
s := make([]string, len(conn.names))
copy(s, conn.names)
conn.namesLck.RUnlock()
return s
} }
// Object returns the object identified by the given destination name and path. // Object returns the object identified by the given destination name and path.
@@ -423,24 +383,17 @@ func (conn *Conn) Object(dest string, path ObjectPath) BusObject {
// outWorker runs in an own goroutine, encoding and sending messages that are // outWorker runs in an own goroutine, encoding and sending messages that are
// sent to conn.out. // sent to conn.out.
func (conn *Conn) outWorker() { func (conn *Conn) sendMessage(msg *Message) {
for msg := range conn.out { conn.sendMessageAndIfClosed(msg, func() {})
err := conn.SendMessage(msg) }
conn.callsLck.RLock()
if err != nil { func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
if c := conn.calls[msg.serial]; c != nil { err := conn.outHandler.sendAndIfClosed(msg, ifClosed)
c.Err = err conn.calls.handleSendError(msg, err)
c.Done <- c if err != nil {
} conn.serialGen.RetireSerial(msg.serial)
conn.serialLck.Lock() } else if msg.Type != TypeMethodCall {
delete(conn.serialUsed, msg.serial) conn.serialGen.RetireSerial(msg.serial)
conn.serialLck.Unlock()
} else if msg.Type != TypeMethodCall {
conn.serialLck.Lock()
delete(conn.serialUsed, msg.serial)
conn.serialLck.Unlock()
}
conn.callsLck.RUnlock()
} }
} }
@@ -451,8 +404,21 @@ func (conn *Conn) outWorker() {
// once the call is complete. Otherwise, ch is ignored and a Call structure is // once the call is complete. Otherwise, ch is ignored and a Call structure is
// returned of which only the Err member is valid. // returned of which only the Err member is valid.
func (conn *Conn) Send(msg *Message, ch chan *Call) *Call { func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
var call *Call return conn.send(context.Background(), msg, ch)
}
// SendWithContext acts like Send but takes a context
func (conn *Conn) SendWithContext(ctx context.Context, msg *Message, ch chan *Call) *Call {
return conn.send(ctx, msg, ch)
}
func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
if ctx == nil {
panic("nil context")
}
var call *Call
ctx, canceler := context.WithCancel(ctx)
msg.serial = conn.getSerial() msg.serial = conn.getSerial()
if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 { if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 {
if ch == nil { if ch == nil {
@@ -468,26 +434,23 @@ func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
call.Method = iface + "." + member call.Method = iface + "." + member
call.Args = msg.Body call.Args = msg.Body
call.Done = ch call.Done = ch
conn.callsLck.Lock() call.ctx = ctx
conn.calls[msg.serial] = call call.ctxCanceler = canceler
conn.callsLck.Unlock() conn.calls.track(msg.serial, call)
conn.outLck.RLock() go func() {
if conn.closed { <-ctx.Done()
call.Err = ErrClosed conn.calls.handleSendError(msg, ctx.Err())
call.Done <- call }()
} else { conn.sendMessageAndIfClosed(msg, func() {
conn.out <- msg conn.calls.handleSendError(msg, ErrClosed)
} canceler()
conn.outLck.RUnlock() })
} else { } else {
conn.outLck.RLock() canceler()
if conn.closed { call = &Call{Err: nil}
conn.sendMessageAndIfClosed(msg, func() {
call = &Call{Err: ErrClosed} call = &Call{Err: ErrClosed}
} else { })
conn.out <- msg
call = &Call{Err: nil}
}
conn.outLck.RUnlock()
} }
return call return call
} }
@@ -520,11 +483,7 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
if len(e.Body) > 0 { if len(e.Body) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...))
} }
conn.outLck.RLock() conn.sendMessage(msg)
if !conn.closed {
conn.out <- msg
}
conn.outLck.RUnlock()
} }
// sendReply creates a method reply message corresponding to the parameters and // sendReply creates a method reply message corresponding to the parameters and
@@ -542,11 +501,7 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
if len(values) > 0 { if len(values) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
} }
conn.outLck.RLock() conn.sendMessage(msg)
if !conn.closed {
conn.out <- msg
}
conn.outLck.RUnlock()
} }
func (conn *Conn) defaultSignalAction(fn func(h *defaultSignalHandler, ch chan<- *Signal), ch chan<- *Signal) { func (conn *Conn) defaultSignalAction(fn func(h *defaultSignalHandler, ch chan<- *Signal), ch chan<- *Signal) {
@@ -681,3 +636,212 @@ func getKey(s, key string) string {
} }
return "" return ""
} }
type outputHandler struct {
conn *Conn
sendLck sync.Mutex
closed struct {
isClosed bool
lck sync.RWMutex
}
}
func (h *outputHandler) sendAndIfClosed(msg *Message, ifClosed func()) error {
h.closed.lck.RLock()
defer h.closed.lck.RUnlock()
if h.closed.isClosed {
ifClosed()
return nil
}
h.sendLck.Lock()
defer h.sendLck.Unlock()
return h.conn.SendMessage(msg)
}
func (h *outputHandler) close() {
h.closed.lck.Lock()
defer h.closed.lck.Unlock()
h.closed.isClosed = true
}
type serialGenerator struct {
lck sync.Mutex
nextSerial uint32
serialUsed map[uint32]bool
}
func newSerialGenerator() *serialGenerator {
return &serialGenerator{
serialUsed: map[uint32]bool{0: true},
nextSerial: 1,
}
}
func (gen *serialGenerator) GetSerial() uint32 {
gen.lck.Lock()
defer gen.lck.Unlock()
n := gen.nextSerial
for gen.serialUsed[n] {
n++
}
gen.serialUsed[n] = true
gen.nextSerial = n + 1
return n
}
func (gen *serialGenerator) RetireSerial(serial uint32) {
gen.lck.Lock()
defer gen.lck.Unlock()
delete(gen.serialUsed, serial)
}
type nameTracker struct {
lck sync.RWMutex
unique string
names map[string]struct{}
}
func newNameTracker() *nameTracker {
return &nameTracker{names: map[string]struct{}{}}
}
func (tracker *nameTracker) acquireUniqueConnectionName(name string) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
tracker.unique = name
}
func (tracker *nameTracker) acquireName(name string) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
tracker.names[name] = struct{}{}
}
func (tracker *nameTracker) loseName(name string) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
delete(tracker.names, name)
}
func (tracker *nameTracker) uniqueNameIsKnown() bool {
tracker.lck.RLock()
defer tracker.lck.RUnlock()
return tracker.unique != ""
}
func (tracker *nameTracker) isKnownName(name string) bool {
tracker.lck.RLock()
defer tracker.lck.RUnlock()
_, ok := tracker.names[name]
return ok || name == tracker.unique
}
func (tracker *nameTracker) listKnownNames() []string {
tracker.lck.RLock()
defer tracker.lck.RUnlock()
out := make([]string, 0, len(tracker.names)+1)
out = append(out, tracker.unique)
for k := range tracker.names {
out = append(out, k)
}
return out
}
type callTracker struct {
calls map[uint32]*Call
lck sync.RWMutex
}
func newCallTracker() *callTracker {
return &callTracker{calls: map[uint32]*Call{}}
}
func (tracker *callTracker) track(sn uint32, call *Call) {
tracker.lck.Lock()
tracker.calls[sn] = call
tracker.lck.Unlock()
}
func (tracker *callTracker) handleReply(msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock()
_, ok := tracker.calls[serial]
tracker.lck.RUnlock()
if ok {
tracker.finalizeWithBody(serial, msg.Body)
}
return serial
}
func (tracker *callTracker) handleDBusError(msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock()
_, ok := tracker.calls[serial]
tracker.lck.RUnlock()
if ok {
name, _ := msg.Headers[FieldErrorName].value.(string)
tracker.finalizeWithError(serial, Error{name, msg.Body})
}
return serial
}
func (tracker *callTracker) handleSendError(msg *Message, err error) {
if err == nil {
return
}
tracker.lck.RLock()
_, ok := tracker.calls[msg.serial]
tracker.lck.RUnlock()
if ok {
tracker.finalizeWithError(msg.serial, err)
}
}
// finalize was the only func that did not strobe Done
func (tracker *callTracker) finalize(sn uint32) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
c, ok := tracker.calls[sn]
if ok {
delete(tracker.calls, sn)
c.ContextCancel()
}
return
}
func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) {
tracker.lck.Lock()
c, ok := tracker.calls[sn]
if ok {
delete(tracker.calls, sn)
}
tracker.lck.Unlock()
if ok {
c.Body = body
c.done()
}
return
}
func (tracker *callTracker) finalizeWithError(sn uint32, err error) {
tracker.lck.Lock()
c, ok := tracker.calls[sn]
if ok {
delete(tracker.calls, sn)
}
tracker.lck.Unlock()
if ok {
c.Err = err
c.done()
}
return
}
func (tracker *callTracker) finalizeAllWithError(err error) {
tracker.lck.Lock()
closedCalls := make([]*Call, 0, len(tracker.calls))
for sn := range tracker.calls {
closedCalls = append(closedCalls, tracker.calls[sn])
}
tracker.calls = map[uint32]*Call{}
tracker.lck.Unlock()
for _, call := range closedCalls {
call.Err = err
call.done()
}
}

View File

@@ -31,3 +31,7 @@ func getSystemBusPlatformAddress() string {
} }
return defaultSystemBusAddress return defaultSystemBusAddress
} }
func tryDiscoverDbusSessionBusAddress() string {
return ""
}

View File

@@ -6,12 +6,14 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"os/user"
"path"
"strings"
) )
const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
func getSessionBusPlatformAddress() (string, error) { func getSessionBusPlatformAddress() (string, error) {
cmd := exec.Command("dbus-launch") cmd := exec.Command("dbus-launch")
b, err := cmd.CombinedOutput() b, err := cmd.CombinedOutput()
@@ -33,10 +35,57 @@ func getSessionBusPlatformAddress() (string, error) {
return addr, nil return addr, nil
} }
func getSystemBusPlatformAddress() string { // tryDiscoverDbusSessionBusAddress tries to discover an existing dbus session
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS") // and return the value of its DBUS_SESSION_BUS_ADDRESS.
if address != "" { // It tries different techniques employed by different operating systems,
return fmt.Sprintf("unix:path=%s", address) // returning the first valid address it finds, or an empty string.
//
// * /run/user/<uid>/bus if this exists, it *is* the bus socket. present on
// Ubuntu 18.04
// * /run/user/<uid>/dbus-session: if this exists, it can be parsed for the bus
// address. present on Ubuntu 16.04
//
// See https://dbus.freedesktop.org/doc/dbus-launch.1.html
func tryDiscoverDbusSessionBusAddress() string {
if runtimeDirectory, err := getRuntimeDirectory(); err == nil {
if runUserBusFile := path.Join(runtimeDirectory, "bus"); fileExists(runUserBusFile) {
// if /run/user/<uid>/bus exists, that file itself
// *is* the unix socket, so return its path
return fmt.Sprintf("unix:path=%s", runUserBusFile)
}
if runUserSessionDbusFile := path.Join(runtimeDirectory, "dbus-session"); fileExists(runUserSessionDbusFile) {
// if /run/user/<uid>/dbus-session exists, it's a
// text file // containing the address of the socket, e.g.:
// DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-E1c73yNqrG
if f, err := ioutil.ReadFile(runUserSessionDbusFile); err == nil {
fileContent := string(f)
prefix := "DBUS_SESSION_BUS_ADDRESS="
if strings.HasPrefix(fileContent, prefix) {
address := strings.TrimRight(strings.TrimPrefix(fileContent, prefix), "\n\r")
return address
}
}
}
}
return ""
}
func getRuntimeDirectory() (string, error) {
if currentUser, err := user.Current(); err != nil {
return "", err
} else {
return fmt.Sprintf("/run/user/%s", currentUser.Uid), nil
}
}
func fileExists(filename string) bool {
if _, err := os.Stat(filename); !os.IsNotExist(err) {
return true
} else {
return false
} }
return defaultSystemBusAddress
} }

18
vendor/github.com/godbus/dbus/conn_unix.go generated vendored Normal file
View File

@@ -0,0 +1,18 @@
//+build !windows,!solaris,!darwin
package dbus
import (
"os"
"fmt"
)
const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
func getSystemBusPlatformAddress() string {
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
if address != "" {
return fmt.Sprintf("unix:path=%s", address)
}
return defaultSystemBusAddress
}

15
vendor/github.com/godbus/dbus/conn_windows.go generated vendored Normal file
View File

@@ -0,0 +1,15 @@
//+build windows
package dbus
import "os"
const defaultSystemBusAddress = "tcp:host=127.0.0.1,port=12434"
func getSystemBusPlatformAddress() string {
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
if address != "" {
return address
}
return defaultSystemBusAddress
}

View File

@@ -191,7 +191,14 @@ func (dec *decoder) decode(s string, depth int) interface{} {
length := dec.decode("u", depth).(uint32) length := dec.decode("u", depth).(uint32)
v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length)) v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length))
// Even for empty arrays, the correct padding must be included // Even for empty arrays, the correct padding must be included
dec.align(alignment(typeFor(s[1:]))) align := alignment(typeFor(s[1:]))
if len(s) > 1 && s[1] == '(' {
//Special case for arrays of structs
//structs decode as a slice of interface{} values
//but the dbus alignment does not match this
align = 8
}
dec.align(align)
spos := dec.pos spos := dec.pos
for dec.pos < spos+int(length) { for dec.pos < spos+int(length) {
ev := dec.decode(s[1:], depth+1) ev := dec.decode(s[1:], depth+1)

View File

@@ -21,6 +21,8 @@ func newIntrospectIntf(h *defaultHandler) *exportedIntf {
//NewDefaultHandler returns an instance of the default //NewDefaultHandler returns an instance of the default
//call handler. This is useful if you want to implement only //call handler. This is useful if you want to implement only
//one of the two handlers but not both. //one of the two handlers but not both.
//
// Deprecated: this is the default value, don't use it, it will be unexported.
func NewDefaultHandler() *defaultHandler { func NewDefaultHandler() *defaultHandler {
h := &defaultHandler{ h := &defaultHandler{
objects: make(map[ObjectPath]*exportedObj), objects: make(map[ObjectPath]*exportedObj),
@@ -161,6 +163,7 @@ func newExportedObject() *exportedObj {
} }
type exportedObj struct { type exportedObj struct {
mu sync.RWMutex
interfaces map[string]*exportedIntf interfaces map[string]*exportedIntf
} }
@@ -168,19 +171,27 @@ func (obj *exportedObj) LookupInterface(name string) (Interface, bool) {
if name == "" { if name == "" {
return obj, true return obj, true
} }
obj.mu.RLock()
defer obj.mu.RUnlock()
intf, exists := obj.interfaces[name] intf, exists := obj.interfaces[name]
return intf, exists return intf, exists
} }
func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) { func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) {
obj.mu.Lock()
defer obj.mu.Unlock()
obj.interfaces[name] = iface obj.interfaces[name] = iface
} }
func (obj *exportedObj) DeleteInterface(name string) { func (obj *exportedObj) DeleteInterface(name string) {
obj.mu.Lock()
defer obj.mu.Unlock()
delete(obj.interfaces, name) delete(obj.interfaces, name)
} }
func (obj *exportedObj) LookupMethod(name string) (Method, bool) { func (obj *exportedObj) LookupMethod(name string) (Method, bool) {
obj.mu.RLock()
defer obj.mu.RUnlock()
for _, intf := range obj.interfaces { for _, intf := range obj.interfaces {
method, exists := intf.LookupMethod(name) method, exists := intf.LookupMethod(name)
if exists { if exists {
@@ -220,8 +231,12 @@ func (obj *exportedIntf) isFallbackInterface() bool {
//NewDefaultSignalHandler returns an instance of the default //NewDefaultSignalHandler returns an instance of the default
//signal handler. This is useful if you want to implement only //signal handler. This is useful if you want to implement only
//one of the two handlers but not both. //one of the two handlers but not both.
//
// Deprecated: this is the default value, don't use it, it will be unexported.
func NewDefaultSignalHandler() *defaultSignalHandler { func NewDefaultSignalHandler() *defaultSignalHandler {
return &defaultSignalHandler{} return &defaultSignalHandler{
closeChan: make(chan struct{}),
}
} }
func isDefaultSignalHandler(handler SignalHandler) bool { func isDefaultSignalHandler(handler SignalHandler) bool {
@@ -231,32 +246,47 @@ func isDefaultSignalHandler(handler SignalHandler) bool {
type defaultSignalHandler struct { type defaultSignalHandler struct {
sync.RWMutex sync.RWMutex
closed bool closed bool
signals []chan<- *Signal signals []chan<- *Signal
closeChan chan struct{}
} }
func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) { func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) {
go func() { sh.RLock()
sh.RLock() defer sh.RUnlock()
defer sh.RUnlock() if sh.closed {
if sh.closed { return
}
for _, ch := range sh.signals {
select {
case ch <- signal:
case <-sh.closeChan:
return return
default:
go func() {
select {
case ch <- signal:
case <-sh.closeChan:
return
}
}()
} }
for _, ch := range sh.signals { }
ch <- signal
}
}()
} }
func (sh *defaultSignalHandler) Init() error { func (sh *defaultSignalHandler) Init() error {
sh.Lock() sh.Lock()
sh.signals = make([]chan<- *Signal, 0) sh.signals = make([]chan<- *Signal, 0)
sh.closeChan = make(chan struct{})
sh.Unlock() sh.Unlock()
return nil return nil
} }
func (sh *defaultSignalHandler) Terminate() { func (sh *defaultSignalHandler) Terminate() {
sh.Lock() sh.Lock()
if !sh.closed {
close(sh.closeChan)
}
sh.closed = true sh.closed = true
for _, ch := range sh.signals { for _, ch := range sh.signals {
close(ch) close(ch)

View File

@@ -170,11 +170,8 @@ func (conn *Conn) handleCall(msg *Message) {
reply.Body[i] = ret[i] reply.Body[i] = ret[i]
} }
reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...)) reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...))
conn.outLck.RLock()
if !conn.closed { conn.sendMessage(reply)
conn.out <- reply
}
conn.outLck.RUnlock()
} }
} }
@@ -207,12 +204,14 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro
if len(values) > 0 { if len(values) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
} }
conn.outLck.RLock()
defer conn.outLck.RUnlock() var closed bool
if conn.closed { conn.sendMessageAndIfClosed(msg, func() {
closed = true
})
if closed {
return ErrClosed return ErrClosed
} }
conn.out <- msg
return nil return nil
} }

View File

@@ -1,6 +1,7 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
"strings" "strings"
) )
@@ -9,7 +10,11 @@ import (
// invoked. // invoked.
type BusObject interface { type BusObject interface {
Call(method string, flags Flags, args ...interface{}) *Call Call(method string, flags Flags, args ...interface{}) *Call
CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call
Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call
GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call
AddMatchSignal(iface, member string, options ...MatchOption) *Call
RemoveMatchSignal(iface, member string, options ...MatchOption) *Call
GetProperty(p string) (Variant, error) GetProperty(p string) (Variant, error)
Destination() string Destination() string
Path() ObjectPath Path() ObjectPath
@@ -24,16 +29,73 @@ type Object struct {
// Call calls a method with (*Object).Go and waits for its reply. // Call calls a method with (*Object).Go and waits for its reply.
func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call {
return <-o.Go(method, flags, make(chan *Call, 1), args...).Done return <-o.createCall(context.Background(), method, flags, make(chan *Call, 1), args...).Done
} }
// AddMatchSignal subscribes BusObject to signals from specified interface and // CallWithContext acts like Call but takes a context
// method (member). func (o *Object) CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call {
func (o *Object) AddMatchSignal(iface, member string) *Call { return <-o.createCall(ctx, method, flags, make(chan *Call, 1), args...).Done
return o.Call( }
// MatchOption specifies option for dbus routing match rule. Options can be constructed with WithMatch* helpers.
// For full list of available options consult
// https://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules
type MatchOption struct {
key string
value string
}
// WithMatchOption creates match option with given key and value
func WithMatchOption(key, value string) MatchOption {
return MatchOption{key, value}
}
// WithMatchObjectPath creates match option that filters events based on given path
func WithMatchObjectPath(path ObjectPath) MatchOption {
return MatchOption{"path", string(path)}
}
func formatMatchOptions(options []MatchOption) string {
items := make([]string, 0, len(options))
for _, option := range options {
items = append(items, option.key+"='"+option.value+"'")
}
return strings.Join(items, ",")
}
// AddMatchSignal subscribes BusObject to signals from specified interface,
// method (member). Additional filter rules can be added via WithMatch* option constructors.
// Note: To filter events by object path you have to specify this path via an option.
func (o *Object) AddMatchSignal(iface, member string, options ...MatchOption) *Call {
base := []MatchOption{
{"type", "signal"},
{"interface", iface},
{"member", member},
}
options = append(base, options...)
return o.conn.BusObject().Call(
"org.freedesktop.DBus.AddMatch", "org.freedesktop.DBus.AddMatch",
0, 0,
"type='signal',interface='"+iface+"',member='"+member+"'", formatMatchOptions(options),
)
}
// RemoveMatchSignal unsubscribes BusObject from signals from specified interface,
// method (member). Additional filter rules can be added via WithMatch* option constructors
func (o *Object) RemoveMatchSignal(iface, member string, options ...MatchOption) *Call {
base := []MatchOption{
{"type", "signal"},
{"interface", iface},
{"member", member},
}
options = append(base, options...)
return o.conn.BusObject().Call(
"org.freedesktop.DBus.RemoveMatch",
0,
formatMatchOptions(options),
) )
} }
@@ -49,6 +111,18 @@ func (o *Object) AddMatchSignal(iface, member string) *Call {
// If the method parameter contains a dot ('.'), the part before the last dot // If the method parameter contains a dot ('.'), the part before the last dot
// specifies the interface on which the method is called. // specifies the interface on which the method is called.
func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call { func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
return o.createCall(context.Background(), method, flags, ch, args...)
}
// GoWithContext acts like Go but takes a context
func (o *Object) GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
return o.createCall(ctx, method, flags, ch, args...)
}
func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
if ctx == nil {
panic("nil context")
}
iface := "" iface := ""
i := strings.LastIndex(method, ".") i := strings.LastIndex(method, ".")
if i != -1 { if i != -1 {
@@ -76,28 +150,28 @@ func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface
} else if cap(ch) == 0 { } else if cap(ch) == 0 {
panic("dbus: unbuffered channel passed to (*Object).Go") panic("dbus: unbuffered channel passed to (*Object).Go")
} }
ctx, cancel := context.WithCancel(ctx)
call := &Call{ call := &Call{
Destination: o.dest, Destination: o.dest,
Path: o.path, Path: o.path,
Method: method, Method: method,
Args: args, Args: args,
Done: ch, Done: ch,
ctxCanceler: cancel,
ctx: ctx,
} }
o.conn.callsLck.Lock() o.conn.calls.track(msg.serial, call)
o.conn.calls[msg.serial] = call o.conn.sendMessageAndIfClosed(msg, func() {
o.conn.callsLck.Unlock() o.conn.calls.handleSendError(msg, ErrClosed)
o.conn.outLck.RLock() cancel()
if o.conn.closed { })
call.Err = ErrClosed go func() {
call.Done <- call <-ctx.Done()
} else { o.conn.calls.handleSendError(msg, ctx.Err())
o.conn.out <- msg }()
}
o.conn.outLck.RUnlock()
return call return call
} }
o.conn.outLck.RLock()
defer o.conn.outLck.RUnlock()
done := make(chan *Call, 1) done := make(chan *Call, 1)
call := &Call{ call := &Call{
Err: nil, Err: nil,
@@ -107,11 +181,9 @@ func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface
call.Done <- call call.Done <- call
close(done) close(done)
}() }()
if o.conn.closed { o.conn.sendMessageAndIfClosed(msg, func() {
call.Err = ErrClosed call.Err = ErrClosed
return call })
}
o.conn.out <- msg
return call return call
} }

View File

@@ -87,3 +87,13 @@ type SignalHandler interface {
type DBusError interface { type DBusError interface {
DBusError() (string, []interface{}) DBusError() (string, []interface{})
} }
// SerialGenerator is responsible for serials generation.
//
// Different approaches for the serial generation can be used,
// maintaining a map guarded with a mutex (the standard way) or
// simply increment an atomic counter.
type SerialGenerator interface {
GetSerial() uint32
RetireSerial(serial uint32)
}

View File

@@ -11,7 +11,7 @@ var nativeEndian binary.ByteOrder
func detectEndianness() binary.ByteOrder { func detectEndianness() binary.ByteOrder {
var x uint32 = 0x01020304 var x uint32 = 0x01020304
if *(*byte)(unsafe.Pointer(&x)) == 0x01 { if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
return binary.BigEndian return binary.BigEndian
} }
return binary.LittleEndian return binary.LittleEndian

39
vendor/github.com/godbus/dbus/transport_nonce_tcp.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
//+build !windows
package dbus
import (
"errors"
"io/ioutil"
"net"
)
func init() {
transports["nonce-tcp"] = newNonceTcpTransport
}
func newNonceTcpTransport(keys string) (transport, error) {
host := getKey(keys, "host")
port := getKey(keys, "port")
noncefile := getKey(keys, "noncefile")
if host == "" || port == "" || noncefile == "" {
return nil, errors.New("dbus: unsupported address (must set host, port and noncefile)")
}
protocol, err := tcpFamily(keys)
if err != nil {
return nil, err
}
socket, err := net.Dial(protocol, net.JoinHostPort(host, port))
if err != nil {
return nil, err
}
b, err := ioutil.ReadFile(noncefile)
if err != nil {
return nil, err
}
_, err = socket.Write(b)
if err != nil {
return nil, err
}
return NewConn(socket)
}

View File

@@ -31,6 +31,7 @@ func (o *oobReader) Read(b []byte) (n int, err error) {
type unixTransport struct { type unixTransport struct {
*net.UnixConn *net.UnixConn
rdr *oobReader
hasUnixFDs bool hasUnixFDs bool
} }
@@ -79,10 +80,15 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// To be sure that all bytes of out-of-band data are read, we use a special // To be sure that all bytes of out-of-band data are read, we use a special
// reader that uses ReadUnix on the underlying connection instead of Read // reader that uses ReadUnix on the underlying connection instead of Read
// and gathers the out-of-band data in a buffer. // and gathers the out-of-band data in a buffer.
rd := &oobReader{conn: t.UnixConn} if t.rdr == nil {
t.rdr = &oobReader{conn: t.UnixConn}
} else {
t.rdr.oob = nil
}
// read the first 16 bytes (the part of the header that has a constant size), // read the first 16 bytes (the part of the header that has a constant size),
// from which we can figure out the length of the rest of the message // from which we can figure out the length of the rest of the message
if _, err := io.ReadFull(rd, csheader[:]); err != nil { if _, err := io.ReadFull(t.rdr, csheader[:]); err != nil {
return nil, err return nil, err
} }
switch csheader[0] { switch csheader[0] {
@@ -104,7 +110,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// decode headers and look for unix fds // decode headers and look for unix fds
headerdata := make([]byte, hlen+4) headerdata := make([]byte, hlen+4)
copy(headerdata, csheader[12:]) copy(headerdata, csheader[12:])
if _, err := io.ReadFull(t, headerdata[4:]); err != nil { if _, err := io.ReadFull(t.rdr, headerdata[4:]); err != nil {
return nil, err return nil, err
} }
dec := newDecoder(bytes.NewBuffer(headerdata), order) dec := newDecoder(bytes.NewBuffer(headerdata), order)
@@ -122,7 +128,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
all := make([]byte, 16+hlen+blen) all := make([]byte, 16+hlen+blen)
copy(all, csheader[:]) copy(all, csheader[:])
copy(all[16:], headerdata[4:]) copy(all[16:], headerdata[4:])
if _, err := io.ReadFull(rd, all[16+hlen:]); err != nil { if _, err := io.ReadFull(t.rdr, all[16+hlen:]); err != nil {
return nil, err return nil, err
} }
if unixfds != 0 { if unixfds != 0 {
@@ -130,7 +136,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
return nil, errors.New("dbus: got unix fds on unsupported transport") return nil, errors.New("dbus: got unix fds on unsupported transport")
} }
// read the fds from the OOB data // read the fds from the OOB data
scms, err := syscall.ParseSocketControlMessage(rd.oob) scms, err := syscall.ParseSocketControlMessage(t.rdr.oob)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -148,11 +154,23 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// substitute the values in the message body (which are indices for the // substitute the values in the message body (which are indices for the
// array receiver via OOB) with the actual values // array receiver via OOB) with the actual values
for i, v := range msg.Body { for i, v := range msg.Body {
if j, ok := v.(UnixFDIndex); ok { switch v.(type) {
case UnixFDIndex:
j := v.(UnixFDIndex)
if uint32(j) >= unixfds { if uint32(j) >= unixfds {
return nil, InvalidMessageError("invalid index for unix fd") return nil, InvalidMessageError("invalid index for unix fd")
} }
msg.Body[i] = UnixFD(fds[j]) msg.Body[i] = UnixFD(fds[j])
case []UnixFDIndex:
idxArray := v.([]UnixFDIndex)
fdArray := make([]UnixFD, len(idxArray))
for k, j := range idxArray {
if uint32(j) >= unixfds {
return nil, InvalidMessageError("invalid index for unix fd")
}
fdArray[k] = UnixFD(fds[j])
}
msg.Body[i] = fdArray
} }
} }
return msg, nil return msg, nil

Some files were not shown because too many files have changed in this diff Show More