File: [local] / src / usr.bin / cu / command.c (download)
Revision 1.12, Sun Jul 15 06:55:28 2012 UTC (11 years, 11 months ago) by nicm
Branch: MAIN
CVS Tags: OPENBSD_5_4_BASE, OPENBSD_5_4, OPENBSD_5_3_BASE, OPENBSD_5_3, OPENBSD_5_2_BASE, OPENBSD_5_2 Changes since 1.11: +7 -1 lines
Add a command (~D) to drop the DTR line for a second (similar to using
~# for a BREAK). This is useful as it makes some microcontroller boards
reset. From Visa Hankala.
|
/* $OpenBSD: command.c,v 1.12 2012/07/15 06:55:28 nicm Exp $ */
/*
* Copyright (c) 2012 Nicholas Marriott <nicm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <event.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <paths.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "cu.h"
void pipe_command(void);
void connect_command(void);
void send_file(void);
void send_xmodem(void);
void
pipe_command(void)
{
const char *cmd;
pid_t pid;
int fd;
cmd = get_input("Local command?");
if (cmd == NULL || *cmd == '\0')
return;
restore_termios();
switch (pid = fork()) {
case -1:
cu_err(1, "fork");
case 0:
fd = open(_PATH_DEVNULL, O_RDWR);
if (fd < 0 || dup2(fd, STDIN_FILENO) == -1)
_exit(1);
close(fd);
if (signal(SIGINT, SIG_DFL) == SIG_ERR)
_exit(1);
if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
_exit(1);
/* attach stdout to line */
if (dup2(line_fd, STDOUT_FILENO) == -1)
_exit(1);
if (closefrom(STDERR_FILENO + 1) != 0)
_exit(1);
execl(_PATH_BSHELL, "sh", "-c", cmd, (void*)NULL);
_exit(1);
default:
while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
/* nothing */;
break;
}
set_termios();
}
void
connect_command(void)
{
const char *cmd;
pid_t pid;
/*
* Fork a program with:
* 0 <-> remote tty in
* 1 <-> remote tty out
* 2 <-> local tty stderr
*/
cmd = get_input("Local command?");
if (cmd == NULL || *cmd == '\0')
return;
restore_termios();
switch (pid = fork()) {
case -1:
cu_err(1, "fork");
case 0:
if (signal(SIGINT, SIG_DFL) == SIG_ERR)
_exit(1);
if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
_exit(1);
/* attach stdout and stdin to line */
if (dup2(line_fd, STDOUT_FILENO) == -1)
_exit(1);
if (dup2(line_fd, STDIN_FILENO) == -1)
_exit(1);
if (closefrom(STDERR_FILENO + 1) != 0)
_exit(1);
execl(_PATH_BSHELL, "sh", "-c", cmd, (void*)NULL);
_exit(1);
default:
while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
/* nothing */;
break;
}
set_termios();
}
void
send_file(void)
{
const char *file;
FILE *f;
char buf[BUFSIZ], *expanded;
size_t len;
file = get_input("Local file?");
if (file == NULL || *file == '\0')
return;
expanded = tilde_expand(file);
f = fopen(expanded, "r");
if (f == NULL) {
cu_warn("%s", file);
return;
}
while (!feof(f) && !ferror(f)) {
len = fread(buf, 1, sizeof(buf), f);
if (len != 0)
bufferevent_write(line_ev, buf, len);
}
fclose(f);
free(expanded);
}
void
send_xmodem(void)
{
const char *file;
char *expanded;
file = get_input("Local file?");
if (file == NULL || *file == '\0')
return;
expanded = tilde_expand(file);
xmodem_send(expanded);
free(expanded);
}
void
set_speed(void)
{
const char *s, *errstr;
int speed;
s = get_input("New speed?");
if (s == NULL || *s == '\0')
return;
speed = strtonum(s, 0, UINT_MAX, &errstr);
if (errstr != NULL) {
cu_warnx("speed is %s: %s", errstr, s);
return;
}
if (set_line(speed) != 0)
cu_warn("tcsetattr");
}
void
start_record(void)
{
const char *file;
if (record_file != NULL) {
fclose(record_file);
record_file = NULL;
}
file = get_input("Record file?");
if (file == NULL || *file == '\0')
return;
record_file = fopen(file, "a");
if (record_file == NULL)
cu_warnx("%s", file);
}
void
do_command(char c)
{
switch (c) {
case '.':
case '\004': /* ^D */
event_loopexit(NULL);
break;
case '\032': /* ^Z */
restore_termios();
kill(getpid(), SIGTSTP);
set_termios();
break;
case 'C':
connect_command();
break;
case 'D':
ioctl(line_fd, TIOCCDTR, NULL);
sleep(1);
ioctl(line_fd, TIOCSDTR, NULL);
break;
case 'R':
start_record();
break;
case 'S':
set_speed();
break;
case 'X':
send_xmodem();
break;
case '$':
pipe_command();
break;
case '>':
send_file();
break;
case '#':
ioctl(line_fd, TIOCSBRK, NULL);
sleep(1);
ioctl(line_fd, TIOCCBRK, NULL);
break;
case '~':
bufferevent_write(line_ev, "~", 1);
break;
case '?':
printf("\r\n"
"~# send break\r\n"
"~$ pipe local command to remote host\r\n"
"~> send file to remote host\r\n"
"~C connect program to remote host\r\n"
"~D de-assert DTR line briefly\r\n"
"~R start recording to file\r\n"
"~S set speed\r\n"
"~X send file with XMODEM\r\n"
"~? get this summary\r\n"
);
break;
}
}