ftp: don't use restartable signals

Refactor to not rely upon restartable signals (SA_RESTART),
possibly fixing intermittent failures with -q QUITTIME.

ftp transfers: handle EINTR/EAGAIN in copy_bytes(),
instead of relying upon restartable signals.

http/https transfers: Explicitly print an error similar to
progressmeter() when timing-out for -Q QUITTIME in fetch_wait(),
and set errno to ETIMEDOUT so that the warn() in fetch_url()
prints a more accurate error message.

PR/55857
This commit is contained in:
lukem 2021-01-06 04:43:14 +00:00
parent bd9b719c88
commit 920389c199
5 changed files with 36 additions and 75 deletions

View File

@ -1,7 +1,7 @@
/* $NetBSD: ftp.c,v 1.170 2020/07/11 02:19:31 lukem Exp $ */
/* $NetBSD: ftp.c,v 1.171 2021/01/06 04:43:14 lukem Exp $ */
/*-
* Copyright (c) 1996-2020 The NetBSD Foundation, Inc.
* Copyright (c) 1996-2021 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -92,7 +92,7 @@
#if 0
static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
#else
__RCSID("$NetBSD: ftp.c,v 1.170 2020/07/11 02:19:31 lukem Exp $");
__RCSID("$NetBSD: ftp.c,v 1.171 2021/01/06 04:43:14 lukem Exp $");
#endif
#endif /* not lint */
@ -593,7 +593,7 @@ abortxfer(int notused)
/*
* Read data from infd & write to outfd, using buf/bufsize as the temporary
* buffer, dealing with short writes.
* buffer, dealing with short reads or writes.
* If rate_limit != 0, rate-limit the transfer.
* If hash_interval != 0, fputc('c', ttyout) every hash_interval bytes.
* Updates global variables: bytes.
@ -627,15 +627,25 @@ copy_bytes(int infd, int outfd, char *buf, size_t bufsize,
bufrem = bufchunk;
while (bufrem > 0) {
inc = read(infd, buf, MIN((off_t)bufsize, bufrem));
if (inc <= 0)
if (inc < 0) {
if (errno == EINTR || errno == EAGAIN) {
continue;
}
goto copy_done;
} else if (inc == 0) {
goto copy_done;
}
bytes += inc;
bufrem -= inc;
bufp = buf;
while (inc > 0) {
outc = write(outfd, bufp, inc);
if (outc < 0)
if (outc < 0) {
if (errno == EINTR || errno == EAGAIN) {
continue;
}
goto copy_done;
}
inc -= outc;
bufp += outc;
}

View File

@ -1,7 +1,7 @@
/* $NetBSD: progressbar.c,v 1.23 2019/06/22 23:40:33 christos Exp $ */
/* $NetBSD: progressbar.c,v 1.24 2021/01/06 04:43:14 lukem Exp $ */
/*-
* Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
* Copyright (c) 1997-2021 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: progressbar.c,v 1.23 2019/06/22 23:40:33 christos Exp $");
__RCSID("$NetBSD: progressbar.c,v 1.24 2021/01/06 04:43:14 lukem Exp $");
#endif /* not lint */
/*
@ -193,7 +193,7 @@ progressmeter(int flag)
if (quit_time > 0 || progress) {
#endif /* !STANDALONE_PROGRESS */
if (flag == -1) {
(void)xsignal_restart(SIGALRM, updateprogressmeter, 1);
(void)xsignal(SIGALRM, updateprogressmeter);
alarmtimer(1); /* set alarm timer for 1 Hz */
} else if (flag == 1) {
alarmtimer(0);
@ -404,73 +404,21 @@ alarmtimer(int wait)
setitimer(ITIMER_REAL, &itv, NULL);
}
/*
* Install a POSIX signal handler, allowing the invoker to set whether
* the signal should be restartable or not
* Install a non-restartable POSIX signal handler.
*/
sigfunc
xsignal_restart(int sig, sigfunc func, int restartable)
xsignal(int sig, sigfunc func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
#if defined(SA_RESTART) /* 4.4BSD, Posix(?), SVR4 */
act.sa_flags = restartable ? SA_RESTART : 0;
#elif defined(SA_INTERRUPT) /* SunOS 4.x */
act.sa_flags = restartable ? 0 : SA_INTERRUPT;
#else
#error "system must have SA_RESTART or SA_INTERRUPT"
act.sa_flags = 0;
#if defined(SA_INTERRUPT) /* SunOS 4.x */
act.sa_flags = SA_INTERRUPT;
#endif
if (sigaction(sig, &act, &oact) < 0)
return (SIG_ERR);
return (oact.sa_handler);
}
/*
* Install a signal handler with the `restartable' flag set dependent upon
* which signal is being set. (This is a wrapper to xsignal_restart())
*/
sigfunc
xsignal(int sig, sigfunc func)
{
int restartable;
/*
* Some signals print output or change the state of the process.
* There should be restartable, so that reads and writes are
* not affected. Some signals should cause program flow to change;
* these signals should not be restartable, so that the system call
* will return with EINTR, and the program will go do something
* different. If the signal handler calls longjmp() or siglongjmp(),
* it doesn't matter if it's restartable.
*/
switch(sig) {
#ifdef SIGINFO
case SIGINFO:
#endif
case SIGQUIT:
case SIGUSR1:
case SIGUSR2:
case SIGWINCH:
restartable = 1;
break;
case SIGALRM:
case SIGINT:
case SIGPIPE:
restartable = 0;
break;
default:
/*
* This is unpleasant, but I don't know what would be better.
* Right now, this "can't happen"
*/
errx(1, "xsignal_restart: called with signal %d", sig);
}
return(xsignal_restart(sig, func, restartable));
}

View File

@ -1,7 +1,7 @@
/* $NetBSD: progressbar.h,v 1.8 2009/04/12 10:18:52 lukem Exp $ */
/* $NetBSD: progressbar.h,v 1.9 2021/01/06 04:43:14 lukem Exp $ */
/*-
* Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
* Copyright (c) 1996-2021 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -68,7 +68,6 @@ int foregroundproc(void);
void alarmtimer(int);
void progressmeter(int);
sigfunc xsignal(int, sigfunc);
sigfunc xsignal_restart(int, sigfunc, int);
#ifndef STANDALONE_PROGRESS
void psummary(int);

View File

@ -1,4 +1,4 @@
/* $NetBSD: ssl.c,v 1.8 2019/04/07 00:44:54 christos Exp $ */
/* $NetBSD: ssl.c,v 1.9 2021/01/06 04:43:14 lukem Exp $ */
/*-
* Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
@ -34,7 +34,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: ssl.c,v 1.8 2019/04/07 00:44:54 christos Exp $");
__RCSID("$NetBSD: ssl.c,v 1.9 2021/01/06 04:43:14 lukem Exp $");
#endif
#include <time.h>
@ -356,6 +356,10 @@ fetch_wait(struct fetch_connect *conn, ssize_t rlen, struct timeval *timeout)
if (quit_time > 0) {
gettimeofday(&now, NULL);
if (!timercmp(timeout, &now, >)) {
fprintf(ttyout, "\r\n%s: transfer aborted"
" because stalled for %lu sec.\r\n",
getprogname(), (unsigned long)quit_time);
errno = ETIMEDOUT;
conn->iserr = ETIMEDOUT;
return -1;
}

View File

@ -1,7 +1,7 @@
/* $NetBSD: version.h,v 1.91 2020/07/18 03:00:37 lukem Exp $ */
/* $NetBSD: version.h,v 1.92 2021/01/06 04:43:14 lukem Exp $ */
/*-
* Copyright (c) 1999-2020 The NetBSD Foundation, Inc.
* Copyright (c) 1999-2021 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -34,5 +34,5 @@
#endif
#ifndef FTP_VERSION
#define FTP_VERSION "20200718"
#define FTP_VERSION "20210106"
#endif