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
include vswitchd/automake.mk
include ovsdb/automake.mk
include xenserver/automake.mk
-include extras/ezio/automake.mk
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
OVS_CHECK_RUNDIR
OVS_CHECK_MALLOC_HOOKS
OVS_CHECK_VALGRIND
-OVS_CHECK_TTY_LOCK_DIR
OVS_CHECK_SOCKET_LIBS
OVS_CHECK_LINKER_SECTIONS
/openvswitch-pki
/openvswitch-pki-server
/openvswitch-switch
-/openvswitch-switchui
/openvswitch-switch-config
/openvswitch-switch.copyright
/openvswitch-wdt
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 \
Uploaders: Ben Pfaff <blp@nicira.com>, Simon Horman <horms@debian.org>
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
.
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:
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.
-
+++ /dev/null
-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.
+++ /dev/null
-# 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=""
+++ /dev/null
-usr/bin
-usr/sbin
-usr/share/terminfo
+++ /dev/null
-#!/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 <jfs@debian.org>
-#
-# 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
+++ /dev/null
-_debian/extras/ezio/ezio-term usr/sbin
-_debian/extras/ezio/ovs-switchui usr/bin
-debian/reconfigure usr/share/openvswitch-switchui
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
+++ /dev/null
-# 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
+++ /dev/null
-/* 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 <config.h>
-#include <assert.h>
-#include <curses.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <string.h>
-#include <stdlib.h>
-#include <term.h>
-#include <unistd.h>
-#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;
- }
- }
-}
-\f
-/* 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;
-}
-\f
-/* 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);
-}
-\f
-/* 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;
- }
- }
-}
-\f
-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);
-}
+++ /dev/null
-/* 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 <config.h>
-#include "ezio.h"
-#include <assert.h>
-#include <stddef.h>
-#include <string.h>
-#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;
-}
-
+++ /dev/null
-/* 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 <stdbool.h>
-#include <stdint.h>
-
-/* 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 */
+++ /dev/null
-# 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,
-
+++ /dev/null
-/* 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 <config.h>
-#include <arpa/inet.h>
-#include <assert.h>
-#include <ctype.h>
-#include <curses.h>
-#include <errno.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <math.h>
-#include <pcre.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <term.h>
-#include <unistd.h>
-#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();
-}
-\f
-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);
-}
-\f
-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;
- }
- }
- }
-}
-\f
-/* 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;
-}
-\f
-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;
- }
-}
-\f
-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);
-}
-\f
-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);
-}
+++ /dev/null
-/* 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 <config.h>
-#include "terminal.h"
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#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 *);
-\f
-/* 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);
-}
-\f
-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;
- }
-}
-\f
-/* 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;
-}
-\f
-/* 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;
-}
+++ /dev/null
-/* 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 <stdbool.h>
-#include <stdint.h>
-
-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 */
+++ /dev/null
-/* 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 <config.h>
-#include "extras/ezio/tty.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stropts.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#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 <sys/mkdev.h>
-#elif MAJOR_IN_SYSMACROS
-# include <sys/sysmacros.h>
-#else
-# include <sys/types.h>
-# 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;
-}
+++ /dev/null
-/* 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 <termios.h>
-
-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 */
+++ /dev/null
-/* 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 <config.h>
-#include "extras/ezio/vt.h"
-#include <errno.h>
-#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;
-}
+++ /dev/null
-/* 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 <config.h>
-#include "extras/ezio/vt.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/kd.h>
-#include <linux/vt.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#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;
-}
+++ /dev/null
-/* 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 */
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)
VLOG_MODULE(timeval)
VLOG_MODULE(tty)
VLOG_MODULE(socket_util)
-VLOG_MODULE(switchui)
VLOG_MODULE(unixctl)
VLOG_MODULE(util)
VLOG_MODULE(vconn_stream)
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(