Skip to content
This repository has been archived by the owner on May 12, 2021. It is now read-only.

Commit

Permalink
terminal: Add support for Darwin
Browse files Browse the repository at this point in the history
Created a new `terminal_darwin.go` (and associated test).

Made changes to .travis.yml to support travis osx tests

Fixes #86

Signed-off-by: Ricardo Aravena <raravena@branch.io>
  • Loading branch information
raravena80 committed Jun 21, 2018
1 parent 937a9a3 commit 6103bb1
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 4 deletions.
18 changes: 14 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@
# SPDX-License-Identifier: Apache-2.0
#

sudo: required
dist: trusty

os:
- linux
- osx

matrix:
include:
- os: linux
sudo: required
dist: trusty

language: go
go_import_path: github.com/kata-containers/shim
Expand All @@ -17,8 +25,10 @@ before_script:
- ".ci/static-checks.sh"

before_install:
- sudo apt-get update -qq
- sudo apt-get install -y -qq automake
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install automake ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update -qq ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y -qq automake ; fi

install:
- cd ${TRAVIS_BUILD_DIR} && make
Expand Down
49 changes: 49 additions & 0 deletions terminal_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) 2017 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//

package main

import (
"golang.org/x/sys/unix"
)

const (
termiosIFlagRawTermInvMask = (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
termiosOFlagRawTermInvMask = unix.OPOST
termiosLFlagRawTermInvMask = (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
termiosCFlagRawTermInvMask = unix.PARENB
termiosCFlagRawTermMask = unix.CS8
termiosCcVMinRawTermVal = 1
termiosCcVTimeRawTermVal = 0
)

func setupTerminal(fd int) (*unix.Termios, error) {
termios, err := unix.IoctlGetTermios(fd, unix.TIOCGETA)
if err != nil {
return nil, err
}

var savedTermios unix.Termios
savedTermios = *termios

// Set the terminal in raw mode
termios.Iflag &^= termiosIFlagRawTermInvMask
termios.Oflag &^= termiosOFlagRawTermInvMask
termios.Lflag &^= termiosLFlagRawTermInvMask
termios.Cflag &^= termiosCFlagRawTermInvMask
termios.Cflag |= termiosCFlagRawTermMask
termios.Cc[unix.VMIN] = termiosCcVMinRawTermVal
termios.Cc[unix.VTIME] = termiosCcVTimeRawTermVal

if err := unix.IoctlSetTermios(fd, unix.TIOCSETA, termios); err != nil {
return nil, err
}

return &savedTermios, nil
}

func restoreTerminal(fd int, termios *unix.Termios) error {
return unix.IoctlSetTermios(fd, unix.TIOCSETA, termios)
}
72 changes: 72 additions & 0 deletions terminal_darwin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) 2017 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//

package main

import (
"io/ioutil"
"os"
"syscall"
"testing"

"github.com/stretchr/testify/assert"
"golang.org/x/sys/unix"
)

const (
RawModeErr = "should be properly set in raw mode"
FlagRawModeErr = "flag " + RawModeErr
ValueRawModeErr = "value " + RawModeErr
)

func newTestTerminal(t *testing.T) (*os.File, error) {
if os.Getuid() != 0 {
t.Skip("Skipping this test: Requires to be root")
return nil, nil
}

return os.OpenFile("/dev/tty", os.O_RDWR, os.ModeDevice)
}

func TestSetupTerminalOnNonTerminalFailure(t *testing.T) {
file, err := ioutil.TempFile("", "tmp")
assert.Nil(t, err, "Failed to create temporary file")
defer file.Close()

_, err = setupTerminal(int(file.Fd()))
assert.NotNil(t, err, "Should fail because the file is not a terminal")
}

func TestSetupTerminalSuccess(t *testing.T) {
file, err := newTestTerminal(t)

if perr, ok := err.(*os.PathError); ok {
switch perr.Err.(syscall.Errno) {
case syscall.ENXIO:
t.Skip("Skipping this test: Failed to open tty, make sure test is running in a tty")
default:
t.Fatalf("could not open tty %s", err)
}
}

assert.Nil(t, err, "Failed to create terminal")
defer file.Close()

savedTermios, err := setupTerminal(int(file.Fd()))
assert.Nil(t, err, "Should not fail because the file is a terminal")

termios, err := unix.IoctlGetTermios(int(file.Fd()), unix.TIOCGETA)
assert.Nil(t, err, "Failed to get terminal information")
assert.True(t, (termios.Iflag&termiosIFlagRawTermInvMask) == 0, "Termios I %s", FlagRawModeErr)
assert.True(t, (termios.Oflag&termiosOFlagRawTermInvMask) == 0, "Termios O %s", FlagRawModeErr)
assert.True(t, (termios.Lflag&termiosLFlagRawTermInvMask) == 0, "Termios L %s", FlagRawModeErr)
assert.True(t, (termios.Cflag&termiosCFlagRawTermInvMask) == 0, "Termios C %s", FlagRawModeErr)
assert.True(t, (termios.Cflag&termiosCFlagRawTermMask) == termiosCFlagRawTermMask, "Termios C %s", FlagRawModeErr)
assert.True(t, termios.Cc[unix.VMIN] == termiosCcVMinRawTermVal, "Termios CC VMIN %s", ValueRawModeErr)
assert.True(t, termios.Cc[unix.VTIME] == termiosCcVTimeRawTermVal, "Termios CC VTIME %s", ValueRawModeErr)

err = restoreTerminal(int(file.Fd()), savedTermios)
assert.Nil(t, err, "Terminal should be properly restored")
}

0 comments on commit 6103bb1

Please sign in to comment.