diff --git a/ChangeLog b/ChangeLog index ca274eaac..5e60f6c87 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,11 @@ Support for generating Diffie-Hellman groups (/etc/moduli) from ssh-keygen. Based on code from Phil Karn, William Allen Simpson and Niels Provos. ok markus@, thanks jmc@ + - markus@cvs.openbsd.org 2003/07/29 18:24:00 + [LICENCE progressmeter.c] + replace 4 clause BSD licensed progressmeter code with a replacement + from Nils Nordman and myself; ok deraadt@ + (copied from OpenBSD an re-applied portable changes) 20030730 - (djm) [auth-pam.c] Don't use crappy APIs like sprintf. Thanks bal @@ -756,4 +761,4 @@ - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo. Report from murple@murple.net, diagnosis from dtucker@zip.com.au -$Id: ChangeLog,v 1.2871 2003/08/02 12:40:07 dtucker Exp $ +$Id: ChangeLog,v 1.2872 2003/08/02 13:28:38 dtucker Exp $ diff --git a/LICENCE b/LICENCE index 38edcecfe..fac74c6ef 100644 --- a/LICENCE +++ b/LICENCE @@ -166,48 +166,6 @@ OpenSSH contains no GPL code. * SUCH DAMAGE. 6) - The progresssmeter code used by scp(1) and sftp(1) is copyright by - the NetBSD Foundation. - - * Copyright (c) 1997-2003 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Luke Mewburn. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, - * NASA Ames Research Center. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - -7) Remaining components of the software are provided under a standard 2-term BSD licence with the following names as copyright holders: @@ -370,4 +328,4 @@ OpenSSH contains no GPL code. ------ -$OpenBSD: LICENCE,v 1.15 2003/06/12 12:22:47 djm Exp $ +$OpenBSD: LICENCE,v 1.16 2003/07/29 18:24:00 markus Exp $ diff --git a/progressmeter.c b/progressmeter.c index 6aa225adf..170d869f4 100644 --- a/progressmeter.c +++ b/progressmeter.c @@ -1,6 +1,5 @@ /* - * Copyright (c) 1999 Theo de Raadt. All rights reserved. - * Copyright (c) 1999 Aaron Campbell. All rights reserved. + * Copyright (c) 2003 Nils Nordman. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,248 +22,242 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - * Copyright (c) 1997-2003 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Luke Mewburn. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, - * NASA Ames Research Center. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - #include "includes.h" -RCSID("$OpenBSD: progressmeter.c,v 1.8 2003/06/28 16:23:06 deraadt Exp $"); +RCSID("$OpenBSD: progressmeter.c,v 1.13 2003/07/31 22:34:03 markus Exp $"); -#ifdef HAVE_LIBGEN_H -#include -#endif - -#include "atomicio.h" #include "progressmeter.h" +#include "atomicio.h" #include "misc.h" -/* Number of seconds before xfer considered "stalled". */ -#define STALLTIME 5 -/* alarm() interval for updating progress meter. */ -#define PROGRESSTIME 1 +#define DEFAULT_WINSIZE 80 +#define MAX_WINSIZE 512 +#define PADDING 1 /* padding between the progress indicators */ +#define UPDATE_INTERVAL 1 /* update the progress meter every second */ +#define STALL_TIME 5 /* we're stalled after this many seconds */ -/* Signal handler used for updating the progress meter. */ +/* determines whether we can output to the terminal */ +static int can_output(void); + +/* formats and inserts the specified size into the given buffer */ +static void format_size(char *, int, off_t); +static void format_rate(char *, int, off_t); + +/* updates the progressmeter to reflect the current state of the transfer */ +void refresh_progress_meter(void); + +/* signal handler for updating the progress meter */ static void update_progress_meter(int); -/* Returns non-zero if we are the foreground process. */ -static int foregroundproc(void); +static time_t start; /* start progress */ +static time_t last_update; /* last progress update */ +static char *file; /* name of the file being transferred */ +static off_t end_pos; /* ending position of transfer */ +static off_t cur_pos; /* transfer position as of last refresh */ +static volatile off_t *counter; /* progress counter */ +static long stalled; /* how long we have been stalled */ +static int bytes_per_second; /* current speed in bytes per second */ +static int win_size; /* terminal window size */ -/* Returns width of the terminal (for progress meter calculations). */ -static int get_tty_width(void); +/* units for format_size */ +static const char unit[] = " KMGT"; -/* Visual statistics about files as they are transferred. */ -static void draw_progress_meter(void); +static int +can_output(void) +{ + return (getpgrp() == tcgetpgrp(STDOUT_FILENO)); +} -/* Time a transfer started. */ -static struct timeval start; +static void +format_rate(char *buf, int size, off_t bytes) +{ + int i; -/* Number of bytes of current file transferred so far. */ -static volatile off_t *statbytes; + bytes *= 100; + for (i = 0; bytes >= 100*1000 && unit[i] != 'T'; i++) + bytes = (bytes + 512) / 1024; + if (i == 0) { + i++; + bytes = (bytes + 512) / 1024; + } + snprintf(buf, size, "%3lld.%1lld%c%s", + (int64_t) bytes / 100, + (int64_t) (bytes + 5) / 10 % 10, + unit[i], + i ? "B" : " "); +} -/* Total size of current file. */ -static off_t totalbytes; +static void +format_size(char *buf, int size, off_t bytes) +{ + int i; -/* Name of current file being transferred. */ -static char *curfile; - -/* Time of last update. */ -static struct timeval lastupdate; - -/* Size at the time of the last update. */ -static off_t lastsize; + for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++) + bytes = (bytes + 512) / 1024; + snprintf(buf, size, "%4lld%c%s", + (int64_t) bytes, + unit[i], + i ? "B" : " "); +} void -start_progress_meter(char *file, off_t filesize, off_t *counter) +refresh_progress_meter(void) { - if ((curfile = basename(file)) == NULL) - curfile = file; + char buf[MAX_WINSIZE + 1]; + time_t now; + off_t transferred; + double elapsed; + int percent; + int bytes_left; + int cur_speed; + int hours, minutes, seconds; + int i, len; + int file_len; - totalbytes = filesize; - statbytes = counter; - (void) gettimeofday(&start, (struct timezone *) 0); - lastupdate = start; - lastsize = 0; + transferred = *counter - cur_pos; + cur_pos = *counter; + now = time(NULL); + bytes_left = end_pos - cur_pos; + + if (bytes_left > 0) + elapsed = now - last_update; + else + elapsed = now - start; + + /* calculate speed */ + if (elapsed != 0) + cur_speed = (transferred / elapsed); + else + cur_speed = 0; + +#define AGE_FACTOR 0.9 + if (bytes_per_second != 0) { + bytes_per_second = (bytes_per_second * AGE_FACTOR) + + (cur_speed * (1.0 - AGE_FACTOR)); + } else + bytes_per_second = cur_speed; + + /* filename */ + buf[0] = '\0'; + file_len = win_size - 35; + if (file_len > 0) { + len = snprintf(buf, file_len, "\r%s", file); + for (i = len; i < file_len; i++ ) + buf[i] = ' '; + buf[file_len] = '\0'; + } + + /* percent of transfer done */ + if (end_pos != 0) + percent = ((float)cur_pos / end_pos) * 100; + else + percent = 100; + snprintf(buf + strlen(buf), win_size - strlen(buf), + " %3d%% ", percent); + + /* amount transferred */ + format_size(buf + strlen(buf), win_size - strlen(buf), + cur_pos); + strlcat(buf, " ", win_size); + + /* bandwidth usage */ + format_rate(buf + strlen(buf), win_size - strlen(buf), + bytes_per_second); + strlcat(buf, "/s ", win_size); + + /* ETA */ + if (!transferred) + stalled += elapsed; + else + stalled = 0; + + if (stalled >= STALL_TIME) + strlcat(buf, "- stalled -", win_size); + else if (bytes_per_second == 0 && bytes_left) + strlcat(buf, " --:-- ETA", win_size); + else { + if (bytes_left > 0) + seconds = bytes_left / bytes_per_second; + else + seconds = elapsed; + + hours = seconds / 3600; + seconds -= hours * 3600; + minutes = seconds / 60; + seconds -= minutes * 60; + + if (hours != 0) + snprintf(buf + strlen(buf), win_size - strlen(buf), + "%d:%02d:%02d", hours, minutes, seconds); + else + snprintf(buf + strlen(buf), win_size - strlen(buf), + " %02d:%02d", minutes, seconds); + + if (bytes_left > 0) + strlcat(buf, " ETA", win_size); + else + strlcat(buf, " ", win_size); + } + + atomicio(vwrite, STDOUT_FILENO, buf, win_size); + last_update = now; +} + +static void +update_progress_meter(int ignore) +{ + int save_errno; + + save_errno = errno; + + if (can_output()) + refresh_progress_meter(); - draw_progress_meter(); mysignal(SIGALRM, update_progress_meter); - alarm(PROGRESSTIME); + alarm(UPDATE_INTERVAL); + errno = save_errno; +} + +void +start_progress_meter(char *f, off_t filesize, off_t *stat) +{ + struct winsize winsize; + + start = last_update = time(NULL); + file = f; + end_pos = filesize; + cur_pos = 0; + counter = stat; + stalled = 0; + bytes_per_second = 0; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 && + winsize.ws_col != 0) { + if (winsize.ws_col > MAX_WINSIZE) + win_size = MAX_WINSIZE; + else + win_size = winsize.ws_col; + } else + win_size = DEFAULT_WINSIZE; + win_size += 1; /* trailing \0 */ + + if (can_output()) + refresh_progress_meter(); + + mysignal(SIGALRM, update_progress_meter); + alarm(UPDATE_INTERVAL); } void stop_progress_meter(void) { alarm(0); - draw_progress_meter(); - if (foregroundproc() != 0) - atomicio(vwrite, fileno(stdout), "\n", 1); -} -static void -update_progress_meter(int ignore) -{ - int save_errno = errno; - - draw_progress_meter(); - mysignal(SIGALRM, update_progress_meter); - alarm(PROGRESSTIME); - errno = save_errno; -} - -static int -foregroundproc(void) -{ - static pid_t pgrp = -1; - int ctty_pgrp; - - if (pgrp == -1) - pgrp = getpgrp(); - -#ifdef HAVE_TCGETPGRP - return ((ctty_pgrp = tcgetpgrp(STDOUT_FILENO)) != -1 && - ctty_pgrp == pgrp); -#else - return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 && - ctty_pgrp == pgrp)); -#endif -} - -static void -draw_progress_meter(void) -{ - static const char spaces[] = " " - " " - " " - " " - " " - " "; - static const char prefixes[] = " KMGTP"; - struct timeval now, td, wait; - off_t cursize, abbrevsize, bytespersec; - double elapsed; - int ratio, remaining, i, ai, bi, nspaces; - char buf[512]; - - if (foregroundproc() == 0) + if (!can_output()) return; - (void) gettimeofday(&now, (struct timezone *) 0); - cursize = *statbytes; - if (totalbytes != 0) { - ratio = 100.0 * cursize / totalbytes; - ratio = MAX(ratio, 0); - ratio = MIN(ratio, 100); - } else - ratio = 100; + /* Ensure we complete the progress */ + if (cur_pos != end_pos) + refresh_progress_meter(); - abbrevsize = cursize; - for (ai = 0; abbrevsize >= 10000 && ai < sizeof(prefixes); ai++) - abbrevsize >>= 10; - - timersub(&now, &lastupdate, &wait); - if (cursize > lastsize) { - lastupdate = now; - lastsize = cursize; - wait.tv_sec = 0; - } - timersub(&now, &start, &td); - elapsed = td.tv_sec + (td.tv_usec / 1000000.0); - - bytespersec = 0; - if (cursize > 0) { - bytespersec = cursize; - if (elapsed > 0.0) - bytespersec /= elapsed; - } - for (bi = 1; bytespersec >= 1024000 && bi < sizeof(prefixes); bi++) - bytespersec >>= 10; - - nspaces = MIN(get_tty_width() - 79, sizeof(spaces) - 1); - - snprintf(buf, sizeof(buf), - "\r%-45.45s%.*s%3d%% %4lld%c%c %3lld.%01d%cB/s", - curfile, - nspaces, - spaces, - ratio, - (int64_t)abbrevsize, - prefixes[ai], - ai == 0 ? ' ' : 'B', - (int64_t)(bytespersec / 1024), - (int)((bytespersec % 1024) * 10 / 1024), - prefixes[bi] - ); - - if (cursize <= 0 || elapsed <= 0.0 || cursize > totalbytes) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - " --:-- ETA"); - } else if (wait.tv_sec >= STALLTIME) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - " - stalled -"); - } else { - if (cursize != totalbytes) - remaining = (int)(totalbytes / (cursize / elapsed) - - elapsed); - else - remaining = elapsed; - - i = remaining / 3600; - if (i) - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "%2d:", i); - else - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - " "); - i = remaining % 3600; - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "%02d:%02d%s", i / 60, i % 60, - (cursize != totalbytes) ? " ETA" : " "); - } - atomicio(vwrite, fileno(stdout), buf, strlen(buf)); -} - -static int -get_tty_width(void) -{ - struct winsize winsize; - - if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1) - return (winsize.ws_col ? winsize.ws_col : 80); - else - return (80); + atomicio(vwrite, STDOUT_FILENO, "\n", 1); }