blob: 21273a9e83834b2354b6066c3c025c126cb98379 [file] [log] [blame]
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "vm_tools/vsh/scoped_termios.h"
#include <fcntl.h>
#include <sys/types.h>
#include <utility>
#include <base/files/scoped_file.h>
#include <base/logging.h>
namespace vm_tools {
namespace vsh {
ScopedTermios::ScopedTermios(base::ScopedFD tty_fd)
: tty_fd_(std::move(tty_fd)), has_termios_(false) {}
ScopedTermios::~ScopedTermios() {
if (!Restore())
LOG(ERROR) << "Failed to reset termios settings. Terminal may be broken.";
}
bool ScopedTermios::SetTermiosMode(TermiosMode mode) {
if (!has_termios_) {
if (tcgetattr(tty_fd_.get(), &saved_termios_) < 0) {
PLOG(ERROR) << "Error getting termios attributes";
return false;
}
has_termios_ = true;
}
struct termios new_termios = saved_termios_;
// The termios flags below are lifted from cfmakeraw(3).
switch (mode) {
case TermiosMode::RAW:
new_termios.c_iflag &=
~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
new_termios.c_oflag &= ~(OPOST);
new_termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
new_termios.c_cflag &= ~(CSIZE | PARENB);
new_termios.c_cflag |= (CS8);
break;
case TermiosMode::CANON:
new_termios.c_iflag |=
(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
new_termios.c_oflag |= (OPOST);
new_termios.c_lflag |= (ECHO | ECHONL | ICANON | ISIG | IEXTEN);
new_termios.c_cflag |= (CSIZE | PARENB);
new_termios.c_cflag |= (CS8);
break;
}
if (tcsetattr(tty_fd_.get(), TCSAFLUSH, &new_termios) < 0) {
PLOG(ERROR) << "Error setting termios attributes";
return false;
}
return true;
}
bool ScopedTermios::Restore() {
// If SetTermiosMode() was never called, Restore() should do nothing.
if (!has_termios_)
return true;
if (tcsetattr(tty_fd_.get(), TCSAFLUSH, &saved_termios_) < 0) {
PLOG(ERROR) << "Error restoring termios attributes";
return false;
}
// Once the Restore() is done, don't bother doing another Restore() unless
// SetTermiosMode() is called again.
has_termios_ = false;
return true;
}
int ScopedTermios::GetRawFD() {
return tty_fd_.get();
}
} // namespace vsh
} // namespace vm_tools