From 4c1eabc12300be3190d2fb66edc07d9c607f539e Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Fri, 20 Aug 2010 12:37:01 -0700 Subject: [PATCH] Remove ezio-term and ovs-switchui utilities. These utilities were useful when Nicira was building switches with 16x2 LCD front panel displays, but they aren't useful for other environments and even Nicira does not use that kind of switch any longer. So remove them and all the build infrastructure on which they depended. --- Makefile.am | 3 - configure.ac | 4 - debian/.gitignore | 1 - debian/automake.mk | 5 - debian/control | 34 +- debian/openvswitch-switchui.copyright | 21 - debian/openvswitch-switchui.default | 35 - debian/openvswitch-switchui.dirs | 3 - debian/openvswitch-switchui.init | 210 -- debian/openvswitch-switchui.install | 3 - debian/rules | 1 - extras/ezio/automake.mk | 52 - extras/ezio/ezio-term.c | 1037 --------- extras/ezio/ezio.c | 231 -- extras/ezio/ezio.h | 84 - extras/ezio/ezio3.ti | 21 - extras/ezio/ovs-switchui.c | 3004 ------------------------- extras/ezio/terminal.c | 821 ------- extras/ezio/terminal.h | 29 - extras/ezio/tty.c | 394 ---- extras/ezio/tty.h | 27 - extras/ezio/vt-dummy.c | 28 - extras/ezio/vt-linux.c | 127 -- extras/ezio/vt.h | 21 - lib/vlog-modules.def | 2 - m4/openvswitch.m4 | 77 - 26 files changed, 1 insertion(+), 6274 deletions(-) delete mode 100644 debian/openvswitch-switchui.copyright delete mode 100644 debian/openvswitch-switchui.default delete mode 100644 debian/openvswitch-switchui.dirs delete mode 100755 debian/openvswitch-switchui.init delete mode 100644 debian/openvswitch-switchui.install delete mode 100644 extras/ezio/automake.mk delete mode 100644 extras/ezio/ezio-term.c delete mode 100644 extras/ezio/ezio.c delete mode 100644 extras/ezio/ezio.h delete mode 100644 extras/ezio/ezio3.ti delete mode 100644 extras/ezio/ovs-switchui.c delete mode 100644 extras/ezio/terminal.c delete mode 100644 extras/ezio/terminal.h delete mode 100644 extras/ezio/tty.c delete mode 100644 extras/ezio/tty.h delete mode 100644 extras/ezio/vt-dummy.c delete mode 100644 extras/ezio/vt-linux.c delete mode 100644 extras/ezio/vt.h diff --git a/Makefile.am b/Makefile.am index 71833262..eb7f4f78 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,8 +10,6 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = datapath AM_CPPFLAGS = $(SSL_CFLAGS) -AM_CPPFLAGS += $(NCURSES_CFLAGS) -AM_CPPFLAGS += $(PCRE_CFLAGS) AM_CPPFLAGS += -I $(top_srcdir)/include AM_CPPFLAGS += -I $(top_srcdir)/lib @@ -132,5 +130,4 @@ include debian/automake.mk include vswitchd/automake.mk include ovsdb/automake.mk include xenserver/automake.mk -include extras/ezio/automake.mk diff --git a/configure.ac b/configure.ac index 04ffe6e8..3088fa5d 100644 --- a/configure.ac +++ b/configure.ac @@ -47,9 +47,6 @@ OVS_CHECK_NDEBUG OVS_CHECK_NETLINK OVS_CHECK_OPENSSL OVS_CHECK_LOGDIR -OVS_CHECK_CURSES -OVS_CHECK_LINUX_VT_H -OVS_CHECK_PCRE OVS_CHECK_PYTHON OVS_CHECK_PYUIC4 OVS_CHECK_OVSDBMONITOR @@ -64,7 +61,6 @@ OVS_CHECK_PKIDIR OVS_CHECK_RUNDIR OVS_CHECK_MALLOC_HOOKS OVS_CHECK_VALGRIND -OVS_CHECK_TTY_LOCK_DIR OVS_CHECK_SOCKET_LIBS OVS_CHECK_LINKER_SECTIONS diff --git a/debian/.gitignore b/debian/.gitignore index dca99c06..345f3fec 100644 --- a/debian/.gitignore +++ b/debian/.gitignore @@ -15,7 +15,6 @@ /openvswitch-pki /openvswitch-pki-server /openvswitch-switch -/openvswitch-switchui /openvswitch-switch-config /openvswitch-switch.copyright /openvswitch-wdt diff --git a/debian/automake.mk b/debian/automake.mk index f8f91df6..682488a3 100644 --- a/debian/automake.mk +++ b/debian/automake.mk @@ -46,11 +46,6 @@ EXTRA_DIST += \ debian/openvswitch-switch.postinst \ debian/openvswitch-switch.postrm \ debian/openvswitch-switch.template \ - debian/openvswitch-switchui.copyright \ - debian/openvswitch-switchui.default \ - debian/openvswitch-switchui.dirs \ - debian/openvswitch-switchui.init \ - debian/openvswitch-switchui.install \ debian/openvswitch-wdt.default \ debian/openvswitch-wdt.dirs \ debian/openvswitch-wdt.init \ diff --git a/debian/control b/debian/control index d1994d88..b9979d40 100644 --- a/debian/control +++ b/debian/control @@ -5,8 +5,7 @@ Maintainer: Open vSwitch developers Uploaders: Ben Pfaff , Simon Horman Build-Depends: debhelper (>= 5), autoconf (>= 2.64), automake1.10, libssl-dev, - pkg-config (>= 0.21), po-debconf, bzip2, openssl, libncurses5-dev, - libpcre3-dev, python + pkg-config (>= 0.21), po-debconf, bzip2, openssl, python Standards-Version: 3.9.1 Package: openvswitch-datapath-source @@ -49,20 +48,6 @@ Description: Open vSwitch switch implementations . Open vSwitch is a full-featured software-based Ethernet switch. -Package: openvswitch-switchui -Architecture: any -Recommends: openvswitch-switch -Depends: ${shlibs:Depends}, ${misc:Depends}, console-tools -Description: Monitoring utility for OpenFlow switches - The ovs-switchui utility included in this package provides a - "front-panel display" to allow administrators to view the status of - an OpenFlow switch at a glance. - . - The ezio-term utility, also included, provides a VT100-compatible - terminal interface for EZIO3 (aka MTB-134) 16x2 LCD displays found on - server appliances made by Portwell. It allows ovs-switchui to work - with such displays. - Package: openvswitch-pki Architecture: all Depends: @@ -130,20 +115,3 @@ Depends: ${shlibs:Depends}, ${misc:Depends} Description: Watchdog utility for Open vSwitch switches The ovs-wdt program included in this package manages the hardware watchdog timer in switches based on the Portwell NAR-5520 hardware. - -Package: nicira-switch -Architecture: all -Depends: - openvswitch-common (>= ${source:Version}), - openvswitch-common (<< ${source:Version}.1~), - openvswitch-switch (>= ${source:Version}), - openvswitch-switch (<< ${source:Version}.1~), - openvswitch-switchui (>= ${source:Version}), - openvswitch-switchui (<< ${source:Version}.1~), - openvswitch-datapath-module (>= ${source:Version}), - openvswitch-datapath-module (<< ${source:Version}.1~), - corekeeper, openvswitch-monitor, openvswitch-wdt, ${misc:Depends} -Description: A meta-package for installing a Nicira Open vSwitch switch - Installing this package will install everything needed for a Nicira - Portwell-based Open vSwitch switch, including monitoring and the switch UI. - diff --git a/debian/openvswitch-switchui.copyright b/debian/openvswitch-switchui.copyright deleted file mode 100644 index 4a5eea2d..00000000 --- a/debian/openvswitch-switchui.copyright +++ /dev/null @@ -1,21 +0,0 @@ -Upstream Authors: - - Nicira Networks, Inc. - -Copyright: - - Copyright (c) 2008, 2009 Nicira Networks, Inc. - -License: - - 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. diff --git a/debian/openvswitch-switchui.default b/debian/openvswitch-switchui.default deleted file mode 100644 index e888d01f..00000000 --- a/debian/openvswitch-switchui.default +++ /dev/null @@ -1,35 +0,0 @@ -# This is a POSIX shell fragment -*- sh -*- - -# To configure the switch UI, modify the following. Afterward, -# the switch UI will come up automatically at boot time. It can -# be restarted immediately with -# /etc/init.d/openvswitch-switchui start - -# Defaults for initscript -# sourced by /etc/init.d/openvswitch-switchui -# installed at /etc/default/openvswitch-switchui by the maintainer scripts - -# SWITCH_VCONN: The vconn used to connect to the switch (ovs-openflowd). -# The ovs-openflowd must be configured to listen to this vconn. The default -# here set is also listened to by default by the openvswitch-switch -# package, so ordinarily there is no need to modify this. -SWITCH_VCONN="unix:/var/run/openvswitch/ovs-openflowd.mgmt" - -# EZIO3_DEVICE: To display the switch monitor on an EZIO3 (aka -# MTB-134) 16x2 LCD displays found on server appliances made by -# Portwell, set this to the EZIO3 serial device and uncomment it. -#EZIO3_DEVICE="/dev/ttyS1" - -# OPENVT: When EZIO3_DEVICE is unset, this specifies the command under -# which to run ovs-switchui. The default value of "/usr/bin/openvt" -# causes ovs-switchui to run on a new, otherwise empty virtual -# console. -# -# The value must be a command name without arguments. Use a wrapper -# script to provide arguments if you need them. -# -# When EZIO3_DEVICE is set, this variable has no effect. -OPENVT="/usr/bin/openvt" - -# DAEMON_OPTS: Additional options to pass to ovs-switchui. -DAEMON_OPTS="" diff --git a/debian/openvswitch-switchui.dirs b/debian/openvswitch-switchui.dirs deleted file mode 100644 index 4dced02c..00000000 --- a/debian/openvswitch-switchui.dirs +++ /dev/null @@ -1,3 +0,0 @@ -usr/bin -usr/sbin -usr/share/terminfo diff --git a/debian/openvswitch-switchui.init b/debian/openvswitch-switchui.init deleted file mode 100755 index be547b11..00000000 --- a/debian/openvswitch-switchui.init +++ /dev/null @@ -1,210 +0,0 @@ -#!/bin/sh -# -# Example init.d script with LSB support. -# -# Please read this init.d carefully and modify the sections to -# adjust it to the program you want to run. -# -# Copyright (c) 2007, 2009 Javier Fernandez-Sanguino -# -# This is free software; you may redistribute it and/or modify -# it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2, -# or (at your option) any later version. -# -# This 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 with -# the Debian operating system, in /usr/share/common-licenses/GPL; if -# not, write to the Free Software Foundation, Inc., 59 Temple Place, -# Suite 330, Boston, MA 02111-1307 USA -# -### BEGIN INIT INFO -# Provides: openvswitch-switchui -# Required-Start: $network $local_fs $remote_fs -# Required-Stop: $remote_fs -# Should-Start: $named $syslog openvswitch-switch -# Should-Stop: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Open vSwitch switch monitor -### END INIT INFO - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - -DAEMON=/usr/bin/ovs-switchui -NAME=openvswitch-switchui -DESC="Open vSwitch UI" - -PIDFILE=/var/run/openvswitch/$NAME.pid - -test -x $DAEMON || exit 0 - -. /lib/lsb/init-functions - -# Default options, these can be overriden by the information -# at /etc/default/$NAME -DAEMON_OPTS="" # Additional options given to the server - -DODTIME=10 # Time to wait for the server to die, in seconds - # If this value is set too low you might not - # let some servers to die gracefully and - # 'restart' will not work - -# Include defaults if available -if [ -f /etc/default/$NAME ] ; then - . /etc/default/$NAME -fi - -set -e - -running_pid() { -# Check if a given process pid's cmdline matches a given name - pid=$1 - name=$2 - [ -z "$pid" ] && return 1 - [ ! -d /proc/$pid ] && return 1 - return 0 -} - -running() { -# Check if the process is running looking at /proc -# (works for all users) - - # No pidfile, probably no daemon present - [ ! -f "$PIDFILE" ] && return 1 - pid=`cat $PIDFILE` - running_pid $pid $DAEMON || return 1 - return 0 -} - -start_server() { -# Start the process using the wrapper - if test -n "$EZIO3_DEVICE"; then - # Make ezio-term detach and create the pidfile. - WRAPPER="/usr/sbin/ezio-term" - WRAPPER_OPTS="--detach --pidfile=$PIDFILE --ezio=$EZIO3_DEVICE --input=vt" - else - # openvt will detach, so instead make ovs-switchui make the pidfile. - WRAPPER=$OPENVT - WRAPPER_OPTS="" - DAEMON_OPTS="--pidfile=$PIDFILE" - fi - start-stop-daemon --start --quiet --pidfile $PIDFILE \ - --exec $WRAPPER -- $WRAPPER_OPTS -- $DAEMON $DAEMON_OPTS \ - --log-file $SWITCH_VCONN - - # Wait up to 3 seconds for the daemon to start. - for i in 1 2 3; do - if running; then - break - fi - sleep 1 - done -} - -stop_server() { - ovs-kill $PIDFILE -} - -force_stop() { -# Force the process to die killing it manually - [ ! -e "$PIDFILE" ] && return - if running ; then - kill -15 $pid - # Is it really dead? - sleep "$DIETIME"s - if running ; then - kill -9 $pid - sleep "$DIETIME"s - if running ; then - echo "Cannot kill $NAME (pid=$pid)!" - exit 1 - fi - fi - fi - rm -f $PIDFILE -} - - -case "$1" in - start) - log_daemon_msg "Starting $DESC " "$NAME" - # Check if it's running first - if running ; then - log_progress_msg "apparently already running" - log_end_msg 0 - exit 0 - fi - if start_server && running ; then - # It's ok, the server started and is running - log_end_msg 0 - else - # Either we could not start it or it is not running - # after we did - # NOTE: Some servers might die some time after they start, - # this code does not try to detect this and might give - # a false positive (use 'status' for that) - log_end_msg 1 - fi - ;; - stop) - log_daemon_msg "Stopping $DESC" "$NAME" - if running ; then - # Only stop the server if we see it running - stop_server - log_end_msg $? - else - # If it's not running don't do anything - log_progress_msg "apparently not running" - log_end_msg 0 - exit 0 - fi - ;; - force-stop) - # First try to stop gracefully the program - $0 stop - if running; then - # If it's still running try to kill it more forcefully - log_daemon_msg "Stopping (force) $DESC" "$NAME" - force_stop - log_end_msg $? - fi - ;; - restart|force-reload) - log_daemon_msg "Restarting $DESC" "$NAME" - stop_server - # Wait some sensible amount, some server need this - [ -n "$DIETIME" ] && sleep $DIETIME - start_server - running - log_end_msg $? - ;; - status) - - log_daemon_msg "Checking status of $DESC" "$NAME" - if running ; then - log_progress_msg "running" - log_end_msg 0 - else - log_progress_msg "apparently not running" - log_end_msg 1 - exit 1 - fi - ;; - # Use this if the daemon cannot reload - reload) - log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon" - log_warning_msg "cannot re-read the config file (use restart)." - ;; - *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/debian/openvswitch-switchui.install b/debian/openvswitch-switchui.install deleted file mode 100644 index 0cfb2904..00000000 --- a/debian/openvswitch-switchui.install +++ /dev/null @@ -1,3 +0,0 @@ -_debian/extras/ezio/ezio-term usr/sbin -_debian/extras/ezio/ovs-switchui usr/bin -debian/reconfigure usr/share/openvswitch-switchui diff --git a/debian/rules b/debian/rules index 0d0abf16..913d6809 100755 --- a/debian/rules +++ b/debian/rules @@ -86,7 +86,6 @@ install-arch: build-arch cp debian/openvswitch-switch-config.overrides debian/openvswitch-switch-config/usr/share/lintian/overrides/openvswitch-switch-config cp debian/openvswitch-switch.template debian/openvswitch-switch/usr/share/openvswitch/switch/default.template dh_install -s - env TERMINFO=debian/openvswitch-switchui/usr/share/terminfo tic -x extras/ezio/ezio3.ti # Must not depend on anything. This is to be called by # binary-arch/binary-indep diff --git a/extras/ezio/automake.mk b/extras/ezio/automake.mk deleted file mode 100644 index a615fc8c..00000000 --- a/extras/ezio/automake.mk +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (C) 2008, 2009, 2010 Nicira Networks, Inc. -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. This file is offered as-is, -# without warranty of any kind. - -EXTRA_DIST += extras/ezio/ezio3.ti - -if HAVE_CURSES -if HAVE_PCRE_PARTIAL -install-data-hook: - @echo tic -x $(srcdir)/extras/ezio/ezio3.ti - @if ! tic -x $(srcdir)/extras/ezio/ezio3.ti; then \ - echo "-----------------------------------------------------------"; \ - echo "Failed to install ezio3 terminfo file. The ezio-term"; \ - echo "program will not work until it has been installed."; \ - echo "Probably, you need to install the 'tic' program from"; \ - echo "ncurses, e.g. using a command like:"; \ - echo " apt-get install ncurses-bin"; \ - echo "and then re-run \"make install\""; \ - echo "-----------------------------------------------------------"; \ - exit 1; \ - fi - -bin_PROGRAMS += extras/ezio/ezio-term -extras_ezio_ezio_term_SOURCES = \ - extras/ezio/ezio-term.c \ - extras/ezio/ezio.c \ - extras/ezio/ezio.h \ - extras/ezio/terminal.c \ - extras/ezio/terminal.h \ - extras/ezio/tty.c \ - extras/ezio/tty.h \ - extras/ezio/vt.h -if HAVE_LINUX_VT_H -extras_ezio_ezio_term_SOURCES += extras/ezio/vt-linux.c -else -extras_ezio_ezio_term_SOURCES += extras/ezio/vt-dummy.c -endif -extras_ezio_ezio_term_LDADD = lib/libopenvswitch.a $(NCURSES_LIBS) - -bin_PROGRAMS += extras/ezio/ovs-switchui -extras_ezio_ovs_switchui_SOURCES = extras/ezio/ovs-switchui.c -extras_ezio_ovs_switchui_LDADD = \ - lib/libopenvswitch.a \ - $(NCURSES_LIBS) \ - $(PCRE_LIBS) \ - $(SSL_LIBS) \ - -lm -endif # HAVE_PCRE_PARTIAL -endif # HAVE_CURSES diff --git a/extras/ezio/ezio-term.c b/extras/ezio/ezio-term.c deleted file mode 100644 index b41a7c02..00000000 --- a/extras/ezio/ezio-term.c +++ /dev/null @@ -1,1037 +0,0 @@ -/* Copyright (c) 2008, 2009, 2010 Nicira Networks, Inc. - * - * 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. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "byteq.h" -#include "command-line.h" -#include "extras/ezio/tty.h" -#include "extras/ezio/vt.h" -#include "daemon.h" -#include "ezio.h" -#include "poll-loop.h" -#include "socket-util.h" -#include "terminal.h" -#include "timeval.h" -#include "util.h" -#include "vlog.h" - -VLOG_DEFINE_THIS_MODULE(ezio_term) - -/* EZIO button status. */ -enum btn_status { - BTN_UP = 1 << 0, - BTN_DOWN = 1 << 1, - BTN_ENTER = 1 << 2, - BTN_ESC = 1 << 3 -}; - -/* -e, --ezio: EZIO3 serial device file. */ -static char *ezio_dev = "/dev/ttyS1"; - -/* -i, --input: Terminal from which to accept additional keyboard input. */ -static char *input_dev = NULL; - -struct inputdev; -static int inputdev_open(const char *name, struct inputdev **); -static void inputdev_close(struct inputdev *); -static int inputdev_run(struct inputdev *, struct byteq *); -static void inputdev_update(struct inputdev *, const struct ezio *); -static void inputdev_wait(struct inputdev *); - -static struct scanner *scanner_create(void); -static void scanner_destroy(struct scanner *); -static void scanner_run(struct scanner *, struct ezio *); -static void scanner_wait(struct scanner *); -static void scanner_left(struct scanner *, struct ezio *); -static void scanner_right(struct scanner *, struct ezio *); - -static struct updater *updater_create(void); -static void updater_destroy(struct updater *); -static int updater_run(struct updater *, const struct ezio *shadow, - int ezio_fd); -static void updater_wait(struct updater *, int ezio_fd); -enum btn_status updater_get_buttons(struct updater *); -bool updater_has_buttons(const struct updater *); - -static void handle_buttons(struct updater *, struct scanner *, - struct byteq *, struct ezio *); - -static void usage(void) NO_RETURN; -static void parse_options(int argc, char *argv[]); - -int -main(int argc, char *argv[]) -{ - struct terminal *terminal; - struct updater *updater; - struct scanner *scanner; - struct inputdev *inputdev; - struct byteq inputq; - struct ezio ezio; - int ezio_fd, pty_fd, dummy_fd; - int retval; - int i; - - proctitle_init(argc, argv); - set_program_name(argv[0]); - parse_options(argc, argv); - signal(SIGPIPE, SIG_IGN); - - argc -= optind; - argv += optind; - - /* Make sure that the ezio3 terminfo entry is available. */ - dummy_fd = get_null_fd(); - if (dummy_fd >= 0) { - if (setupterm("ezio3", dummy_fd, &retval) == ERR) { - if (retval == 0) { - ovs_fatal(0, "Missing terminfo entry for ezio3. " - "Did you run \"make install\"?"); - } else { - ovs_fatal(0, "Missing terminfo database. Is ncurses " - "properly installed?"); - } - } - del_curterm(cur_term); - } - - /* Lock serial port. */ - retval = tty_lock(ezio_dev); - if (retval) { - ovs_fatal(retval, "%s: lock failed", ezio_dev); - } - - /* Open EZIO and configure as 2400 bps, N-8-1, in raw mode. */ - ezio_fd = open(ezio_dev, O_RDWR | O_NOCTTY); - if (ezio_fd < 0) { - ovs_fatal(errno, "%s: open", ezio_dev); - } - retval = tty_set_raw_mode(ezio_fd, B2400); - if (retval) { - ovs_fatal(retval, "%s: failed to configure tty parameters", ezio_dev); - } - - /* Open keyboard device for input. */ - if (input_dev) { - retval = inputdev_open(input_dev, &inputdev); - if (retval) { - ovs_fatal(retval, "%s: failed to open input device", input_dev); - } - } else { - inputdev = NULL; - } - - /* Open pty master. */ - pty_fd = tty_open_master_pty(); - if (pty_fd < 0) { - ovs_fatal(-pty_fd, "failed to open master pty"); - } - tty_set_window_size(pty_fd, 2, 40); - - /* Start child process. */ - if (argc < 1) { - char *child_argv[2]; - - child_argv[0] = getenv("SHELL"); - if (!child_argv[0]) { - child_argv[0] = "/bin/sh"; - } - child_argv[1] = NULL; - retval = tty_fork_child(pty_fd, child_argv); - } else { - retval = tty_fork_child(pty_fd, argv); - } - if (retval) { - ovs_fatal(retval, "failed to fork child process"); - } - - die_if_already_running(); - daemonize(); - - terminal = terminal_create(); - updater = updater_create(); - scanner = scanner_create(); - ezio_init(&ezio); - for (i = 0; i < 8; i++) { - ezio_set_default_icon(&ezio, i); - } - byteq_init(&inputq); - for (;;) { - /* Get button presses and keyboard input into inputq, then push the - * inputq to the pty. */ - handle_buttons(updater, scanner, &inputq, &ezio); - if (inputdev) { - retval = inputdev_run(inputdev, &inputq); - if (retval) { - VLOG_ERR("error reading from input device: %s", - strerror(retval)); - inputdev_close(inputdev); - inputdev = NULL; - } - } - retval = byteq_write(&inputq, pty_fd); - if (retval && retval != EAGAIN) { - VLOG_ERR("error passing through input: %s", - retval == EOF ? "end of file" : strerror(retval)); - } - - /* Process data from pty in terminal emulator. */ - retval = terminal_run(terminal, &ezio, pty_fd); - if (retval) { - VLOG_ERR("error reading from terminal: %s", - retval == EOF ? "end of file" : strerror(retval)); - break; - } - - /* Scroll left and right through text. */ - scanner_run(scanner, &ezio); - - /* Update the display to match what should be shown. */ - retval = updater_run(updater, &ezio, ezio_fd); - if (retval) { - VLOG_ERR("error writing to ezio: %s", - retval == EOF ? "end of file" : strerror(retval)); - break; - } - if (inputdev) { - inputdev_update(inputdev, &ezio); - } - - /* Wait for something to happen. */ - terminal_wait(terminal, pty_fd); - scanner_wait(scanner); - if (updater_has_buttons(updater)) { - poll_immediate_wake(); - } - updater_wait(updater, ezio_fd); - if (!byteq_is_empty(&inputq)) { - poll_fd_wait(pty_fd, POLLOUT); - } - if (inputdev) { - inputdev_wait(inputdev); - } - poll_block(); - } - terminal_destroy(terminal); - updater_destroy(updater); - scanner_destroy(scanner); - - return 0; -} - -static void -send_keys(struct byteq *q, const char *s) -{ - size_t n = strlen(s); - if (byteq_avail(q) >= n) { - byteq_putn(q, s, n); - } -} - -static void -handle_buttons(struct updater *up, struct scanner *s, - struct byteq *q, struct ezio *ezio) -{ - while (updater_has_buttons(up)) { - int btns = updater_get_buttons(up); - switch (btns) { - case BTN_UP: - send_keys(q, "\x1b\x5b\x41"); /* Up arrow. */ - break; - - case BTN_UP | BTN_ESC: - send_keys(q, "\x1b[5~"); /* Page up. */ - break; - - case BTN_DOWN: - send_keys(q, "\x1b\x5b\x42"); /* Down arrow. */ - break; - - case BTN_DOWN | BTN_ESC: - send_keys(q, "\x1b[6~"); /* Page down. */ - break; - - case BTN_ENTER: - send_keys(q, "\r"); - break; - - case BTN_ESC: - send_keys(q, "\x7f"); - break; - - case BTN_UP | BTN_DOWN: - scanner_left(s, ezio); - break; - - case BTN_ESC | BTN_ENTER: - scanner_right(s, ezio); - break; - - case BTN_UP | BTN_DOWN | BTN_ENTER | BTN_ESC: - send_keys(q, "\x04"); /* End of file. */ - break; - - case BTN_UP | BTN_ENTER | BTN_ESC: - send_keys(q, "y"); - break; - - case BTN_DOWN | BTN_ENTER | BTN_ESC: - send_keys(q, "n"); - break; - } - } -} - -/* EZIO screen updater. */ - -/* EZIO command codes. */ -#define EZIO_CMD 0xfe /* Command prefix byte. */ -#define EZIO_CLEAR 0x01 /* Clear screen. */ -#define EZIO_HOME 0x02 /* Move to (0, 0). */ -#define EZIO_READ 0x06 /* Poll keyboard. */ - -#define EZIO_ENTRY_MODE 0x04 /* Set entry mode: */ -#define EZIO_LTOR_MODE 0x02 /* ...left-to-right (vs. r-to-l). */ -#define EZIO_SHIFT_MODE 0x01 /* ...scroll with output (vs. don't). */ - -#define EZIO_DISPLAY_MODE 0x08 /* Set display mode: */ -#define EZIO_ENABLE_DISPLAY 0x04 /* ...turn on display (vs. blank). */ -#define EZIO_SHOW_CURSOR 0x02 /* ...show cursor (vs. hide). */ -#define EZIO_BLOCK_CURSOR 0x01 /* ...block cursor (vs. underline). */ - -#define EZIO_INIT 0x28 /* Initialize EZIO. */ - -#define EZIO_MOVE_CURSOR 0x80 /* Set cursor position. */ -#define EZIO_COL_SHIFT 0 /* Shift count for column (0-based). */ -#define EZIO_ROW_SHIFT 6 /* Shift count for row (0-based). */ - -#define EZIO_DEFINE_ICON 0x40 /* Define icon. */ -#define EZIO_ICON_SHIFT 3 /* Shift count for icon number (0-7). */ - -#define EZIO_SCROLL_LEFT 0x18 /* Scroll display left 1 position. */ -#define EZIO_SCROLL_RIGHT 0x1c /* Scroll display right 1 position. */ -#define EZIO_CURSOR_LEFT 0x10 /* Move cursor left 1 position. */ -#define EZIO_CURSOR_RIGHT 0x14 /* Move cursor right 1 position. */ - -/* Rate limiting: the EZIO runs at 2400 bps, which is 240 bytes per second. - * Kernel tty buffers, on the other hand, tend to be at least 4 kB. That - * means that, if we keep the kernel buffer filled, then the queued data will - * be 4,096 kB / 240 bytes/s ~= 17 seconds ahead of what is actually - * displayed. This is not a happy situation. So we rate-limit with a token - * bucket. - * - * The parameters below work out as: (6 tokens/ms * 1000 ms) / (25 - * tokens/byte) = 240 bytes/s. */ -#define UP_TOKENS_PER_MS 6 /* Tokens acquired per millisecond. */ -#define UP_BUCKET_SIZE (6 * 100) /* Capacity of the token bukect. */ -#define UP_TOKENS_PER_BYTE 25 /* Tokens required to output a byte. */ - -struct updater { - /* Current state of EZIO device. */ - struct ezio visible; - - /* Output state. */ - struct byteq obuf; /* Output being sent to serial port. */ - int tokens; /* Token bucket content. */ - long long int last_fill; /* Last time we increased 'tokens'.*/ - bool up_to_date; /* Does visible state match shadow state? */ - - /* Input state. */ - struct byteq ibuf; /* Queued button pushes. */ - long long int last_poll; /* Last time we sent a button poll request. */ - enum btn_status last_status; /* Last received button status. */ - long long int last_change; /* Time when status most recently changed. */ - int repeat_count; /* Autorepeat count. */ - bool releasing; /* Waiting for button release? */ -}; - -static void send_command(struct updater *, uint8_t command); -static void recv_button_state(struct updater *, enum btn_status status); -static int range(int value, int min, int max); -static void send_command(struct updater *, uint8_t command); -static void set_cursor_position(struct updater *, int x, int y); -static bool icons_differ(const struct ezio *, const struct ezio *, int *idx); -static void update_char(struct updater *, const struct ezio *, int x, int y); -static void update_cursor_status(struct updater *, const struct ezio *); - -/* Creates and returns a new updater. */ -static struct updater * -updater_create(void) -{ - struct updater *up = xmalloc(sizeof *up); - ezio_init(&up->visible); - byteq_init(&up->obuf); - up->tokens = UP_BUCKET_SIZE; - up->last_fill = time_msec(); - byteq_init(&up->ibuf); - up->last_poll = LLONG_MIN; - up->last_status = 0; - up->last_change = time_msec(); - up->releasing = false; - send_command(up, EZIO_INIT); - send_command(up, EZIO_INIT); - send_command(up, EZIO_CLEAR); - send_command(up, EZIO_HOME); - return up; -} - -/* Destroys updater 'up. */ -static void -updater_destroy(struct updater *up) -{ - free(up); -} - -/* Sends EZIO commands over file descriptor 'ezio_fd' to the EZIO represented - * by updater 'up', to make the EZIO display the contents of 'shadow'. - * Rate-limiting can cause the update to be only partial, but the next call to - * updater_run() will resume the update. - * - * Returns 0 if successful, otherwise a positive errno value. */ -static int -updater_run(struct updater *up, const struct ezio *shadow, int ezio_fd) -{ - uint8_t c; - while (read(ezio_fd, &c, 1) > 0) { - if ((c & 0xf0) == 0xb0) { - recv_button_state(up, ~c & 0x0f); - } - } - - up->up_to_date = false; - for (;;) { - struct ezio *visible = &up->visible; - int idx, x, y; - int retval; - - /* Flush the buffer out to the EZIO device. */ - retval = byteq_write(&up->obuf, ezio_fd); - if (retval == EAGAIN) { - return 0; - } else if (retval) { - VLOG_WARN("error writing ezio: %s", strerror(retval)); - return retval; - } - - /* Make sure we have some tokens before we write anything more. */ - if (up->tokens <= 0) { - long long int now = time_msec(); - if (now > up->last_fill) { - up->tokens += (now - up->last_fill) * UP_TOKENS_PER_MS; - up->last_fill = now; - if (up->tokens > UP_BUCKET_SIZE) { - up->tokens = UP_BUCKET_SIZE; - } - } - if (up->tokens <= 0) { - /* Still out of tokens. */ - return 0; - } - } - - /* Consider what else we might want to send. */ - if (time_msec() >= up->last_poll + 100) { - /* Send a button-read command. */ - send_command(up, EZIO_READ); - up->last_poll = time_msec(); - } else if (visible->show_cursor && !shadow->show_cursor) { - /* Turn off the cursor. */ - update_cursor_status(up, shadow); - } else if (icons_differ(shadow, visible, &idx)) { - /* Update the icons. */ - send_command(up, EZIO_DEFINE_ICON + (idx << EZIO_ICON_SHIFT)); - byteq_putn(&up->obuf, &shadow->icons[idx][0], 8); - set_cursor_position(up, shadow->x, shadow->y); - memcpy(visible->icons[idx], shadow->icons[idx], 8); - } else if (visible->x_ofs != shadow->x_ofs) { - /* Scroll to the correct horizontal position. */ - if (visible->x_ofs < shadow->x_ofs) { - send_command(up, EZIO_SCROLL_LEFT); - visible->x_ofs++; - } else { - send_command(up, EZIO_SCROLL_RIGHT); - visible->x_ofs--; - } - } else if (ezio_chars_differ(shadow, visible, shadow->x_ofs, - shadow->x_ofs + 16, &x, &y)) { - /* Update the visible region. */ - update_char(up, shadow, x, y); - } else if (ezio_chars_differ(shadow, visible, 0, 40, &x, &y)) { - /* Update the off-screen region. */ - update_char(up, shadow, x, y); - } else if ((visible->x != shadow->x || visible->y != shadow->y) - && shadow->show_cursor) { - /* Update the cursor position. (This has to follow updating the - * display content, because updating display content changes the - * cursor position.) */ - set_cursor_position(up, shadow->x, shadow->y); - } else if (visible->show_cursor != shadow->show_cursor - || visible->blink_cursor != shadow->blink_cursor) { - /* Update the cursor type. */ - update_cursor_status(up, shadow); - } else { - /* We're fully up-to-date. */ - up->up_to_date = true; - return 0; - } - up->tokens -= UP_TOKENS_PER_BYTE * byteq_used(&up->obuf); - } -} - -/* Calls poll-loop functions that will cause poll_block() to wake up when - * updater_run() has work to do. */ -static void -updater_wait(struct updater *up, int ezio_fd) -{ - if (!byteq_is_empty(&up->obuf)) { - poll_fd_wait(ezio_fd, POLLOUT); - } else if (up->tokens <= 0) { - poll_timer_wait((-up->tokens / UP_TOKENS_PER_MS) + 1); - } else if (!up->up_to_date) { - poll_immediate_wake(); - } - - if (!up->last_status && time_msec() - up->last_change > 100) { - /* No button presses in a while. Sleep longer. */ - poll_timer_wait(100); - } else { - poll_timer_wait(50); - } -} - -/* Returns a button or buttons that were pushed. Must not be called if - * updater_has_buttons() would return false. One or more BTN_* flags will be - * set in the return value. */ -enum btn_status -updater_get_buttons(struct updater *up) -{ - return byteq_get(&up->ibuf); -} - -/* Any buttons pushed? */ -bool -updater_has_buttons(const struct updater *up) -{ - return !byteq_is_empty(&up->ibuf); -} - -/* Adds 'btns' to the queue of pushed buttons */ -static void -buttons_pushed(struct updater *up, enum btn_status btns) -{ - if (!byteq_is_full(&up->ibuf)) { - byteq_put(&up->ibuf, btns); - } -} - -/* Updates the buttons-pushed queue based on the current button 'status'. */ -static void -recv_button_state(struct updater *up, enum btn_status status) -{ - /* Calculate milliseconds since button status last changed. */ - long long int stable_msec; - if (status != up->last_status) { - up->last_change = time_msec(); - stable_msec = 0; - } else { - stable_msec = time_msec() - up->last_change; - } - - if (up->releasing) { - if (!status) { - up->releasing = false; - } - } else if (up->last_status) { - if (!(status & up->last_status)) { - /* Button(s) were pushed and released. */ - if (!up->repeat_count) { - buttons_pushed(up, up->last_status); - } - } else if (stable_msec >= 150 && !up->repeat_count) { - /* Buttons have been stable for a while, so push them once. */ - buttons_pushed(up, status); - up->repeat_count++; - } else if (stable_msec >= 1000) { - /* Autorepeat 10/second after 1 second hold time. */ - int n = (stable_msec - 1000) / 100 + 1; - while (up->repeat_count < n) { - buttons_pushed(up, status); - up->repeat_count++; - } - } else if ((status & up->last_status) == up->last_status) { - /* More buttons pushed than at last poll. */ - } else { - /* Some, but not all, buttons were released. Ignore the buttons - * until all are released. */ - up->releasing = true; - } - } - if (!status) { - up->repeat_count = 0; - } - up->last_status = status; -} - -static int -range(int value, int min, int max) -{ - return value < min ? min : value > max ? max : value; -} - -static void -send_command(struct updater *up, uint8_t command) -{ - byteq_put(&up->obuf, EZIO_CMD); - byteq_put(&up->obuf, command); -} - -/* Moves the cursor to 0-based position (x, y). Updates 'up->visible' to - * reflect the change. */ -static void -set_cursor_position(struct updater *up, int x, int y) -{ - int command = EZIO_MOVE_CURSOR; - command |= range(x, 0, 39) << EZIO_COL_SHIFT; - command |= range(y, 0, 1) << EZIO_ROW_SHIFT; - send_command(up, command); - up->visible.x = x; - up->visible.y = y; -} - -/* If any of the icons differ from 'a' to 'b', returns true and sets '*idx' to - * the index of the first icon that differs. Otherwise, returns false. */ -static bool -icons_differ(const struct ezio *a, const struct ezio *b, int *idx) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(a->icons); i++) { - if (memcmp(&a->icons[i], &b->icons[i], sizeof a->icons[i])) { - *idx = i; - return true; - } - } - return false; -} - -/* Queues commands in 'up''s output buffer to update the character at 0-based - * position (x,y) to match the character that 'shadow' has there. Updates - * 'up->visible' to reflect the change. */ -static void -update_char(struct updater *up, const struct ezio *shadow, int x, int y) -{ - if (x != up->visible.x || y != up->visible.y) { - set_cursor_position(up, x, y); - } - byteq_put(&up->obuf, shadow->chars[y][x]); - up->visible.chars[y][x] = shadow->chars[y][x]; - up->visible.x++; -} - -/* Queues commands in 'up''s output buffer to change the EZIO's cursor shape to - * match that in 'shadow'. Updates 'up->visible' to reflect the change. */ -static void -update_cursor_status(struct updater *up, const struct ezio *shadow) -{ - uint8_t command = EZIO_DISPLAY_MODE | EZIO_ENABLE_DISPLAY; - if (shadow->show_cursor) { - command |= EZIO_SHOW_CURSOR; - if (shadow->blink_cursor) { - command |= EZIO_BLOCK_CURSOR; - } - } - send_command(up, command); - up->visible.show_cursor = shadow->show_cursor; - up->visible.blink_cursor = shadow->blink_cursor; -} - -/* An input device, such as a tty. */ - -struct inputdev { - /* Input. */ - int fd; /* File descriptor. */ - - /* State for mirroring the EZIO display to the device. */ - bool is_tty; /* We only attempt to mirror to ttys. */ - struct byteq outq; /* Output queue. */ - struct ezio visible; /* Data that we have displayed. */ -}; - -/* Opens 'name' as a input device. If successful, returns 0 and stores a - * pointer to the input device in '*devp'. On failure, returns a positive - * errno value. */ -static int -inputdev_open(const char *name, struct inputdev **devp) -{ - struct inputdev *dev; - int retval; - int fd; - - *devp = NULL; - if (!strcmp(name, "vt")) { - fd = vt_open(O_RDWR | O_NOCTTY); - if (fd < 0) { - return -fd; - } - } else if (!strcmp(name, "-")) { - fd = dup(STDIN_FILENO); - if (fd < 0) { - return errno; - } - } else { - fd = open(name, O_RDWR | O_NOCTTY); - if (fd < 0) { - return errno; - } - } - - retval = tty_set_raw_mode(fd, B0); - if (retval) { - close(fd); - VLOG_WARN("%s: failed to configure tty parameters: %s", - name, strerror(retval)); - return retval; - } - - dev = xmalloc(sizeof *dev); - dev->fd = fd; - dev->is_tty = isatty(fd); - byteq_init(&dev->outq); - ezio_init(&dev->visible); - *devp = dev; - return 0; -} - -/* Closes and destroys input device 'dev'. */ -static void -inputdev_close(struct inputdev *dev) -{ - if (dev) { - close(dev->fd); - free(dev); - } -} - -/* Reads input from 'dev' into 'q'. Returns 0 if successful, otherwise a - * positive errno value. */ -static int -inputdev_run(struct inputdev *dev, struct byteq *q) -{ - int retval = byteq_read(q, dev->fd); - return retval == EAGAIN ? 0 : retval; -} - -/* Dumps data from 'dev''s output queue to the underlying file descriptor, - * updating the tty screen display. */ -static void -flush_inputdev(struct inputdev *dev) -{ - int retval = byteq_write(&dev->outq, dev->fd); - if (retval && retval != EAGAIN) { - VLOG_WARN("error writing input device, " - "disabling further output"); - dev->is_tty = false; - } -} - -/* Updates the tty screen display on 'dev' to match 'e'. */ -static void -inputdev_update(struct inputdev *dev, const struct ezio *e) -{ - struct byteq *q = &dev->outq; - int x, y; - - if (!dev->is_tty) { - return; - } - - flush_inputdev(dev); - if (!byteq_is_empty(q)) { - return; - } - - if (!ezio_chars_differ(e, &dev->visible, 0, 40, &x, &y) - && e->x == dev->visible.x - && e->y == dev->visible.y - && e->x_ofs == dev->visible.x_ofs - && e->show_cursor == dev->visible.show_cursor) { - return; - } - dev->visible = *e; - - byteq_put_string(q, "\033[H\033[2J"); /* Clear screen. */ - for (y = 0; y < 4; y++) { - byteq_put(q, "+||+"[y]); - for (x = 0; x < 40; x++) { - int c; - if (x == e->x_ofs) { - byteq_put(q, '['); - } - c = y == 0 || y == 3 ? '-' : e->chars[y - 1][x]; - if (c == 6) { - c = '\\'; - } else if (c == 7) { - c = '~'; - } else if (c < 0x20 || c > 0x7d) { - c = '?'; - } - byteq_put(q, c); - if (x == e->x_ofs + 15) { - byteq_put(q, ']'); - } - } - byteq_put(q, "+||+"[y]); - byteq_put(q, '\r'); - byteq_put(q, '\n'); - } - if (e->show_cursor) { - int x = range(e->x, 0, 39) + 2 + (e->x >= e->x_ofs) + (e->x > e->x_ofs + 15); - int y = range(e->y, 0, 1) + 2; - char cup[16]; - sprintf(cup, "\033[%d;%dH", y, x); /* Position cursor. */ - byteq_put_string(q, cup); - } - flush_inputdev(dev); -} - -/* Calls poll-loop functions that will cause poll_block() to wake up when - * inputdev_run() has work to do. */ -static void -inputdev_wait(struct inputdev *dev) -{ - int flags = POLLIN; - if (dev->is_tty && !byteq_is_empty(&dev->outq)) { - flags |= POLLOUT; - } - poll_fd_wait(dev->fd, flags); -} - -/* Scrolls the display left and right automatically to display all the - * content. */ - -enum scanner_state { - SCANNER_LEFT, /* Moving left. */ - SCANNER_RIGHT /* Moving right. */ -}; - -struct scanner { - enum scanner_state state; /* Current state. */ - int wait; /* No. of cycles to pause before continuing. */ - long long int last_move; /* Last time the state machine ran. */ -}; - -static void find_min_max(struct ezio *, int *min, int *max); - -static struct scanner * -scanner_create(void) -{ - struct scanner *s = xmalloc(sizeof *s); - s->state = SCANNER_RIGHT; - s->wait = 0; - s->last_move = LLONG_MIN; - return s; -} - -static void -scanner_destroy(struct scanner *s) -{ - free(s); -} - -static void -scanner_run(struct scanner *s, struct ezio *ezio) -{ - long long int now = time_msec(); - if (now >= s->last_move + 750) { - s->last_move = now; - if (s->wait) { - s->wait--; - } else { - int min, max; - - find_min_max(ezio, &min, &max); - if (max - min + 1 <= 16) { - ezio->x_ofs = min; - return; - } - - switch (s->state) { - case SCANNER_RIGHT: - if (ezio->x_ofs + 15 < max) { - ezio->x_ofs++; - } else { - s->state = SCANNER_LEFT; - s->wait = 1; - } - break; - - case SCANNER_LEFT: - if (ezio->x_ofs > min) { - ezio->x_ofs--; - } else { - s->state = SCANNER_RIGHT; - s->wait = 1; - } - break; - } - } - } -} - -static void -scanner_wait(struct scanner *s) -{ - poll_timer_wait_until(s->last_move + 750); -} - -static void -scanner_left(struct scanner *s, struct ezio *ezio) -{ - s->wait = 7; - if (ezio->x_ofs > 0) { - ezio->x_ofs--; - } -} - -static void -scanner_right(struct scanner *s, struct ezio *ezio) -{ - s->wait = 7; - if (ezio->x_ofs < 40 - 16) { - ezio->x_ofs++; - } -} - -static void -find_min_max(struct ezio *ezio, int *min, int *max) -{ - int x; - - *min = 0; - for (x = 0; x < 40; x++) { - if (ezio->chars[0][x] != ' ' || ezio->chars[1][x] != ' ') { - *min = x; - break; - } - } - - *max = 15; - for (x = 39; x >= 0; x--) { - if (ezio->chars[0][x] != ' ' || ezio->chars[1][x] != ' ') { - *max = x; - break; - } - } - - if (ezio->show_cursor) { - if (ezio->x < *min) { - *min = ezio->x; - } - if (ezio->x > *max) { - *max = ezio->x; - } - } -} - -static void -parse_options(int argc, char *argv[]) -{ - enum { - OPT_DUMMY = UCHAR_MAX + 1, - VLOG_OPTION_ENUMS - }; - static struct option long_options[] = { - {"ezio3", required_argument, 0, 'e'}, - {"input", required_argument, 0, 'i'}, - {"verbose", optional_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - DAEMON_LONG_OPTIONS, - VLOG_LONG_OPTIONS, - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - for (;;) { - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case 'e': - ezio_dev = optarg; - break; - - case 'i': - input_dev = optarg ? optarg : "-"; - break; - - case 'h': - usage(); - - case 'V': - OVS_PRINT_VERSION(0, 0); - exit(EXIT_SUCCESS); - - DAEMON_OPTION_HANDLERS - VLOG_OPTION_HANDLERS - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - -static void -usage(void) -{ - printf("%s: EZIO3 terminal front-end\n" - "Provides a front-end to a 16x2 EZIO3 LCD display that makes\n" - "it look more like a conventional terminal\n" - "usage: %s [OPTIONS] [-- COMMAND [ARG...]]\n" - "where COMMAND is a command to run with stdin, stdout, and\n" - "stderr directed to the EZIO3 display.\n" - "\nSettings (defaults in parentheses):\n" - " -e, --ezio=TTY set EZIO3 serial device (/dev/ttyS1)\n" - " -i, --input=TERMINAL also read input from TERMINAL;\n" - " specify - for stdin, or vt to allocate\n" - " and switch to a free virtual terminal\n" - "\nOther options:\n" - " -v, --verbose=MODULE:FACILITY:LEVEL configure logging levels\n" - " -v, --verbose set maximum verbosity level\n" - " -h, --help display this help message\n" - " -V, --version display version information\n", - program_name, program_name); - exit(EXIT_SUCCESS); -} diff --git a/extras/ezio/ezio.c b/extras/ezio/ezio.c deleted file mode 100644 index c4ad1959..00000000 --- a/extras/ezio/ezio.c +++ /dev/null @@ -1,231 +0,0 @@ -/* Copyright (c) 2008, 2009 Nicira Networks, Inc. - * - * 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. - */ - -#include -#include "ezio.h" -#include -#include -#include -#include "util.h" - -static void remove_elements(uint8_t *p, size_t n_elems, size_t elem_size, - int pos, int n_del); -static void insert_elements(uint8_t *p, size_t n_elems, size_t elem_size, - int pos, int n_insert); -static int range(int value, int min, int max); - -void -ezio_init(struct ezio *e) -{ - memset(e->icons, 0, sizeof e->icons); - ezio_clear(e); - e->x_ofs = 0; - e->show_cursor = true; - e->blink_cursor = false; -} - -void -ezio_set_icon(struct ezio *e, int idx, - int row0, int row1, int row2, int row3, - int row4, int row5, int row6, int row7) -{ - e->icons[idx][0] = row0; - e->icons[idx][1] = row1; - e->icons[idx][2] = row2; - e->icons[idx][3] = row3; - e->icons[idx][4] = row4; - e->icons[idx][5] = row5; - e->icons[idx][6] = row6; - e->icons[idx][7] = row7; -} - -void -ezio_set_default_icon(struct ezio *e, int idx) -{ - uint8_t *icon; - - assert(idx >= 0 && idx < 8); - icon = e->icons[idx]; - if (idx == 6) { - ezio_set_icon(e, idx, - e_____, - eX____, - e_X___, - e__X__, - e___X_, - e____X, - e_____, - e_____); - } else if (idx == 7) { - ezio_set_icon(e, idx, - e_____, - e_____, - e_X___, - eX_X_X, - eX_X_X, - e___X_, - e_____, - e_____); - } else { - ezio_set_icon(e, idx, - e_____, - e_____, - e_____, - e_____, - e_____, - e_____, - e_____, - e_____); - } -} - -void -ezio_clear(struct ezio *e) -{ - memset(e->chars, ' ', sizeof e->chars); - e->x = e->y = 0; -} - -void -ezio_put_char(struct ezio *e, int x, int y, uint8_t c) -{ - assert(x >= 0 && x <= 39); - assert(y >= 0 && y <= 1); - e->chars[y][x] = c != 0xfe ? c : 0xff; -} - -void -ezio_line_feed(struct ezio *e) -{ - if (++e->y >= 2) { - e->y = 1; - ezio_scroll_up(e, 1); - } -} - -void -ezio_newline(struct ezio *e) -{ - e->x = 0; - ezio_line_feed(e); -} - -void -ezio_delete_char(struct ezio *e, int x, int y, int n) -{ - remove_elements(&e->chars[y][0], 40, 1, x, n); -} - -void -ezio_delete_line(struct ezio *e, int y, int n) -{ - remove_elements(e->chars[0], 2, 40, y, n); -} - -void -ezio_insert_char(struct ezio *e, int x, int y, int n) -{ - insert_elements(&e->chars[y][0], 40, 1, x, n); -} - -void -ezio_insert_line(struct ezio *e, int y, int n) -{ - insert_elements(&e->chars[0][0], 2, 40, y, n); -} - -void -ezio_scroll_left(struct ezio *e, int n) -{ - int y; - for (y = 0; y < 2; y++) { - ezio_delete_char(e, 0, y, n); - } -} - -void -ezio_scroll_right(struct ezio *e, int n) -{ - int y; - - for (y = 0; y < 2; y++) { - ezio_insert_char(e, 0, y, n); - } -} - -void -ezio_scroll_up(struct ezio *e, int n) -{ - ezio_delete_line(e, 0, n); -} - -void -ezio_scroll_down(struct ezio *e, int n) -{ - ezio_insert_line(e, 0, n); -} - -bool -ezio_chars_differ(const struct ezio *a, const struct ezio *b, int x0, int x1, - int *xp, int *yp) -{ - int x, y; - - x0 = range(x0, 0, 39); - x1 = range(x1, 1, 40); - for (y = 0; y < 2; y++) { - for (x = x0; x < x1; x++) { - if (a->chars[y][x] != b->chars[y][x]) { - *xp = x; - *yp = y; - return true; - } - } - } - return false; -} - -static void -remove_elements(uint8_t *p, size_t n_elems, size_t elem_size, - int pos, int n_del) -{ - if (pos >= 0 && pos < n_elems) { - n_del = MIN(n_del, n_elems - pos); - memmove(p + elem_size * pos, - p + elem_size * (pos + n_del), - elem_size * (n_elems - pos - n_del)); - memset(p + elem_size * (n_elems - n_del), ' ', n_del * elem_size); - } -} - -static void -insert_elements(uint8_t *p, size_t n_elems, size_t elem_size, - int pos, int n_insert) -{ - if (pos >= 0 && pos < n_elems) { - n_insert = MIN(n_insert, n_elems - pos); - memmove(p + elem_size * (pos + n_insert), - p + elem_size * pos, - elem_size * (n_elems - pos - n_insert)); - memset(p + elem_size * pos, ' ', n_insert * elem_size); - } -} - -static int -range(int value, int min, int max) -{ - return value < min ? min : value > max ? max : value; -} - diff --git a/extras/ezio/ezio.h b/extras/ezio/ezio.h deleted file mode 100644 index da163c84..00000000 --- a/extras/ezio/ezio.h +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (c) 2008, 2009 Nicira Networks, Inc. - * - * 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. - */ - -#ifndef EZIO_H -#define EZIO_H 1 - -#include -#include - -/* Constants for visual representation of a row in an EZIO icon. */ -#define e_____ 0x00 -#define e____X 0x01 -#define e___X_ 0x02 -#define e___XX 0x03 -#define e__X__ 0x04 -#define e__X_X 0x05 -#define e__XX_ 0x06 -#define e__XXX 0x07 -#define e_X___ 0x08 -#define e_X__X 0x09 -#define e_X_X_ 0x0a -#define e_X_XX 0x0b -#define e_XX__ 0x0c -#define e_XX_X 0x0d -#define e_XXX_ 0x0e -#define e_XXXX 0x0f -#define eX____ 0x10 -#define eX___X 0x11 -#define eX__X_ 0x12 -#define eX__XX 0x13 -#define eX_X__ 0x14 -#define eX_X_X 0x15 -#define eX_XX_ 0x16 -#define eX_XXX 0x17 -#define eXX___ 0x18 -#define eXX__X 0x19 -#define eXX_X_ 0x1a -#define eXX_XX 0x1b -#define eXXX__ 0x1c -#define eXXX_X 0x1d -#define eXXXX_ 0x1e -#define eXXXXX 0x1f - -struct ezio { - uint8_t icons[8][8]; - uint8_t chars[2][40]; - int x, y, x_ofs; - bool show_cursor; - bool blink_cursor; -}; - -void ezio_init(struct ezio *); -void ezio_set_icon(struct ezio *, int idx, - int row0, int row1, int row2, int row3, - int row4, int row5, int row6, int row7); -void ezio_set_default_icon(struct ezio *, int idx); -void ezio_clear(struct ezio *); -void ezio_put_char(struct ezio *, int x, int y, uint8_t c); -void ezio_line_feed(struct ezio *); -void ezio_newline(struct ezio *); -void ezio_delete_char(struct ezio *, int x, int y, int n); -void ezio_delete_line(struct ezio *, int y, int n); -void ezio_insert_char(struct ezio *, int x, int y, int n); -void ezio_insert_line(struct ezio *, int y, int n); -void ezio_scroll_left(struct ezio *, int n); -void ezio_scroll_right(struct ezio *, int n); -void ezio_scroll_up(struct ezio *, int n); -void ezio_scroll_down(struct ezio *, int n); -bool ezio_chars_differ(const struct ezio *, const struct ezio *, - int x0, int x1, int *xp, int *yp); - -#endif /* ezio.h */ diff --git a/extras/ezio/ezio3.ti b/extras/ezio/ezio3.ti deleted file mode 100644 index 0bbcb398..00000000 --- a/extras/ezio/ezio3.ti +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (C) 2008, 2009 Nicira Networks, Inc. -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty. This file is offered -# as-is, without warranty of any kind. - -ezio3|16x2 EZIO3 LCD display, - cols#40, lines#2, it#8, am, xenl, npc, - bel=, clear=\E[H\E[J, cr=^M, - cub=\E[%p1%dD, cub1=^H, cud=\E[%p1%dB, cud1=^J, - cuf=\E[%p1%dC, cuf1=\E[C$<2>, - cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, - cuu1=\E[A, ed=\E[J, el=\E[K, el1=\E[1K, - home=\E[H, ht=^I, ind=^J, kbs=^H, - kcub1=\E[D, kcud1=\E[B, kcuf1=\E[C, kcuu1=\E[A, - civis=\E[1r, cnorm=\E[2r, cvvis=\E[3r, - ri=\EM, rs2=\Ec, rmacs=^O, smacs=^N, - dico=\E[%p1%d;%p2%d;%p3%d;%p4%d;%p5%d;%p6%d;%p7%d;%p8%d;%p9%dp, - cico=\E[%p1%dq, - acsc=}\355\,\177+\176~\245f\337{\367, - diff --git a/extras/ezio/ovs-switchui.c b/extras/ezio/ovs-switchui.c deleted file mode 100644 index d2520450..00000000 --- a/extras/ezio/ovs-switchui.c +++ /dev/null @@ -1,3004 +0,0 @@ -/* Copyright (c) 2008, 2009, 2010 Nicira Networks, Inc. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "command-line.h" -#include "daemon.h" -#include "dynamic-string.h" -#include "ezio.h" -#include "fatal-signal.h" -#include "netdev.h" -#include "ofp-util.h" -#include "ofpbuf.h" -#include "openflow/nicira-ext.h" -#include "openflow/openflow.h" -#include "packets.h" -#include "poll-loop.h" -#include "process.h" -#include "random.h" -#include "rconn.h" -#include "socket-util.h" -#include "svec.h" -#include "timeval.h" -#include "util.h" -#include "vconn.h" -#include "vlog.h" -#include "xtoxll.h" - -VLOG_DEFINE_THIS_MODULE(switchui) - -static void parse_options(int argc, char *argv[]); -static void usage(void); - -static void initialize_terminal(void); -static void restore_terminal(void *aux); - -enum priority { - P_STATUS = 5, - P_PROGRESS = 10, - P_WARNING = 15, - P_ERROR = 20, - P_FATAL = 25 -}; - -struct message; -static void emit(struct message **, enum priority, const char *, ...) - PRINTF_FORMAT(3, 4); -static void emit_function(struct message **, enum priority, - void (*function)(void *aux), void *aux); -static int shown(struct message **); -static void clear_messages(void); -static bool empty_message(const struct message *); -static struct message *best_message(void); -static struct message *next_message(struct message *); -static struct message *prev_message(struct message *); -static void put_message(const struct message *); -static void message_shown(struct message *); -static void age_messages(void); - -struct pair { - char *name; - char *value; -}; - -struct dict { - struct pair *pairs; - size_t n, max; -}; - -static void dict_init(struct dict *); -static void dict_add(struct dict *, const char *name, const char *value); -static void dict_add_nocopy(struct dict *, char *name, char *value); -static void dict_delete(struct dict *, const char *name); -static void dict_parse(struct dict *, const char *data, size_t nbytes); -static void dict_free(struct dict *); -static bool dict_lookup(const struct dict *, - const char *name, const char **value); -static int dict_get_int(const struct dict *, const char *name, int def); -static bool dict_get_bool(const struct dict *, const char *name, bool def); -static const char *dict_get_string(const struct dict *, - const char *name, const char *def); -static uint32_t dict_get_ip(const struct dict *, const char *name); - -static void addf(const char *format, ...) PRINTF_FORMAT(1, 2); - -static void fetch_status(struct rconn *, struct dict *, long long int timeout); -static bool parse_reply(void *, struct dict *, uint32_t xid); -static void compose_messages(const struct dict *, struct rconn *rconn); - -static void show_flows(struct rconn *); -static void show_dpid_ip(struct rconn *, const struct dict *); -static void show_ofproto_state(const struct dict *); -static void show_fail_open_state(const struct dict *); -static void show_discovery_state(const struct dict *); -static void show_remote_state(const struct dict *); -static void show_data_rates(struct rconn *, const struct dict *); - -static void init_reboot_notifier(void); -static bool show_reboot_state(void); - -static void show_string(const char *string); -static void block_until(long long timeout); -static void menu(const struct dict *); -static void drain_keyboard_buffer(void); - -static const char *progress(void); - -int -main(int argc, char *argv[]) -{ - struct rconn *rconn; - struct message *msg; - int countdown = 5; - bool user_selected; - bool debug_mode; - - /* Tracking keystroke repeat counts. */ - int last_key = 0; - long long int last_key_time = 0; - int repeat_count = 0; - - proctitle_init(argc, argv); - set_program_name(argv[0]); - parse_options(argc, argv); - signal(SIGPIPE, SIG_IGN); - vlog_set_levels(NULL, VLF_CONSOLE, VLL_EMER); - init_reboot_notifier(); - - argc -= optind; - argv += optind; - if (argc != 1) { - ovs_fatal(0, "exactly one non-option argument required; " - "use --help for help"); - } - - rconn = rconn_create(5, 5); - rconn_connect(rconn, argv[0], NULL); - - die_if_already_running(); - daemonize(); - - initialize_terminal(); - fatal_signal_add_hook(restore_terminal, NULL, NULL, true); - - msg = NULL; - countdown = 0; - user_selected = false; - debug_mode = false; - for (;;) { - struct dict dict; - long long timeout = time_msec() + 1000; - - clear_messages(); - - dict_init(&dict); - fetch_status(rconn, &dict, timeout); - dict_add(&dict, "debug", debug_mode ? "true" : "false"); - compose_messages(&dict, rconn); - - if (countdown) { - if (!empty_message(msg)) { - countdown--; - } else { - msg = user_selected ? next_message(msg) : best_message(); - countdown = 5; - } - } else { - msg = best_message(); - countdown = 5; - user_selected = false; - } - if (!user_selected) { - message_shown(msg); - } - - do { - for (;;) { - int c = getch(); - if (c == ERR) { - break; - } - - if (c != last_key || time_msec() > last_key_time + 250) { - repeat_count = 0; - } - last_key = c; - last_key_time = time_msec(); - repeat_count++; - - if (c == KEY_DOWN || c == KEY_UP) { - msg = (c == KEY_DOWN ? next_message(msg) - : prev_message(msg)); - countdown = 5; - user_selected = true; - } else if (c == '\r' || c == '\n') { - countdown = 60; - user_selected = true; - if (repeat_count >= 20) { - debug_mode = !debug_mode; - show_string(debug_mode - ? "Debug Mode\nEnabled" - : "Debug Mode\nDisabled"); - } - } else if (c == '\b' || c == '\x7f' || - c == '\x1b' || c == KEY_BACKSPACE || c == KEY_DC) { - menu(&dict); - drain_keyboard_buffer(); - break; - } - } - - erase(); - curs_set(0); - move(0, 0); - put_message(msg); - refresh(); - - poll_fd_wait(STDIN_FILENO, POLLIN); - poll_timer_wait_until(timeout); - poll_block(); - } while (time_msec() < timeout); - age_messages(); - dict_free(&dict); - } - - return 0; -} - -static void -compose_messages(const struct dict *dict, struct rconn *rconn) -{ - if (!show_reboot_state()) { - show_flows(rconn); - show_dpid_ip(rconn, dict); - show_ofproto_state(dict); - show_fail_open_state(dict); - show_discovery_state(dict); - show_remote_state(dict); - show_data_rates(rconn, dict); - } -} - -struct put_flows_data { - struct rconn *rconn; - uint32_t xid; - uint32_t flow_count; - bool got_reply; -}; - -static void -parse_flow_reply(void *data, struct put_flows_data *pfd) -{ - struct ofp_header *oh; - struct ofp_stats_reply *rpy; - struct ofp_aggregate_stats_reply *asr; - const size_t min_size = sizeof *rpy + sizeof *asr; - - oh = data; - if (ntohs(oh->length) < min_size) { - VLOG_WARN("reply is too short (%"PRIu16")", ntohs(oh->length)); - return; - } - if (oh->xid != pfd->xid) { - VLOG_WARN("xid 0x%08"PRIx32" != expected 0x%08"PRIx32, - oh->xid, pfd->xid); - return; - } - if (oh->type != OFPT_STATS_REPLY) { - VLOG_WARN("reply is wrong type %"PRIu8, oh->type); - return; - } - - rpy = data; - if (rpy->type != htons(OFPST_AGGREGATE)) { - VLOG_WARN("reply has wrong stat type ID %08"PRIx16, rpy->type); - return; - } - - asr = (struct ofp_aggregate_stats_reply *) rpy->body; - pfd->flow_count = ntohl(asr->flow_count); - pfd->got_reply = true; -} - -static bool -have_icons(void) -{ - const char *dico = tigetstr("dico"); - return dico && dico != (const char *) -1; -} - -static void -set_icon(int num, int r0, int r1, int r2, int r3, int r4, int r5, int r6, - int r7) -{ - if (have_icons()) { - putp(tparm(tigetstr("dico"), num, r0, r1, r2, r3, r4, r5, r6, r7)); - } -} - -static void -set_repeated_icon(int num, int row) -{ - set_icon(num, row, row, row, row, row, row, row, row); -} - -#if 0 -static void -set_brick_icon(int num, int n_solid) -{ - const static int rows[6] = {_____, X____, XX___, XXX__, XXXX_, XXXXX}; - set_repeated_icon(num, rows[n_solid < 0 ? 0 - : n_solid > 5 ? 5 - : n_solid]); -} -#endif - -static int -icon_char(int num, int alternate) -{ - return have_icons() ? 0x80 | num | A_ALTCHARSET : alternate; -} - -static void -put_icon(int num, char alternate) -{ - addch(icon_char(num, alternate)); -} - -#if 0 -static void -bar_graph(int n_chars, int n_pixels) -{ - int i; - - if (n_pixels < 0) { - n_pixels = 0; - } else if (n_pixels > n_chars * 5) { - n_pixels = n_chars * 5; - } - - if (n_pixels > 5) { - set_brick_icon(0, 5); - for (i = 0; i < n_pixels / 5; i++) { - put_icon(0, "#"); - } - } - if (n_pixels % 5) { - set_brick_icon(1, n_pixels % 5); - put_icon(1, "#"); - } -} -#endif - -static void -put_flows(void *pfd_) -{ - struct put_flows_data *pfd = pfd_; - static struct rconn_packet_counter *counter; - char host[64]; - - if (!counter) { - counter = rconn_packet_counter_create(); - } - - if (!pfd->xid) { - struct ofp_stats_request *rq; - struct ofp_aggregate_stats_request *asr; - struct ofpbuf *b; - - pfd->xid = random_uint32(); - rq = make_openflow_xid(sizeof *rq, OFPT_STATS_REQUEST, - pfd->xid, &b); - rq->type = htons(OFPST_AGGREGATE); - rq->flags = htons(0); - asr = ofpbuf_put_uninit(b, sizeof *asr); - memset(asr, 0, sizeof *asr); - asr->match.wildcards = htonl(OFPFW_ALL); - asr->table_id = 0xff; - asr->out_port = htons(OFPP_NONE); - update_openflow_length(b); - rconn_send_with_limit(pfd->rconn, b, counter, 10); - } - - if (!pfd->got_reply) { - int i; - - rconn_run(pfd->rconn); - for (i = 0; i < 50; i++) { - struct ofpbuf *b; - - b = rconn_recv(pfd->rconn); - if (!b) { - break; - } - - parse_flow_reply(b->data, pfd); - ofpbuf_delete(b); - if (pfd->got_reply) { - break; - } - } - } - - gethostname(host, sizeof host); - host[sizeof host - 1] = '\0'; - if (strlen(host) + 6 <= 16) { - addf("Host: %s\n", host); - } else { - addf("%s\n", host); - } - if (pfd->got_reply) { - addf("Flows: %"PRIu32, pfd->flow_count); - } - - if (!pfd->got_reply) { - rconn_run_wait(pfd->rconn); - rconn_recv_wait(pfd->rconn); - } -} - -static void -show_flows(struct rconn *rconn) -{ - static struct message *m; - static struct put_flows_data pfd; - - memset(&pfd, 0, sizeof pfd); - pfd.rconn = rconn; - emit_function(&m, P_STATUS, put_flows, &pfd); - -} - -struct put_dpid_ip_data { - struct rconn *rconn; - uint32_t xid; - uint64_t dpid; - char ip[16]; - bool got_reply; -}; - -static void -parse_dp_reply(void *data, struct put_dpid_ip_data *pdid) -{ - struct ofp_switch_features *osf; - struct ofp_header *oh; - - oh = data; - if (ntohs(oh->length) < sizeof *osf) { - VLOG_WARN("reply is too short (%"PRIu16")", ntohs(oh->length)); - return; - } - if (oh->xid != pdid->xid) { - VLOG_WARN("xid 0x%08"PRIx32" != expected 0x%08"PRIx32, - oh->xid, pdid->xid); - return; - } - if (oh->type != OFPT_FEATURES_REPLY) { - VLOG_WARN("reply is wrong type %"PRIu8, oh->type); - return; - } - - osf = data; - pdid->dpid = ntohll(osf->datapath_id); - pdid->got_reply = true; -} - -static void -put_dpid_id(void *pdid_) -{ - struct put_dpid_ip_data *pdid = pdid_; - static struct rconn_packet_counter *counter; - - if (!counter) { - counter = rconn_packet_counter_create(); - } - - if (!pdid->xid) { - struct ofp_header *oh; - struct ofpbuf *b; - - pdid->xid = random_uint32(); - oh = make_openflow_xid(sizeof *oh, OFPT_FEATURES_REQUEST, - pdid->xid, &b); - rconn_send_with_limit(pdid->rconn, b, counter, 10); - } - - if (!pdid->got_reply) { - int i; - - rconn_run(pdid->rconn); - for (i = 0; i < 50; i++) { - struct ofpbuf *b; - - b = rconn_recv(pdid->rconn); - if (!b) { - break; - } - - parse_dp_reply(b->data, pdid); - ofpbuf_delete(b); - if (pdid->got_reply) { - break; - } - } - } - - addf("DP: "); - if (pdid->got_reply) { - addf("%012"PRIx64, pdid->dpid); - } - addf("\nIP: %s", pdid->ip); - - if (!pdid->got_reply) { - rconn_run_wait(pdid->rconn); - rconn_recv_wait(pdid->rconn); - } -} - -static void -show_dpid_ip(struct rconn *rconn, const struct dict *dict) -{ - static struct message *m; - static struct put_dpid_ip_data pdid; - const char *is_connected, *local_ip; - - dict_lookup(dict, "local.is-connected", &is_connected); - dict_lookup(dict, "remote.local-ip", &local_ip); - if (!is_connected && !local_ip) { - /* If we're not connected to the datapath and don't have a local IP, - * then we won't have anything useful to show anyhow. */ - return; - } - - memset(&pdid, 0, sizeof pdid); - pdid.rconn = rconn; - ovs_strlcpy(pdid.ip, local_ip ? local_ip : "", sizeof pdid.ip); - emit_function(&m, P_STATUS, put_dpid_id, &pdid); -} - -static size_t -dict_find(const struct dict *dict, const char *name) -{ - size_t i; - - for (i = 0; i < dict->n; i++) { - const struct pair *p = &dict->pairs[i]; - if (!strcmp(p->name, name)) { - return i; - } - } - - return SIZE_MAX; -} - -static bool -dict_lookup(const struct dict *dict, const char *name, const char **value) -{ - size_t idx = dict_find(dict, name); - if (idx != SIZE_MAX) { - *value = dict->pairs[idx].value; - return true; - } else { - *value = NULL; - return false; - } -} - -static const char * -dict_get(const struct dict *dict, const char *name) -{ - const char *value; - return dict_lookup(dict, name, &value) ? value : NULL; -} - -static int -dict_get_int(const struct dict *dict, const char *name, int def) -{ - const char *value; - return dict_lookup(dict, name, &value) ? atoi(value) : def; -} - -static bool -dict_get_bool(const struct dict *dict, const char *name, bool def) -{ - const char *value; - if (dict_lookup(dict, name, &value)) { - if (!strcmp(value, "true")) { - return true; - } - if (!strcmp(value, "false")) { - return false; - } - } - return def; -} - -static const char * -dict_get_string(const struct dict *dict, const char *name, const char *def) -{ - const char *value; - return dict_lookup(dict, name, &value) ? value : def; -} - -static uint32_t -dict_get_ip(const struct dict *dict, const char *name) -{ - struct in_addr in; - return (inet_aton(dict_get_string(dict, name, ""), &in) ? in.s_addr - : htonl(0)); -} - -static void -addf(const char *format, ...) -{ - char buf[128]; - va_list args; - - va_start(args, format); - vsnprintf(buf, sizeof buf, format, args); - va_end(args); - - addstr(buf); -} - -static void -show_ofproto_state(const struct dict *dict) -{ - static struct message *msg; - const char *is_connected; - - if (!dict_lookup(dict, "remote.is-connected", &is_connected)) { - /* Secchan not running or not responding. */ - emit(&msg, P_ERROR, "Switch disabled"); - } -} - -static const char * -discovery_state_label(const char *name) -{ - static struct dict *states; - if (!states) { - states = xmalloc(sizeof *states); - dict_init(states); - dict_add(states, "INIT", "Init"); - dict_add(states, "INIT_REBOOT", "Init"); - dict_add(states, "REBOOTING", "Init"); - dict_add(states, "SELECTING", "Searching"); - dict_add(states, "REQUESTING", "Requesting"); - dict_add(states, "BOUND", "Got"); - dict_add(states, "RENEWING", "Renewing"); - dict_add(states, "REBINDING", "Rebinding"); - dict_add(states, "RELEASED", "Released"); - } - return dict_get_string(states, name, "Error"); -} - -static void -show_discovery_state(const struct dict *dict) -{ - static struct message *m_bound, *m_other; - struct message **m; - const char *state, *ip; - enum priority priority; - int state_elapsed; - - state = dict_get_string(dict, "discovery.state", NULL); - if (!state) { - return; - } - ip = dict_get_string(dict, "discovery.ip", NULL); - state_elapsed = dict_get_int(dict, "discovery.state-elapsed", 0); - - if (!strcmp(state, "BOUND")) { - m = &m_bound; - priority = P_STATUS; - } else { - m = &m_other; - priority = P_PROGRESS; - } - emit(m, priority, "Discovery %s\n%s", - progress(), discovery_state_label(state)); - if (ip) { - emit(m, priority, " %s", ip); - } -} - -static void -human_time(int seconds, char *buf, size_t size) -{ - const char *sign = ""; - if (seconds < 0) { - sign = "-"; - seconds = seconds == INT_MIN ? INT_MAX : -seconds; - } - - if (seconds <= 60) { - snprintf(buf, size, "%s%d s", sign, seconds); - } else if (seconds <= 60 * 60) { - snprintf(buf, size, "%s%d min", sign, seconds / 60); - } else if (seconds <= 60 * 60 * 24 * 2) { - snprintf(buf, size, "%s%d h", sign, seconds / 60 / 60); - } else { - snprintf(buf, size, "%s%d days", sign, seconds / 60 / 60 / 24); - } -} - -static void -show_fail_open_state(const struct dict *dict) -{ - static struct message *m; - int cur_duration, trigger_duration; - - if (!dict_get_bool(dict, "fail-open.triggered", false)) { - return; - } - trigger_duration = dict_get_int(dict, "fail-open.trigger-duration", 0); - cur_duration = dict_get_int(dict, "fail-open.current-duration", 0); - if (shown(&m) < 5) { - emit(&m, P_WARNING, "Failed open %s\nafter %d secs", - progress(), trigger_duration); - } else { - char buf[16]; - human_time(cur_duration - trigger_duration, buf, sizeof buf); - emit(&m, P_WARNING, "In fail open for\n%s now %s", buf, progress()); - } -} - -static const char * -progress(void) -{ - return "..." + (3 - (unsigned int) time_now() % 4); -} - -static void -show_remote_state(const struct dict *dict) -{ - bool debug_mode = dict_get_bool(dict, "debug", false); - const char *state, *is_connected; - - state = dict_get_string(dict, "remote.state", NULL); - if (!state) { - return; - } - is_connected = dict_get_string(dict, "remote.is-connected", "false"); - if (!strcmp(is_connected, "true")) { - if (debug_mode) { - static struct message *m_connected; - char buf[16]; - human_time(dict_get_int(dict, "remote.last-connection", 0), - buf, sizeof buf); - emit(&m_connected, P_STATUS, - "Connected for\nlast %s %s", buf, progress()); - } - - if (!strcmp(state, "IDLE")) { - static struct message *m_idle; - emit(&m_idle, P_PROGRESS, "Sent idle probe"); - } - - if (debug_mode) { - const char *name = dict_get_string(dict, "remote.name", NULL); - if (name) { - static struct message *m_name; - emit(&m_name, P_STATUS, "Connected to\n%s", name); - } - } - } else { - int elapsed, backoff; - const char *name, *error; - - elapsed = dict_get_int(dict, "remote.state-elapsed", 0); - backoff = dict_get_int(dict, "remote.backoff", 0); - name = dict_get_string(dict, "remote.name", "unknown"); - state = dict_get_string(dict, "remote.state", "VOID"); - error = dict_get_string(dict, "remote.last-connect-error", NULL); - if (!strcmp(state, "VOID")) { - static struct message *m; - emit(&m, P_PROGRESS, "Controller not\nfound"); - } else if (!strcmp(state, "BACKOFF")) { - static struct message *m[3]; - char buf[16]; - - if (error) { - emit(&m[0], P_PROGRESS, "Connect failed:\n%s", error); - } - emit(&m[2], P_STATUS, "Last connected\n%s ago", buf); - emit(&m[1], P_PROGRESS, - "Disconnected\nReconnect in %d", backoff - elapsed); - human_time(dict_get_int(dict, "remote.last-connection", 0), - buf, sizeof buf); - } else if (!strcmp(state, "CONNECTING")) { - static struct message *m; - emit(&m, P_PROGRESS, "Connecting %s\n%s", progress(), name); - } - } -} - -static void -fetch_status(struct rconn *rconn, struct dict *dict, long long timeout) -{ - static struct rconn_packet_counter *counter; - static uint32_t xid; - struct nicira_header *rq; - struct ofpbuf *b; - int retval; - - if (!counter) { - counter = rconn_packet_counter_create(); - } - if (!xid) { - xid = random_uint32(); - } - - rq = make_openflow_xid(sizeof *rq, OFPT_VENDOR, ++xid, &b); - rq->vendor = htonl(NX_VENDOR_ID); - rq->subtype = htonl(NXT_STATUS_REQUEST); - retval = rconn_send_with_limit(rconn, b, counter, 10); - if (retval) { - /* continue into the loop so that we pause for a while */ - } - - while (time_msec() < timeout) { - int i; - - rconn_run(rconn); - - for (i = 0; i < 50; i++) { - struct ofpbuf *b; - bool got_reply; - - b = rconn_recv(rconn); - if (!b) { - break; - } - - got_reply = parse_reply(b->data, dict, xid); - ofpbuf_delete(b); - if (got_reply) { - return; - } - } - - rconn_run_wait(rconn); - rconn_recv_wait(rconn); - poll_timer_wait_until(timeout); - poll_block(); - } -} - -static bool -parse_reply(void *data, struct dict *dict, uint32_t xid) -{ - struct ofp_header *oh; - struct nicira_header *rpy; - - oh = data; - if (ntohs(oh->length) < sizeof *rpy) { - VLOG_WARN("reply is too short (%"PRIu16")", ntohs(oh->length)); - return false; - } - if (oh->xid != xid) { - VLOG_WARN("xid 0x%08"PRIx32" != expected 0x%08"PRIx32, oh->xid, xid); - return false; - } - if (oh->type != OFPT_VENDOR) { - VLOG_WARN("reply is wrong type %"PRIu8, oh->type); - return false; - } - - rpy = data; - if (rpy->vendor != htonl(NX_VENDOR_ID)) { - VLOG_WARN("reply has wrong vendor ID %08"PRIx32, rpy->vendor); - return false; - } - if (rpy->subtype != htonl(NXT_STATUS_REPLY)) { - VLOG_WARN("reply has wrong subtype %08"PRIx32, rpy->subtype); - return false; - } - - dict_parse(dict, (const char *) (rpy + 1), - ntohs(oh->length) - sizeof *rpy); - return true; -} - -static void -dict_parse(struct dict *dict, const char *data, size_t nbytes) -{ - char *save_ptr = NULL; - char *copy, *name; - - copy = xmemdup0(data, nbytes); - for (name = strtok_r(copy, "=", &save_ptr); name; - name = strtok_r(NULL, "=", &save_ptr)) - { - char *value = strtok_r(NULL, "\n", &save_ptr); - if (!value) { - break; - } - dict_add(dict, name, value); - } - free(copy); -} - -static void -dict_init(struct dict *dict) -{ - dict->n = 0; - dict->max = 16; - dict->pairs = xmalloc(sizeof *dict->pairs * dict->max); -} - -static void -dict_add(struct dict *dict, const char *name, const char *value) -{ - dict_add_nocopy(dict, xstrdup(name), xstrdup(value)); -} - -static void -dict_add_nocopy(struct dict *dict, char *name, char *value) -{ - struct pair *p; - - if (dict->n >= dict->max) { - dict->max *= 2; - dict->pairs = xrealloc(dict->pairs, sizeof *dict->pairs * dict->max); - } - p = &dict->pairs[dict->n++]; - p->name = name; - p->value = value; -} - -static void -dict_delete(struct dict *dict, const char *name) -{ - size_t idx; - while ((idx = dict_find(dict, name)) != SIZE_MAX) { - struct pair *pair = &dict->pairs[idx]; - free(pair->name); - free(pair->value); - dict->pairs[idx] = dict->pairs[--dict->n]; - } -} - -static void -dict_free(struct dict *dict) -{ - if (dict) { - size_t i; - - for (i = 0; i < dict->n; i++) { - free(dict->pairs[i].name); - free(dict->pairs[i].value); - } - free(dict->pairs); - } -} - -static void -initialize_terminal(void) -{ - initscr(); - cbreak(); - noecho(); - nonl(); - intrflush(stdscr, FALSE); - keypad(stdscr, TRUE); - nodelay(stdscr, TRUE); - typeahead(-1); - scrollok(stdscr, TRUE); -} - -static void -restore_terminal(void *aux OVS_UNUSED) -{ - endwin(); -} - -struct byte_count { - long long int when; - uint64_t tx_bytes; -}; - -struct show_rates_data { - struct rconn *rconn; - uint32_t xid; - struct byte_count prev, now; - bool got_reply; -}; - -static void -parse_port_reply(void *data, struct show_rates_data *rates) -{ - struct ofp_header *oh; - struct ofp_stats_reply *rpy; - struct ofp_port_stats *ops; - size_t n_ports; - size_t i; - - oh = data; - if (ntohs(oh->length) < sizeof *rpy) { - VLOG_WARN("reply is too short (%"PRIu16")", ntohs(oh->length)); - return; - } - if (oh->xid != rates->xid) { - VLOG_WARN("xid 0x%08"PRIx32" != expected 0x%08"PRIx32, - oh->xid, rates->xid); - return; - } - if (oh->type != OFPT_STATS_REPLY) { - VLOG_WARN("reply is wrong type %"PRIu8, oh->type); - return; - } - - rpy = data; - if (rpy->type != htons(OFPST_PORT)) { - VLOG_WARN("reply has wrong stat type ID %08"PRIx16, rpy->type); - return; - } - - n_ports = ((ntohs(oh->length) - offsetof(struct ofp_stats_reply, body)) - / sizeof *ops); - ops = (struct ofp_port_stats *) rpy->body; - rates->prev = rates->now; - rates->now.when = time_msec(); - rates->now.tx_bytes = UINT64_MAX; - for (i = 0; i < n_ports; i++, ops++) { - if (ops->tx_bytes != htonll(UINT64_MAX)) { - if (rates->now.tx_bytes == UINT64_MAX) { - rates->now.tx_bytes = 0; - } - rates->now.tx_bytes += ntohll(ops->tx_bytes); - } - } - rates->got_reply = true; -} - -static void -dump_graph(const bool graph[80]) -{ - signed char icons[32]; - int n_icons = 3; - int i; - - memset(icons, -1, sizeof icons); - for (i = 0; i < 16; i++) { - uint8_t row; - int j; - - row = 0; - for (j = 0; j < 5; j++) { - row = (row << 1) | graph[i * 5 + j]; - } - if (!row) { - addch(' '); - continue; - } - - if (icons[row] < 0) { - if (n_icons >= 8) { - addch('X'); - continue; - } - set_repeated_icon(n_icons, row); - icons[row] = n_icons++; - } - put_icon(icons[row], row == 0x1f ? '#' : ' '); - } -} - -static void -do_show_data_rates(void *rates_) -{ - struct show_rates_data *rates = rates_; - static struct rconn_packet_counter *counter; - bool graph[80]; - - if (!counter) { - counter = rconn_packet_counter_create(); - } - if (!rates->xid) { - struct ofp_stats_request *rq; - struct ofp_port_stats_request *psr; - struct ofpbuf *b; - - rates->xid = random_uint32(); - rq = make_openflow_xid(sizeof *rq, OFPT_STATS_REQUEST, - rates->xid, &b); - rq->type = htons(OFPST_PORT); - rq->flags = htons(0); - psr = ofpbuf_put_uninit(b, sizeof *psr); - memset(psr, 0, sizeof *psr); - psr->port_no = htons(OFPP_NONE); - update_openflow_length(b); - rconn_send_with_limit(rates->rconn, b, counter, 10); - } - - if (!rates->got_reply) { - int i; - - rconn_run(rates->rconn); - for (i = 0; i < 50; i++) { - struct ofpbuf *b; - - b = rconn_recv(rates->rconn); - if (!b) { - break; - } - - parse_port_reply(b->data, rates); - ofpbuf_delete(b); - if (rates->got_reply) { - break; - } - } - } - - set_icon(0, - e_____, - e_____, - e_____, - e__X__, - e__X__, - e__X_X, - e__XX_, - e__X_X); - set_icon(1, - e_____, - e_____, - e_____, - eX___X, - eXX_XX, - eX_X_X, - eX___X, - eX___X); - set_icon(2, - e_____, - e_____, - e_____, - e_XXX_, - eX____, - eX_XXX, - eX___X, - e_XXX_); - - memset(graph, 0, sizeof graph); - graph[24] = 1; - graph[48] = 1; - graph[72] = 1; - - addstr("TX: "); - put_icon(0, 'k'); - addstr(" "); - put_icon(1, 'M'); - addstr(" "); - put_icon(2, 'G'); - addch('\n'); - - if (rates->now.tx_bytes != UINT64_MAX - && rates->prev.tx_bytes != UINT64_MAX - && rates->now.when - rates->prev.when > 500 - && time_msec() - rates->now.when < 2000) - { - uint64_t bits = (rates->now.tx_bytes - rates->prev.tx_bytes) * 8; - uint64_t msecs = rates->now.when - rates->prev.when; - double bps = (double) bits * 1000.0 / msecs; - int pixels = bps > 0 ? log(bps) / log(10.0) * 8 + .5 : 0; - if (pixels < 0) { - pixels = 0; - } else if (pixels > 80) { - pixels = 80; - } - memset(graph, 1, pixels); - } - - dump_graph(graph); - - if (!rates->got_reply) { - rconn_run_wait(rates->rconn); - rconn_recv_wait(rates->rconn); - } -} - -static void -show_data_rates(struct rconn *rconn, const struct dict *dict) -{ - static struct message *m; - static struct show_rates_data rates; - const char *is_connected, *local_ip; - static bool inited = false; - - dict_lookup(dict, "local.is-connected", &is_connected); - dict_lookup(dict, "remote.local-ip", &local_ip); - if (!is_connected && !local_ip) { - /* If we're not connected to the datapath and don't have a local IP, - * then we won't have anything useful to show anyhow. */ - return; - } - - rates.rconn = rconn; - rates.xid = 0; - rates.got_reply = false; - if (!inited) { - rates.now.tx_bytes = UINT64_MAX; - rates.prev.tx_bytes = UINT64_MAX; - inited = true; - } - emit_function(&m, P_STATUS, do_show_data_rates, &rates); -} - -struct message { - /* Content. */ - void (*function)(void *aux); - void *aux; - char string[128]; - - size_t index; - enum priority priority; - int age; - int shown; -}; - -static struct message **messages; -static size_t n_messages, allocated_messages; - -static struct message * -allocate_message(struct message **msgp) -{ - if (!*msgp) { - /* Allocate and initialize message. */ - *msgp = xzalloc(sizeof **msgp); - (*msgp)->index = n_messages; - - /* Add to list of messages. */ - if (n_messages >= allocated_messages) { - allocated_messages = 2 * allocated_messages + 1; - messages = xrealloc(messages, - sizeof *messages * allocated_messages); - } - messages[n_messages++] = *msgp; - } - return *msgp; -} - -static void -emit(struct message **msgp, enum priority priority, const char *format, ...) -{ - struct message *msg = allocate_message(msgp); - va_list args; - size_t length; - - msg->priority = priority; - - va_start(args, format); - length = strlen(msg->string); - vsnprintf(msg->string + length, sizeof msg->string - length, format, args); - va_end(args); -} - -static void -emit_function(struct message **msgp, enum priority priority, - void (*function)(void *aux), void *aux) -{ - struct message *msg = allocate_message(msgp); - msg->priority = priority; - msg->function = function; - msg->aux = aux; -} - -static int -shown(struct message **msgp) -{ - struct message *msg = allocate_message(msgp); - return msg->shown; -} - -static void -clear_messages(void) -{ - size_t i; - - for (i = 0; i < n_messages; i++) { - struct message *msg = messages[i]; - msg->string[0] = '\0'; - msg->function = NULL; - } -} - -static struct message * -best_message(void) -{ - struct message *best_msg; - int best_score; - size_t i; - - best_score = INT_MIN; - best_msg = NULL; - for (i = 0; i < n_messages; i++) { - struct message *msg = messages[i]; - int score; - - if (empty_message(msg)) { - continue; - } - - score = msg->priority; - if (!msg->shown) { - score += msg->age; - } else { - score -= msg->shown; - } - if (score > best_score) { - best_score = score; - best_msg = msg; - } - } - return best_msg; -} - -static void -message_shown(struct message *msg) -{ - if (msg && msg->shown++ > 3600) { - msg->shown = 0; - } -} - -static bool -empty_message(const struct message *msg) -{ - return !msg || (!msg->string[0] && !msg->function); -} - -static struct message *get_message(size_t index) -{ - assert(index <= n_messages || index == SIZE_MAX); - return (index < n_messages ? messages[index] - : index == SIZE_MAX ? messages[n_messages - 1] - : messages[0]); -} - -static struct message * -next_message(struct message *msg) -{ - struct message *p; - - for (p = get_message(msg->index + 1); p != msg; - p = get_message(p->index + 1)) { - if (!empty_message(p)) { - break; - } - } - return p; -} - -static struct message * -prev_message(struct message *msg) -{ - struct message *p; - - for (p = get_message(msg->index - 1); p != msg; - p = get_message(p->index - 1)) { - if (!empty_message(p)) { - break; - } - } - return p; -} - -static void -put_message(const struct message *m) -{ - if (m->string[0]) { - addstr(m->string); - } else if (m->function) { - m->function(m->aux); - } -} - -static void -age_messages(void) -{ - size_t i; - int load; - - load = 0; - for (i = 0; i < n_messages; i++) { - struct message *msg = messages[i]; - if (!empty_message(msg)) { - load++; - } - } - - for (i = 0; i < n_messages; i++) { - struct message *msg = messages[i]; - if (empty_message(msg)) { - msg->age = msg->shown = 0; - } else { - if (msg->age && msg->age % 60 == 0) { - msg->shown -= MAX(0, 5 - (load + 6) / 12); - if (msg->shown < 0) { - msg->shown = 0; - } - } - if (msg->age++ > 3600) { - msg->age = 0; - } - } - } -} - -/* Set by SIGUSR1 handler. */ -static volatile sig_atomic_t sigusr1_triggered; - -/* The time after which we stop indicating that the switch is rebooting. - * (This is just in case the reboot fails.) */ -static time_t reboot_deadline = TIME_MIN; - -static void sigusr1_handler(int); - -static void -init_reboot_notifier(void) -{ - signal(SIGUSR1, sigusr1_handler); -} - -static void -sigusr1_handler(int signr OVS_UNUSED) -{ - sigusr1_triggered = true; -} - -static bool -show_reboot_state(void) -{ - if (sigusr1_triggered) { - reboot_deadline = time_now() + 30; - sigusr1_triggered = false; - } - if (time_now() < reboot_deadline) { - static struct message *msg; - emit(&msg, P_FATAL, "Rebooting"); - return true; - } - return false; -} - -struct menu_item { - char *text; - void (*f)(const struct dict *); - int id; - bool enabled; - int toggle; -}; - -struct menu { - struct menu_item **items; - size_t n_items, allocated_items; -}; - -static void menu_init(struct menu *); -static void menu_free(struct menu *); -static struct menu_item *menu_add_item(struct menu *, const char *text, ...) - PRINTF_FORMAT(2, 3); -static int menu_show(const struct menu *, int start, bool select); - -static void cmd_shell(const struct dict *); -static void cmd_show_version(const struct dict *); -static void cmd_configure(const struct dict *); -static void cmd_set_up_pki(const struct dict *); -static void cmd_browse_status(const struct dict *); -static void cmd_show_motto(const struct dict *); - -static void -menu_init(struct menu *menu) -{ - memset(menu, 0, sizeof *menu); -} - -static void -menu_free(struct menu *menu) -{ - size_t i; - - for (i = 0; i < menu->n_items; i++) { - struct menu_item *item = menu->items[i]; - free(item->text); - free(item); - } - free(menu->items); -} - -static struct menu_item * -menu_add_item(struct menu *menu, const char *text, ...) -{ - struct menu_item *item; - va_list args; - - if (menu->n_items >= menu->allocated_items) { - menu->allocated_items = 2 * menu->allocated_items + 1; - menu->items = xrealloc(menu->items, - sizeof *menu->items * menu->allocated_items); - } - item = menu->items[menu->n_items++] = xmalloc(sizeof *item); - va_start(args, text); - item->text = xvasprintf(text, args); - va_end(args); - item->f = NULL; - item->id = -1; - item->enabled = true; - item->toggle = -1; - return item; -} - -static void -menu(const struct dict *dict) -{ - bool debug_mode = dict_get_bool(dict, "debug", false); - struct menu menu; - int choice; - - menu_init(&menu); - menu_add_item(&menu, "Exit"); - menu_add_item(&menu, "Show Version")->f = cmd_show_version; - menu_add_item(&menu, "Configure")->f = cmd_configure; - menu_add_item(&menu, "Set up PKI")->f = cmd_set_up_pki; - if (debug_mode) { - menu_add_item(&menu, "Browse Status")->f = cmd_browse_status; - menu_add_item(&menu, "Shell")->f = cmd_shell; - menu_add_item(&menu, "Show Motto")->f = cmd_show_motto; - } - - choice = menu_show(&menu, 0, true); - if (choice >= 0) { - void (*f)(const struct dict *) = menu.items[choice]->f; - if (f) { - (f)(dict); - } - } - - menu_free(&menu); -} - -static int -menu_show(const struct menu *menu, int start, bool select) -{ - long long int adjust = LLONG_MAX; - int min = 0, max = MAX(menu->n_items - 2, 0); - int pos, selection; - set_icon(0, - eXX___, - eXXX__, - eXXXX_, - eXXXXX, - eXXXX_, - eXXX__, - eXX___, - e_____); - set_icon(1, - eXXXXX, - eX___X, - eX___X, - eX___X, - eX___X, - eX___X, - eXXXXX, - e_____); - set_icon(2, - eXXXXX, - eX___X, - eXX_XX, - eX_X_X, - eXX_XX, - eX___X, - eXXXXX, - e_____); - if (menu->n_items) { - pos = MIN(menu->n_items - 1, MAX(0, start)); - selection = pos; - } else { - pos = 0; - selection = -1; - } - for (;;) { - int key; - - while ((key = getch()) != ERR) { - switch (key) { - case KEY_UP: - if (select && selection > 0) { - selection--; - if (selection >= pos) { - break; - } - } - if (pos >= min) { - pos--; - } - break; - - case KEY_DOWN: - if (select && selection < menu->n_items - 1) { - selection++; - if (selection <= pos + 1) { - break; - } - } - if (pos <= max) { - pos++; - } - break; - - case '\r': case '\n': - if (select && selection >= 0 && selection < menu->n_items) { - struct menu_item *item = menu->items[selection]; - if (!item->enabled) { - show_string("Item disabled"); - break; - } else if (item->toggle >= 0) { - item->toggle = !item->toggle; - break; - } - } - return selection; - - case '\b': case '\x7f': case '\x1b': - case KEY_BACKSPACE: case KEY_DC: - return -1; - } - adjust = time_msec() + 1000; - } - if (time_msec() >= adjust && menu->n_items > 1) { - if (pos < min) { - pos = min; - } else if (pos > max) { - pos = max; - } - } - - erase(); - curs_set(0); - move(0, 0); - if (!menu->n_items) { - addstr("[Empty]"); - } else { - int idx; - for (idx = pos; idx < pos + 2; idx++) { - size_t width = 40; - - if (select) { - width--; - if (selection == idx) { - put_icon(0, '>'); - } else { - addch(' '); - } - } - - if (idx < 0) { - addstr("[Top]"); - } else if (idx >= menu->n_items) { - addstr("[Bottom]"); - } else { - const struct menu_item *item = menu->items[idx]; - size_t length = strlen(item->text); - if (!item->enabled) { - width -= 2; - addch('('); - } - if (item->toggle >= 0) { - if (have_icons()) { - addch(icon_char(item->toggle ? 2 : 1, 0)); - width--; - } else { - addstr(item->toggle ? "[X]" : "[ ]"); - width -= 3; - } - } - addnstr(item->text, MIN(width, length)); - if (!item->enabled) { - addch(')'); - } - } - if (idx == pos) { - addch('\n'); - } - } - } - refresh(); - - if (pos < min || pos > max) { - poll_timer_wait_until(adjust); - } - poll_fd_wait(STDIN_FILENO, POLLIN); - poll_block(); - } -} - -static int -menu_show2(const struct menu *menu, int start, bool select) -{ - int pos; - if (menu->n_items) { - pos = MIN(menu->n_items - 1, MAX(0, start)); - } else { - pos = -1; - } - set_icon(0, - e__X__, - e_XXX_, - eXXXXX, - e__X__, - e__X__, - e__X__, - e__X__, - e__X__); - set_icon(1, - e__X__, - e__X__, - e__X__, - e__X__, - e__X__, - eXXXXX, - e_XXX_, - e__X__); - for (;;) { - int key; - - while ((key = getch()) != ERR) { - switch (key) { - case KEY_UP: - if (pos > 0) { - pos--; - } - break; - - case KEY_DOWN: - if (menu->n_items > 0 && pos < menu->n_items - 1) { - pos++; - } - break; - - case '\r': case '\n': - if (select && !menu->items[pos]->enabled) { - show_string("Item disabled"); - break; - } - return pos; - - case '\b': case '\x7f': case '\x1b': - case KEY_BACKSPACE: case KEY_DC: - return -1; - } - } - - erase(); - curs_set(0); - move(0, 0); - if (pos == -1) { - addstr("[Empty]"); - } else { - const struct menu_item *item = menu->items[pos]; - const char *line1 = item->text; - size_t len1 = strcspn(line1, "\n"); - const char *line2 = line1[len1] ? &line1[len1 + 1] : ""; - size_t len2 = strcspn(line2, "\n"); - size_t width = 39 - 2 * !item->enabled; - - /* First line. */ - addch(pos > 0 ? icon_char(0, '^') : ' '); - if (!item->enabled && len1) { - addch('('); - } - addnstr(line1, MIN(len1, width)); - if (!item->enabled && len1) { - addch(')'); - } - addch('\n'); - - /* Second line. */ - addch(pos < menu->n_items - 1 ? icon_char(1, 'V') : ' '); - if (!item->enabled && len2) { - addch('('); - } - addnstr(line2, MIN(len2, width)); - if (!item->enabled && len2) { - addch(')'); - } - } - refresh(); - - poll_fd_wait(STDIN_FILENO, POLLIN); - poll_block(); - } -} - -static bool -yesno(const char *title, bool def) -{ - bool answer = def; - - set_icon(0, - eXX___, - eXXX__, - eXXXX_, - eXXXXX, - eXXXX_, - eXXX__, - eXX___, - e_____); - - for (;;) { - int key; - - while ((key = getch()) != ERR) { - switch (key) { - case KEY_UP: - case KEY_DOWN: - case KEY_LEFT: - case KEY_RIGHT: - answer = !answer; - break; - - case 'y': case 'Y': - answer = true; - break; - - case 'n': case 'N': - answer = false; - break; - - case '\r': case '\n': - return answer; - } - } - - erase(); - curs_set(0); - move(0, 0); - addstr(title); - - move(0, 12); - addch(answer ? icon_char(0, '>') : ' '); - addstr("Yes"); - - move(1, 12); - addch(!answer ? icon_char(0, '>') : ' '); - addstr("No"); - - refresh(); - - poll_fd_wait(STDIN_FILENO, POLLIN); - poll_block(); - } -} - -static void -cmd_show_version(const struct dict *dict OVS_UNUSED) -{ - show_string(VERSION BUILDNR); -} - -static void -cmd_browse_status(const struct dict *dict) -{ - struct menu menu; - size_t i; - - menu_init(&menu); - for (i = 0; i < dict->n; i++) { - const struct pair *p = &dict->pairs[i]; - menu_add_item(&menu, "%s = %s", p->name, p->value); - } - menu_show(&menu, 0, false); - menu_free(&menu); -} - -static void -cmd_shell(const struct dict *dict OVS_UNUSED) -{ - const char *home; - - erase(); - refresh(); - endwin(); - - printf("Type ^D to exit\n"); - fflush(stdout); - - putenv("PS1=#"); - putenv("PS2=>"); - putenv("PS3=?"); - putenv("PS4=+"); - home = getenv("HOME"); - if (home) { - chdir(home); - } - system("/bin/sh"); - initialize_terminal(); -} - -static void -cmd_show_motto(const struct dict *dict OVS_UNUSED) -{ - show_string("\"Just Add Ice\""); -} - -static void -show_string(const char *string) -{ - VLOG_INFO("%s", string); - erase(); - curs_set(0); - move(0, 0); - addstr(string); - refresh(); - block_until(time_msec() + 5000); -} - -static void -block_until(long long timeout) -{ - while (timeout > time_msec()) { - poll_timer_wait_until(timeout); - poll_block(); - } - drain_keyboard_buffer(); -} - -static void -drain_keyboard_buffer(void) -{ - while (getch() != ERR) { - continue; - } -} - -static int -read_vars(const char *cmd, struct dict *dict) -{ - struct ds ds; - FILE *stream; - int status; - - stream = popen(cmd, "r"); - if (!stream) { - VLOG_ERR("popen(\"%s\") failed: %s", cmd, strerror(errno)); - return errno; - } - - dict_init(dict); - ds_init(&ds); - while (!ds_get_line(&ds, stream)) { - const char *s = ds_cstr(&ds); - const char *equals = strchr(s, '='); - if (equals) { - dict_add_nocopy(dict, - xmemdup0(s, equals - s), xstrdup(equals + 1)); - } - } - status = pclose(stream); - if (status) { - char *msg = process_status_msg(status); - VLOG_ERR("pclose(\"%s\") reported subprocess failure: %s", - cmd, msg); - free(msg); - dict_free(dict); - return ECHILD; - } - return 0; -} - -static bool -run_and_report_failure(char **argv, const char *title) -{ - int null_fds[3] = {0, 1, 2}; - int status; - int retval; - char *s; - - s = process_escape_args(argv); - VLOG_INFO("starting subprocess: %s", s); - free(s); - - retval = process_run(argv, NULL, 0, null_fds, 3, &status); - if (retval) { - char *s = xasprintf("%s:\n%s", title, strerror(retval)); - show_string(s); - free(s); - return false; - } else if (status) { - char *msg = process_status_msg(status); - char *s = xasprintf("%s:\n%s", title, msg); - show_string(s); - free(msg); - free(s); - return false; - } else { - VLOG_INFO("subprocess exited with status 0"); - return true; - } -} - -static int -do_load_config(const char *file_name, struct dict *dict) -{ - struct dict auto_vars; - int retval; - char *cmd; - size_t i; - - /* Get the list of the variables that the shell sets automatically. */ - retval = read_vars("set -a && env", &auto_vars); - if (retval) { - return retval; - } - - /* Get the variables from 'file_name'. */ - cmd = xasprintf("set -a && . '%s' && env", file_name); - retval = read_vars(cmd, dict); - free(cmd); - if (retval) { - dict_free(&auto_vars); - return retval; - } - - /* Subtract. */ - for (i = 0; i < auto_vars.n; i++) { - dict_delete(dict, auto_vars.pairs[i].name); - } - dict_free(&auto_vars); - return 0; -} - -static bool -load_config(struct dict *dict) -{ - static const char default_file[] = "/etc/default/openflow-switch"; - int retval = do_load_config(default_file, dict); - if (!retval) { - return true; - } else { - char *s = xasprintf("Cfg load failed:\n%s", strerror(retval)); - show_string(s); - free(s); - return false; - } -} - -static bool -save_config(const struct svec *settings) -{ - struct svec argv; - size_t i; - bool ok; - - VLOG_INFO("Saving configuration:"); - for (i = 0; i < settings->n; i++) { - VLOG_INFO("%s", settings->names[i]); - } - - svec_init(&argv); - svec_add(&argv, "/usr/share/openvswitch-switchui/reconfigure"); - svec_append(&argv, settings); - svec_terminate(&argv); - ok = run_and_report_failure(argv.names, "Save failed"); - if (ok) { - long long int timeout = time_msec() + 5000; - - erase(); - curs_set(0); - move(0, 0); - addstr("Saved.\nRestarting..."); - refresh(); - - svec_clear(&argv); - svec_add(&argv, "/bin/sh"); - svec_add(&argv, "-c"); - svec_add(&argv, - "/etc/init.d/openflow-switch restart >/dev/null 2>&1"); - svec_terminate(&argv); - - ok = run_and_report_failure(argv.names, "Restart failed"); - if (ok) { - block_until(timeout); - } - } - svec_destroy(&argv); - - if (ok) { - VLOG_INFO("Save completed successfully"); - } else { - VLOG_WARN("Save failed"); - } - return ok; -} - -static int -match(pcre *re, const char *string, int length) -{ - int ovec[999]; - int retval; - - retval = pcre_exec(re, NULL, string, length, 0, PCRE_PARTIAL, - ovec, ARRAY_SIZE(ovec)); - if (retval >= 0) { - if (ovec[0] >= 0 && ovec[1] >= length) { - /* 're' matched all of 'string'. */ - return 0; - } else { - /* 're' matched the initial part of 'string' but not all of it. */ - return PCRE_ERROR_NOMATCH; - } - } else { - return retval; - } -} - -static void -figure_choices(pcre *re, struct ds *s, int pos, struct ds *choices) -{ - struct ds tmp; - int retval; - char c; - - ds_clear(choices); - - /* See whether the current string is a complete match. */ - if (!match(re, s->string, pos)) { - ds_put_char(choices, '\n'); - } - - /* Then try all the other possibilities. */ - ds_init(&tmp); - ds_put_buffer(&tmp, s->string, pos); - for (c = 0x20; c < 0x7f; c++) { - ds_put_char(&tmp, c); - retval = match(re, tmp.string, pos + 1); - if (retval == PCRE_ERROR_PARTIAL || !retval) { - ds_put_char(choices, c); - } - tmp.length--; - } - ds_destroy(&tmp); - - if (!choices->length) { - ds_put_char(choices, '\n'); - } -} - -static void -figure_completion(pcre *re, struct ds *s) -{ - for (;;) { - int found = -1; - int c; - - /* See whether the current string is a complete match. */ - if (!match(re, s->string, s->length)) { - return; - } - for (c = 0x20; c < 0x7f; c++) { - int retval; - - ds_put_char(s, c); - retval = match(re, s->string, s->length); - s->length--; - - if (retval == PCRE_ERROR_PARTIAL || !retval) { - if (found != -1) { - return; - } - found = c; - } - } - if (found == -1) { - return; - } - ds_put_char(s, found); - } -} - -#define OCTET_RE "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" -#define IP_RE "("OCTET_RE"\\."OCTET_RE"\\."OCTET_RE"\\."OCTET_RE")" -#define PORT_RE \ - "([0-9]|" \ - "[1-9][0-9]|" \ - "[1-9][0-9][0-9]|" \ - "[1-9][0-9][0-9][0-9]|" \ - "[1-5][0-9][0-9][0-9][0-9]|" \ - "6[1-4][0-9][0-9][0-9]|" \ - "65[1-4][0-9][0-9]|" \ - "655[1-2][0-9]|" \ - "6553[1-5])" -#define XOCTET_RE "[0-9A-F][0-9A-F]" -#define MAC_RE \ - XOCTET_RE":"XOCTET_RE":"XOCTET_RE":"\ - XOCTET_RE":"XOCTET_RE":"XOCTET_RE -#define NUM100_TO_99999_RE \ - "([1-9][0-9][0-9]|" \ - "[1-9][0-9][0-9][0-9]|" \ - "[1-9][0-9][0-9][0-9][0-9])" -#define NUM5_TO_99999_RE \ - "([5-9]|" \ - "[1-9][0-9]|" \ - "[1-9][0-9][0-9]|" \ - "[1-9][0-9][0-9][0-9]|" \ - "[1-9][0-9][0-9][0-9][0-9])" -#define NUM1_TO_99999_RE \ - "([1-9]|" \ - "[1-9][0-9]|" \ - "[1-9][0-9][0-9]|" \ - "[1-9][0-9][0-9][0-9]|" \ - "[1-9][0-9][0-9][0-9][0-9])" - -static char * -prompt(const char *prompt, const char *initial, const char *pattern) -{ - struct ds ds; - int pos, chidx; - struct ds choices; - const char *error; - int erroffset; - pcre *re; - int retval; - int okpartial; - char *p; - - set_icon(0, - e____X, - e____X, - e__X_X, - e_X__X, - eXXXXX, - e_X___, - e__X__, - e_____); - - re = pcre_compile(pattern, PCRE_ANCHORED, &error, &erroffset, NULL); - if (!re) { - VLOG_ERR("PCRE error for pattern \"%s\" at offset %d: %s", - pattern, erroffset, error); - return xstrdup(initial); - } - - retval = pcre_fullinfo(re, NULL, PCRE_INFO_OKPARTIAL, &okpartial); - assert(!retval); - assert(okpartial); - - pos = 0; - ds_init(&ds); - ds_put_cstr(&ds, initial); - ds_init(&choices); - figure_choices(re, &ds, pos, &choices); - p = memchr(choices.string, initial[0], choices.length); - chidx = p ? p - choices.string : 0; - for (;;) { - int c, key; - - while ((key = getch()) != ERR) { - switch (key) { - case KEY_UP: - if (choices.length > 1) { - if (++chidx >= choices.length) { - chidx = 0; - } - ds.string[pos] = choices.string[chidx]; - ds_truncate(&ds, pos + 1); - figure_completion(re, &ds); - } - break; - - case KEY_DOWN: - if (choices.length > 1) { - if (--chidx < 0) { - chidx = choices.length - 1; - } - ds.string[pos] = choices.string[chidx]; - ds_truncate(&ds, pos + 1); - figure_completion(re, &ds); - } - break; - - case '\r': case '\n': - if (choices.string[chidx] == '\n') { - ds_truncate(&ds, pos); - return ds_cstr(&ds); - } else { - if (pos >= ds.length) { - pos++; - ds_put_char(&ds, choices.string[chidx]); - figure_choices(re, &ds, pos, &choices); - chidx = 0; - figure_completion(re, &ds); - } else { - pos = ds.length; - figure_choices(re, &ds, pos, &choices); - chidx = 0; - figure_completion(re, &ds); - } - } - break; - - case '\f': - ds_truncate(&ds, pos + 1); - figure_choices(re, &ds, pos, &choices); - chidx = 0; - break; - - case '\b': case '\x7f': case '\x1b': - case KEY_BACKSPACE: case KEY_DC: - if (pos) { - pos--; - } else { - return xstrdup(initial); - } - figure_choices(re, &ds, pos, &choices); - chidx = 0; - if (pos < ds.length) { - p = memchr(choices.string, ds.string[pos], - choices.length); - if (p) { - chidx = p - choices.string; - } - } - break; - - default: - if (key >= 0x20 && key < 0x7f) { - /* Check whether 'key' is valid and toggle case if - * necessary. */ - if (!memchr(choices.string, key, choices.length)) { - if (memchr(choices.string, toupper(key), - choices.length)) { - key = toupper(key); - } else if (memchr(choices.string, tolower(key), - choices.length)) { - key = tolower(key); - } else { - break; - } - } - - /* Insert 'key' and advance the position. */ - if (pos >= ds.length) { - ds_put_char(&ds, key); - } else { - ds.string[pos] = key; - } - pos++; - - if (choices.string[chidx] != key) { - ds_truncate(&ds, pos); - } - figure_choices(re, &ds, pos, &choices); - chidx = 0; - if (pos < ds.length) { - p = memchr(choices.string, ds.string[pos], - choices.length); - if (p) { - chidx = p - choices.string; - } - } - figure_completion(re, &ds); - } - } - } - - erase(); - curs_set(1); - move(0, 0); - addnstr(prompt, MIN(40, strlen(prompt))); - - c = choices.string[chidx]; - move(1, 0); - addstr(ds_cstr(&ds)); - move(1, pos); - if (c == '\n') { - put_icon(0, '$'); - } else { - addch(c); - } - move(1, pos); - refresh(); - - poll_fd_wait(STDIN_FILENO, POLLIN); - poll_block(); - } -} - -static void -prompt_ip(const char *title, uint32_t *ip) -{ - char *in = xasprintf(IP_FMT, IP_ARGS(ip)); - char *out = prompt(title, in, "^"IP_RE"$"); - *ip = inet_addr(out); - free(in); - free(out); -} - -static void -abbreviate_netdevs(const struct svec *netdevs, struct ds *abbrev) -{ - size_t i; - - ds_init(abbrev); - for (i = 0; i < netdevs->n; ) { - size_t i_len = strlen(netdevs->names[i]); - size_t j; - - for (j = i + 1; j < netdevs->n; j++) { - size_t j_len = strlen(netdevs->names[j]); - if (!i_len || !j_len || i_len != j_len - || memcmp(netdevs->names[i], netdevs->names[j], i_len - 1)) { - break; - } - } - - if (abbrev->length) { - ds_put_char(abbrev, ' '); - } - if (j - i == 1) { - ds_put_cstr(abbrev, netdevs->names[i]); - } else { - size_t k; - - ds_put_buffer(abbrev, netdevs->names[i], i_len - 1); - ds_put_char(abbrev, '['); - for (k = i; k < j; k++) { - ds_put_char(abbrev, netdevs->names[k][i_len - 1]); - } - ds_put_char(abbrev, ']'); - } - i = j; - } -} - -static void -choose_netdevs(struct svec *choices) -{ - struct svec netdevs = SVEC_EMPTY_INITIALIZER; - struct menu menu; - size_t i; - - netdev_enumerate(&netdevs); - svec_sort(&netdevs); - - menu_init(&menu); - menu_add_item(&menu, "Exit"); - for (i = 0; i < netdevs.n; i++) { - const char *name = netdevs.names[i]; - struct menu_item *item; - struct netdev *netdev; - int retval; - - if (!strncmp(name, "wmaster", strlen("wmaster")) - || !strncmp(name, "of", strlen("of")) - || !strcmp(name, "lo")) { - continue; - } - - retval = netdev_open_default(name, &netdev); - if (!retval) { - bool exclude = netdev_get_in4(netdev, NULL, NULL) == 0; - netdev_close(netdev); - if (exclude) { - continue; - } - } - - item = menu_add_item(&menu, "%s", name); - item->toggle = svec_contains(choices, name); - } - if (menu.n_items > 1) { - menu_show(&menu, 0, true); - } else { - show_string("No available\nbridge ports"); - } - - svec_clear(choices); - for (i = 0; i < menu.n_items; i++) { - struct menu_item *item = menu.items[i]; - if (item->toggle > 0) { - svec_add(choices, item->text); - } - } - - menu_free(&menu); -} - -static bool -is_datapath_id_in_dmi(void) -{ - FILE *dmidecode; - char line[256]; - bool is_in_dmi; - - dmidecode = popen("dmidecode -s system-uuid", "r"); - if (!dmidecode) { - return false; - } - is_in_dmi = fgets(line, sizeof line, dmidecode) && strstr(line, "-002320"); - fclose(dmidecode); - return is_in_dmi; -} - -struct switch_config { - struct svec netdevs; - enum { DISCOVERY, IN_BAND } mode; - uint32_t switch_ip; - uint32_t switch_mask; - uint32_t switch_gw; - enum { FAIL_DROP, FAIL_SWITCH } disconnected; - int rate_limit; - int inactivity_probe; - int max_backoff; - char *controller_vconn; - char *datapath_id; -}; - -static const char * -disconnected_string(int value) -{ -#define FAIL_SWITCH_STRING "Switch packets" -#define FAIL_DROP_STRING "Drop packets" - return value == FAIL_SWITCH ? FAIL_SWITCH_STRING : FAIL_DROP_STRING; -} - -static void -cmd_configure(const struct dict *dict OVS_UNUSED) -{ - bool debug_mode = dict_get_bool(dict, "debug", false); - struct dict config_dict; - struct switch_config config; - int start; - - if (!load_config(&config_dict)) { - return; - } - svec_init(&config.netdevs); - svec_parse_words(&config.netdevs, - dict_get_string(&config_dict, "NETDEVS", "")); - config.mode = (!strcmp(dict_get_string(&config_dict, "MODE", "discovery"), - "in-band") ? IN_BAND : DISCOVERY); - config.switch_ip = dict_get_ip(&config_dict, "SWITCH_IP"); - config.switch_mask = dict_get_ip(&config_dict, "SWITCH_NETMASK"); - config.switch_gw = dict_get_ip(&config_dict, "SWITCH_GATEWAY"); - config.controller_vconn = xstrdup(dict_get_string(&config_dict, - "CONTROLLER", "")); - config.disconnected = (!strcmp(dict_get_string(&config_dict, - "DISCONNECTED_MODE", ""), - "switch") - ? FAIL_SWITCH : FAIL_DROP); - config.rate_limit = dict_get_int(&config_dict, "RATE_LIMIT", -1); - config.inactivity_probe = dict_get_int(&config_dict, "INACTIVITY_PROBE", - -1); - config.max_backoff = dict_get_int(&config_dict, "MAX_BACKOFF", -1); - if (is_datapath_id_in_dmi()) { - config.datapath_id = xstrdup("DMI"); - } else { - const char *dpid = dict_get(&config_dict, "DATAPATH_ID"); - if (dpid) { - struct ds ds = DS_EMPTY_INITIALIZER; - const char *cp; - for (cp = dpid; *cp != '\0'; cp++) { - if (*cp != ':') { - ds_put_char(&ds, toupper((unsigned char) *cp)); - } - } - config.datapath_id = ds_cstr(&ds); - } else { - config.datapath_id = xstrdup("Random"); - } - } - dict_free(&config_dict); - - start = 0; - while (start != -1) { - enum { - MENU_EXIT, - MENU_NETDEVS, - MENU_MODE, - MENU_IP, - MENU_NETMASK, - MENU_GATEWAY, - MENU_CONTROLLER, - MENU_DISCONNECTED_MODE, - MENU_DATAPATH_ID, - MENU_RATE_LIMIT, - MENU_INACTIVITY_PROBE, - MENU_MAX_BACKOFF, - }; - - struct ds ports; - struct menu_item *item; - struct menu menu; - char *in, *out; - uint32_t ip; - - menu_init(&menu); - - /* Exit. */ - item = menu_add_item(&menu, "Exit"); - item->id = MENU_EXIT; - - /* Bridge Ports. */ - abbreviate_netdevs(&config.netdevs, &ports); - item = menu_add_item(&menu, "Bridge Ports:\n%s", ds_cstr(&ports)); - item->id = MENU_NETDEVS; - ds_destroy(&ports); - - /* Mode. */ - item = menu_add_item(&menu, "Mode:\n%s", - (config.mode == DISCOVERY - ? "Discovery" : "In-Band")); - item->id = MENU_MODE; - - /* IP address. */ - if (config.switch_ip == htonl(0)) { - item = menu_add_item(&menu, "Switch IP Addr:\nDHCP"); - } else { - item = menu_add_item(&menu, "Switch IP Addr:\n"IP_FMT, - IP_ARGS(&config.switch_ip)); - } - item->id = MENU_IP; - item->enabled = config.mode == IN_BAND; - - /* Netmask. */ - item = menu_add_item(&menu, "Switch Netmask:\n"IP_FMT, - IP_ARGS(&config.switch_mask)); - item->id = MENU_NETMASK; - item->enabled = config.mode == IN_BAND && config.switch_ip != htonl(0); - - /* Gateway. */ - item = menu_add_item(&menu, "Switch Gateway:\n"IP_FMT, - IP_ARGS(&config.switch_gw)); - item->id = MENU_GATEWAY; - item->enabled = config.mode == IN_BAND && config.switch_ip != htonl(0); - - /* Controller. */ - item = menu_add_item(&menu, "Controller:\n%s", - config.controller_vconn); - item->id = MENU_CONTROLLER; - item->enabled = config.mode == IN_BAND; - - /* Disconnected mode. */ - item = menu_add_item(&menu, "If disconnected:\n%s\n", - disconnected_string(config.disconnected)); - item->id = MENU_DISCONNECTED_MODE; - - /* Datapath ID. */ - item = menu_add_item(&menu, "Datapath ID:\n%s", config.datapath_id); - item->id = MENU_DATAPATH_ID; - item->enabled = strcmp(config.datapath_id, "DMI"); - - /* Rate-limiting. */ - if (debug_mode) { - if (config.rate_limit < 0) { - item = menu_add_item(&menu, "Ctlr rate limit:\nDisabled"); - } else { - item = menu_add_item(&menu, "Ctlr rate limit:\n%d/s", - config.rate_limit); - } - item->id = MENU_RATE_LIMIT; - } - - /* Inactivity probe. */ - if (debug_mode) { - if (config.inactivity_probe < 0) { - item = menu_add_item(&menu, "Activity probe:\nDefault"); - } else { - item = menu_add_item(&menu, "Activity probe:\n%d s", - config.inactivity_probe); - } - item->id = MENU_INACTIVITY_PROBE; - } - - /* Max backoff. */ - if (debug_mode) { - if (config.max_backoff < 0) { - item = menu_add_item(&menu, "Max backoff:\nDefault"); - } else { - item = menu_add_item(&menu, "Max backoff:\n%d s", - config.max_backoff); - } - item->id = MENU_MAX_BACKOFF; - } - - start = menu_show2(&menu, start, true); - menu_free(&menu); - - in = out = NULL; - switch (start) { - case MENU_EXIT: - start = -1; - break; - - case MENU_NETDEVS: - choose_netdevs(&config.netdevs); - break; - - case MENU_MODE: - out = prompt("Mode:", - config.mode == DISCOVERY ? "Discovery" : "In-Band", - "^(Discovery|In-Band)$"); - config.mode = !strcmp(out, "Discovery") ? DISCOVERY : IN_BAND; - free(out); - break; - - case MENU_IP: - in = (config.switch_ip == htonl(0) ? xstrdup("DHCP") - : xasprintf(IP_FMT, IP_ARGS(&config.switch_ip))); - out = prompt("Switch IP:", in, "^(DHCP|"IP_RE")$"); - ip = strcmp(out, "DHCP") ? inet_addr(out) : htonl(0); - free(in); - free(out); - if (ip != config.switch_ip) { - config.switch_ip = ip; - if (ip != htonl(0)) { - uint32_t mask = guess_netmask(ip); - if (mask) { - config.switch_mask = mask; - config.switch_gw = (ip & mask) | htonl(1); - } - } - } - break; - - case MENU_NETMASK: - prompt_ip("Switch Netmask:", &config.switch_mask); - break; - - case MENU_GATEWAY: - prompt_ip("Switch Gateway:", &config.switch_gw); - break; - - case MENU_CONTROLLER: - out = prompt("Controller:", config.controller_vconn, - "^(tcp|ssl):"IP_RE"(:"PORT_RE")?$"); - free(config.controller_vconn); - config.controller_vconn = out; - break; - - case MENU_DISCONNECTED_MODE: - out = prompt("If disconnected", - disconnected_string(config.disconnected), - "^("FAIL_DROP_STRING"|"FAIL_SWITCH_STRING")$"); - config.disconnected = (!strcmp(out, FAIL_DROP_STRING) - ? FAIL_DROP : FAIL_SWITCH); - free(out); - break; - - case MENU_DATAPATH_ID: - out = prompt("Datapath ID:", config.datapath_id, - "^Random|"MAC_RE"$"); - free(config.datapath_id); - config.datapath_id = out; - break; - - case MENU_RATE_LIMIT: - in = (config.rate_limit < 0 - ? xstrdup("Disabled") - : xasprintf("%d/s", config.rate_limit)); - out = prompt("Ctlr rate limit:", in, - "^(Disabled|("NUM100_TO_99999_RE")/s)$"); - free(in); - config.rate_limit - = isdigit((unsigned char)out[0]) ? atoi(out) : -1; - free(out); - break; - - case MENU_INACTIVITY_PROBE: - in = (config.inactivity_probe < 0 - ? xstrdup("Default") - : xasprintf("%d s", config.inactivity_probe)); - out = prompt("Activity probe:", in, - "^(Default|("NUM5_TO_99999_RE") s)$"); - free(in); - config.inactivity_probe - = isdigit((unsigned char)out[0]) ? atoi(out) : -1; - free(out); - break; - - case MENU_MAX_BACKOFF: - in = (config.max_backoff < 0 - ? xstrdup("Default") - : xasprintf("%d s", config.max_backoff)); - out = prompt("Max backoff:", in, - "^(Default|("NUM1_TO_99999_RE") s)$"); - free(in); - config.max_backoff - = isdigit((unsigned char)out[0]) ? atoi(out) : -1; - free(out); - break; - } - } - - if (yesno("Save\nChanges?", false)) { - struct svec set; - char *netdevs; - - svec_init(&set); - netdevs = svec_join(&config.netdevs, " ", ""); - svec_add_nocopy(&set, xasprintf("NETDEVS=%s", netdevs)); - free(netdevs); - svec_add(&set, - config.mode == IN_BAND ? "MODE=in-band" : "MODE=discovery"); - if (config.mode == IN_BAND) { - if (config.switch_ip == htonl(0)) { - svec_add(&set, "SWITCH_IP=dhcp"); - } else { - svec_add_nocopy(&set, xasprintf("SWITCH_IP="IP_FMT, - IP_ARGS(&config.switch_ip))); - svec_add_nocopy(&set, - xasprintf("SWITCH_NETMASK="IP_FMT, - IP_ARGS(&config.switch_mask))); - svec_add_nocopy(&set, xasprintf("SWITCH_GATEWAY="IP_FMT, - IP_ARGS(&config.switch_gw))); - svec_add_nocopy(&set, xasprintf("CONTROLLER=%s", - config.controller_vconn)); - } - } - svec_add(&set, (config.disconnected == FAIL_DROP - ? "DISCONNECTED_MODE=drop" - : "DISCONNECTED_MODE=switch")); - if (config.rate_limit < 0) { - svec_add(&set, "RATE_LIMIT="); - } else { - svec_add_nocopy(&set, - xasprintf("RATE_LIMIT=%d", config.rate_limit)); - } - if (config.inactivity_probe < 0) { - svec_add(&set, "INACTIVITY_PROBE="); - } else { - svec_add_nocopy(&set, xasprintf("INACTIVITY_PROBE=%d", - config.inactivity_probe)); - } - if (config.max_backoff < 0) { - svec_add(&set, "MAX_BACKOFF="); - } else { - svec_add_nocopy(&set, xasprintf("MAX_BACKOFF=%d", - config.max_backoff)); - } - save_config(&set); - svec_destroy(&set); - } - - svec_destroy(&config.netdevs); - free(config.controller_vconn); - free(config.datapath_id); -} - -static void -cmd_set_up_pki(const struct dict *dict OVS_UNUSED) -{ - static const char def_privkey_file[] - = "/etc/openflow-switch/of0-privkey.pem"; - static const char def_cert_file[] = "/etc/openflow-switch/of0-cert.pem"; - static const char def_cacert_file[] = "/etc/openflow-switch/cacert.pem"; - struct dict config_dict; - const char *privkey_file, *cert_file, *cacert_file; - bool bootstrap; - struct stat s; - struct svec set; - bool has_keys; - - if (!load_config(&config_dict)) { - return; - } - privkey_file = dict_get_string(&config_dict, "PRIVKEY", def_privkey_file); - cert_file = dict_get_string(&config_dict, "CERT", def_cert_file); - cacert_file = dict_get_string(&config_dict, "CACERT", def_cacert_file); - bootstrap = !strcmp(dict_get_string(&config_dict, "CACERT_MODE", "secure"), - "bootstrap"); - - has_keys = !stat(privkey_file, &s) && !stat(cert_file, &s); - if (!has_keys - ? yesno("Generate\nkeys?", true) - : yesno("Generate\nnew keys?", false)) { - struct svec argv; - bool ok; - - privkey_file = def_privkey_file; - cert_file = def_cert_file; - - svec_init(&argv); - svec_parse_words(&argv, "sh -c 'cd /etc/openflow-switch " - "&& ovs-pki --force req of0" - "&& ovs-pki --force self-sign of0'"); - svec_terminate(&argv); - ok = run_and_report_failure(argv.names, "Key gen failed"); - svec_destroy(&argv); - if (!ok) { - return; - } - has_keys = true; - } - if (!has_keys) { - return; - } - - if (stat(cacert_file, &s) && errno == ENOENT) { - bootstrap = yesno("Bootstrap\nCA cert?", bootstrap); - } else if (yesno("Replace\nCA cert?", false)) { - unlink(cacert_file); - bootstrap = true; - } - - svec_init(&set); - svec_add_nocopy(&set, xasprintf("PRIVKEY=%s", privkey_file)); - svec_add_nocopy(&set, xasprintf("CERT=%s", cert_file)); - svec_add_nocopy(&set, xasprintf("CACERT=%s", cacert_file)); - svec_add_nocopy(&set, xasprintf("CACERT_MODE=%s", - bootstrap ? "bootstrap" : "secure")); - save_config(&set); - svec_destroy(&set); -} - -static void -parse_options(int argc, char *argv[]) -{ - enum { - OPT_DUMMY = UCHAR_MAX + 1, - VLOG_OPTION_ENUMS - }; - static struct option long_options[] = { - {"verbose", optional_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - DAEMON_LONG_OPTIONS, - VLOG_LONG_OPTIONS, - {0, 0, 0, 0}, - }; - char *short_options = long_options_to_short_options(long_options); - - for (;;) { - int c; - - c = getopt_long(argc, argv, short_options, long_options, NULL); - if (c == -1) { - break; - } - - switch (c) { - case 'h': - usage(); - - case 'V': - OVS_PRINT_VERSION(OFP_VERSION, OFP_VERSION); - exit(EXIT_SUCCESS); - - VLOG_OPTION_HANDLERS - DAEMON_OPTION_HANDLERS - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - } - } - free(short_options); -} - -static void -usage(void) -{ - printf("%s: OpenFlow switch monitoring user interface\n" - "usage: %s [OPTIONS] SWITCH\n" - "where SWITCH is an active OpenFlow connection method.\n", - program_name, program_name); - vconn_usage(true, false, false); - printf("\nOptions:\n" - " -v, --verbose=MODULE:FACILITY:LEVEL configure logging levels\n" - " -v, --verbose set maximum verbosity level\n" - " -h, --help display this help message\n" - " -V, --version display version information\n"); - exit(EXIT_SUCCESS); -} diff --git a/extras/ezio/terminal.c b/extras/ezio/terminal.c deleted file mode 100644 index 3e499ab0..00000000 --- a/extras/ezio/terminal.c +++ /dev/null @@ -1,821 +0,0 @@ -/* Copyright (c) 2008, 2009, 2010 Nicira Networks, Inc. - * - * 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. - */ - -#include -#include "terminal.h" -#include -#include -#include -#include -#include -#include -#include -#include "dynamic-string.h" -#include "ezio.h" -#include "poll-loop.h" -#include "util.h" -#include "vlog.h" - -VLOG_DEFINE_THIS_MODULE(terminal) - -/* UTF-8 decoding. */ -static struct utf8_reader *utf8_reader_create(void); -static void utf8_reader_destroy(struct utf8_reader *); -static int utf8_reader_read(struct utf8_reader *, uint8_t c); - -/* ANSI escape sequence decoding. */ -struct ansi_sequence { - int n_args; -#define ANSI_MAX_ARGS 16 - int args[ANSI_MAX_ARGS]; - int function; -}; - -static struct ansi_decoder *ansi_decoder_create(void); -static void ansi_decoder_destroy(struct ansi_decoder *); -static int ansi_decoder_put(struct ansi_decoder *, uint8_t c); -static const struct ansi_sequence *ansi_decoder_get(struct ansi_decoder *); - -/* Terminal emulation. */ -struct terminal { - struct ansi_decoder *ansi; - struct utf8_reader *utf8; - enum { EZIO, UTF8 } encoding; -}; - -static void recv_byte(struct terminal *term, struct ezio *ezio, uint8_t c); - -struct terminal * -terminal_create(void) -{ - struct terminal *term = xmalloc(sizeof *term); - term->ansi = ansi_decoder_create(); - term->utf8 = utf8_reader_create(); - term->encoding = UTF8; - return term; -} - -void -terminal_destroy(struct terminal *term) -{ - if (term) { - utf8_reader_destroy(term->utf8); - ansi_decoder_destroy(term->ansi); - free(term); - } -} - -int -terminal_run(struct terminal *term, struct ezio *ezio, int input_fd) -{ - char input[512]; - int n; - - n = read(input_fd, input, sizeof input); - if (n > 0) { - int i; - - for (i = 0; i < n; i++) { - recv_byte(term, ezio, input[i]); - } - return 0; - } else { - return !n ? EOF : errno == EAGAIN ? 0 : errno; - } -} - -void -terminal_wait(struct terminal *term OVS_UNUSED, int input_fd) -{ - poll_fd_wait(input_fd, POLLIN); -} - -static void recv_ansi_sequence(const struct ansi_sequence *, struct ezio *); -static void recv_control(uint8_t c, struct ezio *); -static void recv_character(uint8_t byte, struct ezio *); -static int unicode_to_ezio(uint16_t unicode); -static int default_arg(int value, int default_value); -static int range(int value, int min, int max); -static void clear_elements(uint8_t *p, size_t size, int pos, int clear_type); -static void define_icon(struct ezio *e, const int *args); -static void clear_icon(struct ezio *e, int icon_nr); -static void set_cursor(struct ezio *e, int visibility); - -static void -recv_byte(struct terminal *term, struct ezio *ezio, uint8_t c) -{ - int retval; - - /* Decode and interpret ANSI escape sequences. */ - retval = ansi_decoder_put(term->ansi, c); - if (retval <= 0) { - if (retval < 0) { - recv_ansi_sequence(ansi_decoder_get(term->ansi), ezio); - return; - } - return; - } - - /* Encoding selection. */ - if (c == 0x0e) { - /* Shift Out. */ - term->encoding = EZIO; - return; - } else if (c == 0x0f) { - /* Shift In. */ - term->encoding = UTF8; - return; - } - - if (term->encoding == UTF8) { - int unicode, ezchar; - - /* Convert UTF-8 input to Unicode code point. */ - unicode = utf8_reader_read(term->utf8, c); - if (unicode < 0) { - return; - } - - /* Convert Unicode code point to EZIO encoding. */ - ezchar = unicode_to_ezio(unicode); - if (ezchar >= 0) { - if (ezchar & 0xff00) { - recv_character(ezchar >> 8, ezio); - } - recv_character(ezchar, ezio); - } else if (unicode < 0x100) { - recv_control(unicode, ezio); - } else { - /* Unsupported Unicode code point. */ - return; - } - } else { - if (c >= 0x80 && c < 0x87) { - c &= 0x07; - } - if (c != 0xfe) { - recv_character(c, ezio); - } - } -} - -static void -log_ansi_sequence(const struct ansi_sequence *seq, struct ezio *e) -{ - struct sequence { - int function; - const char *name; - }; - static const struct sequence sequences[] = { - {0x5a, "CBT: Cursor Backward Tabulation"}, - {0x47, "CHA: Cursor Character Absolute"}, - {0x49, "CHT: Cursor Forward Tabulation"}, - {0x45, "CNL: Cursor Next Line"}, - {0x46, "CPL: Cursor Preceding Line"}, - {0x44, "CUB: Cursor Left"}, - {0x42, "CUD: Cursor Down"}, - {0x43, "CUF: Cursor Right"}, - {0x48, "CUP: Cursor Position"}, - {0x41, "CUU: Cursor Up"}, - {0x50, "DCH: Delete Character"}, - {0x4d, "DL: Delete Line"}, - {0x58, "ECH: Erase Character"}, - {0x4a, "ED: Erase in Page"}, - {0x4b, "EL: Erase in Line"}, - {0x40, "ICH: Insert Character"}, - {0x4c, "IL: Insert Line"}, - {0x4500, "NEL: Next Line"}, - {0x4d00, "RI: Reverse Line Feed"}, - {0x6300, "RIS: Reset to Initial State"}, - {0x54, "SD: Scroll Down"}, - {0x240, "SL: Scroll Left"}, - {0x241, "SR: Scroll Right"}, - {0x53, "SU: Scroll Up"}, - {0x70, "DICO: Define Icon"}, - {0x71, "CICO: Clear Icon"}, - {0x72, "Set cursor visibility"}, - }; - const struct sequence *s; - struct ds ds; - int i; - - ds_init(&ds); - for (s = sequences; s < &sequences[ARRAY_SIZE(sequences)]; s++) { - if (s->function == seq->function) { - ds_put_cstr(&ds, s->name); - goto found; - } - } - ds_put_format(&ds, "0x%02x", s->function); - if (s->function < 0x100) { - ds_put_format(&ds, "(%02d/%02d)", s->function / 16, s->function % 16); - } - -found: - for (i = 0; i < seq->n_args; i++) { - ds_put_format(&ds, ", %d", seq->args[i]); - } - VLOG_DBG("%s (cursor:%d,%d)", ds_cstr(&ds), e->x, e->y); - ds_destroy(&ds); -} - -static void -recv_ansi_sequence(const struct ansi_sequence *seq, struct ezio *e) -{ -#define ARG1(DEFAULT) default_arg(seq->args[0], DEFAULT) -#define ARG2(DEFAULT) default_arg(seq->args[1], DEFAULT) - if (VLOG_IS_DBG_ENABLED()) { - log_ansi_sequence(seq, e); - } - switch (seq->function) { - case 0x5a: /* CBT: Cursor Backward Tabulation. */ - e->x = 8 * (e->x / 8 - ARG1(1)); - break; - case 0x47: /* CHA: Cursor Character Absolute. */ - e->x = ARG1(1) - 1; - break; - case 0x49: /* CHT: Cursor Forward Tabulation. */ - e->x = 8 * (e->x / 8 + ARG1(1)); - break; - case 0x45: /* CNL: Cursor Next Line. */ - e->x = 0; - e->y += ARG1(1); - break; - case 0x46: /* CPL: Cursor Preceding Line. */ - e->x = 0; - e->y -= ARG1(1); - break; - case 0x44: /* CUB: Cursor Left. */ - e->x -= ARG1(1); - break; - case 0x42: /* CUD: Cursor Down. */ - e->y += ARG1(1); - break; - case 0x43: /* CUF: Cursor Right. */ - e->x += ARG1(1); - break; - case 0x48: /* CUP: Cursor Position. */ - e->y = ARG1(1) - 1; - e->x = ARG2(1) - 1; - break; - case 0x41: /* CUU: Cursor Up. */ - e->y -= ARG1(1); - break; - case 0x50: /* DCH: Delete Character. */ - ezio_delete_char(e, e->x, e->y, ARG1(1)); - break; - case 0x4d: /* DL: Delete Line. */ - ezio_delete_line(e, e->y, ARG1(1)); - break; - case 0x58: /* ECH: Erase Character. */ - memset(&e->chars[e->y][e->x], ' ', MIN(ARG1(1), 40 - e->x)); - break; - case 0x4a: /* ED: Erase in Page. */ - clear_elements(&e->chars[0][0], 2 * 40, e->x + 40 * e->y, ARG1(0)); - break; - case 0x4b: /* EL: Erase in Line. */ - clear_elements(&e->chars[e->y][0], 40, e->x, ARG1(0)); - break; - case 0x40: /* ICH: Insert Character. */ - ezio_insert_char(e, e->x, e->y, ARG1(1)); - break; - case 0x4c: /* IL: Insert Line. */ - ezio_insert_line(e, e->y, ARG1(1)); - break; - case 0x4500: /* NEL: Next Line. */ - e->x = 0; - e->y++; - break; - case 0x4d00: /* RI: Reverse Line Feed. */ - e->y--; - break; - case 0x6300: /* RIS: Reset to Initial State. */ - ezio_init(e); - break; - case 0x54: /* SD: Scroll Down. */ - ezio_scroll_down(e, ARG1(1)); - break; - case 0x240: /* SL: Scroll Left. */ - ezio_scroll_left(e, ARG1(1)); - break; - case 0x241: /* SR: Scroll Right. */ - ezio_scroll_right(e, ARG1(1)); - break; - case 0x53: /* SU: Scroll Up. */ - ezio_scroll_up(e, ARG1(1)); - break; - - /* Private sequences. */ - case 0x70: /* DICO: Define Icon. */ - define_icon(e, seq->args); - break; - case 0x71: /* CICO: Clear Icon. */ - clear_icon(e, ARG1(0)); - break; - case 0x72: /* Set cursor visibility. */ - set_cursor(e, ARG1(1)); - break; - } - e->x = range(e->x, 0, 40); - e->y = range(e->y, 0, 1); - VLOG_DBG("cursor:%d,%d", e->x, e->y); -} - -static void -recv_control(uint8_t c, struct ezio *e) -{ - switch (c) { - case '\b': - if (e->x > 0) { - --e->x; - } - break; - - case '\t': - e->x = ROUND_UP(e->x + 1, 8); - if (e->x > 40) { - ezio_newline(e); - } - break; - - case '\n': - ezio_line_feed(e); - break; - - case '\f': - ezio_clear(e); - break; - - case '\r': - e->x = 0; - break; - - default: - VLOG_DBG("Unhandled control character 0x%02"PRIx8, c); - } -} - -static void -recv_character(uint8_t byte, struct ezio *e) -{ - if (e->x >= 40) { - ezio_newline(e); - } - ezio_put_char(e, e->x++, e->y, byte); -} - -static int -default_arg(int value, int default_value) -{ - return value >= 0 ? value : default_value; -} - -static int -range(int value, int min, int max) -{ - return value < min ? min : value > max ? max : value; -} - -static void -clear_elements(uint8_t *p, size_t size, int pos, int clear_type) -{ - switch (clear_type) { - case 0: - /* Clear from 'pos' to end. */ - memset(p + pos, ' ', size - pos); - break; - case 1: - /* Clear from beginning to 'pos'. */ - memset(p, ' ', pos + 1); - break; - case 2: - /* Clear all. */ - memset(p, ' ', size); - break; - } -} - -static void -define_icon(struct ezio *e, const int *args) -{ - int icon_nr; - int row; - - icon_nr = args[0]; - if (icon_nr < 0 || icon_nr > 7) { - return; - } - - for (row = 0; row < 8; row++) { - e->icons[icon_nr][row] = default_arg(args[row + 1], 0) & 0x1f; - } -} - -static void -clear_icon(struct ezio *e, int icon_nr) -{ - if (icon_nr >= 0 && icon_nr <= 7) { - ezio_set_default_icon(e, icon_nr); - } -} - -static void -set_cursor(struct ezio *e, int visibility) -{ - switch (visibility) { - case 1: - e->show_cursor = e->blink_cursor = false; - break; - case 2: - e->show_cursor = true; - e->blink_cursor = false; - break; - case 3: - e->show_cursor = e->blink_cursor = true; - break; - } -} - -static int -unicode_to_ezio(uint16_t unicode) -{ - switch (unicode) { - /* Most ASCII characters map one-to-one. */ - case 0x0020 ... 0x005b: - case 0x005d ... 0x007d: - return unicode; - - /* A few ASCII characters have to be simulated with icons. */ - case 0x005c: return 0x06; /* BACKSLASH */ - case 0x007e: return 0x07; /* TILDE */ - - /* EZIO extended characters equivalents in Unicode - Japanese. */ - case 0x00a5: return '\\'; /* YEN SIGN */ - case 0x3002: return 0xa1; /* IDEOGRAPHIC FULL STOP */ - case 0x300c: return 0xa2; /* LEFT CORNER BRACKET */ - case 0x300d: return 0xa3; /* RIGHT CORNER BRACKET */ - case 0x3001: return 0xa4; /* IDEOGRAPHIC COMMA */ - case 0x30fb: return 0xa5; /* KATAKANA MIDDLE DOT */ - case 0x30f2: return 0xa6; /* KATAKANA LETTER WO */ - case 0x30a1: return 0xa7; /* KATAKANA LETTER SMALL A */ - case 0x30a3: return 0xa8; /* KATAKANA LETTER SMALL I */ - case 0x30a5: return 0xa9; /* KATAKANA LETTER SMALL U */ - case 0x30a7: return 0xaa; /* KATAKANA LETTER SMALL E */ - case 0x30a9: return 0xab; /* KATAKANA LETTER SMALL O */ - case 0x30e3: return 0xac; /* KATAKANA LETTER SMALL YA */ - case 0x30e5: return 0xad; /* KATAKANA LETTER SMALL YU */ - case 0x30e7: return 0xae; /* KATAKANA LETTER SMALL YO */ - case 0x30c3: return 0xaf; /* KATAKANA LETTER SMALL TU = SMALL TSU */ - case 0x30fc: return 0xb0; /* KATAKANA-HIRAGANA PROLONGED SOUND MARK */ - case 0x30a2: return 0xb1; /* KATAKANA LETTER A */ - case 0x30a4: return 0xb2; /* KATAKANA LETTER I */ - case 0x30a6: return 0xb3; /* KATAKANA LETTER U */ - case 0x30a8: return 0xb4; /* KATAKANA LETTER E */ - case 0x30aa: return 0xb5; /* KATAKANA LETTER O */ - case 0x30ab: return 0xb6; /* KATAKANA LETTER KA */ - case 0x30ac: return 0xb6de; /* KATAKANA LETTER GA */ - case 0x30ad: return 0xb7; /* KATAKANA LETTER KI */ - case 0x30ae: return 0xb7de; /* KATAKANA LETTER GI */ - case 0x30af: return 0xb8; /* KATAKANA LETTER KU */ - case 0x30b0: return 0xb8de; /* KATAKANA LETTER GU */ - case 0x30b1: return 0xb9; /* KATAKANA LETTER KE */ - case 0x30b2: return 0xb9de; /* KATAKANA LETTER GE */ - case 0x30b3: return 0xba; /* KATAKANA LETTER KO */ - case 0x30b4: return 0xbade; /* KATAKANA LETTER GO */ - case 0x30b5: return 0xbb; /* KATAKANA LETTER SA */ - case 0x30b6: return 0xbbde; /* KATAKANA LETTER ZA */ - case 0x30b7: return 0xbc; /* KATAKANA LETTER SI = SHI */ - case 0x30b8: return 0xbcde; /* KATAKANA LETTER ZI = JI */ - case 0x30b9: return 0xbd; /* KATAKANA LETTER SU */ - case 0x30ba: return 0xbdde; /* KATAKANA LETTER ZU */ - case 0x30bb: return 0xbe; /* KATAKANA LETTER SE */ - case 0x30bc: return 0xbede; /* KATAKANA LETTER ZE */ - case 0x30bd: return 0xbf; /* KATAKANA LETTER SO */ - case 0x30be: return 0xbfde; /* KATAKANA LETTER ZO */ - case 0x30bf: return 0xc0; /* KATAKANA LETTER TA */ - case 0x30c0: return 0xc0de; /* KATAKANA LETTER DA */ - case 0x30c1: return 0xc1; /* KATAKANA LETTER TI = CHI */ - case 0x30c2: return 0xc1de; /* KATAKANA LETTER DI = JI */ - case 0x30c4: return 0xc2; /* KATAKANA LETTER TU = TSU */ - case 0x30c5: return 0xc2de; /* KATAKANA LETTER DU = ZU */ - case 0x30c6: return 0xc3; /* KATAKANA LETTER TE */ - case 0x30c7: return 0xc3de; /* KATAKANA LETTER DE */ - case 0x30c8: return 0xc4; /* KATAKANA LETTER TO */ - case 0x30c9: return 0xc4de; /* KATAKANA LETTER DO */ - case 0x30ca: return 0xc5; /* KATAKANA LETTER NA */ - case 0x30cb: return 0xc6; /* KATAKANA LETTER NI */ - case 0x30cc: return 0xc7; /* KATAKANA LETTER NU */ - case 0x30cd: return 0xc8; /* KATAKANA LETTER NE */ - case 0x30ce: return 0xc9; /* KATAKANA LETTER NO */ - case 0x30cf: return 0xca; /* KATAKANA LETTER HA */ - case 0x30d0: return 0xcade; /* KATAKANA LETTER BA */ - case 0x30d1: return 0xcadf; /* KATAKANA LETTER PA */ - case 0x30d2: return 0xcb; /* KATAKANA LETTER HI */ - case 0x30d3: return 0xcbde; /* KATAKANA LETTER BI */ - case 0x30d4: return 0xcbdf; /* KATAKANA LETTER PI */ - case 0x30d5: return 0xcc; /* KATAKANA LETTER HU = FU */ - case 0x30d6: return 0xccde; /* KATAKANA LETTER BU */ - case 0x30d7: return 0xccdf; /* KATAKANA LETTER PU */ - case 0x30d8: return 0xcd; /* KATAKANA LETTER HE */ - case 0x30d9: return 0xcdde; /* KATAKANA LETTER BE */ - case 0x30da: return 0xcddf; /* KATAKANA LETTER PE */ - case 0x30db: return 0xce; /* KATAKANA LETTER HO */ - case 0x30dc: return 0xcede; /* KATAKANA LETTER BO */ - case 0x30dd: return 0xcedf; /* KATAKANA LETTER PO */ - case 0x30de: return 0xcf; /* KATAKANA LETTER MA */ - case 0x30df: return 0xd0; /* KATAKANA LETTER MI */ - case 0x30e0: return 0xd1; /* KATAKANA LETTER MU */ - case 0x30e1: return 0xd2; /* KATAKANA LETTER ME */ - case 0x30e2: return 0xd3; /* KATAKANA LETTER MO */ - case 0x30e4: return 0xd4; /* KATAKANA LETTER YA */ - case 0x30e6: return 0xd5; /* KATAKANA LETTER YU */ - case 0x30e8: return 0xd6; /* KATAKANA LETTER YO */ - case 0x30e9: return 0xd7; /* KATAKANA LETTER RA */ - case 0x30ea: return 0xd8; /* KATAKANA LETTER RI */ - case 0x30eb: return 0xd9; /* KATAKANA LETTER RU */ - case 0x30ec: return 0xda; /* KATAKANA LETTER RE */ - case 0x30ed: return 0xdb; /* KATAKANA LETTER RO */ - case 0x30ef: return 0xdc; /* KATAKANA LETTER WA */ - case 0x30f3: return 0xdd; /* KATAKANA LETTER N */ - case 0x30f4: return 0xb3de; /* KATAKANA LETTER VU */ - case 0x30f7: return 0xdcde; /* KATAKANA LETTER VA */ - case 0x3099: return 0xde; /* COMBINING KATAKANA-HIRAGANA VOICED SOUND - * MARK */ - case 0x309a: return 0xdf; /* COMBINING KATAKANA-HIRAGANA SEMI-VOICED - * SOUND MARK */ - case 0x309b: return 0xde; /* KATAKANA-HIRAGANA VOICED SOUND MARK */ - case 0x309c: return 0xdf; /* KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ - - /* EZIO extended characters equivalents in Unicode - other. */ - case 0x2192: return 0x7e; /* RIGHTWARDS ARROW */ - case 0x2190: return 0x7f; /* LEFTWARDS ARROW */ - case 0x03b1: return 0xe0; /* GREEK SMALL LETTER ALPHA */ - case 0x00e4: return 0xe1; /* LATIN SMALL LETTER A WITH DIAERESIS */ - case 0x03b2: return 0xe2; /* GREEK SMALL LETTER BETA */ - case 0x03b5: return 0xe3; /* GREEK SMALL LETTER EPSILON */ - case 0x03bc: return 0xe4; /* GREEK SMALL LETTER MU */ - case 0x03c6: return 0xe5; /* GREEK SMALL LETTER PHI */ - case 0x03c1: return 0xe6; /* GREEK SMALL LETTER RHO */ - /* 0xe7 is 'g'. */ - case 0x221a: return 0xe8; /* SQUARE ROOT = radical sign */ - /* 0xe9 is an unrecognizable symbol. */ - /* 0xea is 'j'. */ - /* 0xeb is an unrecognizable symbol.*/ - case 0x00a2: return 0xec; /* CENT SIGN */ - case 0x00a3: return 0xed; /* POUND SIGN */ - case 0x00f1: return 0xee; /* LATIN SMALL LETTER N WITH TILDE */ - case 0x00f6: return 0xef; /* LATIN SMALL LETTER O WITH DIAERESIS */ - /* 0xf0 is 'p'. */ - /* 0xf1 is 'q'. */ - case 0x03b8: return 0xf2; /* GREEK SMALL LETTER THETA */ - case 0x221e: return 0xf3; /* INFINITY */ - case 0x03a9: return 0xf4; /* GREEK CAPITAL LETTER OMEGA */ - case 0x00fc: return 0xf5; /* LATIN SMALL LETTER U WITH DIAERESIS */ - case 0x03a3: return 0xf6; /* GREEK CAPITAL LETTER SIGMA */ - case 0x03c0: return 0xf7; /* GREEK SMALL LETTER PI */ - /* 0xf8 is x-macron (the sample mean). */ - /* 0xf9 is 'y'. */ - case 0x5343: return 0xfa; /* thousand */ - case 0x4e07: return 0xfb; /* ten thousand */ - case 0x5186: return 0xfc; /* yen */ - case 0x00f7: return 0xfd; /* DIVISION SIGN */ - case 0x2588: return 0xff; /* FULL BLOCK = solid */ - - /* EZIO icons (from the Unicode Private Use corporate subarea). */ - case 0xf8f8: return 0x00; - case 0xf8f9: return 0x01; - case 0xf8fa: return 0x02; - case 0xf8fb: return 0x03; - case 0xf8fc: return 0x04; - case 0xf8fd: return 0x05; - case 0xf8fe: return 0x06; - case 0xf8ff: return 0x07; - - /* No mappings for anything else. */ - default: return -1; - } -} - -/* UTF-8 decoder. */ - -#define UTF_STATES \ - UTF_STATE(UTF8_INIT, 0x00, 0xf4, UTF8_INIT) \ - UTF_STATE(UTF8_3, 0x80, 0xbf, UTF8_2) \ - UTF_STATE(UTF8_2, 0x80, 0xbf, UTF8_1) \ - UTF_STATE(UTF8_1, 0x80, 0xbf, UTF8_INIT) \ - UTF_STATE(UTF8_E0, 0xa0, 0xbf, UTF8_1) \ - UTF_STATE(UTF8_ED, 0x80, 0x9f, UTF8_1) \ - UTF_STATE(UTF8_F0, 0x90, 0xbf, UTF8_INIT) \ - UTF_STATE(UTF8_F4, 0x80, 0x8f, UTF8_INIT) - -enum state { -#define UTF_STATE(NAME, MIN, MAX, NEXT) NAME, - UTF_STATES -#undef UTF_STATE -}; - -struct state_info { - uint8_t min, max; - enum state next; -}; - -static const struct state_info states[] = { -#define UTF_STATE(NAME, MIN, MAX, NEXT) {MIN, MAX, NEXT}, - UTF_STATES -#undef UTF_STATE -}; - -struct utf8_reader { - int cp; - enum state state; -}; - -struct utf8_reader * -utf8_reader_create(void) -{ - struct utf8_reader *r = xmalloc(sizeof *r); - r->state = UTF8_INIT; - return r; -} - -void -utf8_reader_destroy(struct utf8_reader *r) -{ - free(r); -} - -int -utf8_reader_read(struct utf8_reader *r, uint8_t c) -{ - const struct state_info *s = &states[r->state]; - if (c >= s->min && c <= s->max) { - if (r->state == UTF8_INIT) { - if (c < 0x80) { - return c; - } else if (c >= 0xc2 && c <= 0xdf) { - r->cp = c & 0x1f; - r->state = UTF8_1; - return -1; - } else if (c >= 0xe0 && c <= 0xef) { - r->cp = c & 0x0f; - r->state = c == 0xe0 ? UTF8_E0 : c == 0xed ? UTF8_ED : UTF8_2; - return -1; - } else if (c >= 0xf0 && c <= 0xf4) { - r->cp = c & 0x07; - r->state = c == 0xf0 ? UTF8_F0 : c == 0xf4 ? UTF8_F4 : UTF8_3; - return -1; - } - } else { - r->cp = (r->cp << 6) | (c & 0x3f); - r->state = s->next; - return r->state == UTF8_INIT ? r->cp : -1; - } - } - - /* Invalid UTF-8 sequence. Return the Unicode general substitute - * REPLACEMENT CHARACTER. */ - r->state = UTF8_INIT; - return 0xfffd; -} - -/* ANSI control sequence decoder. */ - -/* States are named for what we are looking for in that state. */ -enum ansi_state { - ANSI_ESC, /* Looking for ESC. */ - ANSI_CSI, /* Looking for [ (to complete CSI). */ - ANSI_PARAMETER, /* Looking for parameter. */ - ANSI_INTERMEDIATE, /* Looking for intermediate byte. */ - ANSI_FINAL, /* Looking for final byte. */ - ANSI_COMPLETE /* Got an entire escape sequence. */ -}; - -struct ansi_decoder { - enum ansi_state state; - struct ansi_sequence seq; - int c; -}; - -struct ansi_decoder * -ansi_decoder_create(void) -{ - struct ansi_decoder *d = xmalloc(sizeof *d); - d->state = ANSI_ESC; - return d; -} - -void -ansi_decoder_destroy(struct ansi_decoder *d) -{ - free(d); -} - -int -ansi_decoder_put(struct ansi_decoder *d, uint8_t c) -{ - if (c == 27) { - /* Escape always starts a new escape sequence, aborting an incomplete - * one if necessary. */ - if (d->state != ANSI_ESC) { - VLOG_DBG("Unexpected escape inside escape sequence"); - } - d->state = ANSI_CSI; - return 0; - } - - switch (d->state) { - case ANSI_ESC: - return 1; - - case ANSI_CSI: - if (c == '[') { - d->state = ANSI_PARAMETER; - d->seq.n_args = 0; - d->seq.function = 0; - } else if (c >= 0x40 && c <= 0x5f) { - d->state = ANSI_COMPLETE; - d->seq.n_args = 0; - d->seq.function = 0; - d->seq.function = c << 8; - return -1; - } else { - d->state = ANSI_ESC; - } - break; - - case ANSI_PARAMETER: - if (c >= '0' && c <= '9') { - int *arg; - if (d->seq.n_args == 0) { - d->seq.args[d->seq.n_args++] = 0; - } else if (d->seq.n_args > ANSI_MAX_ARGS) { - break; - } - arg = &d->seq.args[d->seq.n_args - 1]; - if (*arg == -1) { - *arg = 0; - } - *arg = *arg * 10 + (c - '0'); - break; - } else if (c == ';') { - if (d->seq.n_args < ANSI_MAX_ARGS) { - d->seq.args[d->seq.n_args] = -1; - } - d->seq.n_args++; - break; - } - d->state = ANSI_INTERMEDIATE; - /* Fall through. */ - - case ANSI_INTERMEDIATE: - if (c >= 0x20 && c <= 0x2f) { - d->seq.function = d->seq.function * 16 + (c - 0x20); - break; - } - d->state = ANSI_FINAL; - /* Fall through. */ - - case ANSI_FINAL: - if (c >= 0x40 && c <= 0x7e) { - d->seq.function = d->seq.function * 256 + c; - d->state = ANSI_COMPLETE; - return -1; - } else { - /* Invalid sequence. */ - d->state = ANSI_ESC; - } - break; - - case ANSI_COMPLETE: - NOT_REACHED(); - } - return 0; -} - -const struct ansi_sequence * -ansi_decoder_get(struct ansi_decoder *d) -{ - assert(d->state == ANSI_COMPLETE); - d->state = ANSI_ESC; - if (d->seq.n_args < ANSI_MAX_ARGS) { - int i; - for (i = d->seq.n_args; i < ANSI_MAX_ARGS; i++) { - d->seq.args[i] = -1; - } - } else { - d->seq.n_args = ANSI_MAX_ARGS; - } - return &d->seq; -} diff --git a/extras/ezio/terminal.h b/extras/ezio/terminal.h deleted file mode 100644 index a5ac7f3d..00000000 --- a/extras/ezio/terminal.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (c) 2008, 2009 Nicira Networks, Inc. - * - * 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. - */ - -#ifndef TERMINAL_H -#define TERMINAL_H 1 - -#include -#include - -struct ezio; - -struct terminal *terminal_create(void); -void terminal_destroy(struct terminal *); -int terminal_run(struct terminal *, struct ezio *, int input_fd); -void terminal_wait(struct terminal *, int input_fd); - -#endif /* terminal.h */ diff --git a/extras/ezio/tty.c b/extras/ezio/tty.c deleted file mode 100644 index a4bb14ce..00000000 --- a/extras/ezio/tty.c +++ /dev/null @@ -1,394 +0,0 @@ -/* Copyright (c) 2008, 2009, 2010 Nicira Networks, Inc. - * - * 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. - */ - -#include -#include "extras/ezio/tty.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fatal-signal.h" -#include "socket-util.h" -#include "util.h" -#include "vlog.h" - -VLOG_DEFINE_THIS_MODULE(tty) - -/* Get major() and minor() macros. */ -#if MAJOR_IN_MKDEV -# include -#elif MAJOR_IN_SYSMACROS -# include -#else -# include -# ifndef major -# define major(dev) (((dev) >> 8) & 0xff) -# define minor(dev) ((dev) & 0xff) -# endif -#endif - -static int -fcntl_lock(int fd) -{ - struct flock l; - memset(&l, 0, sizeof l); - l.l_type = F_WRLCK; - l.l_whence = SEEK_SET; - l.l_start = 0; - l.l_len = 0; - return fcntl(fd, F_SETLK, &l) == -1 ? errno : 0; -} - -static int -remove_lockfile(const char *name) -{ - char buffer[BUFSIZ]; - ssize_t n; - pid_t pid; - int fd; - - /* Remove existing lockfile. */ - fd = open(name, O_RDWR); - if (fd < 0) { - if (errno == ENOENT) { - return 0; - } else { - VLOG_ERR("%s: open: %s", name, strerror(errno)); - return errno; - } - } - - /* Read lockfile. */ - n = read(fd, buffer, sizeof buffer - 1); - if (n < 0) { - int error = errno; - VLOG_ERR("%s: read: %s", name, strerror(error)); - close(fd); - return error; - } - buffer[n] = '\0'; - if (n == 4 && memchr(buffer, '\0', n)) { - int32_t x; - memcpy(&x, buffer, sizeof x); - pid = x; - } else if (n >= 0) { - pid = strtol(buffer, NULL, 10); - } - if (pid <= 0) { - close(fd); - VLOG_WARN("%s: format not recognized, treating as locked.", name); - return EACCES; - } - - /* Is lockfile fresh? */ - if (strstr(buffer, "fcntl")) { - int retval = fcntl_lock(fd); - if (retval) { - close(fd); - VLOG_ERR("%s: device is locked (via fcntl): %s", - name, strerror(retval)); - return retval; - } else { - VLOG_WARN("%s: removing stale lockfile (checked via fcntl)", name); - } - } else { - if (!(kill(pid, 0) < 0 && errno == ESRCH)) { - close(fd); - VLOG_ERR("%s: device is locked (without fcntl)", name); - return EACCES; - } else { - VLOG_WARN("%s: removing stale lockfile (without fcntl)", name); - } - } - close(fd); - - /* Remove stale lockfile. */ - if (unlink(name)) { - VLOG_ERR("%s: unlink: %s", name, strerror(errno)); - return errno; - } - return 0; -} - -static int -create_lockfile(const char *name) -{ - const char *username; - char buffer[BUFSIZ]; - struct passwd *pwd; - mode_t old_umask; - uid_t uid; - int fd; - - /* Create file. */ - old_umask = umask(022); - fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666); - if (fd < 0) { - int error = errno; - VLOG_ERR("%s: create: %s", name, strerror(error)); - umask(old_umask); - return error; - } - umask(old_umask); - - /* Lock file. */ - if (fcntl_lock(fd)) { - int error = errno; - close(fd); - VLOG_ERR("%s: cannot lock: %s", name, strerror(error)); - return error; - } - - /* Write to file. */ - uid = getuid(); - pwd = getpwuid(uid); - username = pwd ? pwd->pw_name : "unknown"; - snprintf(buffer, sizeof buffer, "%10ld %s %.20s fcntl\n", - (long int) getpid(), program_name, username); - if (write(fd, buffer, strlen(buffer)) != strlen(buffer)) { - int error = errno; - VLOG_ERR("%s: write: %s", name, strerror(error)); - close(fd); - unlink(name); - return error; - } - - /* We intentionally do not close 'fd', to avoid releasing the fcntl lock. - * The asssumption here is that we never unlock a tty. */ - fatal_signal_add_file_to_unlink(name); - - return 0; -} - -static int -do_lock(char *name) -{ - int retval = remove_lockfile(name); - if (!retval) { - retval = create_lockfile(name); - } - free(name); - return retval; -} - -int -tty_lock(const char *dev_name) -{ - struct stat s; - char *name; - int retval; - - /* Check that the lockfile directory exists. */ - if (stat(TTY_LOCK_DIR, &s)) { - VLOG_ERR("%s: stat: %s", TTY_LOCK_DIR, strerror(errno)); - return errno; - } - - /* First lock by device number. */ - if (stat(dev_name, &s)) { - VLOG_ERR("%s: stat: %s", dev_name, strerror(errno)); - return errno; - } - retval = do_lock(xasprintf("%s/LK.%03d.%03d.%03d", TTY_LOCK_DIR, - major(s.st_dev), - major(s.st_rdev), minor(s.st_rdev))); - if (retval) { - return retval; - } - - /* Then lock by device name. */ - if (!strncmp(dev_name, "/dev/", 5)) { - char *cp; - - name = xasprintf("%s/%s", TTY_LOCK_DIR, dev_name + 5); - for (cp = name + strlen(dev_name) + 1; *cp; cp++) { - if (*cp == '/') { - *cp = '_'; - } - } - } else { - char *slash = strrchr(dev_name, '/'); - name = xasprintf ("%s/%s", TTY_LOCK_DIR, slash ? slash + 1 : dev_name); - } - return do_lock(name); -} - -struct saved_termios { - int fd; - struct termios tios; -}; - -static void -restore_termios(void *s_) -{ - struct saved_termios *s = s_; - tcsetattr(s->fd, TCSAFLUSH, &s->tios); -} - -int -tty_set_raw_mode(int fd, speed_t speed) -{ - if (isatty(fd)) { - struct termios tios; - struct saved_termios *s; - - if (tcgetattr(fd, &tios) < 0) { - return errno; - } - - s = xmalloc(sizeof *s); - s->fd = dup(fd); - if (s->fd < 0) { - int error = errno; - VLOG_WARN("dup failed: %s", strerror(error)); - free(s); - return errno; - } - s->tios = tios; - fatal_signal_add_hook(restore_termios, NULL, s, true); - - tios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP - | INLCR | IGNCR | ICRNL | IXON); - tios.c_oflag &= ~OPOST; - tios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - tios.c_cflag &= ~(CSIZE | PARENB); - tios.c_cflag |= CS8; - if (speed != B0) { - cfsetispeed(&tios, speed); - cfsetospeed(&tios, speed); - } - if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { - return errno; - } - } - return set_nonblocking(fd); -} - -int -tty_open_master_pty(void) -{ - int retval; - int fd; - - fd = posix_openpt(O_RDWR | O_NOCTTY); - if (fd < 0) { - int error = errno; - VLOG_WARN("posix_openpt failed: %s", strerror(error)); - close(fd); - return -error; - } - - if (grantpt(fd) < 0) { - int error = errno; - VLOG_WARN("grantpt failed: %s", strerror(error)); - close(fd); - return -error; - } - - if (unlockpt(fd) < 0) { - int error = errno; - VLOG_WARN("unlockpt failed: %s", strerror(error)); - close(fd); - return -error; - } - - retval = set_nonblocking(fd); - if (retval) { - VLOG_WARN("set_nonblocking failed: %s", strerror(retval)); - close(fd); - return retval; - } - - return fd; -} - -int -tty_fork_child(int master_fd, char *argv[]) -{ - int retval = fork(); - if (!retval) { - char *slave_name; - int slave_fd; - int fd; - - /* Running in child process. */ - fatal_signal_fork(); - - /* Open pty slave as controlling terminal. */ - setsid(); - slave_name = ptsname(master_fd); - if (slave_name == NULL) { - ovs_fatal(errno, "ptsname"); - } - slave_fd = open(slave_name, O_RDWR); - if (isastream(slave_fd) - && (ioctl(slave_fd, I_PUSH, "ptem") < 0 - || ioctl(slave_fd, I_PUSH, "ldterm") < 0)) { - ovs_fatal(errno, "STREAMS ioctl"); - } - - /* Make pty slave stdin, stdout. */ - if (dup2(slave_fd, STDIN_FILENO) < 0 - || dup2(slave_fd, STDOUT_FILENO) < 0 - || dup2(slave_fd, STDERR_FILENO) < 0) { - ovs_fatal(errno, "dup2"); - } - - /* Close other file descriptors. */ - for (fd = 3; fd < 20; fd++) { - close(fd); - } - - /* Set terminal type. */ - setenv("TERM", "ezio3", true); - - /* Invoke subprocess. */ - execvp(argv[0], argv); - ovs_fatal(errno, "execvp"); - } else if (retval > 0) { - /* Running in parent process. */ - return 0; - } else { - /* Fork failed. */ - VLOG_WARN("fork failed: %s", strerror(errno)); - return errno; - } -} - -int -tty_set_window_size(int fd OVS_UNUSED, - int rows OVS_UNUSED, - int columns OVS_UNUSED) -{ -#ifdef TIOCGWINSZ - struct winsize win; - win.ws_row = rows; - win.ws_col = columns; - win.ws_xpixel = 0; - win.ws_ypixel = 0; - if (ioctl(fd, TIOCSWINSZ, &win) == -1) { - return errno; - } -#else -#error -#endif - return 0; -} diff --git a/extras/ezio/tty.h b/extras/ezio/tty.h deleted file mode 100644 index 08649b15..00000000 --- a/extras/ezio/tty.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright (c) 2008, 2009 Nicira Networks, Inc. - * - * 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. - */ - -#ifndef TTY_H -#define TTY_H 1 - -#include - -int tty_lock(const char *dev_name); -int tty_set_raw_mode(int fd, speed_t); -int tty_open_master_pty(void); -int tty_fork_child(int master_fd, char *argv[]); -int tty_set_window_size(int fd, int n_rows, int n_columns); - -#endif /* tty.h */ diff --git a/extras/ezio/vt-dummy.c b/extras/ezio/vt-dummy.c deleted file mode 100644 index 18da821d..00000000 --- a/extras/ezio/vt-dummy.c +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (c) 2008, 2009, 2010 Nicira Networks, Inc. - * - * 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. - */ - -#include -#include "extras/ezio/vt.h" -#include -#include "vlog.h" - -VLOG_DEFINE_THIS_MODULE(vt) - -int -vt_open(int open_flags) -{ - VLOG_ERR("no virtual terminal support on this platform"); - return -ENOSYS; -} diff --git a/extras/ezio/vt-linux.c b/extras/ezio/vt-linux.c deleted file mode 100644 index b281c897..00000000 --- a/extras/ezio/vt-linux.c +++ /dev/null @@ -1,127 +0,0 @@ -/* Copyright (c) 2008, 2009, 2010 Nicira Networks, Inc. - * - * 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. - */ - -#include -#include "extras/ezio/vt.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "util.h" -#include "vlog.h" - -VLOG_DEFINE_THIS_MODULE(vt) - -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; -} diff --git a/extras/ezio/vt.h b/extras/ezio/vt.h deleted file mode 100644 index fa5ec4f2..00000000 --- a/extras/ezio/vt.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright (c) 2008, 2009 Nicira Networks, Inc. - * - * 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. - */ - -#ifndef VT_H -#define VT_H 1 - -int vt_open(int open_flags); - -#endif /* vt.h */ diff --git a/lib/vlog-modules.def b/lib/vlog-modules.def index b55472de..20f3b884 100644 --- a/lib/vlog-modules.def +++ b/lib/vlog-modules.def @@ -30,7 +30,6 @@ VLOG_MODULE(dpif_linux) VLOG_MODULE(dpif_netdev) VLOG_MODULE(dpctl) VLOG_MODULE(entropy) -VLOG_MODULE(ezio_term) VLOG_MODULE(fail_open) VLOG_MODULE(fatal_signal) VLOG_MODULE(flow) @@ -81,7 +80,6 @@ VLOG_MODULE(terminal) VLOG_MODULE(timeval) VLOG_MODULE(tty) VLOG_MODULE(socket_util) -VLOG_MODULE(switchui) VLOG_MODULE(unixctl) VLOG_MODULE(util) VLOG_MODULE(vconn_stream) diff --git a/m4/openvswitch.m4 b/m4/openvswitch.m4 index 6fb86099..d3e9f9f0 100644 --- a/m4/openvswitch.m4 +++ b/m4/openvswitch.m4 @@ -153,83 +153,6 @@ dnl Checks for valgrind/valgrind.h. AC_DEFUN([OVS_CHECK_VALGRIND], [AC_CHECK_HEADERS([valgrind/valgrind.h])]) -dnl Searches for a directory to put lockfiles for tty devices. -dnl Defines C preprocessor variable TTY_LOCK_DIR to a quoted string -dnl for that directory. -AC_DEFUN([OVS_CHECK_TTY_LOCK_DIR], - [AC_CACHE_CHECK([directory used for serial device lockfiles], - [ovs_cv_path_tty_locks], - [# This list of candidate directories is from minicom. - ovs_cv_path_tty_locks=none - for dir in /etc/locks /var/lock /usr/spool/locks \ - /var/spool/locks /var/spool/lock \ - /usr/spool/uucp /var/spool/uucp /var/run; do - if test -d $dir; then - ovs_cv_path_tty_locks=$dir - break - fi - done]) - if test "$ovs_cv_path_tty_locks" = none; then - AC_MSG_ERROR([cannot find a directory for tty locks]) - fi - AC_DEFINE_UNQUOTED([TTY_LOCK_DIR], "$ovs_cv_path_tty_locks", - [Directory used for serial device lockfiles])]) - -dnl The following check is adapted from GNU PSPP. -dnl It searches for the ncurses library. If it finds it, it sets -dnl HAVE_CURSES to yes and sets NCURSES_LIBS and NCURSES_CFLAGS -dnl appropriate. Otherwise, it sets HAVE_CURSES to no. -AC_DEFUN([OVS_CHECK_CURSES], - [if test "$cross_compiling" != yes; then - AC_CHECK_PROGS([NCURSES_CONFIG], [ncurses5-config ncurses8-config]) - fi - if test "$NCURSES_CONFIG" = ""; then - AC_SEARCH_LIBS([tgetent], [ncurses], - [AC_CHECK_HEADERS([term.h curses.h], - [HAVE_CURSES=yes], - [HAVE_CURSES=no])]) - else - save_cflags=$CFLAGS - CFLAGS="$CFLAGS $($NCURSES_CONFIG --cflags)" - AC_CHECK_HEADERS([term.h curses.h], - [HAVE_CURSES=yes], - [HAVE_CURSES=no]) - CFLAGS=$save_cflags - if test "$HAVE_CURSES" = yes; then - NCURSES_LIBS=$($NCURSES_CONFIG --libs) - NCURSES_CFLAGS=$($NCURSES_CONFIG --cflags) - AC_SUBST(NCURSES_CFLAGS) - AC_SUBST(NCURSES_LIBS) - fi - fi - AM_CONDITIONAL([HAVE_CURSES], [test "$HAVE_CURSES" = yes])]) - -dnl Checks for linux/vt.h. -AC_DEFUN([OVS_CHECK_LINUX_VT_H], - [AC_CHECK_HEADER([linux/vt.h], - [HAVE_LINUX_VT_H=yes], - [HAVE_LINUX_VT_H=no]) - AM_CONDITIONAL([HAVE_LINUX_VT_H], [test "$HAVE_LINUX_VT_H" = yes]) - if test "$HAVE_LINUX_VT_H" = yes; then - AC_DEFINE([HAVE_LINUX_VT_H], [1], - [Define to 1 if linux/vt.h is available.]) - fi]) - -dnl Checks for libpcre. -dnl -dnl ezio-term wants libpcre that supports the PCRE_PARTIAL feature, -dnl which is libpcre 7.2 or later. -AC_DEFUN([OVS_CHECK_PCRE], - [dnl Make sure that pkg-config is installed. - m4_pattern_forbid([PKG_CHECK_MODULES]) - PKG_CHECK_MODULES([PCRE], - [libpcre >= 7.2], - [HAVE_PCRE_PARTIAL=yes], - [HAVE_PCRE_PARTIAL=no]) - AM_CONDITIONAL([HAVE_PCRE_PARTIAL], [test "$HAVE_PCRE_PARTIAL" = yes]) - AC_SUBST([HAVE_PCRE_PARTIAL]) -]) - dnl Checks for Python 2.x, x >= 4. AC_DEFUN([OVS_CHECK_PYTHON], [AC_CACHE_CHECK( -- 2.30.2