diff options
author | des <des@FreeBSD.org> | 2003-04-23 16:53:02 +0000 |
---|---|---|
committer | des <des@FreeBSD.org> | 2003-04-23 16:53:02 +0000 |
commit | 85b37b9574631df0f7e774dda373514195c74b29 (patch) | |
tree | 70033bf9d0551c1f485a8bf5c04d41148812e33a /crypto/openssh/progressmeter.c | |
parent | 099d1a58f7bc088a9f71af6d32542ca3949468a3 (diff) | |
download | FreeBSD-src-85b37b9574631df0f7e774dda373514195c74b29.zip FreeBSD-src-85b37b9574631df0f7e774dda373514195c74b29.tar.gz |
Vendor import of OpenSSH-portable 3.6.1p1.
Diffstat (limited to 'crypto/openssh/progressmeter.c')
-rw-r--r-- | crypto/openssh/progressmeter.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/crypto/openssh/progressmeter.c b/crypto/openssh/progressmeter.c new file mode 100644 index 0000000..90eb97f --- /dev/null +++ b/crypto/openssh/progressmeter.c @@ -0,0 +1,282 @@ +/* + * Copyright (c) 1999 Theo de Raadt. All rights reserved. + * Copyright (c) 1999 Aaron Campbell. All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * Parts from: + * + * Copyright (c) 1983, 1990, 1992, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * + * 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 University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.3 2003/03/17 10:38:38 markus Exp $"); + +#ifdef HAVE_LIBGEN_H +#include <libgen.h> +#endif + +#include "atomicio.h" +#include "progressmeter.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); + +/* Returns width of the terminal (for progress meter calculations). */ +static int get_tty_width(void); + +/* Visual statistics about files as they are transferred. */ +static void draw_progress_meter(void); + +/* Time a transfer started. */ +static struct timeval start; + +/* Number of bytes of current file transferred so far. */ +static volatile off_t *statbytes; + +/* Total size of current file. */ +static off_t totalbytes; + +/* 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; + +void +start_progress_meter(char *file, off_t filesize, off_t *counter) +{ + if ((curfile = basename(file)) == NULL) + curfile = file; + + totalbytes = filesize; + statbytes = counter; + (void) gettimeofday(&start, (struct timezone *) 0); + lastupdate = start; + lastsize = 0; + + draw_progress_meter(); + signal(SIGALRM, update_progress_meter); + alarm(PROGRESSTIME); +} + +void +stop_progress_meter() +{ + alarm(0); + draw_progress_meter(); + if (foregroundproc() != 0) + atomicio(write, fileno(stdout), "\n", 1); +} + +static void +update_progress_meter(int ignore) +{ + int save_errno = errno; + + draw_progress_meter(); + signal(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() +{ + 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) + 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); + +#ifdef HAVE_LONG_LONG_INT + 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] + ); +#else + /* XXX: Handle integer overflow? */ + snprintf(buf, sizeof(buf), + "\r%-45.45s%.*s%3d%% %4lu%c%c %3lu.%01d%cB/s", + curfile, + nspaces, + spaces, + ratio, + (u_long)abbrevsize, + prefixes[ai], + ai == 0 ? ' ' : 'B', + (u_long)(bytespersec / 1024), + (int)((bytespersec % 1024) * 10 / 1024), + prefixes[bi] + ); +#endif + + 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(write, 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); +} |