SFTP Status Bar..
Nicolas Williams
Nicolas.Williams at ubsw.com
Thu Feb 7 07:53:41 EST 2002
Works, though the patch to scp.c doesn't apply cleanly.
Also, you're enabling the progress bar only on multiple transfers, not
on one transfer. Perhaps there should be a separate sftp command to
enable/disable the progress bar.
How's that for testing feedback? :)
Nico
On Wed, Feb 06, 2002 at 01:23:10PM -0600, mouring wrote:
> This is the LAST version I plan on doing.. If I hear no feed back good
> or bad. Then I'll assume I've wasted my time on a feature that people
> whine about but don't care to try. This is against 3.0.2pX so it
> should be VERY easy for anyone to test.
>
> - Ben
>
> diff -ur openssh-3.0.2p1/misc.c openssh/misc.c
> --- openssh-3.0.2p1/misc.c Tue Jul 3 23:46:58 2001
> +++ openssh/misc.c Wed Feb 6 13:15:55 2002
> @@ -30,6 +30,7 @@
> #include "misc.h"
> #include "log.h"
> #include "xmalloc.h"
> +#include "atomicio.h"
>
> /* remove newline at end of string */
> char *
> @@ -304,6 +305,139 @@
> args->list = xrealloc(args->list, args->nalloc * sizeof(char *));
> args->list[args->num++] = xstrdup(buf);
> args->list[args->num] = NULL;
> +}
> +
> +/* scp/sftp progression meter (from src/usr.bin/ftp/util.c) */
> +static int
> +foregroundproc(void)
> +{
> + static pid_t pgrp = -1;
> + int ctty_pgrp;
> +
> + if (pgrp == -1)
> + pgrp = getpgrp();
> +
> + return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 &&
> + ctty_pgrp == pgrp));
> +}
> +
> +int
> +getttywidth(void)
> +{
> + struct winsize winsize;
> +
> + if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)
> + return (winsize.ws_col ? winsize.ws_col : 80);
> + else
> + return (80);
> +}
> +
> +void
> +progressmeter(off_t statbytes, off_t totalbytes, char *filename)
> +{
> +#define STALLTIME 5 /* number of seconds before xfer assumed "stalled" */
> + static const char prefixes[] = " KMGTP";
> + static char *progressbar = NULL;
> + static struct timeval *start = NULL, lastupdate;
> + static off_t lastsize;
> + static size_t progressbar_size = 0;
> + struct timeval now, td, wait;
> + off_t cursize, abbrevsize;
> + double elapsed;
> + int ratio, barlength, i, remaining;
> + char buf[256];
> +
> + if (!start) {
> + start = xmalloc(sizeof(struct timeval));
> + (void) gettimeofday(start, (struct timezone *) 0);
> + lastupdate = *start;
> + lastsize = 0;
> + }
> + 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;
> +
> + barlength = getttywidth() - 51;
> + if (barlength > progressbar_size) {
> + progressbar_size = barlength;
> + progressbar = xrealloc(progressbar, barlength);
> + memset(progressbar, '*', barlength);
> + }
> +
> + snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ",
> + (filename?filename:""), ratio);
> + if (barlength > 0) {
> + i = barlength * ratio / 100;
> + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
> + "|%.*s%*s|", i, progressbar, barlength - i, "");
> + }
> + i = 0;
> + abbrevsize = cursize;
> + while (abbrevsize >= 100000 && i < sizeof(prefixes)) {
> + i++;
> + abbrevsize >>= 10;
> + }
> + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5llu %c%c ",
> + (unsigned long long) abbrevsize, prefixes[i],
> + prefixes[i] == ' ' ? ' ' : 'B');
> +
> + timersub(&now, &lastupdate, &wait);
> + if (cursize > lastsize) {
> + lastupdate = now;
> + lastsize = cursize;
> + if (wait.tv_sec >= STALLTIME) {
> + start->tv_sec += wait.tv_sec;
> + start->tv_usec += wait.tv_usec;
> + }
> + wait.tv_sec = 0;
> + }
> + timersub(&now, start, &td);
> + elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
> +
> + if ((totalbytes != statbytes) &&
> + (statbytes <= 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 (totalbytes != statbytes)
> + remaining = (int)(totalbytes / (statbytes / 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,
> + (totalbytes != statbytes) ? " ETA" : " ");
> + }
> + atomicio(write, fileno(stdout), buf, strlen(buf));
> +
> + if (totalbytes == statbytes) {
> + atomicio(write, fileno(stdout), "\n", 1);
> +
> + /* Clean up for next usage */
> + xfree(start);
> + start = NULL;
> + statbytes = 0;
> + }
> }
>
> mysig_t
> Only in openssh: misc.c.orig
> diff -ur openssh-3.0.2p1/misc.h openssh/misc.h
> --- openssh-3.0.2p1/misc.h Wed Jul 4 12:25:55 2001
> +++ openssh/misc.h Wed Feb 6 13:02:33 2002
> @@ -29,7 +29,11 @@
> int num;
> int nalloc;
> };
> +
> void addargs(arglist *, char *, ...) __attribute__((format(printf, 2, 3)));
> +void progressmeter(off_t statbytes, off_t totalbytes, char *curfile);
> +
> +#define PROGRESSTIME 1 /* alarm() interval for updating progress meter */
>
> /* wrapper for signal interface */
> typedef void (*mysig_t)(int);
> diff -ur openssh-3.0.2p1/scp.c openssh/scp.c
> --- openssh-3.0.2p1/scp.c Sun Oct 21 19:53:59 2001
> +++ openssh/scp.c Wed Feb 6 13:07:33 2002
> @@ -89,32 +89,12 @@
> char *__progname;
> #endif
>
> -/* For progressmeter() -- number of seconds before xfer considered "stalled" */
> -#define STALLTIME 5
> -/* alarm() interval for updating progress meter */
> -#define PROGRESSTIME 1
> -
> -/* Progress meter bar */
> -#define BAR \
> - "************************************************************"\
> - "************************************************************"\
> - "************************************************************"\
> - "************************************************************"
> -#define MAX_BARLENGTH (sizeof(BAR) - 1)
> -
> -/* Visual statistics about files as they are transferred. */
> -void progressmeter(int);
> -
> -/* Returns width of the terminal (for progress meter calculations). */
> -int getttywidth(void);
> +static void updateprogressmeter(int done);
> int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc);
>
> /* Struct for addargs */
> arglist args;
>
> -/* Time a transfer started. */
> -static struct timeval start;
> -
> /* Number of bytes of current file transferred so far. */
> volatile off_t statbytes;
>
> @@ -569,7 +549,7 @@
> }
> if (showprogress) {
> totalbytes = stb.st_size;
> - progressmeter(-1);
> + updateprogressmeter(0);
> }
> /* Keep writing after an error so that we stay sync'd up. */
> for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
> @@ -591,7 +571,7 @@
> }
> }
> if (showprogress)
> - progressmeter(1);
> + updateprogressmeter(1);
>
> if (close(fd) < 0 && !haderr)
> haderr = errno;
> @@ -835,7 +815,7 @@
>
> if (showprogress) {
> totalbytes = size;
> - progressmeter(-1);
> + updateprogressmeter(0);
> }
> statbytes = 0;
> for (count = i = 0; i < size; i += 4096) {
> @@ -871,7 +851,8 @@
> }
> }
> if (showprogress)
> - progressmeter(1);
> + updateprogressmeter(1);
> +
> if (count != 0 && wrerr == NO &&
> (j = atomicio(write, ofd, bp->buf, count)) != count) {
> wrerr = YES;
> @@ -1079,140 +1060,17 @@
> }
>
> static void
> -updateprogressmeter(int ignore)
> +updateprogressmeter(int done)
> {
> - int save_errno = errno;
> -
> - progressmeter(0);
> - mysignal(SIGALRM, updateprogressmeter);
> - alarm(PROGRESSTIME);
> - errno = save_errno;
> -}
> -
> -static int
> -foregroundproc(void)
> -{
> - static pid_t pgrp = -1;
> - int ctty_pgrp;
> -
> - if (pgrp == -1)
> - pgrp = getpgrp();
> + int save_errno = errno;
>
> -#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
> -}
>
> -void
> -progressmeter(int flag)
> -{
> - static const char prefixes[] = " KMGTP";
> - static struct timeval lastupdate;
> - static off_t lastsize;
> - struct timeval now, td, wait;
> - off_t cursize, abbrevsize;
> - double elapsed;
> - int ratio, barlength, i, remaining;
> - char buf[256];
> -
> - if (flag == -1) {
> - (void) gettimeofday(&start, (struct timezone *) 0);
> - lastupdate = start;
> - lastsize = 0;
> - }
> - if (foregroundproc() == 0)
> - return;
> + progressmeter(statbytes, totalbytes, curfile);
> + if (done == 0) {
> + mysignal(SIGALRM, updateprogressmeter);
> + alarm(PROGRESSTIME);
> + } else
> + alarm(0);
>
> - (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;
> -
> - snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio);
> -
> - barlength = getttywidth() - 51;
> - barlength = (barlength <= MAX_BARLENGTH)?barlength:MAX_BARLENGTH;
> - if (barlength > 0) {
> - i = barlength * ratio / 100;
> - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
> - "|%.*s%*s|", i, BAR, barlength - i, "");
> - }
> - i = 0;
> - abbrevsize = cursize;
> - while (abbrevsize >= 100000 && i < sizeof(prefixes)) {
> - i++;
> - abbrevsize >>= 10;
> - }
> - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5lu %c%c ",
> - (unsigned long) abbrevsize, prefixes[i],
> - prefixes[i] == ' ' ? ' ' : 'B');
> -
> - timersub(&now, &lastupdate, &wait);
> - if (cursize > lastsize) {
> - lastupdate = now;
> - lastsize = cursize;
> - if (wait.tv_sec >= STALLTIME) {
> - start.tv_sec += wait.tv_sec;
> - start.tv_usec += wait.tv_usec;
> - }
> - wait.tv_sec = 0;
> - }
> - timersub(&now, &start, &td);
> - elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
> -
> - if (flag != 1 &&
> - (statbytes <= 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 (flag != 1)
> - remaining = (int)(totalbytes / (statbytes / 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,
> - (flag != 1) ? " ETA" : " ");
> - }
> - atomicio(write, fileno(stdout), buf, strlen(buf));
> -
> - if (flag == -1) {
> - mysignal(SIGALRM, updateprogressmeter);
> - alarm(PROGRESSTIME);
> - } else if (flag == 1) {
> - alarm(0);
> - atomicio(write, fileno(stdout), "\n", 1);
> - statbytes = 0;
> - }
> -}
> -
> -int
> -getttywidth(void)
> -{
> - struct winsize winsize;
> -
> - if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)
> - return (winsize.ws_col ? winsize.ws_col : 80);
> - else
> - return (80);
> + errno = save_errno;
> }
> diff -ur openssh-3.0.2p1/sftp-client.c openssh/sftp-client.c
> --- openssh-3.0.2p1/sftp-client.c Wed Jul 18 10:45:45 2001
> +++ openssh/sftp-client.c Wed Feb 6 13:02:34 2002
> @@ -49,6 +49,11 @@
> /* Message ID */
> static u_int msg_id = 1;
>
> +/* Progress Meter items */
> +off_t statbytes = 0;
> +off_t totalbytes = 0;
> +char *curfile = NULL;
> +
> static void
> send_msg(int fd, Buffer *m)
> {
> @@ -671,7 +676,7 @@
>
> int
> do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
> - int pflag)
> + int pflag, void (*progressbar)(int))
> {
> int local_fd;
> u_int expected_id, handle_len, mode, type, id;
> @@ -724,6 +729,11 @@
> return(-1);
> }
>
> + totalbytes = a->size;
> + curfile = remote_path;
> + if (progressbar)
> + (progressbar)(0);
> +
> /* Read from remote and write to local */
> offset = 0;
> for(;;) {
> @@ -785,6 +795,7 @@
>
> offset += len;
> xfree(data);
> + statbytes = offset;
> }
> status = do_close(fd_in, fd_out, handle, handle_len);
>
> @@ -807,15 +818,18 @@
> }
>
> done:
> + if (progressbar)
> + (progressbar)(1);
> close(local_fd);
> buffer_free(&msg);
> xfree(handle);
> +
> return status;
> }
>
> int
> do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
> - int pflag)
> + int pflag, void (*progressbar)(int))
> {
> int local_fd;
> u_int handle_len, id;
> @@ -865,6 +879,10 @@
> buffer_free(&msg);
> return(-1);
> }
> + totalbytes = a.size;
> + curfile = local_path;
> + if (progressbar)
> + (progressbar)(0);
>
> /* Read from local and write to remote */
> offset = 0;
> @@ -908,6 +926,7 @@
> (u_int64_t)offset);
>
> offset += len;
> + statbytes = offset;
> }
>
> if (close(local_fd) == -1) {
> @@ -925,8 +944,10 @@
> status = do_close(fd_in, fd_out, handle, handle_len);
>
> done:
> + if (progressbar)
> + (progressbar)(1);
> xfree(handle);
> buffer_free(&msg);
> +
> return status;
> }
> -
> diff -ur openssh-3.0.2p1/sftp-client.h openssh/sftp-client.h
> --- openssh-3.0.2p1/sftp-client.h Tue Jul 3 23:07:13 2001
> +++ openssh/sftp-client.h Wed Feb 6 13:02:34 2002
> @@ -88,16 +88,14 @@
> /* Return target of symlink 'path' - caller must free result */
> char *do_readlink(int, int, char *);
>
> -/* XXX: add callbacks to do_download/do_upload so we can do progress meter */
> -
> /*
> * Download 'remote_path' to 'local_path'. Preserve permissions and times
> * if 'pflag' is set
> */
> -int do_download(int, int, char *, char *, int);
> +int do_download(int, int, char *, char *, int, void (*)(int));
>
> /*
> * Upload 'local_path' to 'remote_path'. Preserve permissions and times
> * if 'pflag' is set
> */
> -int do_upload(int, int, char *, char *, int);
> +int do_upload(int, int, char *, char *, int, void (*)(int));
> diff -ur openssh-3.0.2p1/sftp-int.c openssh/sftp-int.c
> --- openssh-3.0.2p1/sftp-int.c Wed Aug 15 18:22:57 2001
> +++ openssh/sftp-int.c Wed Feb 6 13:02:34 2002
> @@ -32,6 +32,7 @@
> #include "xmalloc.h"
> #include "log.h"
> #include "pathnames.h"
> +#include "misc.h"
>
> #include "sftp.h"
> #include "sftp-common.h"
> @@ -113,6 +114,24 @@
> };
>
> static void
> +updateprogressmeter(int done)
> +{
> + int save_errno = errno;
> + extern off_t statbytes;
> + extern off_t totalbytes;
> + extern char *curfile;
> +
> + progressmeter(statbytes, totalbytes, curfile);
> + if (done == 0) {
> + mysignal(SIGALRM, updateprogressmeter);
> + alarm(PROGRESSTIME);
> + } else
> + alarm(0);
> +
> + errno = save_errno;
> +}
> +
> +static void
> help(void)
> {
> printf("Available commands:\n");
> @@ -380,8 +399,8 @@
> err = -1;
> goto out;
> }
> - printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst);
> - err = do_download(in, out, g.gl_pathv[0], abs_dst, pflag);
> + err = do_download(in, out, g.gl_pathv[0], abs_dst, pflag,
> + NULL);
> goto out;
> }
>
> @@ -404,8 +423,8 @@
> } else
> abs_dst = tmp;
>
> - printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
> - if (do_download(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
> + if (do_download(in, out, g.gl_pathv[i], abs_dst, pflag,
> + updateprogressmeter) == -1)
> err = -1;
> xfree(abs_dst);
> abs_dst = NULL;
> @@ -462,8 +481,8 @@
> }
> abs_dst = make_absolute(abs_dst, pwd);
> }
> - printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst);
> - err = do_upload(in, out, g.gl_pathv[0], abs_dst, pflag);
> + err = do_upload(in, out, g.gl_pathv[0], abs_dst, pflag,
> + updateprogressmeter);
> goto out;
> }
>
> @@ -486,8 +505,8 @@
> } else
> abs_dst = make_absolute(tmp, pwd);
>
> - printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
> - if (do_upload(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
> + if (do_upload(in, out, g.gl_pathv[i], abs_dst, pflag,
> + updateprogressmeter) == -1)
> err = -1;
> }
>
> _______________________________________________
> openssh-unix-dev at mindrot.org mailing list
> http://www.mindrot.org/mailman/listinfo/openssh-unix-dev
--
-DISCLAIMER: an automatically appended disclaimer may follow. By posting-
-to a public e-mail mailing list I hereby grant permission to distribute-
-and copy this message.-
Visit our website at http://www.ubswarburg.com
This message contains confidential information and is intended only
for the individual named. If you are not the named addressee you
should not disseminate, distribute or copy this e-mail. Please
notify the sender immediately by e-mail if you have received this
e-mail by mistake and delete this e-mail from your system.
E-mail transmission cannot be guaranteed to be secure or error-free
as information could be intercepted, corrupted, lost, destroyed,
arrive late or incomplete, or contain viruses. The sender therefore
does not accept liability for any errors or omissions in the contents
of this message which arise as a result of e-mail transmission. If
verification is required please request a hard-copy version. This
message is provided for informational purposes and should not be
construed as a solicitation or offer to buy or sell any securities or
related financial instruments.
More information about the openssh-unix-dev
mailing list