diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2003-07-29 18:24:01 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2003-07-29 18:24:01 +0000 |
commit | 34fca2cb7f89329d756c8e323e170acbd05d5825 (patch) | |
tree | 283f83ba88a5eabdd1f10fcc04927b6bcd515303 /usr.bin/ssh/progressmeter.c | |
parent | aa1660f4b72488fed1cd40756e56124e636054ef (diff) |
replace 4 clause BSD licensed progressmeter code with a replacement
from Nils Nordman and myself; ok deraadt@
Diffstat (limited to 'usr.bin/ssh/progressmeter.c')
-rw-r--r-- | usr.bin/ssh/progressmeter.c | 383 |
1 files changed, 182 insertions, 201 deletions
diff --git a/usr.bin/ssh/progressmeter.c b/usr.bin/ssh/progressmeter.c index 8dc77dea0f8..3dfad06d77f 100644 --- a/usr.bin/ssh/progressmeter.c +++ b/usr.bin/ssh/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,240 +22,222 @@ * 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.9 2003/07/29 18:24:00 markus Exp $"); -#include <libgen.h> - -#include "atomicio.h" #include "progressmeter.h" +#include "atomicio.h" -/* Number of seconds before xfer considered "stalled". */ -#define STALLTIME 5 -/* alarm() interval for updating progress meter. */ -#define PROGRESSTIME 1 - -/* Signal handler used for updating the progress meter. */ -static void update_progress_meter(int); - -/* Returns non-zero if we are the foreground process. */ -static int foregroundproc(void); +#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 */ -/* Returns width of the terminal (for progress meter calculations). */ -static int get_tty_width(void); +/* determines whether we can output to the terminal */ +static int can_output(void); -/* Visual statistics about files as they are transferred. */ -static void draw_progress_meter(void); +/* formats and inserts the specified size into the given buffer */ +static void format_size(char *, int, off_t); -/* Time a transfer started. */ -static struct timeval start; +/* updates the progressmeter to reflect the current state of the transfer */ +void refresh_progress_meter(void); -/* Number of bytes of current file transferred so far. */ -static volatile off_t *statbytes; +/* signal handler for updating the progress meter */ +static void update_progress_meter(int); -/* Total size of current file. */ -static off_t totalbytes; +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 */ -/* Name of current file being transferred. */ -static char *curfile; +static int +can_output(void) +{ + return (getpgrp() == tcgetpgrp(STDOUT_FILENO)); +} -/* Time of last update. */ -static struct timeval lastupdate; -/* Size at the time of the last update. */ -static off_t lastsize; +static void +format_size(char *buf, int size, off_t bytes) +{ + static const char unit[] = " KMGT"; + int i; + + for (i = 0; bytes > 10240 && unit[i] != 'T'; i++) + bytes /= 1024; + snprintf(buf, size, "%6lld%c%s", + (long long) 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; + + 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; - totalbytes = filesize; - statbytes = counter; - (void) gettimeofday(&start, (struct timezone *) 0); - lastupdate = start; - lastsize = 0; + /* calculate speed */ + if (elapsed != 0) + cur_speed = (transferred / elapsed); + else + cur_speed = 0; - draw_progress_meter(); - signal(SIGALRM, update_progress_meter); - alarm(PROGRESSTIME); -} +#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; + +memset(buf, 'a', sizeof(buf)); + + /* filename */ + buf[0] = '\0'; + file_len = win_size - 36; + 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'; + } -void -stop_progress_meter(void) -{ - alarm(0); - draw_progress_meter(); - if (foregroundproc() != 0) - atomicio(vwrite, fileno(stdout), "\n", 1); + /* 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_size(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 = errno; + int save_errno; + + save_errno = errno; + + if (can_output()) + refresh_progress_meter(); - draw_progress_meter(); signal(SIGALRM, update_progress_meter); - alarm(PROGRESSTIME); + alarm(UPDATE_INTERVAL); errno = save_errno; } -static int -foregroundproc(void) +void +start_progress_meter(char *f, off_t filesize, off_t *stat) { - static pid_t pgrp = -1; - int ctty_pgrp; + struct winsize winsize; - if (pgrp == -1) - pgrp = getpgrp(); + 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(); - return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 && - ctty_pgrp == pgrp)); + signal(SIGALRM, update_progress_meter); + alarm(UPDATE_INTERVAL); } -static void -draw_progress_meter(void) +void +stop_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]; + alarm(0); - 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; - - 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, - (long long)abbrevsize, - prefixes[ai], - ai == 0 ? ' ' : 'B', - (long long)(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); + /* Ensure we complete the progress */ + if (cur_pos != end_pos) + refresh_progress_meter(); + + atomicio(vwrite, STDOUT_FILENO, "\n", 1); } |