[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.4.1 and 1.3.4.2

version 1.3.4.1, 2003/04/01 10:38:57 version 1.3.4.2, 2003/09/16 21:20:26
Line 1 
Line 1 
 /*  /*
  * Copyright (c) 1999 Theo de Raadt.  All rights reserved.   * Copyright (c) 2003 Nils Nordman.  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 23 
Line 22 
  * 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 <libgen.h>  
   
 #include "atomicio.h"  
 #include "progressmeter.h"  #include "progressmeter.h"
   #include "atomicio.h"
   
 /* Number of seconds before xfer considered "stalled". */  #define DEFAULT_WINSIZE 80
 #define STALLTIME       5  #define MAX_WINSIZE 512
 /* alarm() interval for updating progress meter. */  #define PADDING 1               /* padding between the progress indicators */
 #define PROGRESSTIME    1  #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 void update_progress_meter(int);  static int can_output(void);
   
 /* Returns non-zero if we are the foreground process. */  /* formats and inserts the specified size into the given buffer */
 static int foregroundproc(void);  static void format_size(char *, int, off_t);
   static void format_rate(char *, int, off_t);
   
 /* Returns width of the terminal (for progress meter calculations). */  /* updates the progressmeter to reflect the current state of the transfer */
 static int get_tty_width(void);  void refresh_progress_meter(void);
   
 /* Visual statistics about files as they are transferred. */  /* signal handler for updating the progress meter */
 static void draw_progress_meter(void);  static void update_progress_meter(int);
   
 /* Time a transfer started. */  static time_t start;            /* start progress */
 static struct timeval start;  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 */
   
 /* Number of bytes of current file transferred so far. */  /* units for format_size */
 static volatile off_t *statbytes;  static const char unit[] = " KMGT";
   
 /* Total size of current file. */  static int
 static off_t totalbytes;  can_output(void)
   
 /* 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)          return (getpgrp() == tcgetpgrp(STDOUT_FILENO));
                 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
 update_progress_meter(int ignore)  format_rate(char *buf, int size, off_t bytes)
 {  {
         int save_errno = errno;          int i;
   
         draw_progress_meter();          bytes *= 100;
         signal(SIGALRM, update_progress_meter);          for (i = 0; bytes >= 100*1000 && unit[i] != 'T'; i++)
         alarm(PROGRESSTIME);                  bytes = (bytes + 512) / 1024;
         errno = save_errno;          if (i == 0) {
                   i++;
                   bytes = (bytes + 512) / 1024;
           }
           snprintf(buf, size, "%3lld.%1lld%c%s",
               (long long) bytes / 100,
               (long long) (bytes + 5) / 10 % 10,
               unit[i],
               i ? "B" : " ");
 }  }
   
 static int  static void
 foregroundproc(void)  format_size(char *buf, int size, off_t bytes)
 {  {
         static pid_t pgrp = -1;          int i;
         int ctty_pgrp;  
   
         if (pgrp == -1)          for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++)
                 pgrp = getpgrp();                  bytes = (bytes + 512) / 1024;
           snprintf(buf, size, "%4lld%c%s",
         return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 &&              (long long) bytes,
                  ctty_pgrp == pgrp));              unit[i],
               i ? "B" : " ");
 }  }
   
 static void  void
 draw_progress_meter()  refresh_progress_meter(void)
 {  {
         static const char spaces[] = "                          "          char buf[MAX_WINSIZE + 1];
             "                                                   "          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 ratio, remaining, i, ai, bi, nspaces;          int percent;
         char buf[512];          int bytes_left;
           int cur_speed;
           int hours, minutes, seconds;
           int i, len;
           int file_len;
   
         if (foregroundproc() == 0)          transferred = *counter - cur_pos;
                 return;          cur_pos = *counter;
           now = time(NULL);
           bytes_left = end_pos - cur_pos;
   
         (void) gettimeofday(&now, (struct timezone *) 0);          if (bytes_left > 0)
         cursize = *statbytes;                  elapsed = now - last_update;
         if (totalbytes != 0) {          else
                 ratio = 100.0 * cursize / totalbytes;                  elapsed = now - start;
                 ratio = MAX(ratio, 0);  
                 ratio = MIN(ratio, 100);  
         } else  
                 ratio = 100;  
   
         abbrevsize = cursize;          /* calculate speed */
         for (ai = 0; abbrevsize >= 10000 && ai < sizeof(prefixes); ai++)          if (elapsed != 0)
                 abbrevsize >>= 10;                  cur_speed = (transferred / elapsed);
           else
                   cur_speed = 0;
   
         timersub(&now, &lastupdate, &wait);  #define AGE_FACTOR 0.9
         if (cursize > lastsize) {          if (bytes_per_second != 0) {
                 lastupdate = now;                  bytes_per_second = (bytes_per_second * AGE_FACTOR) +
                 lastsize = cursize;                      (cur_speed * (1.0 - AGE_FACTOR));
                 wait.tv_sec = 0;          } else
         }                  bytes_per_second = cur_speed;
         timersub(&now, &start, &td);  
         elapsed = td.tv_sec + (td.tv_usec / 1000000.0);  
   
         bytespersec = 0;          /* filename */
         if (cursize > 0) {          buf[0] = '\0';
                 bytespersec = cursize;          file_len = win_size - 35;
                 if (elapsed > 0.0)          if (file_len > 0) {
                         bytespersec /= elapsed;                  len = snprintf(buf, file_len + 1, "\r%s", file);
                   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;  
   
         nspaces = MIN(get_tty_width() - 79, sizeof(spaces) - 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);
   
         snprintf(buf, sizeof(buf),          /* amount transferred */
             "\r%-45.45s%.*s%3d%% %4lld%c%c %3lld.%01d%cB/s",          format_size(buf + strlen(buf), win_size - strlen(buf),
             curfile,              cur_pos);
             nspaces,          strlcat(buf, " ", win_size);
             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) {          /* bandwidth usage */
                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),          format_rate(buf + strlen(buf), win_size - strlen(buf),
                     "   --:-- ETA");              bytes_per_second);
         } else if (wait.tv_sec >= STALLTIME) {          strlcat(buf, "/s ", win_size);
                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),  
                     " - stalled -");          /* ETA */
         } else {          if (!transferred)
                 if (cursize != totalbytes)                  stalled += elapsed;
                         remaining = (int)(totalbytes / (cursize / elapsed) -          else
                             elapsed);                  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                  else
                         remaining = elapsed;                          seconds = elapsed;
   
                 i = remaining / 3600;                  hours = seconds / 3600;
                 if (i)                  seconds -= hours * 3600;
                         snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),                  minutes = seconds / 60;
                             "%2d:", i);                  seconds -= minutes * 60;
   
                   if (hours != 0)
                           snprintf(buf + strlen(buf), win_size - strlen(buf),
                               "%d:%02d:%02d", hours, minutes, seconds);
                 else                  else
                         snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),                          snprintf(buf + strlen(buf), win_size - strlen(buf),
                             "   ");                              "  %02d:%02d", minutes, seconds);
                 i = remaining % 3600;  
                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),                  if (bytes_left > 0)
                     "%02d:%02d%s", i / 60, i % 60,                          strlcat(buf, " ETA", win_size);
                     (cursize != totalbytes) ? " ETA" : "    ");                  else
                           strlcat(buf, "    ", win_size);
         }          }
         atomicio(write, fileno(stdout), buf, strlen(buf));  
           atomicio(vwrite, STDOUT_FILENO, buf, win_size);
           last_update = now;
 }  }
   
 static int  static void
 get_tty_width(void)  update_progress_meter(int ignore)
 {  {
           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;
   
         if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1)          start = last_update = time(NULL);
                 return (winsize.ws_col ? winsize.ws_col : 80);          file = f;
         else          end_pos = filesize;
                 return (80);          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();
   
           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.4.1  
changed lines
  Added in v.1.3.4.2