[BACK]Return to progressmeter.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/progressmeter.c between version 1.3.2.2 and 1.4

version 1.3.2.2, 2004/03/04 18:18:16 version 1.4, 2003/04/03 07:25:27
Line 1 
Line 1 
   /*      $OpenBSD$       */
   
 /*  /*
  * Copyright (c) 2003 Nils Nordman.  All rights reserved.   * 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   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions   * modification, are permitted provided that the following conditions
Line 22 
Line 25 
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   * 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"  #include "includes.h"
 RCSID("$OpenBSD$");  RCSID("$OpenBSD$");
   
 #include "progressmeter.h"  #include <libgen.h>
   
 #include "atomicio.h"  #include "atomicio.h"
   #include "progressmeter.h"
   
 #define DEFAULT_WINSIZE 80  /* Number of seconds before xfer considered "stalled". */
 #define MAX_WINSIZE 512  #define STALLTIME       5
 #define PADDING 1               /* padding between the progress indicators */  /* alarm() interval for updating progress meter. */
 #define UPDATE_INTERVAL 1       /* update the progress meter every second */  #define PROGRESSTIME    1
 #define STALL_TIME 5            /* we're stalled after this many seconds */  
   
 /* determines whether we can output to the terminal */  /* Signal handler used for updating the progress meter. */
 static int can_output(void);  static void update_progress_meter(int);
   
 /* formats and inserts the specified size into the given buffer */  /* Returns non-zero if we are the foreground process. */
 static void format_size(char *, int, off_t);  static int foregroundproc(void);
 static void format_rate(char *, int, off_t);  
   
 /* updates the progressmeter to reflect the current state of the transfer */  /* Returns width of the terminal (for progress meter calculations). */
 void refresh_progress_meter(void);  static int get_tty_width(void);
   
 /* signal handler for updating the progress meter */  /* Visual statistics about files as they are transferred. */
 static void update_progress_meter(int);  static void draw_progress_meter(void);
   
 static time_t start;            /* start progress */  /* Time a transfer started. */
 static time_t last_update;      /* last progress update */  static struct timeval start;
 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 */  
   
 /* units for format_size */  /* Number of bytes of current file transferred so far. */
 static const char unit[] = " KMGT";  static volatile off_t *statbytes;
   
 static int  /* Total size of current file. */
 can_output(void)  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)
 {  {
         return (getpgrp() == tcgetpgrp(STDOUT_FILENO));          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  static void
 format_rate(char *buf, int size, off_t bytes)  update_progress_meter(int ignore)
 {  {
         int i;          int save_errno = errno;
   
         bytes *= 100;          draw_progress_meter();
         for (i = 0; bytes >= 100*1000 && unit[i] != 'T'; i++)          signal(SIGALRM, update_progress_meter);
                 bytes = (bytes + 512) / 1024;          alarm(PROGRESSTIME);
         if (i == 0) {          errno = save_errno;
                 i++;  
                 bytes = (bytes + 512) / 1024;  
         }  
         snprintf(buf, size, "%3lld.%1lld%c%s",  
             (long long) (bytes + 5) / 100,  
             (long long) (bytes + 5) / 10 % 10,  
             unit[i],  
             i ? "B" : " ");  
 }  }
   
 static void  static int
 format_size(char *buf, int size, off_t bytes)  foregroundproc(void)
 {  {
         int i;          static pid_t pgrp = -1;
           int ctty_pgrp;
   
         for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++)          if (pgrp == -1)
                 bytes = (bytes + 512) / 1024;                  pgrp = getpgrp();
         snprintf(buf, size, "%4lld%c%s",  
             (long long) bytes,          return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 &&
             unit[i],                   ctty_pgrp == pgrp));
             i ? "B" : " ");  
 }  }
   
 void  static void
 refresh_progress_meter(void)  draw_progress_meter()
 {  {
         char buf[MAX_WINSIZE + 1];          static const char spaces[] = "                          "
         time_t now;              "                                                   "
         off_t transferred;              "                                                   "
               "                                                   "
               "                                                   "
               "                                                   ";
           static const char prefixes[] = " KMGTP";
           struct timeval now, td, wait;
           off_t cursize, abbrevsize, bytespersec;
         double elapsed;          double elapsed;
         int percent;          int ratio, remaining, i, ai, bi, nspaces;
         off_t bytes_left;          char buf[512];
         int cur_speed;  
         int hours, minutes, seconds;  
         int i, len;  
         int file_len;  
   
         transferred = *counter - cur_pos;          if (foregroundproc() == 0)
         cur_pos = *counter;                  return;
         now = time(NULL);  
         bytes_left = end_pos - cur_pos;  
   
         if (bytes_left > 0)          (void) gettimeofday(&now, (struct timezone *) 0);
                 elapsed = now - last_update;          cursize = *statbytes;
         else {          if (totalbytes != 0) {
                 elapsed = now - start;                  ratio = 100.0 * cursize / totalbytes;
                 /* Calculate true total speed when done */                  ratio = MAX(ratio, 0);
                 transferred = end_pos;                  ratio = MIN(ratio, 100);
                 bytes_per_second = 0;          } else
         }                  ratio = 100;
   
         /* calculate speed */          abbrevsize = cursize;
         if (elapsed != 0)          for (ai = 0; abbrevsize >= 10000 && ai < sizeof(prefixes); ai++)
                 cur_speed = (transferred / elapsed);                  abbrevsize >>= 10;
         else  
                 cur_speed = transferred;  
   
 #define AGE_FACTOR 0.9          timersub(&now, &lastupdate, &wait);
         if (bytes_per_second != 0) {          if (cursize > lastsize) {
                 bytes_per_second = (bytes_per_second * AGE_FACTOR) +                  lastupdate = now;
                     (cur_speed * (1.0 - AGE_FACTOR));                  lastsize = cursize;
         } else                  wait.tv_sec = 0;
                 bytes_per_second = cur_speed;          }
           timersub(&now, &start, &td);
           elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
   
         /* filename */          bytespersec = 0;
         buf[0] = '\0';          if (cursize > 0) {
         file_len = win_size - 35;                  bytespersec = cursize;
         if (file_len > 0) {                  if (elapsed > 0.0)
                 len = snprintf(buf, file_len + 1, "\r%s", file);                          bytespersec /= elapsed;
                 if (len < 0)  
                         len = 0;  
                 for (i = len;  i < file_len; i++ )  
                         buf[i] = ' ';  
                 buf[file_len] = '\0';  
         }          }
           for (bi = 1; bytespersec >= 1024000 && bi < sizeof(prefixes); bi++)
                   bytespersec >>= 10;
   
         /* percent of transfer done */          nspaces = MIN(get_tty_width() - 79, sizeof(spaces) - 1);
         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 */          snprintf(buf, sizeof(buf),
         format_size(buf + strlen(buf), win_size - strlen(buf),              "\r%-45.45s%.*s%3d%% %4lld%c%c %3lld.%01d%cB/s",
             cur_pos);              curfile,
         strlcat(buf, " ", win_size);              nspaces,
               spaces,
               ratio,
               (long long)abbrevsize,
               prefixes[ai],
               ai == 0 ? ' ' : 'B',
               (long long)(bytespersec / 1024),
               (int)((bytespersec % 1024) * 10 / 1024),
               prefixes[bi]
           );
   
         /* bandwidth usage */          if (cursize <= 0 || elapsed <= 0.0 || cursize > totalbytes) {
         format_rate(buf + strlen(buf), win_size - strlen(buf),                  snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
             bytes_per_second);                      "   --:-- ETA");
         strlcat(buf, "/s ", win_size);          } else if (wait.tv_sec >= STALLTIME) {
                   snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
         /* ETA */                      " - stalled -");
         if (!transferred)          } else {
                 stalled += elapsed;                  if (cursize != totalbytes)
         else                          remaining = (int)(totalbytes / (cursize / elapsed) -
                 stalled = 0;                              elapsed);
   
         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                  else
                         seconds = elapsed;                          remaining = elapsed;
   
                 hours = seconds / 3600;                  i = remaining / 3600;
                 seconds -= hours * 3600;                  if (i)
                 minutes = seconds / 60;                          snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
                 seconds -= minutes * 60;                              "%2d:", i);
   
                 if (hours != 0)  
                         snprintf(buf + strlen(buf), win_size - strlen(buf),  
                             "%d:%02d:%02d", hours, minutes, seconds);  
                 else                  else
                         snprintf(buf + strlen(buf), win_size - strlen(buf),                          snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
                             "  %02d:%02d", minutes, seconds);                              "   ");
                   i = remaining % 3600;
                 if (bytes_left > 0)                  snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
                         strlcat(buf, " ETA", win_size);                      "%02d:%02d%s", i / 60, i % 60,
                 else                      (cursize != totalbytes) ? " ETA" : "    ");
                         strlcat(buf, "    ", win_size);  
         }          }
           atomicio(write, fileno(stdout), buf, strlen(buf));
         atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1);  
         last_update = now;  
 }  }
   
 static void  static int
 update_progress_meter(int ignore)  get_tty_width(void)
 {  {
         int save_errno;  
   
         save_errno = errno;  
   
         if (can_output())  
                 refresh_progress_meter();  
   
         signal(SIGALRM, update_progress_meter);  
         alarm(UPDATE_INTERVAL);  
         errno = save_errno;  
 }  
   
 void  
 start_progress_meter(char *f, off_t filesize, off_t *stat)  
 {  
         struct winsize winsize;          struct winsize winsize;
   
         start = last_update = time(NULL);          if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)
         file = f;                  return (winsize.ws_col ? winsize.ws_col : 80);
         end_pos = filesize;          else
         cur_pos = 0;                  return (80);
         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();  
   
         signal(SIGALRM, update_progress_meter);  
         alarm(UPDATE_INTERVAL);  
 }  
   
 void  
 stop_progress_meter(void)  
 {  
         alarm(0);  
   
         if (!can_output())  
                 return;  
   
         /* Ensure we complete the progress */  
         if (cur_pos != end_pos)  
                 refresh_progress_meter();  
   
         atomicio(vwrite, STDOUT_FILENO, "\n", 1);  
 }  }

Legend:
Removed from v.1.3.2.2  
changed lines
  Added in v.1.4