diff --git a/.golangci.yml b/.golangci.yml index 421b8075..68e4a90a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -32,7 +32,7 @@ linters: # currently active linters: # #INFO [lintersdb] Active 35 linters: [asasalint asciicheck bidichk contextcheck decorder depguard durationcheck errcheck exportloopref - # gocheckcompilerdirectives gomoddirectives gomodguard goprintffuncname gosimple govet grouper importas ineffassign mirror musttag + # gocheckcompilerdirectives gomoddirectives gomodguard goprintffuncname gosimple govet grouper ineffassign mirror musttag # nilerr nilnil nolintlint nosprintfhostport prealloc reassign revive staticcheck tagalign tenv testableexamples tparallel typecheck unused wastedassign] enable-all: true @@ -62,6 +62,7 @@ linters: - goerr113 # not used (we allow error creation at return statement) - gofumpt # not used (we use "go fmt" or "gofmt" not gofumpt" - gosmopolitan # not needed (report i18n/l10n anti-patterns) + - importas # not needed (there is no alias rule at the moment) - ireturn # not used (we allow return interfaces) - loggercheck # not needed (relates to kitlog, klog, logr, zap) - paralleltest # not used diff --git a/Makefile b/Makefile index 75757935..4d7c4b56 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ including_except := $(shell go list ./... | grep -v platforms/opencv) # Run tests on nearly all directories without test cache test: - go test -count=1 -v $(including_except) + go test -failfast -count=1 -v $(including_except) # Run tests with race detection test_race: diff --git a/drivers/i2c/i2c_connection_test.go b/drivers/i2c/i2c_connection_test.go index f8a1a17d..7e760074 100644 --- a/drivers/i2c/i2c_connection_test.go +++ b/drivers/i2c/i2c_connection_test.go @@ -7,7 +7,6 @@ import ( "errors" "testing" - "syscall" "unsafe" "gobot.io/x/gobot/v2" @@ -17,13 +16,13 @@ import ( const dev = "/dev/i2c-1" -func getSyscallFuncImpl(errorMask byte) func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { +func getSyscallFuncImpl(errorMask byte) func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err system.SyscallErrno) { // bit 0: error on function query // bit 1: error on set address // bit 2: error on command - return func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { + return func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err system.SyscallErrno) { // function query - if (trap == syscall.SYS_IOCTL) && (a2 == system.I2C_FUNCS) { + if (trap == system.Syscall_SYS_IOCTL) && (a2 == system.I2C_FUNCS) { if errorMask&0x01 == 0x01 { return 0, 0, 1 } @@ -35,13 +34,13 @@ func getSyscallFuncImpl(errorMask byte) func(trap, a1, a2, a3 uintptr) (r1, r2 u system.I2C_FUNC_SMBUS_WRITE_WORD_DATA } // set address - if (trap == syscall.SYS_IOCTL) && (a2 == system.I2C_SLAVE) { + if (trap == system.Syscall_SYS_IOCTL) && (a2 == system.I2C_SLAVE) { if errorMask&0x02 == 0x02 { return 0, 0, 1 } } // command - if (trap == syscall.SYS_IOCTL) && (a2 == system.I2C_SMBUS) { + if (trap == system.Syscall_SYS_IOCTL) && (a2 == system.I2C_SMBUS) { if errorMask&0x04 == 0x04 { return 0, 0, 1 } diff --git a/system/digitalpin_sysfs.go b/system/digitalpin_sysfs.go index 7516a49d..b716ff63 100644 --- a/system/digitalpin_sysfs.go +++ b/system/digitalpin_sysfs.go @@ -7,7 +7,6 @@ import ( "log" "os" "strconv" - "syscall" "time" "gobot.io/x/gobot/v2" @@ -92,7 +91,7 @@ func (d *digitalPinSysfs) Unexport() error { if err != nil { // If EINVAL then the pin is reserved in the system and can't be unexported e, ok := err.(*os.PathError) - if !ok || e.Err != syscall.EINVAL { + if !ok || e.Err != Syscall_EINVAL { return err } } @@ -126,7 +125,7 @@ func (d *digitalPinSysfs) reconfigure() error { if err != nil { // If EBUSY then the pin has already been exported e, ok := err.(*os.PathError) - if !ok || e.Err != syscall.EBUSY { + if !ok || e.Err != Syscall_EBUSY { return err } } diff --git a/system/digitalpin_sysfs_test.go b/system/digitalpin_sysfs_test.go index ba169984..992a06be 100644 --- a/system/digitalpin_sysfs_test.go +++ b/system/digitalpin_sysfs_test.go @@ -3,7 +3,6 @@ package system import ( "errors" "os" - "syscall" "testing" "gobot.io/x/gobot/v2" @@ -63,7 +62,7 @@ func TestDigitalPin(t *testing.T) { gobottest.Assert(t, data, 0) writeFile = func(File, []byte) (int, error) { - return 0, &os.PathError{Err: syscall.EINVAL} + return 0, &os.PathError{Err: Syscall_EINVAL} } err = pin.Unexport() @@ -81,7 +80,7 @@ func TestDigitalPin(t *testing.T) { writeFile = func(File, []byte) (int, error) { cnt++ if cnt == 1 { - return 0, &os.PathError{Err: syscall.EBUSY} + return 0, &os.PathError{Err: Syscall_EBUSY} } return 0, nil } @@ -104,7 +103,7 @@ func TestDigitalPinExportError(t *testing.T) { pin, _ := initTestDigitalPinSysFsWithMockedFilesystem(mockPaths) writeFile = func(File, []byte) (int, error) { - return 0, &os.PathError{Err: syscall.EBUSY} + return 0, &os.PathError{Err: Syscall_EBUSY} } err := pin.Export() @@ -118,7 +117,7 @@ func TestDigitalPinUnexportError(t *testing.T) { pin, _ := initTestDigitalPinSysFsWithMockedFilesystem(mockPaths) writeFile = func(File, []byte) (int, error) { - return 0, &os.PathError{Err: syscall.EBUSY} + return 0, &os.PathError{Err: Syscall_EBUSY} } err := pin.Unexport() diff --git a/system/i2c_device.go b/system/i2c_device.go index 754d2a53..9b771752 100644 --- a/system/i2c_device.go +++ b/system/i2c_device.go @@ -5,7 +5,6 @@ import ( "log" "os" "sync" - "syscall" "unsafe" ) @@ -375,7 +374,7 @@ func (d *i2cDevice) syscallIoctl(signal uintptr, payload unsafe.Pointer, sender if err := d.openFileLazy(sender); err != nil { return err } - if _, _, errno := d.sys.syscall(syscall.SYS_IOCTL, d.file, signal, payload); errno != 0 { + if _, _, errno := d.sys.syscall(Syscall_SYS_IOCTL, d.file, signal, payload); errno != 0 { return fmt.Errorf("%s failed with syscall.Errno %v", sender, errno) } diff --git a/system/i2c_device_test.go b/system/i2c_device_test.go index deeacb34..f40124d0 100644 --- a/system/i2c_device_test.go +++ b/system/i2c_device_test.go @@ -3,7 +3,6 @@ package system import ( "errors" "os" - "syscall" "testing" "unsafe" @@ -13,13 +12,13 @@ import ( const dev = "/dev/i2c-1" -func getSyscallFuncImpl(errorMask byte) func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { +func getSyscallFuncImpl(errorMask byte) func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err SyscallErrno) { // bit 0: error on function query // bit 1: error on set address // bit 2: error on command - return func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { + return func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err SyscallErrno) { // function query - if (trap == syscall.SYS_IOCTL) && (a2 == I2C_FUNCS) { + if (trap == Syscall_SYS_IOCTL) && (a2 == I2C_FUNCS) { if errorMask&0x01 == 0x01 { return 0, 0, 1 } @@ -31,13 +30,13 @@ func getSyscallFuncImpl(errorMask byte) func(trap, a1, a2, a3 uintptr) (r1, r2 u I2C_FUNC_SMBUS_WRITE_WORD_DATA } // set address - if (trap == syscall.SYS_IOCTL) && (a2 == I2C_SLAVE) { + if (trap == Syscall_SYS_IOCTL) && (a2 == I2C_SLAVE) { if errorMask&0x02 == 0x02 { return 0, 0, 1 } } // command - if (trap == syscall.SYS_IOCTL) && (a2 == I2C_SMBUS) { + if (trap == Syscall_SYS_IOCTL) && (a2 == I2C_SMBUS) { if errorMask&0x04 == 0x04 { return 0, 0, 1 } @@ -117,7 +116,7 @@ func TestWriteRead(t *testing.T) { func TestReadByte(t *testing.T) { var tests = map[string]struct { funcs uint64 - syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) + syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "read_byte_ok": { @@ -161,7 +160,7 @@ func TestReadByte(t *testing.T) { func TestReadByteData(t *testing.T) { var tests = map[string]struct { funcs uint64 - syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) + syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "read_byte_data_ok": { @@ -208,7 +207,7 @@ func TestReadByteData(t *testing.T) { func TestReadWordData(t *testing.T) { var tests = map[string]struct { funcs uint64 - syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) + syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "read_word_data_ok": { @@ -272,7 +271,7 @@ func TestReadBlockData(t *testing.T) { ) var tests = map[string]struct { funcs uint64 - syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) + syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "read_block_data_ok": { @@ -317,7 +316,7 @@ func TestReadBlockData(t *testing.T) { func TestWriteByte(t *testing.T) { var tests = map[string]struct { funcs uint64 - syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) + syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "write_byte_ok": { @@ -359,7 +358,7 @@ func TestWriteByte(t *testing.T) { func TestWriteByteData(t *testing.T) { var tests = map[string]struct { funcs uint64 - syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) + syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "write_byte_data_ok": { @@ -406,7 +405,7 @@ func TestWriteByteData(t *testing.T) { func TestWriteWordData(t *testing.T) { var tests = map[string]struct { funcs uint64 - syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) + syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "write_word_data_ok": { @@ -471,7 +470,7 @@ func TestWriteBlockData(t *testing.T) { ) var tests = map[string]struct { funcs uint64 - syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) + syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err SyscallErrno) wantErr string }{ "write_block_data_ok": { @@ -533,7 +532,7 @@ func Test_queryFunctionality(t *testing.T) { var tests = map[string]struct { requested uint64 dev string - syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) + syscallImpl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err SyscallErrno) wantErr string wantFile bool wantFuncs uint64 diff --git a/system/pwmpin_sysfs.go b/system/pwmpin_sysfs.go index 1b1cf78e..d695c676 100644 --- a/system/pwmpin_sysfs.go +++ b/system/pwmpin_sysfs.go @@ -6,7 +6,6 @@ import ( "os" "path" "strconv" - "syscall" "time" ) @@ -50,7 +49,7 @@ func (p *pwmPinSysFs) Export() error { if err != nil { // If EBUSY then the pin has already been exported e, ok := err.(*os.PathError) - if !ok || e.Err != syscall.EBUSY { + if !ok || e.Err != Syscall_EBUSY { return fmt.Errorf(pwmPinErrorPattern, "Export", p.pin, err) } } diff --git a/system/pwmpin_sysfs_test.go b/system/pwmpin_sysfs_test.go index 986fc43a..44c22497 100644 --- a/system/pwmpin_sysfs_test.go +++ b/system/pwmpin_sysfs_test.go @@ -2,7 +2,6 @@ package system import ( "os" - "syscall" "testing" "gobot.io/x/gobot/v2" @@ -85,7 +84,7 @@ func TestPwmPinAlreadyExported(t *testing.T) { pin, _ := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) pin.write = func(filesystem, string, []byte) (int, error) { - return 0, &os.PathError{Err: syscall.EBUSY} + return 0, &os.PathError{Err: Syscall_EBUSY} } // no error indicates that the pin was already exported @@ -103,7 +102,7 @@ func TestPwmPinExportError(t *testing.T) { pin, _ := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) pin.write = func(filesystem, string, []byte) (int, error) { - return 0, &os.PathError{Err: syscall.EFAULT} + return 0, &os.PathError{Err: Syscall_EFAULT} } // no error indicates that the pin was already exported @@ -122,7 +121,7 @@ func TestPwmPinUnxportError(t *testing.T) { pin, _ := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) pin.write = func(filesystem, string, []byte) (int, error) { - return 0, &os.PathError{Err: syscall.EBUSY} + return 0, &os.PathError{Err: Syscall_EBUSY} } err := pin.Unexport() @@ -140,7 +139,7 @@ func TestPwmPinPeriodError(t *testing.T) { pin, _ := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) pin.read = func(filesystem, string) ([]byte, error) { - return nil, &os.PathError{Err: syscall.EBUSY} + return nil, &os.PathError{Err: Syscall_EBUSY} } _, err := pin.Period() @@ -158,7 +157,7 @@ func TestPwmPinPolarityError(t *testing.T) { pin, _ := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) pin.read = func(filesystem, string) ([]byte, error) { - return nil, &os.PathError{Err: syscall.EBUSY} + return nil, &os.PathError{Err: Syscall_EBUSY} } _, err := pin.Polarity() @@ -176,7 +175,7 @@ func TestPwmPinDutyCycleError(t *testing.T) { pin, _ := initTestPWMPinSysFsWithMockedFilesystem(mockedPaths) pin.read = func(filesystem, string) ([]byte, error) { - return nil, &os.PathError{Err: syscall.EBUSY} + return nil, &os.PathError{Err: Syscall_EBUSY} } _, err := pin.DutyCycle() diff --git a/system/syscall.go b/system/syscall.go index ae630ade..633bd9ba 100644 --- a/system/syscall.go +++ b/system/syscall.go @@ -1,14 +1,32 @@ package system import ( - "syscall" "unsafe" + + "golang.org/x/sys/unix" +) + +// SyscallErrno wraps the "unix.Errno" +type SyscallErrno unix.Errno + +// wrapping for used constants of unix package +const ( + Syscall_SYS_IOCTL = unix.SYS_IOCTL + Syscall_EINVAL = unix.EINVAL + Syscall_EBUSY = unix.EBUSY + Syscall_EFAULT = unix.EFAULT ) // nativeSyscall represents the native Syscall type nativeSyscall struct{} -// Syscall calls the native syscall.Syscall, implements the SystemCaller interface -func (sys *nativeSyscall) syscall(trap uintptr, f File, signal uintptr, payload unsafe.Pointer) (r1, r2 uintptr, err syscall.Errno) { - return syscall.Syscall(trap, f.Fd(), signal, uintptr(payload)) +// Syscall calls the native unix.Syscall, implements the SystemCaller interface +func (sys *nativeSyscall) syscall(trap uintptr, f File, signal uintptr, payload unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) { + r1, r2, errNo := unix.Syscall(trap, f.Fd(), signal, uintptr(payload)) + return r1, r2, SyscallErrno(errNo) +} + +// Error implements the error interface. It wraps the "unix.Errno.Error()". +func (e SyscallErrno) Error() string { + return unix.Errno(e).Error() } diff --git a/system/syscall_mock.go b/system/syscall_mock.go index ce849612..8f00d019 100644 --- a/system/syscall_mock.go +++ b/system/syscall_mock.go @@ -1,7 +1,6 @@ package system import ( - "syscall" "unsafe" ) @@ -14,11 +13,11 @@ type mockSyscall struct { smbus *i2cSmbusIoctlData sliceSize uint8 dataSlice []byte - Impl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) + Impl func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err SyscallErrno) } // Syscall calls the user defined implementation, used for tests, implements the SystemCaller interface -func (sys *mockSyscall) syscall(trap uintptr, f File, signal uintptr, payload unsafe.Pointer) (r1, r2 uintptr, err syscall.Errno) { +func (sys *mockSyscall) syscall(trap uintptr, f File, signal uintptr, payload unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) { sys.lastTrap = trap // points to the used syscall (e.g. "SYS_IOCTL") sys.lastFile = f // a character device file (e.g. file to path "/dev/i2c-1") sys.lastSignal = signal // points to used function type (e.g. I2C_SMBUS, I2C_RDWR) diff --git a/system/system.go b/system/system.go index 06111acd..824d4386 100644 --- a/system/system.go +++ b/system/system.go @@ -2,7 +2,6 @@ package system import ( "os" - "syscall" "unsafe" "gobot.io/x/gobot/v2" @@ -33,7 +32,7 @@ type filesystem interface { // systemCaller represents unexposed Syscall interface to allow the switch between native and mocked implementation // Prevent unsafe call, since go 1.15, see "Pattern 4" in: https://go101.org/article/unsafe.html type systemCaller interface { - syscall(trap uintptr, f File, signal uintptr, payload unsafe.Pointer) (r1, r2 uintptr, err syscall.Errno) + syscall(trap uintptr, f File, signal uintptr, payload unsafe.Pointer) (r1, r2 uintptr, err SyscallErrno) } // digitalPinAccesser represents unexposed interface to allow the switch between different implementations and