tftp(1): Fix libedit state corruption involving signals

This bug was first reported 14 years ago.  The problem was understood 8.5
years ago.  A patch that is functionally identical to this one was proposed
almost 8 years ago and languished in the PR system / Bugzilla.

PR:		63197
Submitted by:	lxv AT omut.org, fernando.apesteguia AT gmail.com
Reported by:	freebsd AT nbritton.org
This commit is contained in:
cem 2018-02-09 19:46:51 +00:00
parent 9ccdf8ab4d
commit 103b9a66bb

View File

@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
#include <netdb.h>
#include <setjmp.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -114,7 +115,7 @@ static void setoptions(int, char **);
static void setrollover(int, char **);
static void setpacketdrop(int, char **);
static void command(void) __dead2;
static void command(bool, EditLine *, History *, HistEvent *) __dead2;
static const char *command_prompt(void);
static void urihandling(char *URI);
@ -176,11 +177,28 @@ static struct modes {
int
main(int argc, char *argv[])
{
HistEvent he;
EditLine *el;
History *hist;
bool interactive;
acting_as_client = 1;
peer = -1;
strcpy(mode, "netascii");
signal(SIGINT, intr);
interactive = isatty(STDIN_FILENO);
if (interactive) {
el = el_init("tftp", stdin, stdout, stderr);
hist = history_init();
history(hist, &he, H_SETSIZE, 100);
el_set(el, EL_HIST, history, hist);
el_set(el, EL_EDITOR, "emacs");
el_set(el, EL_PROMPT, command_prompt);
el_set(el, EL_SIGNAL, 1);
el_source(el, NULL);
}
if (argc > 1) {
if (setjmp(toplevel) != 0)
exit(txrx_error);
@ -192,11 +210,15 @@ main(int argc, char *argv[])
setpeer(argc, argv);
}
if (setjmp(toplevel) != 0)
if (setjmp(toplevel) != 0) {
if (interactive)
el_reset(el);
(void)putchar('\n');
}
init_options();
command();
command(interactive, el, hist, &he);
}
/*
@ -703,36 +725,22 @@ command_prompt(void)
* Command parser.
*/
static void
command(void)
command(bool interactive, EditLine *el, History *hist, HistEvent *hep)
{
HistEvent he;
struct cmd *c;
static EditLine *el;
static History *hist;
const char *bp;
char *cp;
int len, num, vrbose;
int len, num;
char line[MAXLINE];
vrbose = isatty(0);
if (vrbose) {
el = el_init("tftp", stdin, stdout, stderr);
hist = history_init();
history(hist, &he, H_SETSIZE, 100);
el_set(el, EL_HIST, history, hist);
el_set(el, EL_EDITOR, "emacs");
el_set(el, EL_PROMPT, command_prompt);
el_set(el, EL_SIGNAL, 1);
el_source(el, NULL);
}
for (;;) {
if (vrbose) {
if (interactive) {
if ((bp = el_gets(el, &num)) == NULL || num == 0)
exit(0);
len = MIN(MAXLINE, num);
memcpy(line, bp, len);
line[len] = '\0';
history(hist, &he, H_ENTER, bp);
history(hist, hep, H_ENTER, bp);
} else {
line[0] = 0;
if (fgets(line, sizeof line , stdin) == NULL) {