/* Copyright (c) 2008, 2009 Nicira Networks, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* In addition, as a special exception, Nicira Networks gives permission
* to link the code of its release of vswitchd with the OpenSSL project's
* "OpenSSL" library (or with modified versions of it that use the same
* license as the "OpenSSL" library), and distribute the linked
* executables. You must obey the GNU General Public License in all
* respects for all of the code used other than "OpenSSL". If you modify
* this file, you may extend this exception to your version of the file,
* but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version.
*
*/
#include
#include "extras/ezio/vt.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include "util.h"
#define THIS_MODULE VLM_vt
#include "vlog.h"
static bool get_console_fd(int *fd);
int
vt_open(int open_flags)
{
int console_fd, vt_fd;
char name[16];
int vt;
if (!get_console_fd(&console_fd)) {
return -EACCES;
}
/* Deallocate all unused virtual terminals, so that we don't proliferate an
* excess of empty ones over multiple runs. */
if (ioctl(console_fd, VT_DISALLOCATE, 0) < 0) {
VLOG_WARN("failed to deallocate empty virtual terminals: %s",
strerror(errno));
}
/* Find a unused virtual terminal. */
if (ioctl(console_fd, VT_OPENQRY, &vt) < 0) {
int error = errno;
VLOG_ERR("failed to find a free virtual terminal: %s",
strerror(error));
close(console_fd);
return -error;
}
/* Open virtual terminal. */
sprintf(name, "/dev/tty%d", vt);
vt_fd = open(name, open_flags);
if (vt_fd < 0) {
int error = errno;
VLOG_ERR("failed to open %s: %s", name, strerror(error));
close(console_fd);
return -error;
}
/* Activate virtual terminal. */
if (ioctl(console_fd, VT_ACTIVATE, vt) < 0
|| ioctl(console_fd, VT_WAITACTIVE, vt) < 0) {
int error = errno;
VLOG_ERR("could not activate virtual terminal %d: %s",
vt, strerror(error));
close(console_fd);
close(vt_fd);
return -error;
}
/* Success. */
VLOG_DBG("allocated virtual terminal %d (%s)", vt, name);
close(console_fd);
return vt_fd;
}
static bool
is_console(int fd)
{
uint8_t type = 0;
return !ioctl(fd, KDGKBTYPE, &type) && (type == KB_101 || type == KB_84);
}
static bool
open_console(const char *name, int *fdp)
{
*fdp = open(name, O_RDWR | O_NOCTTY);
if (*fdp >= 0) {
if (is_console(*fdp)) {
return true;
}
close(*fdp);
}
return false;
}
static bool
get_console_fd(int *fdp)
{
int fd;
if (open_console("/dev/tty", fdp)
|| open_console("/dev/tty0", fdp)
|| open_console("/dev/console", fdp)) {
return true;
}
for (fd = 0; fd < 3; fd++) {
if (is_console(fd)) {
*fdp = dup(fd);
if (*fdp >= 0) {
return true;
}
}
}
VLOG_ERR("unable to obtain a file descriptor for the console");
return false;
}