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:
Conrad Meyer 2018-02-09 19:46:51 +00:00
parent 16c0c8eeec
commit 49fb06154b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=329077

View File

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